commit 51f037f03e08c06412edefe2714427ae8b4812a2 Author: archive Date: Tue Jun 13 04:19:35 2023 +0000 as released 1998-11-24 diff --git a/Toolkit/Designer/Download Acrobat Reader.url b/Toolkit/Designer/Download Acrobat Reader.url new file mode 100644 index 0000000..c6db7f4 --- /dev/null +++ b/Toolkit/Designer/Download Acrobat Reader.url @@ -0,0 +1,3 @@ +[InternetShortcut] +URL=http://www.adobe.com/acrobat/ +Modified=E0B6E1A7070EBE01F2 diff --git a/Toolkit/Designer/HereticEd.lnk b/Toolkit/Designer/HereticEd.lnk new file mode 100644 index 0000000..445500f Binary files /dev/null and b/Toolkit/Designer/HereticEd.lnk differ diff --git a/Toolkit/Designer/HereticEd/Heretic2.qe4 b/Toolkit/Designer/HereticEd/Heretic2.qe4 new file mode 100644 index 0000000..0bbab2c --- /dev/null +++ b/Toolkit/Designer/HereticEd/Heretic2.qe4 @@ -0,0 +1,55 @@ +{ +// maps will be loaded and saved from /maps +"basepath" "C:\PROG~FBU\HERE~VP5\base" + +// you are using your local machine to bsp, set rshcmd to "" +// and remotebasebath to the same thing as basepath. +// if you are using a remote unix host, remotebasepath +// will usually be different. +// +// +"rshcmd" "C:\PROG~FBU\HERE~VP5\Toolkit\Designer\HereticEd\batch\" + +"remotebasepath" "C:\PROG~FBU\HERE~VP5\base" + + + +// the entity classes are found by parsing through +// all the files in , looking for +// /*QUAKED comments + +"entitypath" "C:\PROG~FBU\HERE~VP5\Toolkit\Programming\GameCode\game\*.c" + +// the "textures" menu is filled with all of the directories +// found under . All texture references from maps +// have implicitly prepended. +// The textures directory can be duplicated on a local harddrive +// for better performance. + +"texturepath" "C:\PROG~FBU\HERE~VP5\base\textures" + +// every five minutes, the editor will autosave a map if it is dirty. +// this should be on a local drive, so multiple people editing +// maps don't collide + +"autosave" "C:\PROG~FBU\HERE~VP5\base\maps\autosave.map" + +// the "bsp" menu in QuakeEd is filled with the following bsp_* commands +// when selected, the value string will be expanded then executed in the +// background. +// ! will be replaced with +// $ will be replaced with /maps/ +// @ is changed to a quote(in case you need one in the command line) + +"bsp_Relight_Qrad" "!relight.bat $" +"bsp_novis" "!novis.bat $" +"bsp_Entities" "!onlyents.bat $" +"bsp_FullVis (nowater)" "!fullvisw.bat $" +"bsp_FullVis" "!fullvis.bat $" +"bsp_FullVis (no qrad)" "!fullvisnoq.bat $" +"bsp_FullVis (qrad -extra)" "!fullvisxq.bat $" +"bsp_FullVis (nodetail, qrad -extra)" "!fullvisnodetail.bat $" +"bsp_FastVis" "!fastvis.bat $" +"bsp_FastVis (nowater)" "!fastvisnowater.bat $" +} + diff --git a/Toolkit/Designer/HereticEd/HereticEd.exe b/Toolkit/Designer/HereticEd/HereticEd.exe new file mode 100755 index 0000000..e94a99b Binary files /dev/null and b/Toolkit/Designer/HereticEd/HereticEd.exe differ diff --git a/Toolkit/Designer/HereticEd/batch/1024fullvis.bat b/Toolkit/Designer/HereticEd/batch/1024fullvis.bat new file mode 100644 index 0000000..c24ab27 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/1024fullvis.bat @@ -0,0 +1,5 @@ +@echo Full Vis +@echo . +qbsp3 -chop 1024 %1 +qvis3 %1 +qrad3 %1 diff --git a/Toolkit/Designer/HereticEd/batch/512fullvis.bat b/Toolkit/Designer/HereticEd/batch/512fullvis.bat new file mode 100644 index 0000000..ec7e549 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/512fullvis.bat @@ -0,0 +1,5 @@ +@echo Full Vis +@echo . +qbsp3 -chop 512 %1 +qvis3 %1 +qrad3 %1 diff --git a/Toolkit/Designer/HereticEd/batch/FULLVIS.BAT b/Toolkit/Designer/HereticEd/batch/FULLVIS.BAT new file mode 100644 index 0000000..f7116b7 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/FULLVIS.BAT @@ -0,0 +1,5 @@ +@echo Full Vis +@echo . +qbsp3 %1 +qvis3 %1 +qrad3 %1 diff --git a/Toolkit/Designer/HereticEd/batch/Visrad.bat b/Toolkit/Designer/HereticEd/batch/Visrad.bat new file mode 100644 index 0000000..0b5cc3c --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/Visrad.bat @@ -0,0 +1,5 @@ +@echo Vis Rad +@echo . +qbsp3 -onlyents %1 +qvis3 %1 +qrad3 %1 diff --git a/Toolkit/Designer/HereticEd/batch/fastvis.bat b/Toolkit/Designer/HereticEd/batch/fastvis.bat new file mode 100644 index 0000000..e2d75b3 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/fastvis.bat @@ -0,0 +1,5 @@ +@echo Fast Vis +@echo . +qbsp3 %1 +qvis3 -fast %1 +qrad3 -bounce 0 %1 diff --git a/Toolkit/Designer/HereticEd/batch/fastvisnoqrad.bat b/Toolkit/Designer/HereticEd/batch/fastvisnoqrad.bat new file mode 100644 index 0000000..1884368 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/fastvisnoqrad.bat @@ -0,0 +1,4 @@ +@echo Fast Vis No QRad +@echo . +qbsp3 %1 +qvis3 -fast %1 diff --git a/Toolkit/Designer/HereticEd/batch/fastvisnowater.bat b/Toolkit/Designer/HereticEd/batch/fastvisnowater.bat new file mode 100644 index 0000000..bd99160 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/fastvisnowater.bat @@ -0,0 +1,5 @@ +@echo Fast Vis No Water +@echo . +qbsp3 -nowater %1 +qvis3 -fast %1 +qrad3 -bounce 0 %1 diff --git a/Toolkit/Designer/HereticEd/batch/fullvisd.bat b/Toolkit/Designer/HereticEd/batch/fullvisd.bat new file mode 100644 index 0000000..50d1965 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/fullvisd.bat @@ -0,0 +1,5 @@ +@echo Full Vis +@echo . +bin_nt\qbsp3 %1 +bin_nt\qvis3 %1 +bin_nt\qrad3 -chop 256 %1 diff --git a/Toolkit/Designer/HereticEd/batch/fullvisnodetail.bat b/Toolkit/Designer/HereticEd/batch/fullvisnodetail.bat new file mode 100644 index 0000000..45f2e85 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/fullvisnodetail.bat @@ -0,0 +1,5 @@ +@echo Full Vis No Detail +@echo . +qbsp3 -nodetail %1 +qvis3 %1 +qrad3 -extra %1 diff --git a/Toolkit/Designer/HereticEd/batch/fullvisnoq.bat b/Toolkit/Designer/HereticEd/batch/fullvisnoq.bat new file mode 100644 index 0000000..ba2e123 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/fullvisnoq.bat @@ -0,0 +1,4 @@ +@echo Full Vis No QRad +@echo . +qbsp3 %1 +qvis3 %1 diff --git a/Toolkit/Designer/HereticEd/batch/fullvisw.bat b/Toolkit/Designer/HereticEd/batch/fullvisw.bat new file mode 100644 index 0000000..19d8830 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/fullvisw.bat @@ -0,0 +1,5 @@ +@echo Full Vis No Water +@echo . +qbsp3 -nowater %1 +qvis3 %1 +qrad3 %1 diff --git a/Toolkit/Designer/HereticEd/batch/fullvisxq.bat b/Toolkit/Designer/HereticEd/batch/fullvisxq.bat new file mode 100644 index 0000000..00e1ac7 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/fullvisxq.bat @@ -0,0 +1,5 @@ +@echo Full Vis Extra QRad +@echo . +qbsp3 %1 +qvis3 %1 +qrad3 -extra %1 diff --git a/Toolkit/Designer/HereticEd/batch/minefullvis.bat b/Toolkit/Designer/HereticEd/batch/minefullvis.bat new file mode 100644 index 0000000..a0d8ac2 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/minefullvis.bat @@ -0,0 +1,5 @@ +@echo Full Vis +@echo . +qbsp3 %1 +qvis3 %1 +qrad3 -chop 128 %1 \ No newline at end of file diff --git a/Toolkit/Designer/HereticEd/batch/novis.bat b/Toolkit/Designer/HereticEd/batch/novis.bat new file mode 100644 index 0000000..3663e7e --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/novis.bat @@ -0,0 +1,3 @@ +@echo No Vis +@echo . +qbsp3 %1 diff --git a/Toolkit/Designer/HereticEd/batch/onlyents.bat b/Toolkit/Designer/HereticEd/batch/onlyents.bat new file mode 100644 index 0000000..bdeb92a --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/onlyents.bat @@ -0,0 +1,3 @@ +@echo Only Ents +@echo . +qbsp3 -onlyents %1 diff --git a/Toolkit/Designer/HereticEd/batch/relight.bat b/Toolkit/Designer/HereticEd/batch/relight.bat new file mode 100644 index 0000000..41de587 --- /dev/null +++ b/Toolkit/Designer/HereticEd/batch/relight.bat @@ -0,0 +1,4 @@ +@echo Relight +@echo . +qbsp3 -onlyents %1 +qrad3 %1 diff --git a/Toolkit/Designer/HereticEd/hereticed.bat b/Toolkit/Designer/HereticEd/hereticed.bat new file mode 100644 index 0000000..82e1040 --- /dev/null +++ b/Toolkit/Designer/HereticEd/hereticed.bat @@ -0,0 +1,4 @@ +@rem edit this line to the path where you installed the toolkit editor +path C:\PROG~FBU\HERE~VP5\Toolkit\Designer\HereticEd;%path +hereticed.exe heretic2.qe4 + diff --git a/Toolkit/Designer/HereticEd/qbsp3.exe b/Toolkit/Designer/HereticEd/qbsp3.exe new file mode 100755 index 0000000..afed2c9 Binary files /dev/null and b/Toolkit/Designer/HereticEd/qbsp3.exe differ diff --git a/Toolkit/Designer/HereticEd/qrad3.exe b/Toolkit/Designer/HereticEd/qrad3.exe new file mode 100755 index 0000000..6bc26f7 Binary files /dev/null and b/Toolkit/Designer/HereticEd/qrad3.exe differ diff --git a/Toolkit/Designer/HereticEd/qvis3.exe b/Toolkit/Designer/HereticEd/qvis3.exe new file mode 100755 index 0000000..1c4ff39 Binary files /dev/null and b/Toolkit/Designer/HereticEd/qvis3.exe differ diff --git a/Toolkit/Designer/HereticEdAcrobat.PDF b/Toolkit/Designer/HereticEdAcrobat.PDF new file mode 100644 index 0000000..94cd696 Binary files /dev/null and b/Toolkit/Designer/HereticEdAcrobat.PDF differ diff --git a/Toolkit/Designer/HereticEdDoc.doc b/Toolkit/Designer/HereticEdDoc.doc new file mode 100644 index 0000000..60bed19 Binary files /dev/null and b/Toolkit/Designer/HereticEdDoc.doc differ diff --git a/Toolkit/Designer/M8VIEW.EXE b/Toolkit/Designer/M8VIEW.EXE new file mode 100755 index 0000000..2e32cdb Binary files /dev/null and b/Toolkit/Designer/M8VIEW.EXE differ diff --git a/Toolkit/Designer/Shortcut to HereticEd.lnk b/Toolkit/Designer/Shortcut to HereticEd.lnk new file mode 100644 index 0000000..7f66f5e Binary files /dev/null and b/Toolkit/Designer/Shortcut to HereticEd.lnk differ diff --git a/Toolkit/Designer/ds.exe b/Toolkit/Designer/ds.exe new file mode 100755 index 0000000..5723570 Binary files /dev/null and b/Toolkit/Designer/ds.exe differ diff --git a/Toolkit/Designer/dsexamples/andoria/MSsithraStatue.ds b/Toolkit/Designer/dsexamples/andoria/MSsithraStatue.ds new file mode 100644 index 0000000..2cc378a --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/MSsithraStatue.ds @@ -0,0 +1,20 @@ +// Big statue falling if the Mutant Ssithra hits the tower. + +#include "../common/header.ds" +output "r:/base/ds/andoria" + +local entity tower +local entity statue + +tower = find entity with targetname "stbase" +statue = find entity with targetname "BigFatStatue" + +rotate entity tower by [-15,0,0] at 200 speed +move entity tower by [0,0,-16] at 100 speed + +rotate entity statue by [-15,0,0] at 400 speed +move entity statue by [-96,0,-24] at 400 speed + +play sound "misc/plattrem.wav" for entity tower + +exit diff --git a/Toolkit/Designer/dsexamples/andoria/breakout.ds b/Toolkit/Designer/dsexamples/andoria/breakout.ds new file mode 100644 index 0000000..10e43fb --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/breakout.ds @@ -0,0 +1,41 @@ +//the gorgon's break through the freakin wall! + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity blockone +local entity blocktwo +local int sig +local int sig2 +local int sig3 +local int sig4 + +field vector "velocity" + +blockone = find entity with targetname "blockone" +blocktwo = find entity with targetname "blocktwo" + +//start of script + +blockone.movetype = PHYSICSTYPE_NOCLIP +blocktwo.movetype = PHYSICSTYPE_NOCLIP + +play sound "doors/stoneend.wav" for entity blockone +play sound "doors/stoneend.wav" for entity blocktwo +move entity blockone by [0, -150, -24] at 700 speed signaling sig +rotate entity blockone by [0, 70, 90] at 400 speed signaling sig2 + +move entity blocktwo by [0, -200, -24] at 800 speed signaling sig3 +rotate entity blocktwo by [0, 130, 100] at 500 speed signaling sig4 + +wait for any clearing sig, sig2, sig3, sig4 + +use entity blocktwo + +blockone.movetype = PHYSICSTYPE_NONE +blocktwo.movetype = PHYSICSTYPE_NONE + +exit diff --git a/Toolkit/Designer/dsexamples/andoria/counter.ds b/Toolkit/Designer/dsexamples/andoria/counter.ds new file mode 100644 index 0000000..c876adf --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/counter.ds @@ -0,0 +1,42 @@ +//A one and a two and a... + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity door +local entity door2 +local entity camera +local int sig +local int sig2 + +door = find entity with targetname "bigdoor1" +door2 = find entity with targetname "bigdoor2" +camera = find entity with targetname "doorcam" + +//start er up + +suspend + +enable cinematics + +use entity camera + +move entity door by [0, 120, 0] at 30 speed signaling sig +move entity door2 by [0, -120, 0] at 30 speed signaling sig2 +play sound "doors/gendoorstart.wav" for entity door +play sound "doors/gendoorstart.wav" for entity door2 +wait 4.0 seconds +play sound "doors/gendoorstop.wav" for entity door +play sound "doors/gendoorstop.wav" for entity door2 +wait for all clearing sig, sig2 + +use entity camera + +disable cinematics + +exit + + diff --git a/Toolkit/Designer/dsexamples/andoria/crystal.ds b/Toolkit/Designer/dsexamples/andoria/crystal.ds new file mode 100644 index 0000000..3cade3b --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/crystal.ds @@ -0,0 +1,20 @@ +// the floating crystal puzzle piece. + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + + +local entity train1 +local entity train2 +field vector "angle_velocity" + + +train1 = find entity with targetname "train" +train2 = find entity with targetname "trainpuz" +train2.owner = train1 +train2.distance = 80 +train2.start_origin = [-80, 0, 0] +train2.movetype = PHYSICSTYPE_SCRIPT_ANGULAR + +train1.angle_velocity = [0, 90, 0] diff --git a/Toolkit/Designer/dsexamples/andoria/crystal2.ds b/Toolkit/Designer/dsexamples/andoria/crystal2.ds new file mode 100644 index 0000000..fe3f774 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/crystal2.ds @@ -0,0 +1,20 @@ +// the floating crystal puzzle piece. + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + + +local entity train1 +local entity train2 +field vector "angle_velocity" + + +train1 = find entity with targetname "train" +train2 = find entity with targetname "trainpuz" +train2.owner = train1 +train2.distance = 80 +train2.start_origin = [80, 0, 0] +train2.movetype = PHYSICSTYPE_SCRIPT_ANGULAR + +train1.angle_velocity = [0, 90, 0] diff --git a/Toolkit/Designer/dsexamples/andoria/diamondsign.ds b/Toolkit/Designer/dsexamples/andoria/diamondsign.ds new file mode 100644 index 0000000..4e82b1c --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/diamondsign.ds @@ -0,0 +1,131 @@ +// The Diamond thing falls down and goes boom. + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +local entity piece1 +local entity piece2 +local entity piece3 +local entity break + +local int sig +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int b1 +local int b2 + +piece1 = find entity with targetname "d1" +piece2 = find entity with targetname "d2" +piece3 = find entity with targetname "d3" +break = find entity with targetname "break" + + + +// in the begining + + break.movetype = PHYSICSTYPE_PUSH + + move entity piece1 by [0, 10, 5] at 300 speed signaling sig + move entity piece2 by [0, 10, 5] at 300 speed signaling sig1 + move entity piece3 by [0, 10, 5] at 300 speed signaling sig2 + move entity break by [0, 10, 5] at 300 speed signaling b1 + wait for all clearing sig, sig1, sig2, b1 + +//------------- + + move entity piece1 by [0, 10, -20] at 300 speed signaling sig + move entity piece2 by [0, 10, -20] at 300 speed signaling sig1 + move entity piece3 by [0, 10, -20] at 300 speed signaling sig2 + move entity break by [0, 10, -20] at 300 speed signaling b1 + wait for all clearing sig, sig1, sig2, b1 + +//------------- + + rotate entity piece1 by [-45, 0, 0] at 300 speed signaling sig + move entity piece1 by [0, 50, 0] at 300 speed signaling sig3 + + rotate entity piece2 by [-45, 0, 0] at 300 speed signaling sig1 + move entity piece2 by [0, 50, 0] at 300 speed signaling sig4 + + rotate entity piece3 by [-45, 0, 0] at 300 speed signaling sig2 + move entity piece3 by [0, 50, 0] at 300 speed signaling sig5 + + rotate entity break by [-45, 0, 0] at 300 speed signaling b1 + move entity break by [0, 50, 0] at 300 speed signaling b2 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, b1, b2 + +//-------------- + + rotate entity piece1 to [0, 45, -90] at 300 speed signaling sig + move entity piece1 by [20, 10, 15] at 300 speed signaling sig3 + + rotate entity piece2 to [0, 45, -90] at 300 speed signaling sig1 + move entity piece2 by [20, 10, 15] at 300 speed signaling sig4 + + rotate entity piece3 to [0, 45, -90] at 300 speed signaling sig2 + move entity piece3 by [20, 10, 15] at 300 speed signaling sig5 + + rotate entity break to [0, 45, -90] at 300 speed signaling b1 + move entity break by [20, 10, 15] at 300 speed signaling b2 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, b1, b2 + +//--------------- + + move entity piece1 by [30, 75, -255] at 500 speed signaling sig + move entity piece2 by [30, 75, -255] at 500 speed signaling sig1 + move entity piece3 by [30, 75, -255] at 500 speed signaling sig2 + move entity break by [30, 75, -255] at 500 speed signaling b1 + wait for all clearing sig, sig1, sig2, b1 + + use entity break + + play sound "misc/breakstone.wav" for entity piece1 + +//---------------- + + move entity piece1 by [0, 10, 10] at 300 speed signaling sig + move entity piece2 by [-10, 0, 10] at 300 speed signaling sig1 + move entity piece3 by [0, -10, 10] at 300 speed signaling sig2 + wait for all clearing sig, sig1, sig2 + +//---------------- + + move entity piece1 by [0, 10, -10] at 300 speed signaling sig + move entity piece2 by [-10, 0, -10] at 300 speed signaling sig1 + move entity piece3 by [0, -10, -10] at 300 speed signaling sig2 + wait for all clearing sig, sig1, sig2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/andoria/diamondsign2.ds b/Toolkit/Designer/dsexamples/andoria/diamondsign2.ds new file mode 100644 index 0000000..f0e16f4 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/diamondsign2.ds @@ -0,0 +1,46 @@ +// The Diamond thing falls down and goes boom. +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +local entity piece2 +local int sig + +field vector "velocity" + +piece2 = find entity with targetname "d2" + +move entity piece2 by [0, 0, 5] at 500 speed signaling sig +wait for all clearing sig + +move entity piece2 by [0, 0, -16] at 500 speed signaling sig +wait for all clearing sig + +rotate entity piece2 by [-45, 0, 0] at 300 speed signaling sig +wait for all clearing sig + +piece2.velocity = [0, 50, 0] + +rotate entity piece2 to [0, 45, -90] at 400 speed signaling sig +wait for all clearing sig + +piece2.velocity = [0, 0, 0] + +move entity piece2 by [0, 20, 40] at 500 speed signaling sig +wait for all clearing sig + +piece2.velocity = [0, 470, -270] + +rotate entity piece2 to [0, 0, -270] at 400 speed signaling sig +wait for all clearing sig + +piece2.velocity = [0, 0, 0] + +move entity piece2 by [0, 50, -130] at 450 speed signaling sig +wait for all clearing sig + +move entity piece2 by [-10, -10, 10] at 500 speed signaling sig +wait for all clearing sig + +move entity piece2 by [-10, -10, -10] at 500 speed signaling sig +wait for all clearing sig \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/andoria/diamondsign3.ds b/Toolkit/Designer/dsexamples/andoria/diamondsign3.ds new file mode 100644 index 0000000..de7058d --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/diamondsign3.ds @@ -0,0 +1,47 @@ +// The Diamond thing falls down and goes boom. + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +local entity piece3 +local int sig + +field vector "velocity" + +piece3 = find entity with targetname "d3" + +move entity piece3 by [0, 0, 5] at 500 speed signaling sig +wait for all clearing sig + +move entity piece3 by [0, 0, -16] at 500 speed signaling sig +wait for all clearing sig + +rotate entity piece3 by [-45, 0, 0] at 300 speed signaling sig +wait for all clearing sig + +piece3.velocity = [0, 50, 0] + +rotate entity piece3 to [0, 45, -90] at 400 speed signaling sig +wait for all clearing sig + +piece3.velocity = [0, 0, 0] + +move entity piece3 by [0, 20, 40] at 500 speed signaling sig +wait for all clearing sig + +piece3.velocity = [0, 470, -270] + +rotate entity piece3 to [0, 0, -270] at 400 speed signaling sig +wait for all clearing sig + +piece3.velocity = [0, 0, 0] + +move entity piece3 by [0, 50, -130] at 450 speed signaling sig +wait for all clearing sig + +move entity piece3 by [10, -5, 10] at 500 speed signaling sig +wait for all clearing sig + +move entity piece3 by [10, -5, -10] at 500 speed signaling sig +wait for all clearing sig \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/andoria/firewall.ds b/Toolkit/Designer/dsexamples/andoria/firewall.ds new file mode 100644 index 0000000..c004d4e --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/firewall.ds @@ -0,0 +1,117 @@ +//Picking up firewall weapon. + + +#include "../common/header.ds" + +output "R:/base/ds/andoria" + +//define entity + +local entity flamel +local entity flamer +//local entity ped +local entity barreltop +local entity barrelback +local entity rubblefront +local entity rubbleback +local entity camera +local entity camtarget +local entity c1 +local entity player1 +local entity wall + +local int sig +local int sig1 + +flamel = find entity with targetname "flamel" +flamer = find entity with targetname "flamer" +//ped = find entity with targetname "ped" +barreltop = find entity with targetname "barreltop" +barrelback = find entity with targetname "barrelback" +rubblefront = find entity with targetname "rubble1" +rubbleback = find entity with targetname "r2" +camera = find entity with targetname "camera" +camtarget = find entity with targetname "camtarget" +c1 = find entity with targetname "c1" +player1 = get entity activator +wall = find entity with targetname "wall" + +enable cinematics + + copy player attributes from entity player1 to entity c1 + c1.modelindex = c1.count + c1.solid = SOLID_SOLID + c1.movetype = 4 + +// move entity ped by [0, 0, -12] at 30 speed signaling sig +// wait for all clearing sig + + +//move fire + + use entity camera + + flamel.movetype = PHYSICSTYPE_NOCLIP + flamer.movetype = PHYSICSTYPE_NOCLIP + + move entity flamel by [64, 4, 0] at 60 speed signaling sig + + move entity flamer by [64, 0, 0] at 60 speed signaling sig1 + wait for all clearing sig, sig1 + + move entity flamel by [0, 0, -16] at 60 speed signaling sig + + move entity flamer by [0, 0, -16] at 60 speed signaling sig1 + wait for all clearing sig, sig1 + + move entity flamel by [48, 0, 0] at 60 speed signaling sig + + move entity flamer by [48, 0, 0] at 60 speed signaling sig1 + wait for all clearing sig, sig1 + + move entity flamel by [0, 0, -20] at 60 speed signaling sig + + move entity flamer by [0, 0, -20] at 60 speed signaling sig1 + wait for all clearing sig, sig1 + + camtarget.movetype = PHYSICSTYPE_PUSH + move entity camtarget by [640, 0, 0] at 100 speed + + move entity flamel by [640, 0, 0] at 400 speed signaling sig + + move entity flamer by [640, 0, 0] at 400 speed signaling sig1 + wait for all clearing sig, sig1 + + use entity rubblefront + + use entity barreltop + + wait .3 seconds + + use entity wall + + use entity rubbleback + + use entity barrelback + +// move entity flamel by [0, 0, -640] at 1000 speed signaling sig + +// move entity flamer by [0, 0, -640] at 1000 speed signaling sig1 +// wait for all clearing sig, sig1 + + + wait 2 seconds + + use entity camera + + player1.origin = c1.origin + player1.p_origin = c1.origin + set view angles of entity player1 to c1.angles + + c1.modelindex = 0 + c1.solid = SOLID_NOT + +disable cinematics + + + diff --git a/Toolkit/Designer/dsexamples/andoria/flydoor.ds b/Toolkit/Designer/dsexamples/andoria/flydoor.ds new file mode 100644 index 0000000..e4ddee7 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/flydoor.ds @@ -0,0 +1,32 @@ +//the gorgon's break through the freakin wall! + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity door +local int sig +local int sig2 + +door = find entity with targetname "metaldoor" + +//start of script + +//door.movetype = PHYSICSTYPE_NOCLIP + +play sound "objects/klang.wav" for entity door + +move entity door by [60, -150, -56] at 400 speed signaling sig +rotate entity door by [0, 160, 90] at 400 speed signaling sig2 + +wait for all clearing sig, sig2 + +use entity door + +play sound "doors/thud4.wav" for entity door + +//door.movetype = PHYSICSTYPE_PUSH + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/andoria/healerstatue.ds b/Toolkit/Designer/dsexamples/andoria/healerstatue.ds new file mode 100644 index 0000000..a990683 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/healerstatue.ds @@ -0,0 +1,80 @@ +//The super duper guardian statue rotater lever-o-matic thing a ma bob! + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity leverblock +local entity lever +local entity guardian +local entity secdoor +local entity camera +local entity activate +local entity counter +local entity c1 +local entity player1 + +local int sig +local int sig2 + +leverblock = find entity with targetname "block" +lever = find entity with targetname "lever" +guardian = find entity with targetname "guard1" +secdoor = find entity with targetname "secret" +camera = find entity with targetname "guardcam" +activate = find entity with targetname "active" +counter = find entity with targetname "counter" +c1 = find entity with targetname "c1" +player1 = get entity activator + +//move lever outward (cool huh?) +move entity secdoor by [-16, 0, 0] at 30 speed signaling sig +wait for all clearing sig +move entity secdoor by [0, 120, 0] at 40 speed signaling sig +wait for all clearing sig + +wait .3 seconds +lever.movetype = PHYSICSTYPE_PUSH +play sound "doors/stonestart.wav" for entity lever +move entity lever by [48, 0, 0] at 30 speed signaling sig +move entity leverblock by [48, 0, 0] at 30 speed signaling sig2 +wait for all clearing sig, sig2 + +enable trigger entity activate + +suspend + +//use lever... rotate statue + +use entity lever +wait 1 seconds + +enable cinematics + + copy player attributes from entity player1 to entity c1 + c1.modelindex = c1.count + c1.solid = SOLID_SOLID + c1.movetype = 4 + +use entity camera + +guardian.movetype = PHYSICSTYPE_PUSH +play sound "doors/gendoorstart.wav" for entity guardian +rotate entity guardian by [0, -90, 0] over 3 seconds signaling sig +wait 3.0 seconds +play sound "doors/gendoorstop.wav" for entity guardian +wait for all clearing sig + + player1.origin = c1.origin + player1.p_origin = c1.origin + set view angles of entity player1 to c1.angles + + c1.modelindex = 0 + c1.solid = SOLID_NOT + +disable cinematics +use entity camera +use entity counter +exit diff --git a/Toolkit/Designer/dsexamples/andoria/healerstatue2.ds b/Toolkit/Designer/dsexamples/andoria/healerstatue2.ds new file mode 100644 index 0000000..94cf3a5 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/healerstatue2.ds @@ -0,0 +1,80 @@ +//The super duper guardian statue (part 2) + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity leverblock +local entity lever +local entity guardian +local entity secdoor +local entity camera +local entity activate +local entity counter +local entity c2 +local entity player1 + +local int sig +local int sig2 + +leverblock = find entity with targetname "block2" +lever = find entity with targetname "lever2" +guardian = find entity with targetname "guard2" +secdoor = find entity with targetname "secret2" +camera = find entity with targetname "guardcam2" +activate = find entity with targetname "active2" +counter = find entity with targetname "counter" +c2 = find entity with targetname "c2" +player1 = get entity activator + +//move lever outward (cool huh?) +move entity secdoor by [-16, 0, 0] at 30 speed signaling sig +wait for all clearing sig +move entity secdoor by [0, -120, 0] at 40 speed signaling sig +wait for all clearing sig + +wait .3 seconds +lever.movetype = PHYSICSTYPE_PUSH +play sound "doors/stonestart.wav" for entity lever +move entity lever by [48, 0, 0] at 30 speed signaling sig +move entity leverblock by [48, 0, 0] at 30 speed signaling sig2 +wait for all clearing sig, sig2 + +enable trigger entity activate + +suspend + +//use lever... rotate statue + +use entity lever +wait 1 seconds + +enable cinematics + + copy player attributes from entity player1 to entity c2 + c2.modelindex = c2.count + c2.solid = SOLID_SOLID + c2.movetype = 4 + +use entity camera + +guardian.movetype = PHYSICSTYPE_PUSH +play sound "doors/gendoorstart.wav" for entity guardian +rotate entity guardian by [0, 90, 0] over 3 seconds signaling sig +wait 3.0 seconds +play sound "doors/gendoorstop.wav" for entity guardian +wait for all clearing sig + + player1.origin = c2.origin + player1.p_origin = c2.origin + set view angles of entity player1 to c2.angles + + c2.modelindex = 0 + c2.solid = SOLID_NOT + +disable cinematics +use entity camera +use entity counter +exit diff --git a/Toolkit/Designer/dsexamples/andoria/jumplift1.ds b/Toolkit/Designer/dsexamples/andoria/jumplift1.ds new file mode 100644 index 0000000..46336b4 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/jumplift1.ds @@ -0,0 +1,111 @@ +//platform that raises block over stairs + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity plat +local entity buttons +local entity punch +local entity bars +local entity block +local entity back +local entity saw +local entity rope + +local int sig +local int sig2 +local int sig3 + +global int up_or_down1 +global int up_or_down2 + +plat = find entity with targetname "lifter" +buttons = find entity with targetname "buttonpunchers" +punch = find entity with targetname "punch" +bars = find entity with targetname "pusher2" +block = find entity with targetname "pickmeup" +back = find entity with targetname "pusher1" +saw = find entity with targetname "blade" +rope = find entity with targetname "rope" + +//start of script + +//plat moves down after checking to see if bars are in place +label downsy +if up_or_down2 = 0 + up_or_down1 = 1 + play sound "doors/elevatorstart.wav" for entity plat +// wait 0.9 seconds +// play sound "doors/elevatormove.wav" for entity plat + move entity plat by [0, 0, -176] at 100 speed signaling sig + wait for all clearing sig + play sound "doors/elevatorstop.wav" for entity plat + up_or_down1 = 0 + goto checkit +else + up_or_down1 = 1 + play sound "doors/elevatorstart.wav" for entity plat +// wait 0.9 seconds +// play sound "doors/elevatormove.wav" for entity plat + move entity plat by [0, 0, -144] at 100 speed signaling sig + wait for all clearing sig + play sound "doors/elevatorstop.wav" for entity plat + wait 2 seconds + play sound "doors/elevatorstart.wav" for entity plat +// wait 0.9 seconds +// play sound "doors/elevatormove.wav" for entity plat + move entity plat by [0, 0, 144] at 100 speed signaling sig + wait for all clearing sig + play sound "doors/elevatorstop.wav" for entity plat + up_or_down1 = 0 + goto holdon +endif + + +//pause to allow bars to be moved into place +label checkit + wait 10 seconds + goto upsy + +//plat moves up after checking to see if bars are in place +label upsy +if up_or_down2 = 0 + up_or_down1 = 1 + play sound "doors/elevatorstart.wav" for entity plat +// wait 0.9 seconds +// play sound "doors/elevatormove.wav" for entity plat + move entity plat by [0, 0, 176] at 100 speed signaling sig + wait for all clearing sig + play sound "doors/elevatorstop.wav" for entity plat + up_or_down1 = 0 + goto holdon +else + up_or_down1 = 1 + disable trigger entity buttons + disable trigger entity punch + play sound "doors/elevatorstart.wav" for entity plat +// wait 0.9 seconds +// play sound "doors/elevatormove.wav" for entity plat + move entity saw by [0, 0, 384] at 400 speed + move entity rope by [0, 0, 384] at 400 speed + move entity plat by [0, 0, 176] at 100 speed signaling sig + move entity bars by [0, 0, 176] at 100 speed signaling sig2 + move entity block by [0, 0, 176] at 100 speed signaling sig3 + wait for all clearing sig, sig2, sig3 + play sound "doors/elevatorstop.wav" for entity plat + play sound "doors/stonestart.wav" for entity back + move entity back by [0, -176, 0] at 300 speed signaling sig + exit +endif + +label holdon +suspend + +goto downsy + + + + diff --git a/Toolkit/Designer/dsexamples/andoria/jumplift2.ds b/Toolkit/Designer/dsexamples/andoria/jumplift2.ds new file mode 100644 index 0000000..de11017 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/jumplift2.ds @@ -0,0 +1,47 @@ +//blocking entities + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity back +local entity front +local entity crap + +global int up_or_down1 +global int up_or_down2 + +local int sig +local int sig2 + +back = find entity with targetname "pusher1" +front = find entity with targetname "pusher2" +crap = find entity with targetname "pickmeup" + +//start of script + +label start +if up_or_down1 = 0 + + if up_or_down2 = 0 + up_or_down2 = 1 + play sound "doors/stonestart.wav" for entity crap + play sound "doors/stonestart.wav" for entity back + move entity back by [0, 400, 0] at 300 speed signaling sig + move entity front by [0, 400, 0] at 300 speed signaling sig2 + else + up_or_down2 = 0 + play sound "doors/stonestart.wav" for entity front + play sound "doors/stonestart.wav" for entity back + move entity back by [0, -400, 0] at 300 speed signaling sig + move entity front by [0, -400, 0] at 300 speed signaling sig2 +endif +else + print 51 captioned +endif + +suspend + +goto start \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/andoria/jumpyboy.ds b/Toolkit/Designer/dsexamples/andoria/jumpyboy.ds new file mode 100644 index 0000000..4fcac29 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/jumpyboy.ds @@ -0,0 +1,24 @@ +//breaking part of jump platform + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity drop + +local int sig1 +local int sig2 + +drop = find entity with targetname "jumpbreak2" + +//start of script + +//drop.movetype = PHYSICSTYPE_NOCLIP +rotate entity drop by [0, 10, -180] at 400 speed signaling sig1 +move entity drop by [60, 80, -176] at 700 speed signaling sig2 +play sound "doors/objectdrop.wav" for entity drop +wait for all clearing sig1, sig2 +//drop.movetype = PHYSICSTYPE_PUSH +exit diff --git a/Toolkit/Designer/dsexamples/andoria/lift.ds b/Toolkit/Designer/dsexamples/andoria/lift.ds new file mode 100644 index 0000000..0bf308f --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/lift.ds @@ -0,0 +1,31 @@ +// a stupid lift i can't get to work anyother way. + + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + + +local entity lift + +local int sig + +lift = find entity with targetname "tom" + + +// start + +label start + +move entity lift by [0, 0, 246] over 3 seconds signaling sig +wait for all clearing sig + +wait 2 seconds + +move entity lift by [0, 0, -246] over 3 seconds signaling sig +wait for all clearing sig + +suspend + +goto start + diff --git a/Toolkit/Designer/dsexamples/andoria/roofcave.ds b/Toolkit/Designer/dsexamples/andoria/roofcave.ds new file mode 100644 index 0000000..019a7e6 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/roofcave.ds @@ -0,0 +1,160 @@ +//Roof caving in, in Andslums + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity roofcam +local entity camtrain +local entity domebreak1 +local entity domebreak3 +local entity domebreak4 +local entity domebreak5 +local entity domebreak6 +local entity domebreak7 +local entity domebreak8 +local entity domebreak9 +local entity dometrain +local entity dometrain10 +local entity dome1 +local entity dome2 +local entity dome3 +local entity walkway +local entity walkwaya +local entity quaker +local entity dmg +local entity corv +local entity player1 + +local int sig +local int sig2 +local int sig3 +local int sig4 + +roofcam = find entity with targetname "t111" +camtrain = find entity with scripttarget "camtrain" +domebreak1 = find entity with targetname "domebreak1" +domebreak3 = find entity with targetname "domebreak3" +domebreak4 = find entity with targetname "domebreak4" +domebreak5 = find entity with targetname "domebreak5" +domebreak6 = find entity with targetname "domebreak6" +domebreak7 = find entity with targetname "domeJS1" +domebreak8 = find entity with targetname "domeJS2" +domebreak9 = find entity with targetname "domeJS3" +dometrain = find entity with targetname "dometrain" +dometrain10 = find entity with targetname "dometrain10" +dome1 = find entity with targetname "t20" +dome2 = find entity with targetname "dome2" +dome3 = find entity with targetname "dome3" +walkway = find entity with targetname "walkway" +walkwaya = find entity with targetname "walkwaya" +quaker = find entity with targetname "quaker" +dmg = find entity with targetname "dmg" +corv = find entity with targetname "corv" + +dometrain.movetype = PHYSICSTYPE_PUSH +dometrain10.movetype = PHYSICSTYPE_PUSH + + player1 = get entity activator + + copy player attributes from entity player1 to entity corv + corv.modelindex = corv.count + corv.solid = SOLID_SOLID + corv.movetype = 4 + +//start er up + +enable cinematics + +enable trigger entity quaker + +use entity roofcam + +animate entity corv performing action ACTION7_ANIMATION repeating for 10 times + +play sound "world/quake.wav" for entity corv on channel 10 + +use entity quaker + +wait 1 seconds + +use entity domebreak6 + +wait .5 seconds + +use entity domebreak3 + +wait .5 seconds + +use entity dome3 + +use entity domebreak5 +use entity domebreak8 + +wait .7 seconds + +use entity dome1 + +use entity dome2 + +wait .5 seconds + +use entity domebreak1 + +use entity domebreak4 +use entity domebreak9 +use entity domebreak7 + +enable trigger entity dmg + +move entity camtrain by [0, 0, -256] at 225 speed + +move entity dometrain by [0, 0, -568] at 800 speed signaling sig +rotate entity dometrain by [0, 0, 45] at 80 speed signaling sig2 + +wait .2 seconds + +move entity dometrain10 by [36, -16, -256] at 800 speed signaling sig3 +rotate entity dometrain10 by [52, 0, 42] at 160 speed signaling sig4 + +wait for all clearing sig3, sig4 + +move entity dometrain10 by [36, -16, -200] at 1000 speed signaling sig3 + +move entity walkwaya by [0, 0, -168] at 800 speed + +use entity walkway + +wait for all clearing sig, sig2, sig3 + +use entity dometrain + +use entity dometrain10 + +play sound "world/quakend.wav" for entity corv on channel 10 + +wait 2 seconds + +animate entity corv performing action ACTION8_ANIMATION repeating for 1 times + +wait 1 seconds + +disable trigger entity quaker + +disable trigger entity dmg + +use entity roofcam + +walkwaya.movetype = PHYSICSTYPE_NONE + + player1.origin = corv.origin + player1.p_origin = corv.origin + set view angles of entity player1 to corv.angles + + + corv.modelindex = 0 + corv.solid = SOLID_NOT + +disable cinematics diff --git a/Toolkit/Designer/dsexamples/andoria/rubble.ds b/Toolkit/Designer/dsexamples/andoria/rubble.ds new file mode 100644 index 0000000..fad878d --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/rubble.ds @@ -0,0 +1,27 @@ +//rubble falling + +#include "../common/header.ds" + +output "R:base/ds/andoria" + + +//define variables + +local entity rubble +local entity dust +local int sig + +rubble = find entity with targetname "r1" +dust = find entity with targetname "r2" + +//rubble falls + + use entity dust + + wait 0.5 seconds + + move entity rubble by [0, 0, -308] at 800 speed signaling sig + play sound "doors/objectdrop.wav" for entity rubble + rotate entity rubble to [0, 0, 18] at 400 speed + wait for all clearing sig + diff --git a/Toolkit/Designer/dsexamples/andoria/sawblade.ds b/Toolkit/Designer/dsexamples/andoria/sawblade.ds new file mode 100644 index 0000000..23539a1 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/sawblade.ds @@ -0,0 +1,46 @@ +//saw blade from hell + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity saw +local entity rope +local entity dam + +local int sig +local int sig2 + +saw = find entity with targetname "blade" +rope = find entity with targetname "rope" +dam = find entity with targetname "dam" + +//start of script + +label start + +saw.angle_velocity = [0, 0, 480] +play sound "objects/yoyo.wav" for entity saw +move entity saw by [0, 0, -416] at 400 speed signaling sig +move entity rope by [0, 0, -416] at 400 speed signaling sig2 +wait for all clearing sig, sig2 + +enable trigger entity dam +play sound "objects/yoyo.wav" for entity dam + +wait 3 seconds + +disable trigger entity dam + +saw.angle_velocity = [0, 0, -480] +play sound "objects/yoyo.wav" for entity saw +move entity saw by [0, 0, 416] at 300 speed signaling sig +move entity rope by [0, 0, 416] at 300 speed signaling sig2 +wait for all clearing sig, sig2 +saw.angle_velocity = [0, 0, 0] + +suspend + +goto start \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/andoria/siernan.ds b/Toolkit/Designer/dsexamples/andoria/siernan.ds new file mode 100644 index 0000000..f0db382 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/siernan.ds @@ -0,0 +1,68 @@ +// Corvus goes back to siernan. if he does not have both puzzle items that he needs +// this script will play. + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +local entity siernan +local entity camera +local entity player1 + +local int sig + +cache sound "cinematics/second siernan/question.wav" +cache sound "cinematics/second siernan/getitems.wav" +cache sound "corvus/no.wav" + +siernan = find entity with targetname "siernan" +camera = find entity with targetname "luke" +player1 = get entity activator + +// here we go. +enable cinematics + siernan.yaw_speed = 4 + + use entity camera + + animate entity siernan performing action WALK1_ANIMATION by turning [-45, 0, 0] signaling sig + wait for all clearing sig + + play sound "cinematics/second siernan/question.wav" for entity siernan + print 185 captioned + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action IDLE1_ANIMATION + + play sound "corvus/no.wav" for entity siernan + print 186 captioned + + wait 1 seconds + + play sound "cinematics/second siernan/getitems.wav" for entity siernan + print 187 captioned + + animate entity siernan performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + wait 1 seconds + + animate entity siernan performing action WALK1_ANIMATION by turning [45, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action IDLE1_ANIMATION + +disable cinematics + + use entity camera + + + + + + diff --git a/Toolkit/Designer/dsexamples/andoria/siernan1.ds b/Toolkit/Designer/dsexamples/andoria/siernan1.ds new file mode 100644 index 0000000..3df83df --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/siernan1.ds @@ -0,0 +1,431 @@ +// The first time corvus meets siernan. + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +local entity camera1 +local entity camera2 +local entity camera3 +local entity camera4 +local entity camera5 +local entity camera6 +local entity camera7 +local entity camera8 +local entity objective +local entity take +local entity siernan +local entity corvus +local entity player1 +local entity movecam1 + +local int sig + +cache sound "cinematics/first siernan/48-4.wav" +cache sound "cinematics/first siernan/49-6.wav" +cache sound "cinematics/first siernan/50-5.wav" +cache sound "cinematics/first siernan/51-5.wav" +cache sound "cinematics/first siernan/52-8.wav" +cache sound "cinematics/first siernan/53-3.wav" +cache sound "cinematics/first siernan/54-2.wav" +cache sound "cinematics/first siernan/55-12.wav" +cache sound "cinematics/first siernan/56-1.wav" +cache sound "cinematics/first siernan/57-2.wav" +cache sound "cinematics/first siernan/58-2.wav" +cache sound "cinematics/first siernan/59-8.wav" + +camera1 = find entity with targetname "camera1" +camera2 = find entity with targetname "camera2" +camera3 = find entity with targetname "camera3" +camera4 = find entity with targetname "camera4" +camera5 = find entity with targetname "camera5" +camera6 = find entity with targetname "camera6" +camera7 = find entity with targetname "camera7" +camera8 = find entity with targetname "camera8" +objective = find entity with targetname "objective3" +take = find entity with targetname "take3" +siernan = find entity with targetname "siernan" +corvus = find entity with targetname "corvus" +movecam1 = find entity with targetname "movecam1" +player1 = get entity activator + +// lets start this sucker. + + siernan.yaw_speed = 7 + + copy player attributes from entity player1 to entity corvus + corvus.modelindex = corvus.count + corvus.solid = SOLID_SOLID + corvus.movetype = 4 + + siernan.movetype = 5 + + enable cinematics + +//camera1, high on right side of corvus looking at siernan. + + use entity camera1 + + animate entity corvus performing action WALK2_ANIMATION by moving [100, 0, 0] by turning [-15, 0, 0] signaling sig + wait for all clearing sig + + animate entity corvus performing action WALKSTOP2_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE1_ANIMATION + + play sound "cinematics/first siernan/48-4.wav" for entity siernan + print 168 captioned + + animate entity siernan performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action IDLE2_ANIMATION + + play sound "cinematics/first siernan/49-6.wav" for entity corvus + print 169 captioned + + animate entity corvus performing action ACTION9_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE1_ANIMATION + + use entity camera1 + +//camera2, middle shot of siernan. + + use entity camera2 + + animate entity siernan performing action WALK1_ANIMATION by turning [-90, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action WALKSTART_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action WALK1_ANIMATION by moving [100, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action WALK1_ANIMATION by moving [100, 0, 0] by turning [45, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action WALKSTOP1_ANIMATION signaling sig + wait for all clearing sig + + play sound "cinematics/first siernan/50-5.wav" for entity siernan + print 170 captioned + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION4_ANIMATION repeating for 2 times signaling sig + wait for all clearing sig + + animate entity siernan performing action IDLE1_ANIMATION + + use entity camera2 + +//camera3, middle shot of corvus + + use entity camera3 + +//----------------------------------------------- + + animate entity corvus performing action WALK2_ANIMATION by moving [75, 0, 0] signaling sig + wait for all clearing sig + +// animate entity corvus performing action WALKSTOP1_ANIMATION signaling sig +// wait for all clearing sig + +//------------------------------------------------ + + play sound "cinematics/first siernan/51-5.wav" for entity corvus + print 171 captioned + + animate entity siernan performing action IDLE1_ANIMATION + + animate entity corvus performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION11_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION12_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION6_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION11_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION12_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE1_ANIMATION + + use entity camera3 + +//camera4, side shot of both charactors + + use entity camera4 + + play sound "cinematics/first siernan/52-8.wav" for entity siernan + print 172 captioned + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + play sound "cinematics/first siernan/53-3.wav" for entity corvus + print 173 captioned + + animate entity siernan performing action IDLE1_ANIMATION + + animate entity corvus performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION11_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION12_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION10_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE1_ANIMATION + + use entity camera4 + +//camera7, side shot. + + use entity camera7 + + play sound "cinematics/first siernan/54-2.wav" for entity siernan + print 174 captioned + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION3_ANIMATION signaling sig + print 175 captioned + wait for all clearing sig + + animate entity siernan performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + use entity camera7 + +//camera6, back to looking straight on corvus. + + use entity camera6 + + animate entity corvus performing action ACTION11_ANIMATION signaling sig + wait for all clearing sig + + play sound "cinematics/first siernan/55-12.wav" for entity corvus + print 176 captioned + + animate entity siernan performing action IDLE1_ANIMATION + + animate entity corvus performing action ACTION12_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION10_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION11_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action IDLE2_ANIMATION + + animate entity corvus performing action ACTION12_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE1_ANIMATION + + use entity camera6 + +//camera5, looking at siernan and moving a little bit. + + use entity camera5 + + play sound "cinematics/first siernan/56-1.wav" for entity siernan + print 177 captioned + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + print 178 captioned + + animate entity siernan performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + move entity movecam1 by [50, 0, 20] over 15 seconds + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + print 179 captioned + wait for all clearing sig + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + print 180 captioned + wait for all clearing sig + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + use entity camera5 + +//camera8, side shot of both charactors (same as camera4) + + use entity camera8 + + play sound "cinematics/first siernan/57-2.wav" for entity corvus + print 181 captioned + + animate entity siernan performing action IDLE1_ANIMATION + + animate entity corvus performing action ACTION10_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION6_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE1_ANIMATION + + play sound "cinematics/first siernan/58-2.wav" for entity siernan + print 182 captioned + + animate entity siernan performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + play sound "cinematics/first siernan/59-8.wav" for entity siernan + + animate entity siernan performing action ACTION1_ANIMATION signaling sig + print 183 captioned + wait for all clearing sig + + animate entity siernan performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan performing action IDLE1_ANIMATION signaling sig + wait for all clearing sig + + use entity take + use entity objective + + disable cinematics + + player1.origin = corvus.origin + player1.p_origin = corvus.origin + set view angles of entity player1 to corvus.angles + + corvus.modelindex = 0 + corvus.solid = SOLID_NOT + + use entity camera8 + + animate entity siernan performing action WALK1_ANIMATION by turning [90, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action WALK1_ANIMATION by turning [90, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action WALK1_ANIMATION by moving [20, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action WALK1_ANIMATION by turning [-45, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action WALK1_ANIMATION by moving [20, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action WALK1_ANIMATION by turning [-90, 0, 0] signaling sig + wait for all clearing sig + + animate entity siernan performing action IDLE1_ANIMATION signaling sig + wait for all clearing sig + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/andoria/siernan2.ds b/Toolkit/Designer/dsexamples/andoria/siernan2.ds new file mode 100644 index 0000000..8d91491 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/siernan2.ds @@ -0,0 +1,118 @@ +// The second time corvus meets siernan. + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +local entity camera1a +local entity objective +local entity take +local entity siernan +local entity siernan2 +local entity corvus2 +local entity spreader +local entity assassin +local entity player2 + +local int sig + +cache sound "cinematics/second siernan/60-14.wav" +cache sound "cinematics/second siernan/61-16.wav" +cache sound "cinematics/second siernan/62-14.wav" +cache sound "cinematics/second siernan/63-18.wav" + +camera1a = find entity with targetname "camera1a" +objective = find entity with targetname "objective4" +take = find entity with targetname "take4" +siernan = find entity with targetname "siernan" +siernan2 = find entity with targetname "siernan2" +corvus2 = find entity with targetname "corvus2" +player2 = get entity activator + +// bring in the boys + + spreader = spawn entity with fields "classname" = "monster_spreader", "angle" = 225, "origin" = [-2192, -16, -456], "target" = "monsters" + + assassin = spawn entity with fields "classname" = "monster_assassin", "angle" = 180, "origin" = [-2064, -160, -424], "target" = "monsters" + + siernan.modelindex = 0 + siernan.solid = SOLID_NOT + + siernan2.modelindex = siernan2.count + siernan2.solid = SOLID_SOLID + + suspend + +//camera1a, side shot of both charactors. corvus walks into view. kneels etc. + + copy player attributes from entity player2 to entity corvus2 + corvus2.modelindex = corvus2.count + corvus2.solid = SOLID_SOLID + corvus2.movetype = 4 + + siernan2.movetype = 5 + + enable cinematics + + use entity camera1a + + animate entity corvus2 performing action WALK2_ANIMATION by moving [75, 0, 0] signaling sig + wait for all clearing sig + + play sound "cinematics/second siernan/60-14.wav" for entity corvus2 + print 189 captioned + + animate entity corvus2 performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + play sound "cinematics/second siernan/61-16.wav" for entity siernan2 + print 190 captioned + + animate entity siernan2 performing action ACTION1_ANIMATION + + animate entity corvus2 performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus2 performing action ACTION3_ANIMATION repeating for 10 times signaling sig + wait for all clearing sig + + play sound "cinematics/second siernan/62-14.wav" for entity corvus2 + print 191 captioned + + animate entity corvus2 performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + + animate entity corvus2 performing action ACTION3_ANIMATION repeating + + + play sound "cinematics/second siernan/63-18.wav" for entity siernan2 + print 192 captioned + + animate entity siernan2 performing action ACTION2_ANIMATION + + wait 1 seconds + + animate entity corvus2 performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus2 performing action IDLE1_ANIMATION + + wait 11 seconds + + use entity take + use entity objective + + player2.origin = corvus2.origin + player2.p_origin = corvus2.origin + set view angles of entity player2 to corvus2.angles + + corvus2.modelindex = 0 + corvus2.solid = SOLID_NOT + + disable cinematics + + use entity camera1a + +//this is where the script stop until corvus combines the earth blood and the crystal and brings the cure back to siernan. + diff --git a/Toolkit/Designer/dsexamples/andoria/siernan3.ds b/Toolkit/Designer/dsexamples/andoria/siernan3.ds new file mode 100644 index 0000000..65799e9 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/siernan3.ds @@ -0,0 +1,358 @@ +// The third time corvus meets siernan. corvus now has the potion. hopefully. + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + + +local entity camera3a +local entity camera4a +local entity camera5a +local entity camera6a +local entity camera7a +local entity camera8a +local entity camera9a +local entity aremac +local entity aremac1 +local entity aremac2 +local entity funcwall +local entity siernan2 +local entity siernan3 +local entity nan +local entity corvus3 +local entity player3 +local entity trian +local entity portal +local entity trian2 +local entity target +local entity objective +local entity take + +local int sig +local int sig1 + +field vector "movetype" + +cache sound "cinematics/second siernan/64-18.wav" +cache sound "cinematics/second siernan/65-18.wav" +cache sound "cinematics/second siernan/66-20.wav" +cache sound "cinematics/second siernan/67-16.wav" +cache sound "cinematics/second siernan/68-23.wav" +cache sound "cinematics/second siernan/69-16.wav" +cache sound "cinematics/second siernan/70-18.wav" +cache sound "cinematics/second siernan/71-21.wav" +cache sound "cinematics/second siernan/72-14.wav" +cache sound "cinematics/second siernan/73-16.wav" +cache sound "cinematics/second siernan/74-21.wav" +cache sound "cinematics/second siernan/75-14.wav" + +camera3a = find entity with targetname "camera3a" +camera4a = find entity with targetname "camera4a" +camera5a = find entity with targetname "camera5a" +camera6a = find entity with targetname "camera6a" +camera7a = find entity with targetname "camera7a" +camera8a = find entity with targetname "camera8a" +camera9a = find entity with targetname "camera9a" +aremac = find entity with targetname "aremac" +aremac1 = find entity with targetname "aremac1" +aremac2 = find entity with targetname "aremac2" +funcwall = find entity with targetname "funcwall" +siernan2 = find entity with targetname "siernan2" +siernan3 = find entity with targetname "siernan3" +nan = find entity with targetname "nan" +corvus3 = find entity with targetname "corvus3" +trian = find entity with targetname "trian" +portal = find entity with targetname "t130" +trian2 = find entity with targetname "trian2" +target = find entity with targetname "target" +objective = find entity with targetname "objective5" +take = find entity with targetname "take5" + +//switching siernans + + use entity funcwall + + wait .1 seconds + + siernan2.modelindex = 0 + siernan2.solid = SOLID_NOT + + nan.modelindex = nan.count + nan.solid = SOLID_SOLID + + suspend + +// here we go + + player3 = get entity activator + + copy player attributes from entity player3 to entity corvus3 + + corvus3.modelindex = corvus3.count + corvus3.solid = SOLID_SOLID + corvus3.movetype = 4 + + siernan3.movetype = 5 + nan.movetype = 5 + + enable cinematics + +//camera3a, away looking at both charactors. + + use entity camera3a + + move entity aremac by [50, -25 , 20] over 10 seconds + + wait 1 seconds + + animate entity corvus3 performing action WALK3_ANIMATION by moving [116, 0, 0] signaling sig + wait for all clearing sig + + animate entity corvus3 performing action ACTION18_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus3 performing action IDLE2_ANIMATION repeating for 100 times + +// siernan reaching out + + animate entity nan performing action ACTION13_ANIMATION signaling sig by turning [-35, 0, 0] + wait for all clearing sig + + animate entity nan performing action IDLE4_ANIMATION repeating for 100 times + +// corvus pouring the juice in siernan's hands + + animate entity corvus3 performing action ACTION20_ANIMATION signaling sig + wait for all clearing sig + +// siernan takes a sip + + animate entity nan performing action ACTION12_ANIMATION by turning [-55, 0, 0] + +// corvus takes a drink + + animate entity corvus3 performing action ACTION19_ANIMATION + + wait 1 seconds + + use entity camera3a + +//aremac2, close up of siernan. + + use entity aremac2 + + wait 1 seconds + + animate entity corvus3 performing action IDLE1_ANIMATION repeating for 100 times + + play sound "cinematics/second siernan/64-18.wav" for entity nan + print 194 captioned + + animate entity nan performing action ACTION11_ANIMATION signaling sig + wait for all clearing sig + + animate entity nan performing action IDLE1_ANIMATION + + use entity aremac2 + +//aremac1, close up of corvus. + + use entity aremac1 + + play sound "cinematics/second siernan/65-18.wav" for entity corvus3 + print 195 captioned + + animate entity corvus3 performing action ACTION17_ANIMATION signaling sig + wait for all clearing sig + +//-------- + + nan.modelindex = 0 + nan.solid = SOLID_NOT + + siernan3.modelindex = siernan3.count + siernan3.solid = SOLID_SOLID + +//-------- + + animate entity corvus3 performing action IDLE1_ANIMATION + + use entity aremac1 + +//camera4a, close up of siernan. + + use entity camera4a + + play sound "cinematics/second siernan/66-20.wav" for entity siernan3 + print 196 captioned + + animate entity siernan3 performing action ACTION9_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan3 performing action IDLE1_ANIMATION + + use entity camera4a + +//camera5a, behind siernan looking at corvus + + use entity camera5a + + play sound "cinematics/second siernan/67-16.wav" for entity corvus3 + print 197 captioned + + animate entity corvus3 performing action ACTION14_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus3 performing action IDLE1_ANIMATION + + move entity trian by [75, 0, 30] over 10 seconds + + play sound "cinematics/second siernan/68-23.wav" for entity siernan3 + print 198 captioned + + animate entity siernan3 performing action ACTION10_ANIMATION signaling sig + + wait 3 seconds + + print 199 captioned + + wait for all clearing sig + + animate entity siernan3 performing action IDLE1_ANIMATION + + use entity camera5a + +//camera6a, long shot so you can see the door open. + + use entity camera6a + + play sound "cinematics/second siernan/69-16.wav" for entity corvus3 + print 200 captioned + + animate entity corvus3 performing action ACTION16_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus3 performing action IDLE1_ANIMATION + + play sound "cinematics/second siernan/70-18.wav" for entity siernan3 + print 201 captioned + + use entity portal + + animate entity siernan3 performing action ACTION10_ANIMATION + +// wait 4 seconds + + target.movetype = PHYSICSTYPE_PUSH + + move entity trian2 by [0, 0, 20] over 1 seconds signaling sig + move entity target by [0, 0, 50] over 2 seconds signaling sig1 + wait for all clearing sig, sig1 + + move entity trian2 by [-325, -100, 50] over 5 seconds signaling sig + move entity target by [-175, -100, 50] over 5 seconds signaling sig1 + wait for all clearing sig, sig1 + + move entity target by [0, -300, 0] over 1 seconds signaling sig + wait for all clearing sig + + print 202 captioned + + move entity trian2 by [0, -325, 0] over 3 seconds signaling sig + wait for all clearing sig + + move entity trian2 by [0, -300, 0] over 3 seconds signaling sig + move entity target by [-400, -300, 0] over 3 seconds signaling sig1 + wait for all clearing sig, sig1 + + animate entity siernan3 performing action IDLE1_ANIMATION + + move entity target by [-450, 0, 0] over 3 seconds signaling sig + wait for all clearing sig + + use entity camera6a + +//camera7a, side shot of charactors. + + use entity camera7a + + play sound "cinematics/second siernan/71-21.wav" for entity corvus3 + print 203 captioned + + animate entity corvus3 performing action ACTION13_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus3 performing action IDLE1_ANIMATION + + play sound "cinematics/second siernan/72-14.wav" for entity siernan3 + print 204 captioned + + animate entity siernan3 performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + + play sound "cinematics/second siernan/73-16.wav" for entity siernan3 + print 205 captioned + + animate entity siernan3 performing action ACTION7_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan3 performing action IDLE1_ANIMATION + + use entity camera7a + +//camera8a, looking over siernan'n shoulder at corvus (something like camera5a) + + use entity camera8a + + play sound "cinematics/second siernan/74-21.wav" for entity corvus3 + print 206 captioned + + animate entity corvus3 performing action ACTION15_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus3 performing action IDLE1_ANIMATION + + use entity camera8a + +//camera9a, waist up shot of siernan. + + use entity camera9a + + play sound "cinematics/second siernan/75-14.wav" for entity siernan3 + print 207 captioned + + animate entity siernan3 performing action ACTION6_ANIMATION signaling sig + wait for all clearing sig + + animate entity siernan3 performing action IDLE1_ANIMATION + + use entity take + use entity objective + + disable cinematics + + player3.origin = corvus3.origin + player3.p_origin = corvus3.origin + set view angles of entity player3 to corvus3.angles + + corvus3.modelindex = 0 + corvus3.solid = SOLID_NOT + siernan3.solid = SOLID_SOLID + + use entity camera9a + + + + + + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/andoria/topple.ds b/Toolkit/Designer/dsexamples/andoria/topple.ds new file mode 100644 index 0000000..2f243b9 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/topple.ds @@ -0,0 +1,28 @@ +//rubble falling + +#include "../common/header.ds" + +output "R:base/ds/andoria" + + +//define variables + +local entity rubble +local entity rubble2 +local int sig + +rubble = find entity with targetname "toppler" +rubble2 = find entity with targetname "topl2" + +//pillar falls + + rubble.movetype = PHYSICSTYPE_NOCLIP + play sound "doors/objectdrop.wav" for entity rubble + rotate entity rubble by [0, 45, -90] at 200 speed + wait 0.2 seconds + move entity rubble by [0, 0, -120] at 400 speed signaling sig + wait 0.2 seconds + use entity rubble2 + wait for all clearing sig + rubble.movetype = PHYSICSTYPE_PUSH + diff --git a/Toolkit/Designer/dsexamples/andoria/tportdoors.ds b/Toolkit/Designer/dsexamples/andoria/tportdoors.ds new file mode 100644 index 0000000..44efa26 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/tportdoors.ds @@ -0,0 +1,35 @@ +//teleporter secret doors... ooooooh. + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity door1 +local entity door2 +local entity cam +local int sig +local int sig2 + +door1 = find entity with targetname "tportdoor1" +door2 = find entity with targetname "tportdoor2" +cam = find entity with targetname "tportcam" + +//start script, meng + +use entity cam + +move entity door1 by [0, 0, -24] at 50 speed signaling sig + +move entity door2 by [0, 0, -24] at 50 speed signaling sig2 + +wait for all clearing sig, sig2 + +move entity door1 by [0, 56, 0] at 50 speed signaling sig + +move entity door2 by [0, -56, 0] at 50 speed signaling sig2 + +wait for all clearing sig, sig2 + +use entity cam \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/andoria/watrrr.ds b/Toolkit/Designer/dsexamples/andoria/watrrr.ds new file mode 100644 index 0000000..9815e39 --- /dev/null +++ b/Toolkit/Designer/dsexamples/andoria/watrrr.ds @@ -0,0 +1,63 @@ +//raise water and close doors + +#include "../common/header.ds" + +output "r:/base/ds/andoria" + +//define variables + +local entity water +local entity door1 +local entity door2 +local entity cam + +local int sig1 +local int sig2 +local int sig3 +local int wait4me + + +water = find entity with targetname "movewater" +door1 = find entity with targetname "waterdoor2" +door2 = find entity with targetname "waterdoor1" +cam = find entity with targetname "watrcammm" + +//start of script + +label start +if wait4me != 666 + wait4me = 666 + //use entity cam + play sound "objects/oilpump.wav" for entity cam on channel 10 + play sound "doors/stonestart.wav" for entity door1 on channel 10 + move entity door1 by [0, 0, -272] at 300 speed signaling sig1 + play sound "doors/stonestart.wav" for entity door2 on channel 10 + play sound "objects/oilpump.wav" for entity cam on channel 10 + rotate entity door2 by [-90, 0, 0] at 30 speed signaling sig2 + wait for all clearing sig1, sig2 + play sound "doors/stonestop.wav" for entity door1 on channel 10 + play sound "doors/stonestop.wav" for entity door2 on channel 10 + play sound "objects/oilpump.wav" for entity cam on channel 10 + wait .5 seconds + //use entity cam +// play sound "ambient/river.wav" for entity water on channel 2 + move entity water by [0, 0, 260] at 20 speed signaling sig3 + wait for all clearing sig3 +// play sound "misc/null.wav" for entity water on channel 2 + wait 20 seconds +// play sound "ambient/river.wav" for entity water + move entity water by [0, 0, -260] at 20 speed signaling sig3 + wait for all clearing sig3 +// play sound "misc/null.wav" for entity water on channel 2 + wait 3 seconds + play sound "doors/stonestart.wav" for entity door1 on channel 10 + move entity door1 by [0, 0, 272] at 300 speed signaling sig1 + play sound "doors/stonestart.wav" for entity door2 on channel 10 + rotate entity door2 by [90, 0, 0] at 30 speed signaling sig2 + wait for all clearing sig1, sig2 + play sound "doors/stonestop.wav" for entity door1 on channel 10 + play sound "doors/stonestop.wav" for entity door2 on channel 10 + wait4me = 0 +endif +suspend +goto start \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/canyon/boom.ds b/Toolkit/Designer/dsexamples/canyon/boom.ds new file mode 100644 index 0000000..630602d --- /dev/null +++ b/Toolkit/Designer/dsexamples/canyon/boom.ds @@ -0,0 +1,39 @@ +//Assassin's explosive trap. + + +#include "../common/header.ds" + +output "R:/base/ds/canyon" + +//define entity + +local entity flamel +local entity rubble +local entity activate +local entity deactivate +local int sig + + +flamel = find entity with targetname "flamel" +rubble = find entity with targetname "rubble" +activate = find entity with targetname "activate" +deactivate = find entity with targetname "deactivate" + + +//move fire + + + flamel.movetype = PHYSICSTYPE_PUSH + move entity flamel by [0, 0, -120] at 200 speed signaling sig + wait for all clearing sig + + use entity rubble + + wait .1 seconds + + use entity activate + + wait .1 seconds + + use entity deactivate + diff --git a/Toolkit/Designer/dsexamples/canyon/drop.ds b/Toolkit/Designer/dsexamples/canyon/drop.ds new file mode 100644 index 0000000..f56ea48 --- /dev/null +++ b/Toolkit/Designer/dsexamples/canyon/drop.ds @@ -0,0 +1,61 @@ +//Lever pushes crates out of doorway at bottom of SSDocks tower + +#include "../common/header.ds" +output "r:/base/ds/canyon" + +//define variables + +local entity pivot1 +local entity pivot2 +local entity break1 +local entity break2 +local entity break3 +local entity drop1 +local entity drop2 +local entity drop3 + +local int sig1 +local int sig2 + +pivot1 = find entity with targetname "brid1" +pivot2 = find entity with targetname "brid2" +drop1 = find entity with targetname "brid3" +drop2 = find entity with targetname "brid4" +drop3 = find entity with targetname "brid5" +break1 = find entity with targetname "rope1" +break2 = find entity with targetname "rope2" +break3 = find entity with targetname "rope3" + +pivot1.movetype = PHYSICSTYPE_NOCLIP +pivot2.movetype = PHYSICSTYPE_NOCLIP +drop1.movetype = PHYSICSTYPE_NOCLIP +drop2.movetype = PHYSICSTYPE_NOCLIP +drop3.movetype = PHYSICSTYPE_NOCLIP + +use entity break3 +wait 0.2 seconds +use entity break1 +use entity break2 +wait 0.2 seconds +move entity drop1 by [-16, 10, -384] at 300 speed +drop1.angle_velocity = [0, 200, 100] +rotate entity pivot1 by [40, 20, 50] at 400 speed signaling sig1 +move entity pivot1 by [0, 0, 8] at 300 speed +rotate entity pivot2 by [-40, 20, -50] at 300 speed signaling sig2 +move entity pivot2 by [0, 0, 8] at 300 speed +move entity drop2 by [0, 0, -384] at 400 speed +rotate entity drop2 by [100, 100, -300] at 300 speed +move entity drop3 by [0, 0, -384] at 350 speed +rotate entity drop3 by [100, 100, -300] at 200 speed +wait 0.8 seconds +use entity drop1 +use entity drop2 +wait 0.4 seconds +use entity drop3 +//use entity pivot2 + +wait for all clearing sig1, sig2 +pivot1.movetype = PHYSICSTYPE_PUSH +pivot2.movetype = PHYSICSTYPE_PUSH + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/canyon/scout.ds b/Toolkit/Designer/dsexamples/canyon/scout.ds new file mode 100644 index 0000000..bea9017 --- /dev/null +++ b/Toolkit/Designer/dsexamples/canyon/scout.ds @@ -0,0 +1,227 @@ +//Ssithra scout encounter + +#include "../common/header.ds" + +output "r:/base/ds/canyon" + +//define variables + +local entity corvus +local entity scout +local entity cam1 +local entity cam2 +local entity cam2t +local entity cam2train +local entity cam3 +local entity cam3b +local entity cam4 +local entity cam1b +local entity cam4b +local entity cam5 +local entity cam6 +local entity cam6b +local entity objective +local int sig +local int sig1 +local int sig2 +local entity player1 + +corvus = find entity with targetname "corvus" +scout = find entity with targetname "scout" +cam1 = find entity with targetname "c1" +cam1b = find entity with targetname "camtrain" +cam2 = find entity with targetname "c2" +cam2t = find entity with targetname "cam2target" +cam2train = find entity with targetname "cam2train" +cam3 = find entity with targetname "c3" +cam3b = find entity with targetname "t41" +cam4 = find entity with targetname "c4" +cam4b = find entity with targetname "cam4b" +cam5 = find entity with targetname "nothing" +cam6 = find entity with targetname "cam6" +cam6b = find entity with targetname "cam6b" +objective = find entity with targetname "objective5" + +cache sound "cinematics/Scout/76-334.wav" +cache sound "cinematics/Scout/77-332.wav" +cache sound "cinematics/Scout/78-332.wav" +cache sound "cinematics/Scout/79-330.wav" +cache sound "cinematics/Scout/80-335.wav" +cache sound "cinematics/Scout/81-335.wav" +cache sound "cinematics/Scout/82-330.wav" +cache sound "cinematics/Scout/83-335.wav" + +player1 = get entity activator // Get player who set off trigger +copy player attributes from entity player1 to entity corvus +corvus.modelindex = corvus.count // Turn on cinematic corvus +corvus.solid = SOLID_SOLID // Make him block + +enable cinematics + +//First camera closing in on both Corvus and Scout + + use entity cam1 + + wait 1 seconds + + move entity cam1b by [-16, 80, -24] over 3.5 seconds + +//You are the scout? + + animate entity corvus performing action WALK2_ANIMATION by moving [80, 0, 0] by turning [35, 0, 0] signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + print 209 captioned to entity player1 + play sound "cinematics/Scout/76-334.wav" for entity corvus + + animate entity corvus performing action ACTION2_ANIMATION signaling sig1 + + wait .2 seconds + + animate entity scout performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig, sig1 + + animate entity corvus performing action IDLE2_ANIMATION signaling sig1 +use entity cam1 +//Scout, cough, cough... yup. Corvus..."infected?" + + use entity cam2 + + cam2t.movetype = PHYSICSTYPE_PUSH + move entity cam2t by [16, 8, 0] over 12 seconds + move entity cam2train by [16, 8, 16] over 12 seconds + + print 210 captioned to entity player1 + play sound "cinematics/Scout/77-332.wav" for entity scout + + animate entity scout performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig, sig1 + + wait 7 seconds + + use entity cam2 + + use entity cam3 + + print 211 captioned to entity player1 + play sound "cinematics/Scout/78-332.wav" for entity corvus + + animate entity corvus performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE2_ANIMATION signaling sig + + animate entity scout performing action IDLE2_ANIMATION signaling sig2 + wait for all clearing sig, sig2 + + use entity cam3 + +//Action breakdown #1 Scout... they seem immune. + + use entity cam4 + + move entity cam4b by [36, 56, 24] over 30 seconds + + print 212 captioned to entity player1 + play sound "cinematics/Scout/79-330.wav" for entity scout + + animate entity scout performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity scout performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + print 213 captioned to entity player1 + animate entity scout performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity scout performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity scout performing action IDLE3_ANIMATION signaling sig + wait for all clearing sig + + use entity cam4 + +//My journey has been for nothing. + + use entity cam5 + + print 214 captioned to entity player1 + play sound "cinematics/Scout/80-335.wav" for entity corvus + + animate entity corvus performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE2_ANIMATION signaling sig + //wait for all clearing sig + + use entity cam5 + +//Action breakdown #2 No. She may listen. + + use entity cam6 + + print 215 captioned to entity player1 + play sound "cinematics/Scout/81-335.wav" for entity scout + + move entity cam6b by [-84, -170, 32] over 59 seconds + + animate entity scout performing action ACTION6_ANIMATION signaling sig + wait for all clearing sig + + animate entity scout performing action ACTION7_ANIMATION signaling sig + wait for all clearing sig + + animate entity scout performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + + animate entity scout performing action ACTION10_ANIMATION signaling sig + wait for all clearing sig + + +//ACTION BREAKDOWN #3 + + print 216 captioned to entity player1 + play sound "cinematics/Scout/82-330.wav" for entity scout + + animate entity scout performing action ACTION7_ANIMATION signaling sig + wait for all clearing sig + + animate entity scout performing action ACTION7_ANIMATION signaling sig + wait for all clearing sig + + animate entity scout performing action ACTION7_ANIMATION signaling sig + wait for all clearing sig + + animate entity scout performing action ACTION9_ANIMATION signaling sig + wait for all clearing sig + +//DEATH OF SCOUT + + play sound "cinematics/Scout/83-335.wav" for entity scout + + animate entity scout performing action DEATH1_ANIMATION signaling sig + + use entity objective + + wait 1 seconds + + animate entity corvus performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE1_ANIMATION signaling sig + + wait .5 seconds + + use entity cam6 + +disable cinematics + +player1.origin = corvus.origin +player1.p_origin = corvus.origin // Put player where Cinematic corvus is set view angles of entity player1 to hero.angles +corvus.modelindex = 0 +corvus.solid = SOLID_NOT \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/canyon/swinger.ds b/Toolkit/Designer/dsexamples/canyon/swinger.ds new file mode 100644 index 0000000..b4da6b5 --- /dev/null +++ b/Toolkit/Designer/dsexamples/canyon/swinger.ds @@ -0,0 +1,47 @@ +//Swinging wood on a broken bridge. + +#include "../common/header.ds" + +output "r:/base/ds/canyon" + +parameter entity parm1 +parameter vector parm2 +parameter float parm3 + +local entity thing +local vector distance +local vector tvec +local float time_var +local int sgnl +local float ttime +local float counter + +thing = parm1 +distance = parm2 +time_var = parm3 +counter = 0 + +label begin + +counter += 9 +ttime = sin counter +ttime += 1 +ttime /= 4 +ttime += time_var +tvec = distance +tvec *= -1 + +rotate entity thing to tvec over ttime seconds signaling sgnl +wait for any clearing sgnl + +counter += 17 +ttime = sin counter +ttime += 1 +ttime /= 4 +ttime += time_var +tvec = distance + +rotate entity thing to tvec over ttime seconds signaling sgnl +wait for any clearing sgnl + +goto begin \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/canyon/swinger2.ds b/Toolkit/Designer/dsexamples/canyon/swinger2.ds new file mode 100644 index 0000000..c5063a2 --- /dev/null +++ b/Toolkit/Designer/dsexamples/canyon/swinger2.ds @@ -0,0 +1,45 @@ +//Swinging wood on a broken bridge + +output "r:/base/ds/canyon" + +parameter entity parm1 +parameter vector parm2 +parameter float parm3 + +local entity thing +local vector distance +local vector tvec +local float time_var +local int sgnl +local float ttime +local float counter + +thing = parm1 +distance = parm2 +time_var = parm3 +counter = 0 + +label begin + +counter += 9 +ttime = sin counter +ttime += 1 +ttime /= 4 +ttime += time_var +tvec = distance +tvec *= -1 + +rotate entity thing to tvec over ttime seconds signaling sgnl +wait for any clearing sgnl + +counter += 17 +ttime = sin counter +ttime += 1 +ttime /= 4 +ttime += time_var +tvec = distance + +rotate entity thing to tvec over ttime seconds signaling sgnl +wait for any clearing sgnl + +goto begin \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/beddn.ds b/Toolkit/Designer/dsexamples/cloud/beddn.ds new file mode 100644 index 0000000..78c4a2f --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/beddn.ds @@ -0,0 +1,22 @@ +//bed goes down + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity bed +local int sig + +bed = find entity with targetname "bed" + +//label loop + +play sound "doors/gendoorstart.wav" for entity bed on channel 10 + +move entity bed by [0, 0, -280] at 75 speed signaling sig +wait for all clearing sig + +play sound "doors/gendoorstop.wav" for entity bed on channel 10 + +//suspend +//goto loop \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/bedtel.ds b/Toolkit/Designer/dsexamples/cloud/bedtel.ds new file mode 100644 index 0000000..49f6fe0 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/bedtel.ds @@ -0,0 +1,32 @@ +//teleporter in secret bed room if player is stupid. + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + + +local entity teleporter +local entity plat +local entity cam +local int sig + +teleporter = find entity with targetname "telactivate" +plat = find entity with targetname "beddoor" +cam = find entity with targetname "bedcam" + + + +//move it + +use entity cam + +rotate entity plat by [0, 0, 90] at 75 speed signaling sig +wait for all clearing sig + +use entity teleporter + +wait 2 seconds + +use entity cam + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/bedtel2.ds b/Toolkit/Designer/dsexamples/cloud/bedtel2.ds new file mode 100644 index 0000000..2bdbbac --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/bedtel2.ds @@ -0,0 +1,27 @@ +//teleporter thing goes back up + + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + + +local entity teleporter +local entity plat + +local int sig + +teleporter = find entity with targetname "telactivate" +plat = find entity with targetname "beddoor" + +//move it + +wait 1 seconds + +use entity teleporter + +rotate entity plat by [0, 0, -90] at 75 speed signaling sig +wait for all clearing sig + + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/bedup.ds b/Toolkit/Designer/dsexamples/cloud/bedup.ds new file mode 100644 index 0000000..86e3bed --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/bedup.ds @@ -0,0 +1,23 @@ +// Bed goes up + + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity bed +local int sig + +//label loop + +bed = find entity with targetname "bed" + +play sound "doors/gendoorstart.wav" for entity bed on channel 10 + +move entity bed by [0, 0, 280] at 75 speed signaling sig +wait for all clearing sig + +play sound "doors/gendoorstop.wav" for entity bed on channel 10 + +//suspend +//goto loop \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/bigdoor.ds b/Toolkit/Designer/dsexamples/cloud/bigdoor.ds new file mode 100644 index 0000000..3f45c0d --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/bigdoor.ds @@ -0,0 +1,186 @@ +// Big honkin' door! + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity toplf +local entity toprt +local entity topup +local entity topdn +local entity midupout +local entity midupin +local entity middnout +local entity middnin +local entity botup +local entity botdn +local entity bar1 +local entity bar2 +local entity bar3 +local entity bar4 +local entity bar5 +local entity bar6 +local entity bar7 +local entity bar8 +local entity portal + +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int sig6 +local int sig7 +local int sig8 + +toplf = find entity with targetname "toplf" +toprt = find entity with targetname "toprt" +topup = find entity with targetname "topup" +topdn = find entity with targetname "topdn" +midupout = find entity with targetname "midupout" +midupin = find entity with targetname "midupin" +middnout = find entity with targetname "middnout" +middnin = find entity with targetname "middnin" +botup = find entity with targetname "botup" +botdn = find entity with targetname "botdn" +bar1 = find entity with targetname "bar1" +bar2 = find entity with targetname "bar2" +bar3 = find entity with targetname "bar3" +bar4 = find entity with targetname "bar4" +bar5 = find entity with targetname "bar5" +bar6 = find entity with targetname "bar6" +bar7 = find entity with targetname "bar7" +bar8 = find entity with targetname "bar8" +portal = find entity with targetname "portal" + +label weee + +use entity portal + +wait .5 seconds + +play sound "doors/kchunk5.wav" for entity bar1 on channel 10 +play sound "doors/kchunk5.wav" for entity bar3 on channel 10 + +move entity bar1 by [16,0,0] at 50 speed signaling sig1 +move entity bar2 by [16,0,0] at 50 speed signaling sig2 +move entity bar3 by [16,0,0] at 50 speed signaling sig3 +move entity bar4 by [16,0,0] at 50 speed signaling sig4 +move entity bar5 by [-16,0,0] at 50 speed signaling sig5 +move entity bar6 by [-16,0,0] at 50 speed signaling sig6 +move entity bar7 by [-16,0,0] at 50 speed signaling sig7 +move entity bar8 by [-16,0,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +wait .5 seconds + +play sound "objects/gearsmove.wav" for entity bar1 on channel 10 +play sound "objects/gearsmove.wav" for entity bar3 on channel 10 + +move entity bar1 by [0,160,0] at 50 speed signaling sig1 +move entity bar2 by [0,-96,0] at 50 speed signaling sig2 +move entity bar3 by [0,96,0] at 50 speed signaling sig3 +move entity bar4 by [0,-160,0] at 50 speed signaling sig4 +move entity bar5 by [0,160,0] at 50 speed signaling sig5 +move entity bar6 by [0,-96,0] at 50 speed signaling sig6 +move entity bar7 by [0,96,0] at 50 speed signaling sig7 +move entity bar8 by [0,-160,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +play sound "doors/thud4.wav" for entity bar1 on channel 10 +play sound "doors/thud4.wav" for entity bar3 on channel 10 + +wait 2 seconds + +move entity botdn by [0,0,-60] at 30 speed +move entity botup by [0,0,-60] at 30 speed +move entity middnout by [0,-64,0] at 30 speed +move entity midupout by [0,64,0] at 30 speed +move entity middnin by [0,-120,0] at 60 speed +move entity midupin by [0,120,0] at 60 speed +move entity topup by [0,112,0] at 40 speed +move entity topdn by [0,-112,0] at 40 speed +move entity toprt by [0,0,224] at 40 speed +move entity toplf by [0,0,224] at 40 speed + +play sound "doors/stonestart.wav" for entity botup on channel 10 +play sound "doors/stonestart.wav" for entity botdn on channel 10 + +wait.5 seconds + +play sound "doors/stoneloop.wav" for entity botup on channel 10 +play sound "doors/stoneloop.wav" for entity botdn on channel 10 + +wait 5 seconds + +play sound "doors/stoneend.wav" for entity botup on channel 10 +play sound "doors/stoneend.wav" for entity botdn on channel 10 + +wait 2 seconds + +move entity botdn by [0,0,60] at 30 speed +move entity botup by [0,0,60] at 30 speed +move entity middnout by [0,64,0] at 30 speed +move entity midupout by [0,-64,0] at 30 speed +move entity middnin by [0,120,0] at 60 speed +move entity midupin by [0,-120,0] at 60 speed +move entity topup by [0,-112,0] at 40 speed +move entity topdn by [0,112,0] at 40 speed +move entity toprt by [0,0,-224] at 40 speed +move entity toplf by [0,0,-224] at 40 speed + +play sound "doors/stonestart.wav" for entity botup on channel 10 +play sound "doors/stonestart.wav" for entity botdn on channel 10 + +wait.5 seconds + +play sound "doors/stoneloop.wav" for entity botup on channel 10 +play sound "doors/stoneloop.wav" for entity botdn on channel 10 + +wait 5 seconds + +play sound "doors/stoneend.wav" for entity botup on channel 10 +play sound "doors/stoneend.wav" for entity botdn on channel 10 + +wait 2 seconds + +play sound "doors/kchunk5.wav" for entity bar1 on channel 10 +play sound "doors/kchunk5.wav" for entity bar3 on channel 10 + +wait .5 seconds + +play sound "objects/gearsmove.wav" for entity bar1 on channel 10 +play sound "objects/gearsmove.wav" for entity bar3 on channel 10 + +move entity bar1 by [0,-160,0] at 50 speed signaling sig1 +move entity bar2 by [0,96,0] at 50 speed signaling sig2 +move entity bar3 by [0,-96,0] at 50 speed signaling sig3 +move entity bar4 by [0,160,0] at 50 speed signaling sig4 +move entity bar5 by [0,-160,0] at 50 speed signaling sig5 +move entity bar6 by [0,96,0] at 50 speed signaling sig6 +move entity bar7 by [0,-96,0] at 50 speed signaling sig7 +move entity bar8 by [0,160,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +move entity bar1 by [-16,0,0] at 50 speed signaling sig1 +move entity bar2 by [-16,0,0] at 50 speed signaling sig2 +move entity bar3 by [-16,0,0] at 50 speed signaling sig3 +move entity bar4 by [-16,0,0] at 50 speed signaling sig4 +move entity bar5 by [16,0,0] at 50 speed signaling sig5 +move entity bar6 by [16,0,0] at 50 speed signaling sig6 +move entity bar7 by [16,0,0] at 50 speed signaling sig7 +move entity bar8 by [16,0,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +play sound "doors/thud4.wav" for entity bar1 on channel 10 +play sound "doors/thud4.wav" for entity bar3 on channel 10 + +use entity portal + +suspend + +goto weee diff --git a/Toolkit/Designer/dsexamples/cloud/bigdoorclose.ds b/Toolkit/Designer/dsexamples/cloud/bigdoorclose.ds new file mode 100644 index 0000000..46024ca --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/bigdoorclose.ds @@ -0,0 +1,122 @@ +// Big honkin' door! + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity toplf +local entity toprt +local entity topup +local entity topdn +local entity midupout +local entity midupin +local entity middnout +local entity middnin +local entity botup +local entity botdn +local entity bar1 +local entity bar2 +local entity bar3 +local entity bar4 +local entity bar5 +local entity bar6 +local entity bar7 +local entity bar8 +local entity portal + +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int sig6 +local int sig7 +local int sig8 + +toplf = find entity with targetname "toplf" +toprt = find entity with targetname "toprt" +topup = find entity with targetname "topup" +topdn = find entity with targetname "topdn" +midupout = find entity with targetname "midupout" +midupin = find entity with targetname "midupin" +middnout = find entity with targetname "middnout" +middnin = find entity with targetname "middnin" +botup = find entity with targetname "botup" +botdn = find entity with targetname "botdn" +bar1 = find entity with targetname "bar1" +bar2 = find entity with targetname "bar2" +bar3 = find entity with targetname "bar3" +bar4 = find entity with targetname "bar4" +bar5 = find entity with targetname "bar5" +bar6 = find entity with targetname "bar6" +bar7 = find entity with targetname "bar7" +bar8 = find entity with targetname "bar8" +portal = find entity with targetname "portal" + +label weee + +move entity botdn by [0,0,64] at 30 speed +move entity botup by [0,0,64] at 30 speed +move entity middnout by [0,64,0] at 30 speed +move entity midupout by [0,-64,0] at 30 speed +move entity middnin by [0,120,0] at 60 speed +move entity midupin by [0,-120,0] at 60 speed +move entity topup by [0,-112,0] at 40 speed +move entity topdn by [0,112,0] at 40 speed +move entity toprt by [0,0,-112] at 40 speed +move entity toplf by [0,0,-112] at 40 speed + +play sound "doors/stonestart.wav" for entity botup on channel 10 +play sound "doors/stonestart.wav" for entity botdn on channel 10 + +wait.5 seconds + +play sound "doors/stoneloop.wav" for entity botup on channel 10 +play sound "doors/stoneloop.wav" for entity botdn on channel 10 + +wait 1.5 seconds + +play sound "doors/stoneend.wav" for entity botup on channel 10 +play sound "doors/stoneend.wav" for entity botdn on channel 10 + +wait 2 seconds + +play sound "doors/kchunk5.wav" for entity bar1 on channel 10 +play sound "doors/kchunk5.wav" for entity bar3 on channel 10 + +wait .5 seconds + +play sound "objects/gearsmove.wav" for entity bar1 on channel 10 +play sound "objects/gearsmove.wav" for entity bar3 on channel 10 + +move entity bar1 by [0,-160,0] at 50 speed signaling sig1 +move entity bar2 by [0,96,0] at 50 speed signaling sig2 +move entity bar3 by [0,-96,0] at 50 speed signaling sig3 +move entity bar4 by [0,160,0] at 50 speed signaling sig4 +move entity bar5 by [0,-160,0] at 50 speed signaling sig5 +move entity bar6 by [0,96,0] at 50 speed signaling sig6 +move entity bar7 by [0,-96,0] at 50 speed signaling sig7 +move entity bar8 by [0,160,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +move entity bar1 by [-16,0,0] at 50 speed signaling sig1 +move entity bar2 by [-16,0,0] at 50 speed signaling sig2 +move entity bar3 by [-16,0,0] at 50 speed signaling sig3 +move entity bar4 by [-16,0,0] at 50 speed signaling sig4 +move entity bar5 by [16,0,0] at 50 speed signaling sig5 +move entity bar6 by [16,0,0] at 50 speed signaling sig6 +move entity bar7 by [16,0,0] at 50 speed signaling sig7 +move entity bar8 by [16,0,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +play sound "doors/thud4.wav" for entity bar1 on channel 10 +play sound "doors/thud4.wav" for entity bar3 on channel 10 + +use entity portal + + +suspend + +goto weee diff --git a/Toolkit/Designer/dsexamples/cloud/bigdooropen.ds b/Toolkit/Designer/dsexamples/cloud/bigdooropen.ds new file mode 100644 index 0000000..6df05d0 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/bigdooropen.ds @@ -0,0 +1,132 @@ +// Big honkin' door! + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity toplf +local entity toprt +local entity topup +local entity topdn +local entity midupout +local entity midupin +local entity middnout +local entity middnin +local entity botup +local entity botdn +local entity bar1 +local entity bar2 +local entity bar3 +local entity bar4 +local entity bar5 +local entity bar6 +local entity bar7 +local entity bar8 +local entity portal +local entity doorcam + +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int sig6 +local int sig7 +local int sig8 + +toplf = find entity with targetname "toplf" +toprt = find entity with targetname "toprt" +topup = find entity with targetname "topup" +topdn = find entity with targetname "topdn" +midupout = find entity with targetname "midupout" +midupin = find entity with targetname "midupin" +middnout = find entity with targetname "middnout" +middnin = find entity with targetname "middnin" +botup = find entity with targetname "botup" +botdn = find entity with targetname "botdn" +bar1 = find entity with targetname "bar1" +bar2 = find entity with targetname "bar2" +bar3 = find entity with targetname "bar3" +bar4 = find entity with targetname "bar4" +bar5 = find entity with targetname "bar5" +bar6 = find entity with targetname "bar6" +bar7 = find entity with targetname "bar7" +bar8 = find entity with targetname "bar8" +portal = find entity with targetname "portal" +doorcam = find entity with targetname "doorcam" +label weee + +use entity doorcam + +use entity portal + +wait .5 seconds + +play sound "doors/kchunk5.wav" for entity bar1 on channel 10 +play sound "doors/kchunk5.wav" for entity bar3 on channel 10 + +move entity bar1 by [16,0,0] at 50 speed signaling sig1 +move entity bar2 by [16,0,0] at 50 speed signaling sig2 +move entity bar3 by [16,0,0] at 50 speed signaling sig3 +move entity bar4 by [16,0,0] at 50 speed signaling sig4 +move entity bar5 by [-16,0,0] at 50 speed signaling sig5 +move entity bar6 by [-16,0,0] at 50 speed signaling sig6 +move entity bar7 by [-16,0,0] at 50 speed signaling sig7 +move entity bar8 by [-16,0,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +wait .5 seconds + +play sound "objects/gearsmove.wav" for entity bar1 on channel 10 +play sound "objects/gearsmove.wav" for entity bar3 on channel 10 + +move entity bar1 by [0,160,0] at 50 speed signaling sig1 +move entity bar2 by [0,-96,0] at 50 speed signaling sig2 +move entity bar3 by [0,96,0] at 50 speed signaling sig3 +move entity bar4 by [0,-160,0] at 50 speed signaling sig4 +move entity bar5 by [0,160,0] at 50 speed signaling sig5 +move entity bar6 by [0,-96,0] at 50 speed signaling sig6 +move entity bar7 by [0,96,0] at 50 speed signaling sig7 +move entity bar8 by [0,-160,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +play sound "doors/thud4.wav" for entity bar1 on channel 10 +play sound "doors/thud4.wav" for entity bar3 on channel 10 + +wait 2 seconds + +move entity botdn by [0,0,-64] at 30 speed +move entity botup by [0,0,-64] at 30 speed +move entity middnout by [0,-64,0] at 30 speed +move entity midupout by [0,64,0] at 30 speed +move entity middnin by [0,-120,0] at 60 speed +move entity midupin by [0,120,0] at 60 speed +move entity topup by [0,112,0] at 40 speed +move entity topdn by [0,-112,0] at 40 speed +move entity toprt by [0,0,112] at 40 speed +move entity toplf by [0,0,112] at 40 speed + +play sound "doors/stonestart.wav" for entity botup on channel 10 +play sound "doors/stonestart.wav" for entity botdn on channel 10 + +wait.5 seconds + +play sound "doors/stoneloop.wav" for entity botup on channel 10 +play sound "doors/stoneloop.wav" for entity botdn on channel 10 + +wait 1.5 seconds + +play sound "doors/stoneend.wav" for entity botup on channel 10 +play sound "doors/stoneend.wav" for entity botdn on channel 10 + +wait .5 seconds + +use entity doorcam + +exit + +//suspend + +//goto weee diff --git a/Toolkit/Designer/dsexamples/cloud/flames.ds b/Toolkit/Designer/dsexamples/cloud/flames.ds new file mode 100644 index 0000000..e9ed8bf --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/flames.ds @@ -0,0 +1,28 @@ +//gaurds die, ogles cheer, flames go out + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +//define variables + +local entity fire +local entity fire1 +local entity hurt +local entity light +local int sig + +fire = find entity with targetname "fire" +fire1 = find entity with targetname "fire1" +hurt = find entity with targetname "firedamage" +light = find entity with targetname "flamelight" + +//turn stuff off. + + use entity fire + use entity fire1 + + move entity hurt by [0, 0, -256] over 1 seconds + + move entity light by [0, 0, -256] over 1 seconds signaling sig + wait for all clearing sig \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/labtable.ds b/Toolkit/Designer/dsexamples/cloud/labtable.ds new file mode 100644 index 0000000..12c39ee --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/labtable.ds @@ -0,0 +1,41 @@ +// The fantabulous rotating lab table! + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity labtable +local entity arm +local int sig + +labtable = find entity with targetname "t100" +arm = find entity with targetname "t200" + + +label loop + +wait 3 seconds + +labtable.owner = arm +labtable.state = 0 +labtable.distance = 240 +labtable.start_origin = [0, 0, 240] +labtable.movetype = PHYSICSTYPE_SCRIPT_ANGULAR + +play sound "objects/globebottomstart.wav" for entity arm on channel 10 +rotate entity arm by [0,0,-180] at 30 speed signaling sig +wait for all clearing sig +play sound "objects/globebottomend.wav" for entity arm on channel 10 + +wait 15 seconds + +play sound "objects/globebottomstart.wav" for entity arm on channel 10 +rotate entity arm by [0,0, 180] at 30 speed signaling sig +wait for all clearing sig +play sound "objects/globebottomend.wav" for entity arm on channel 10 + +suspend +goto loop + + + diff --git a/Toolkit/Designer/dsexamples/cloud/levers.ds b/Toolkit/Designer/dsexamples/cloud/levers.ds new file mode 100644 index 0000000..65e54a7 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/levers.ds @@ -0,0 +1,56 @@ +//Levers come from the walls in the sanctum. + + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +// define varibles + +local entity leverr +local entity leverl +local entity leverbaser +local entity leverbasel +local entity doorr +local entity doorl +local entity steps +local int sig +local int sig1 +local int sig2 +local int sig3 + +leverr = find entity with targetname "leverr" +leverl = find entity with targetname "leverl" +leverbaser = find entity with targetname "t50" +leverbasel = find entity with targetname "t62" +doorr = find entity with targetname "r7" +doorl = find entity with targetname "d7" +steps = find entity with targetname "steps" + +//move it + + play sound "doors/kchunk3.wav" for entity doorl on channel 10 + move entity doorr by [-16, 0, 0] at 75 speed signaling sig + move entity doorl by [-16, 0, 0] at 75 speed signaling sig1 + wait for all clearing sig, sig1 + + wait .5 seconds + move entity doorr by [0, 32, 0] at 75 speed signaling sig + move entity doorl by [0, -32, 0] at 75 speed signaling sig1 + wait for all clearing sig, sig1 + + play sound "doors/slide2.wav" for entity leverbasel on channel 10 + leverr.movetype = PHYSICSTYPE_PUSH + leverl.movetype = PHYSICSTYPE_PUSH + move entity leverr by [104, 0, 0] at 75 speed signaling sig + move entity leverl by [104, 0, 0] at 75 speed signaling sig1 + move entity leverbaser by [104, 0, 0] at 75 speed signaling sig2 + move entity leverbasel by [104, 0, 0] at 75 speed signaling sig3 + wait for all clearing sig, sig1, sig2, sig3 + play sound "doors/thud4.wav" for entity leverbasel on channel 10 + + move entity steps by [32, 0, 0] at 75 speed signaling sig + wait for all clearing sig + + + \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/lift.ds b/Toolkit/Designer/dsexamples/cloud/lift.ds new file mode 100644 index 0000000..3a60349 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/lift.ds @@ -0,0 +1,35 @@ +//lift in boiler room + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + + +//define variables + +local entity roll +local entity lift +local int sig +local int sig1 + +roll = find entity with targetname "roll" +lift = find entity with targetname "lift" + +label loop + +//lift goes up + + move entity lift by [0, 0, 576] at 60 speed signaling sig + + rotate entity roll to [-576, 0, 0] at 60 speed signaling sig1 + wait for all clearing sig, sig1 + + wait 2 seconds + + move entity lift by [0, 0, -576] at 80 speed signaling sig + + rotate entity roll to [576, 0, 0] at 80 speed signaling sig1 + wait for all clearing sig, sig1 + +suspend +goto loop \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/monster.ds b/Toolkit/Designer/dsexamples/cloud/monster.ds new file mode 100644 index 0000000..94e987c --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/monster.ds @@ -0,0 +1,61 @@ +// Big Gaurd comes out and whoops ass! + + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +//varibles + +local entity light +local entity chain +local entity tablef +local entity tableb +local entity rubble +local entity junk +local entity kill +local entity kill1 +local entity throne +local int sig +local int sig1 +local int sig2 + +light = find entity with targetname "chandelier" +chain = find entity with targetname "chain" +tablef = find entity with targetname "tablefront" +tableb = find entity with targetname "tableback" +rubble = find entity with targetname "tablerubble" +kill = find entity with targetname "kill" +kill1 = find entity with targetname "kill1" +throne = find entity with targetname "throne" +junk = find entity with targetname "junk" + + + + +// wow + + use entity chain + + light.movetype = PHYSICSTYPE_PUSH + move entity light by [0, 0, -336] over .25 seconds signaling sig + wait for all clearing sig + play sound "monsters/tbeast/slam.wav" for entity rubble + use entity rubble + use entity junk + rotate entity tablef by [0, 0, -15] at 300 speed signaling sig + rotate entity tableb by [0, 0, 15] at 300 speed signaling sig1 + wait for all clearing sig, sig1 + + use entity kill + use entity kill1 + use entity throne + + wait 10 seconds + + light.modelindex = 0 + light.solid = SOLID_NOT + +exit + + \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/morcalavin.ds b/Toolkit/Designer/dsexamples/cloud/morcalavin.ds new file mode 100644 index 0000000..28b9337 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/morcalavin.ds @@ -0,0 +1,301 @@ +// The big boss man + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity barrier + +local entity cam1 +local entity cam2 +local entity cam3 +local entity cam4 +local entity cam5 +local entity camone +local entity dolly1 +local entity dolly2 +local entity dolly3 +local entity dolly4 +local entity cam1train +local entity cam2train +local entity cam3train +local entity cam4train +local entity boss +parameter entity hero +local entity player1 +local entity monster +local entity cd +local entity close +local entity hero +local entity doorcam +local entity coop + +local entity toplf +local entity toprt +local entity topup +local entity topdn +local entity midupout +local entity midupin +local entity middnout +local entity middnin +local entity botup +local entity botdn +local entity bar1 +local entity bar2 +local entity bar3 +local entity bar4 +local entity bar5 +local entity bar6 +local entity bar7 +local entity bar8 +local entity portal +local entity take + +local int sig +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int sig6 +local int sig7 +local int sig8 + + +//hero.yaw_speed = 8 + +barrier = find entity with targetname "barrier" + +cam1 = find entity with targetname "shot1" +cam1train = find entity with scripttarget "train1" +cam2 = find entity with targetname "shot2" +cam2train = find entity with scripttarget "train2" +cam3 = find entity with targetname "shot3" +cam3train = find entity with scripttarget "train3" +cam4 = find entity with targetname "shot4" +cam4train = find entity with scripttarget "train4" +cam5 = find entity with targetname "cam5" +camone = find entity with targetname "camone" +dolly1 = find entity with scripttarget "pan1" +dolly2 = find entity with scripttarget "pan2" +dolly3 = find entity with scripttarget "pan3" +dolly4 = find entity with scripttarget "pan4" +boss = find entity with targetname "boss" +monster = find entity with targetname "monster" +cd = find entity with targetname "cd" +close = find entity with targetname "close" +hero = find entity with targetname "hero" +doorcam = find entity with targetname "doorcam2" +coop = find entity with targetname "telcoop" + +toplf = find entity with targetname "toplf" +toprt = find entity with targetname "toprt" +topup = find entity with targetname "topup" +topdn = find entity with targetname "topdn" +midupout = find entity with targetname "midupout" +midupin = find entity with targetname "midupin" +middnout = find entity with targetname "middnout" +middnin = find entity with targetname "middnin" +botup = find entity with targetname "botup" +botdn = find entity with targetname "botdn" +bar1 = find entity with targetname "bar1" +bar2 = find entity with targetname "bar2" +bar3 = find entity with targetname "bar3" +bar4 = find entity with targetname "bar4" +bar5 = find entity with targetname "bar5" +bar6 = find entity with targetname "bar6" +bar7 = find entity with targetname "bar7" +bar8 = find entity with targetname "bar8" +portal = find entity with targetname "portal" +take = find entity with targetname "take" + +//Switching player + +player1 = get entity activator // Get player who set off trigger + +copy player attributes from entity player1 to entity hero +hero.modelindex = hero.count // Turn on cinematic corvus +hero.solid = SOLID_SOLID // Make him block +hero.movetype = PHYSICSTYPE_STEP + +enable cinematics +cache sound "cinematics/morcalavin/120-54.wav" +cache sound "cinematics/morcalavin/121-60.wav" +cache sound "cinematics/morcalavin/122-52.wav" +cache sound "cinematics/morcalavin/123-66.wav" +cache sound "cinematics/morcalavin/124-52.wav" +cache sound "cinematics/morcalavin/125-76.wav" + +// Corvus walks in and door closes. + + use entity doorcam + + animate entity hero performing action WALK2_ANIMATION by moving [302, 0, 0] signaling sig + wait for all clearing sig + animate entity hero performing action IDLE1_ANIMATION + + wait .5 seconds + + +move entity botdn by [0,0,64] at 30 speed +move entity botup by [0,0,64] at 30 speed +move entity middnout by [0,64,0] at 30 speed +move entity midupout by [0,-64,0] at 30 speed +move entity middnin by [0,120,0] at 60 speed +move entity midupin by [0,-120,0] at 60 speed +move entity topup by [0,-112,0] at 40 speed +move entity topdn by [0,112,0] at 40 speed +move entity toprt by [0,0,-112] at 40 speed +move entity toplf by [0,0,-112] at 40 speed + +play sound "doors/stonestart.wav" for entity botup on channel 10 +play sound "doors/stonestart.wav" for entity botdn on channel 10 + +wait.5 seconds + +play sound "doors/stoneloop.wav" for entity botup on channel 10 +play sound "doors/stoneloop.wav" for entity botdn on channel 10 + +wait 1.5 seconds + +play sound "doors/stoneend.wav" for entity botup on channel 10 +play sound "doors/stoneend.wav" for entity botdn on channel 10 + +wait 2 seconds + +play sound "doors/kchunk5.wav" for entity bar1 on channel 10 +play sound "doors/kchunk5.wav" for entity bar3 on channel 10 + +wait .5 seconds + +play sound "objects/gearsmove.wav" for entity bar1 on channel 10 +play sound "objects/gearsmove.wav" for entity bar3 on channel 10 + +move entity bar1 by [0,-160,0] at 50 speed signaling sig1 +move entity bar2 by [0,96,0] at 50 speed signaling sig2 +move entity bar3 by [0,-96,0] at 50 speed signaling sig3 +move entity bar4 by [0,160,0] at 50 speed signaling sig4 +move entity bar5 by [0,-160,0] at 50 speed signaling sig5 +move entity bar6 by [0,96,0] at 50 speed signaling sig6 +move entity bar7 by [0,-96,0] at 50 speed signaling sig7 +move entity bar8 by [0,160,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +move entity bar1 by [-16,0,0] at 50 speed signaling sig1 +move entity bar2 by [-16,0,0] at 50 speed signaling sig2 +move entity bar3 by [-16,0,0] at 50 speed signaling sig3 +move entity bar4 by [-16,0,0] at 50 speed signaling sig4 +move entity bar5 by [16,0,0] at 50 speed signaling sig5 +move entity bar6 by [16,0,0] at 50 speed signaling sig6 +move entity bar7 by [16,0,0] at 50 speed signaling sig7 +move entity bar8 by [16,0,0] at 50 speed signaling sig8 + +wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + +play sound "doors/thud4.wav" for entity bar1 on channel 10 +play sound "doors/thud4.wav" for entity bar3 on channel 10 + +use entity portal + + wait 1.5 seconds + + use entity doorcam + +// Establishing shot + + use entity camone + + animate entity hero performing action WALK2_ANIMATION by moving [370, 0, 0] signaling sig + wait for all clearing sig + + use entity camone + +// Morcalavin speaks + + use entity cam1 + + print 263 captioned + play sound "cinematics/morcalavin/120-54.wav" for entity boss + move entity cam1train by [96, 16, 0] over 28 seconds + animate entity boss performing action ACTION1_ANIMATION signaling sig + animate entity hero performing action IDLE2_ANIMATION signaling sig1 + wait 10 seconds + print 264 captioned + wait for all clearing sig, sig1 +// wait .5 seconds + use entity cam1 + + +// Corvus replies + + use entity cam2 + + print 265 captioned + play sound "cinematics/morcalavin/121-60.wav" for entity hero + animate entity hero performing action ACTION1_ANIMATION signaling sig + animate entity boss performing action IDLE2_ANIMATION signaling sig1 + wait for all clearing sig, sig1 +// wait .5 seconds + use entity cam2 + +// Morcalavin is sarcastic + + use entity cam3 + + print 266 captioned + play sound "cinematics/morcalavin/122-52.wav" for entity boss + animate entity boss performing action ACTION2_ANIMATION signaling sig + animate entity hero performing action IDLE2_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + wait .2 seconds + use entity cam3 + +// They banter back and forth + + use entity cam4 + + print 267 captioned + play sound "cinematics/morcalavin/123-66.wav" for entity hero + animate entity hero performing action ACTION2_ANIMATION signaling sig + animate entity boss performing action IDLE3_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + + print 268 captioned + play sound "cinematics/morcalavin/124-52.wav" for entity boss + animate entity boss performing action ACTION3_ANIMATION signaling sig + animate entity hero performing action IDLE3_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + use entity cam4 + + use entity cam5 + print 269 captioned + play sound "cinematics/morcalavin/125-76.wav" for entity hero + animate entity hero performing action ACTION3_ANIMATION signaling sig + animate entity boss performing action IDLE4_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + use entity cam5 + +//Switching back + +player1.origin = hero.origin // Put player where Cinematic corvus is +player1.p_origin = hero.origin // Put player where Cinematic corvus is set view angles of entity player1 to hero.angles +hero.modelindex = 0 // Turn off the cinematic corvus model +hero.solid = SOLID_NOT // Make him not solid + +//Switching Morcalavin + +monster.origin = boss.origin // Put Monster where Morcalavin is +monster.angles = boss.angles // Make Monster angles like Morcalavin +boss.modelindex = 0 // Turn off the cinematic Morcalavin model +boss.solid = SOLID_NOT // Make him not solid + +disable cinematics + +use entity take + +use entity coop + +use entity barrier + +use entity cd diff --git a/Toolkit/Designer/dsexamples/cloud/newarm.ds b/Toolkit/Designer/dsexamples/cloud/newarm.ds new file mode 100644 index 0000000..d67bb97 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/newarm.ds @@ -0,0 +1,55 @@ +// The fantabulous rotating lab table! + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity table +local entity kill +local entity light +local entity flame +local entity flame1 +local entity lever + +local int sig +local int sig1 + +lever = find entity with targetname "lablever" +table = find entity with targetname "newtable" +kill = find entity with targetname "kill" +light = find entity with targetname "strike" +flame = find entity with targetname "burn" +flame = find entity with targetname "burn1" + +//CRANK IT UP!!!! + +//use entity light +//play sound "Weapons/lightning.wav" for entity lever + +//wait .25 seconds + +//use entity kill + +suspend + +label loop + +play sound "doors/elevatorstop.wav" for entity table on channel 10 +wait 1 seconds +move entity table by [0, 0, 440] at 60 speed signaling sig +play sound "objects/hugewheel.wav" for entity table on channel 10 +wait for all clearing sig +play sound "objects/piston.wav" for entity table on channel 10 + +wait 5 seconds + +play sound "doors/elevatorstop.wav" for entity table on channel 10 +wait 1 seconds +move entity table by [0, 0, -440] at 60 speed signaling sig +play sound "objects/hugewheel.wav" for entity table on channel 10 +wait for all clearing sig +play sound "objects/piston.wav" for entity table on channel 10 + +wait 5 seconds + +goto loop \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/ogle.ds b/Toolkit/Designer/dsexamples/cloud/ogle.ds new file mode 100644 index 0000000..67c0468 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/ogle.ds @@ -0,0 +1,40 @@ +// ogles pushing a wheel + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity ogle1 +local entity ogle2 +local entity wheel +local int sig + +ogle1 = find entity with targetname "ogle1" +ogle2 = find entity with targetname "ogle2" +wheel = find entity with targetname "t289" + + +ogle1.owner = wheel +ogle1.distance = 155 +ogle1.start_origin = wheel.origin - [0, 0, 184] +ogle1.start_angles = [0, 160, 0] +ogle1.movetype = PHYSICSTYPE_SCRIPT_ANGULAR +ogle1.state = 3 + +ogle2.owner = wheel +ogle2.distance = 155 +ogle2.start_origin = wheel.origin - [0, 0, 184] +ogle2.start_angles = [0, 300, 0] +ogle2.movetype = PHYSICSTYPE_SCRIPT_ANGULAR +ogle2.state = 3 + +label loop + +rotate entity wheel by [0,-360,0] at 10 speed signaling sig +wait for all clearing sig + + +goto loop + + + diff --git a/Toolkit/Designer/dsexamples/cloud/secretdoor.ds b/Toolkit/Designer/dsexamples/cloud/secretdoor.ds new file mode 100644 index 0000000..798bbf5 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/secretdoor.ds @@ -0,0 +1,26 @@ +//secret door in the labs + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +//define varibales + +local entity sdoor +local int sig + +sdoor = find entity with targetname "secretdoor" + +play sound "doors/thud4.wav" for entity sdoor + +move entity sdoor by [-16, 0, 0] at 50 speed signaling sig +wait for all clearing sig + +play sound "doors/metal1.wav" for entity sdoor + +move entity sdoor by [0, 192, 0] over 2 seconds signaling sig +wait for all clearing sig + +wait .5 seconds + +play sound "doors/kchunk6.wav" for entity sdoor \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/secretdoor1.ds b/Toolkit/Designer/dsexamples/cloud/secretdoor1.ds new file mode 100644 index 0000000..cf6abba --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/secretdoor1.ds @@ -0,0 +1,22 @@ +// secret door moves back + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +//define varibales + +local entity sdoor +local int sig + +sdoor = find entity with targetname "secretdoor" + +play sound "doors/metal1.wav" for entity sdoor + +move entity sdoor by [0, -192, 0] over 2 seconds signaling sig +wait for all clearing sig + +play sound "doors/thud3.wav" for entity sdoor + +move entity sdoor by [16, 0, 0] at 50 speed signaling sig +wait for all clearing sig \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/sixtomesdone.ds b/Toolkit/Designer/dsexamples/cloud/sixtomesdone.ds new file mode 100644 index 0000000..f4346e3 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/sixtomesdone.ds @@ -0,0 +1,86 @@ +// After all 6 tomes are turned off. + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity tome +local entity camera1 +local entity target1 +local entity hero +local entity player1 +local entity puzztome +local vector holdpos +local entity miss +local entity take + +local int sig +local int sig1 +local int sig2 +local int holdindex +local vector holdangles + +tome = find entity with targetname "tome" +camera1 = find entity with targetname "cam1" +target1 = find entity with scripttarget "target1" +hero = find entity with targetname "hero" +puzztome = find entity with targetname "puzztome" +miss = find entity with targetname "miss" +take = find entity with targetname "take" +player1 = get entity activator +//Switching player + + + +copy player attributes from entity player1 to entity hero +hero.origin = player1.origin +hero.angles = player1.angles +hero.modelindex = hero.count // Turn on cinematic corvus +hero.solid = SOLID_SOLID // Make him block +hero.movetype = PHYSICSTYPE_STEP + +camera1.origin = player1.origin + [8, 72, 16] +target1.origin = player1.origin + [0, -16, 0] +tome.origin = player1.origin + [24, 32, 0] +tome.angles = hero.angles + [0, 180, 0] +holdangles = tome.angles +tome.ideal_yaw = holdangles.y +tome.solid = SOLID_SOLID +tome.modelindex = tome.count +enable cinematics +use entity camera1 +wait 1 seconds + +animate entity tome performing action IDLE1_ANIMATION repeating for 5 times +animate entity hero performing action PIVOTLEFT_ANIMATION by turning [60, 0, 0] + +print 75 captioned +play sound "tome/place_tome.wav" for entity tome +wait 16 seconds +use entity camera1 + +//Switching back +disable cinematics +player1.origin = hero.origin // Put player where Cinematic corvus is +player1.p_origin = hero.origin // Put player where Cinematic corvus is +set view angles of entity player1 to hero.angles +hero.modelindex = 0 // Turn off the cinematic corvus model +hero.solid = SOLID_NOT // Make him not solid +holdpos = tome.origin + [0, 0, 8] +tome.modelindex = 0 +tome.solid = SOLID_NOT + +target1.movetype = PHYSICSTYPE_NOCLIP +//holdpos = player1.origin + [24, 32, 8] + +//puzztome = spawn entity with fields "classname" = "item_puzzle_tome", "origin" = holdpos +puzztome.origin = player1.origin + [0, 0, 8] +use entity puzztome + +use entity take +wait .1 seconds +use entity miss +wait .5 seconds + +exit + \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/stairs.ds b/Toolkit/Designer/dsexamples/cloud/stairs.ds new file mode 100644 index 0000000..664693e --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/stairs.ds @@ -0,0 +1,65 @@ +// stairs go down to secret room + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + + +//define variables + +local entity step1 +local entity step2 +local entity step3 +local entity step4 +local entity step5 +local entity step6 +local entity step7 +local entity step8 +local entity panelr +local entity panell + +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int sig6 +local int sig7 +local int sig8 + +step1 = find entity with targetname "s1" +step2 = find entity with targetname "s2" +step3 = find entity with targetname "s3" +step4 = find entity with targetname "s4" +step5 = find entity with targetname "s5" +step6 = find entity with targetname "s6" +step7 = find entity with targetname "s7" +step8 = find entity with targetname "s8" +panelr = find entity with targetname "pr" +panell = find entity with targetname "pl" + + +// move stuff + +label loop + + move entity step1 by [0, 0, -16] at 50 speed signaling sig1 + move entity step2 by [0, 0, -32] at 55 speed signaling sig2 + move entity step3 by [0, 0, -48] at 60 speed signaling sig3 + move entity step4 by [0, 0, -64] at 65 speed signaling sig4 + move entity step5 by [0, 0, -80] at 70 speed signaling sig5 + move entity step6 by [0, 0, -96] at 75 speed signaling sig6 + move entity step7 by [0, 0, -112] at 80 speed signaling sig7 + move entity step8 by [0, 0, -128] at 85 speed signaling sig8 + wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6, sig7, sig8 + + + play sound "doors/kchunk7.wav" for entity panelr on channel 10 + move entity panelr by [56, 0, 0] at 50 speed signaling sig1 + move entity panell by [-56, 0, 0] at 50 speed signaling sig2 + wait for all clearing sig1, sig2 + play sound "doors/kchunk6.wav" for entity panelr on channel 10 + + +suspend +goto loop diff --git a/Toolkit/Designer/dsexamples/cloud/stairsdn.ds b/Toolkit/Designer/dsexamples/cloud/stairsdn.ds new file mode 100644 index 0000000..4f2549d --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/stairsdn.ds @@ -0,0 +1,66 @@ +// stairs go down to secret room + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + + +//define variables + +local entity step1 +local entity step2 +local entity step3 +local entity step4 +local entity step5 +local entity step6 +local entity step7 +local entity step8 +local entity panelr +local entity panell + +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int sig6 +local int sig7 +local int sig8 + +step1 = find entity with targetname "s1" +step2 = find entity with targetname "s2" +step3 = find entity with targetname "s3" +step4 = find entity with targetname "s4" +step5 = find entity with targetname "s5" +step6 = find entity with targetname "s6" +step7 = find entity with targetname "s7" +step8 = find entity with targetname "s8" +panelr = find entity with targetname "pr" +panell = find entity with targetname "pl" + + +// move stuff + +label loop + + + play sound "doors/kchunk6.wav" for entity panelr on channel 10 + move entity panelr by [-56, 0, 0] at 50 speed signaling sig1 + move entity panell by [56, 0, 0] at 50 speed signaling sig2 + wait for all clearing sig1, sig2 + play sound "doors/kchunk7.wav" for entity panelr on channel 10 + + move entity step8 by [0, 0, 128] at 50 speed signaling sig8 + move entity step7 by [0, 0, 112] at 45 speed signaling sig7 + move entity step6 by [0, 0, 96] at 40 speed signaling sig6 + move entity step5 by [0, 0, 80] at 35 speed signaling sig5 + move entity step4 by [0, 0, 64] at 30 speed signaling sig4 + move entity step3 by [0, 0, 48] at 25 speed signaling sig3 + move entity step2 by [0, 0, 32] at 20 speed signaling sig2 + move entity step1 by [0, 0, 16] at 15 speed signaling sig1 + wait for all clearing sig8, sig7, sig6, sig5, sig4, sig3, sig2, sig1 + + +suspend +goto loop + diff --git a/Toolkit/Designer/dsexamples/cloud/tankdoor.ds b/Toolkit/Designer/dsexamples/cloud/tankdoor.ds new file mode 100644 index 0000000..0ee79fc --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/tankdoor.ds @@ -0,0 +1,60 @@ +// biotank secret room + + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +// define varibles + +local entity doorr +local entity doorl +local entity floor +local entity cover + +local entity cam +local entity portal +local entity light +local entity lablight +local int sig +local int sig1 +local int sig2 + +doorr = find entity with targetname "biodoor1" +doorl = find entity with targetname "biodoor" +floor = find entity with targetname "tankdoor1" +cover = find entity with targetname "tankdoor2" + +light = find entity with targetname "biolight" +lablight = find entity with targetname "biolight2" +cam = find entity with targetname "tankcam" +portal = find entity with targetname "portal" + +// wow + +label loop + + use entity cam + + light.movetype = PHYSICSTYPE_NOCLIP + play sound "doors/kchunk7.wav" for entity floor + move entity floor by [0, 0, -154] over 2 seconds signaling sig + wait for all clearing sig + + play sound "doors/kchunk6.wav" for entity doorr + move entity doorr by [72, 0, 0] over 1 seconds signaling sig + move entity doorl by [-72, 0, 0] over 1 seconds signaling sig1 + wait for all clearing sig, sig1 + + use entity lablight + + play sound "doors/kchunk5.wav" for entity cover + move entity cover by [0, 56, 0] over 1 seconds signaling sig + wait for all clearing sig + + wait .5 seconds + + use entity cam + +suspend +goto loop \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/tankdoor1.ds b/Toolkit/Designer/dsexamples/cloud/tankdoor1.ds new file mode 100644 index 0000000..3e30f97 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/tankdoor1.ds @@ -0,0 +1,59 @@ +// biotank secret room + + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +// define varibles + +local entity doorr +local entity doorl +local entity floor +local entity cover + +local entity cam1 +local entity portal +local entity light +local entity lablight +local int sig +local int sig1 +local int sig2 + +doorr = find entity with targetname "biodoor1" +doorl = find entity with targetname "biodoor" +floor = find entity with targetname "tankdoor1" +cover = find entity with targetname "tankdoor2" + +light = find entity with targetname "biolight" +lablight = find entity with targetname "biolight2" +cam1 = find entity with targetname "tankcam1" +portal = find entity with targetname "portal" + +// wow + +label loop + + use entity cam1 + + play sound "doors/kchunk5.wav" for entity cover + move entity cover by [0, -56, 0] over 1 seconds signaling sig + wait for all clearing sig + + use entity lablight + + play sound "doors/kchunk6.wav" for entity doorr + move entity doorr by [-72, 0, 0] over 1 seconds signaling sig + move entity doorl by [72, 0, 0] over 1 seconds signaling sig1 + wait for all clearing sig, sig1 + + play sound "doors/kchunk7.wav" for entity floor + move entity floor by [0, 0, 154] over 2 seconds signaling sig + wait for all clearing sig + + wait .5 seconds + + use entity cam1 + +suspend +goto loop \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/tomecam.ds b/Toolkit/Designer/dsexamples/cloud/tomecam.ds new file mode 100644 index 0000000..70a7d7e --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/tomecam.ds @@ -0,0 +1,36 @@ +// Pivoting cam to run while sister_tome plays + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity cam +local entity ctr +local entity mess +local entity give + +local int sig + +cam = find entity with targetname "rotcam" +ctr = find entity with scripttarget "camtrain" +mess = find entity with targetname "mess" +give = find entity with targetname "mission" + +//start action! + + +enable cinematics + +use entity cam + +wait 1 seconds + +print 72 captioned +move entity ctr by [-256, -256, 0] over 20 seconds signaling sig +wait for all clearing sig + +use entity cam + +use entity give + +disable cinematics diff --git a/Toolkit/Designer/dsexamples/cloud/tomecount.ds b/Toolkit/Designer/dsexamples/cloud/tomecount.ds new file mode 100644 index 0000000..5b93e2b --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/tomecount.ds @@ -0,0 +1,20 @@ +// Pivoting cam to run while sister_tome plays + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +global int countem + +label countloop +countem += 1 + +if countem = 6 + wait 12 seconds + print 75 + wait 16 seconds + exit +endif +suspend + +goto countloop \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/cloud/wowcam.ds b/Toolkit/Designer/dsexamples/cloud/wowcam.ds new file mode 100644 index 0000000..46fa002 --- /dev/null +++ b/Toolkit/Designer/dsexamples/cloud/wowcam.ds @@ -0,0 +1,82 @@ +//wow cam for the cloudhub + + + +#include "../common/header.ds" + +output "r:/base/ds/cloud" + +local entity cam +local entity cambase +local entity null + +local entity light +local entity light2 +local entity light3 +local entity player1 +local entity hero +local int sig +local int sig1 + +cam = find entity with targetname "t66" +cambase = find entity with targetname "t64" +null = find entity with targetname "t65" +light = find entity with targetname "t82" +light2 = find entity with targetname "t76" +light3 = find entity with targetname "t81" +hero = find entity with targetname "wowcorvus" + +player1 = get entity activator // Get player who set off trigger + +copy player attributes from entity player1 to entity hero +hero.modelindex = hero.count // Turn on cinematic corvus +hero.solid = SOLID_SOLID // Make him block +hero.movetype = PHYSICSTYPE_STEP + + +//wow + +enable cinematics + +use entity cam + + animate entity hero performing action IDLE1_ANIMATION + + move entity cambase by [450, -712, 360] over 3.5 seconds signaling sig + wait for all clearing sig + + use entity light + play sound "Weapons/lightning.wav" for entity cam + + wait .5 seconds + + use entity light2 + play sound "Weapons/lightning.wav" for entity cam + + wait 1 seconds + + use entity light2 + play sound "Weapons/lightning.wav" for entity cam + + wait .25 seconds + + use entity light + play sound "Weapons/lightning.wav" for entity cam + + wait .25 seconds + + use entity light + play sound "Weapons/lightning.wav" for entity cam + + wait 1.5 seconds + +use entity cam + +player1.origin = hero.origin // Put player where Cinematic corvus is +player1.p_origin = hero.origin // Put player where Cinematic corvus is set view angles of entity player1 to hero.angles +hero.modelindex = 0 // Turn off the cinematic corvus model +hero.solid = SOLID_NOT // Make him not solid + +disable cinematics + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/common/DoorSwing.ds b/Toolkit/Designer/dsexamples/common/DoorSwing.ds new file mode 100644 index 0000000..8321137 --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/DoorSwing.ds @@ -0,0 +1,42 @@ +// This thing is intended to allow the creation of a rotating door +// that always swings away from the player, thus avoiding those +// annoying hitches when the door swings towards you. + +output "r:/base/ds/common" + +parameter entity parm1 +parameter vector parm2 +parameter int parm3 +parameter int parm4 +parameter entity parm5 + +local entity door +local vector angles +local int spd +local int delay + +local int sgnl + +label beginning + +door = parm1 +angles = parm2 +spd = parm3 +delay = parm4 + +use entity parm5 +rotate entity door to angles at spd speed signaling sgnl + +wait for any clearing sgnl +wait delay seconds + +angles = [0,0,0] + +rotate entity door to angles at spd speed signaling sgnl + +wait for any clearing sgnl +use entity parm5 + +suspend + +goto beginning \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/common/Heretic2.BCE b/Toolkit/Designer/dsexamples/common/Heretic2.BCE new file mode 100644 index 0000000..df2b774 Binary files /dev/null and b/Toolkit/Designer/dsexamples/common/Heretic2.BCE differ diff --git a/Toolkit/Designer/dsexamples/common/InsetDoor.ds b/Toolkit/Designer/dsexamples/common/InsetDoor.ds new file mode 100644 index 0000000..d7df198 --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/InsetDoor.ds @@ -0,0 +1,52 @@ +output "r:/base/ds/common" + +parameter entity parm1 +parameter entity parm2 +parameter int parm3 +parameter vector parm4 +parameter vector parm5 + +local entity door +local entity areaportal +local int spd +local vector d1 +local vector d2 +local vector d1a +local vector d2a + +local int sgnl + +label beginning + +door = parm1 +areaportal = parm2 +spd = parm3 +d1 = parm4 +d2 = parm5 +d1a = [0,0,0] +d2a = [0,0,0] + +use entity areaportal + +move entity door by d1 at spd speed signaling sgnl +wait for any clearing sgnl + +move entity door by d2 at spd speed signaling sgnl +wait for any clearing sgnl + +wait 0.5 seconds + +d1a -= d1 +d2a -= d2 + +move entity door by d2a at spd speed signaling sgnl +wait for any clearing sgnl + +move entity door by d1a at spd speed signaling sgnl +wait for any clearing sgnl + +use entity areaportal + +suspend + +goto beginning \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/common/bug.ds b/Toolkit/Designer/dsexamples/common/bug.ds new file mode 100644 index 0000000..db17aea --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/bug.ds @@ -0,0 +1,54 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local int sig + +parameter entity bug + + +bug.yaw_speed = 5 + +// Idle 1 +animate entity bug performing action IDLE1_ANIMATION by turning [180, 0, 0] signaling sig +wait for any clearing sig + +// Pain 1 +animate entity bug performing action PAIN1_ANIMATION repeating for 2 times signaling sig +wait for any clearing sig + + +// Walking +animate entity bug performing action WALK1_ANIMATION by moving [200, 0, 0] by turning [180, 0, 0] signaling sig +wait for any clearing sig + +// Backpedal +animate entity bug performing action BACKPEDAL1_ANIMATION by moving [-200, 0, 0] by turning [0, 0,0] signaling sig +wait for any clearing sig + + +// Idling +animate entity bug performing action IDLE1_ANIMATION by turning [-200, 0, 0] signaling sig +wait for any clearing sig + + +animate entity bug performing action ATTACK1_ANIMATION signaling sig +wait for any clearing sig + + +animate entity bug performing action PAIN2_ANIMATION signaling sig +wait for any clearing sig + + +animate entity bug performing action ATTACK2_ANIMATION signaling sig +wait for any clearing sig + + +animate entity bug performing action RUN1_ANIMATION by moving [200, 0, 0] signaling sig +wait for any clearing sig + + +// Death +animate entity bug performing action DEATH1_ANIMATION by turning [300, 0, 0] signaling sig diff --git a/Toolkit/Designer/dsexamples/common/camera.ds b/Toolkit/Designer/dsexamples/common/camera.ds new file mode 100644 index 0000000..d2e1a35 --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/camera.ds @@ -0,0 +1,34 @@ +// A camera test! + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local entity camera +local entity cameratarget +local int cut + +camera = find entity with targetname "rollem" +cameratarget = find entity with targetname "camlook" + +// move camera (I hope) + +use entity camera + +move entity cameratarget by [128,32,16] at 35 speed signaling cut + +wait for all clearing cut + +move entity camera by [16,96,32] at 35 speed signaling cut + +wait for all clearing cut + +wait 2 seconds + +move entity cameratarget by [8,128,-48] at 35 speed signaling cut + +wait for all clearing cut + +use entity camera + +suspend diff --git a/Toolkit/Designer/dsexamples/common/camera1.ds b/Toolkit/Designer/dsexamples/common/camera1.ds new file mode 100644 index 0000000..a28b74f --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/camera1.ds @@ -0,0 +1,29 @@ +//This is the cool camera script! + +#include "../common/header.ds" + +output "r:/base/ds/common" + +//define variables + +local entity train +local entity rollem +local int sig + +train = find entity with targetname "t100" +rollem = find entity with targetname "camera" + +//move camera + +use entity rollem +move entity train by [128, 128, 0] at 100 speed signaling sig +wait for all clearing sig +rotate entity train by [0, 0, 128] at 200 speed signaling sig +wait for all clearing sig +wait 3 seconds +move entity train by [16, 16, 64] at 100 speed signaling sig +wait for all clearing sig +use entity rollem + +suspend + diff --git a/Toolkit/Designer/dsexamples/common/corvus.ds b/Toolkit/Designer/dsexamples/common/corvus.ds new file mode 100644 index 0000000..040e36f --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/corvus.ds @@ -0,0 +1,112 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local int sig +local entity camera1 + +parameter entity corvus + +camera1 = find entity with targetname "camera1" + +corvus.yaw_speed = 15 + +use entity camera1 + +// Walk start +animate entity corvus performing action WALKSTART_ANIMATION signaling sig +wait for any clearing sig + +// Walk 1 +animate entity corvus performing action WALK1_ANIMATION by moving [240, 0, 0] signaling sig +wait for any clearing sig + +// Walk stop1 +animate entity corvus performing action WALKSTOP1_ANIMATION signaling sig +wait for any clearing sig + +// Walk start +animate entity corvus performing action WALKSTART_ANIMATION signaling sig +wait for any clearing sig + +// Walk 1 +animate entity corvus performing action WALK1_ANIMATION by moving [140, 0, 0] signaling sig +wait for any clearing sig + +// Walk stop2 +animate entity corvus performing action WALKSTOP2_ANIMATION signaling sig +wait for any clearing sig + +// Idle 1 +animate entity corvus performing action IDLE1_ANIMATION repeating for 2 times signaling sig +wait for any clearing sig + + +// Pivot Left Go +animate entity corvus performing action PIVOTLEFTGO_ANIMATION signaling sig +wait for any clearing sig + +// Pivot Left +animate entity corvus performing action PIVOTLEFT_ANIMATION by turning [180, 0, 0] signaling sig +wait for any clearing sig + +// Pivot Left Stop +animate entity corvus performing action PIVOTLEFTSTOP_ANIMATION signaling sig +wait for any clearing sig + + +// Idle 1 +animate entity corvus performing action IDLE1_ANIMATION repeating for 2 times signaling sig +wait for any clearing sig + +// Pivot Right Go +animate entity corvus performing action PIVOTRIGHTGO_ANIMATION signaling sig +wait for any clearing sig + +// Pivot Right +animate entity corvus performing action PIVOTRIGHT_ANIMATION by turning [-180, 0, 0] signaling sig +wait for any clearing sig + +// Pivot Right Stop +animate entity corvus performing action PIVOTLEFTSTOP_ANIMATION signaling sig +wait for any clearing sig + + +// Action 1 +animate entity corvus performing action ACTION1_ANIMATION signaling sig +wait for any clearing sig + +// Action 2 +animate entity corvus performing action ACTION2_ANIMATION signaling sig +wait for any clearing sig + +// Action 3 +animate entity corvus performing action ACTION3_ANIMATION signaling sig +wait for any clearing sig + +// Idle 2 +animate entity corvus performing action IDLE2_ANIMATION by turning [180, 0, 0] repeating for 4 times signaling sig +wait for any clearing sig + +// Walk start +animate entity corvus performing action WALKSTART_ANIMATION signaling sig +wait for any clearing sig + +// Walk 2 +animate entity corvus performing action WALK2_ANIMATION by moving [240, 0, 0] signaling sig +wait for any clearing sig + + +// Strafe Left +//animate entity corvus performing action STRAFELEFT_ANIMATION signaling sig +//wait for any clearing sig + +// Strafe Right +//animate entity corvus performing action STRAFERIGHT_ANIMATION signaling sig +//wait for any clearing sig + + +// Idle 1 +animate entity corvus performing action IDLE1_ANIMATION diff --git a/Toolkit/Designer/dsexamples/common/corvus2.ds b/Toolkit/Designer/dsexamples/common/corvus2.ds new file mode 100644 index 0000000..4cb3c78 --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/corvus2.ds @@ -0,0 +1,145 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local int sig +local int modelindex + +local entity camera1 +local entity player1 +local vector character_pos +local vector player_pos +local int holdindex + +parameter entity corvus + +corvus.yaw_speed = 15 + +camera1 = find entity with targetname "camera1" + +use entity camera1 + + + + +player1 = get entity activator // Get player who set off trigger + +holdindex = player1.modelindex // Save players model +player1.modelindex = 0 // Make players model disappear +player1.solid = SOLID_NOT // Player won't block now + + +corvus.modelindex = corvus.count // Turn on cinematic corvus +corvus.solid = SOLID_SOLID // Make him block + + + + +enable cinematics + + +// Walk start +animate entity corvus performing action WALKSTART_ANIMATION signaling sig +wait for any clearing sig + +// Walk 1 +animate entity corvus performing action WALK1_ANIMATION by moving [200, 0, 0] signaling sig +wait for any clearing sig + +// Walk stop1 +animate entity corvus performing action WALKSTOP1_ANIMATION signaling sig +wait for any clearing sig + +// Walk start +animate entity corvus performing action WALKSTART_ANIMATION signaling sig +wait for any clearing sig + +disable cinematics + +player1.origin = corvus.origin // Put player where Cinematic corvus is +player1.angles = corvus.angles // Make player angles like Cinematic Corvus + +player1.modelindex = holdindex // Return the model to the player +player1.solid = SOLID_SOLID // Make the player solid + +corvus.modelindex = 0 // Turn off the cinematic corvus model +corvus.solid = SOLID_NOT // Make him not solid + + + +use entity camera1 + + + + + +// Pivot Left Go +animate entity corvus performing action PIVOTLEFTGO_ANIMATION signaling sig +wait for any clearing sig + +// Pivot Left +animate entity corvus performing action PIVOTLEFT_ANIMATION by turning [180, 0, 0] signaling sig +wait for any clearing sig + +// Pivot Left Stop +animate entity corvus performing action PIVOTLEFTSTOP_ANIMATION signaling sig +wait for any clearing sig + + + +// Walk 1 +animate entity corvus performing action WALK1_ANIMATION by moving [200, 0, 0] signaling sig +wait for any clearing sig + +// Walk stop2 +animate entity corvus performing action WALKSTOP2_ANIMATION signaling sig +wait for any clearing sig + + + +// Pivot Right Go +animate entity corvus performing action PIVOTRIGHTGO_ANIMATION signaling sig +wait for any clearing sig + +// Pivot Right +animate entity corvus performing action PIVOTRIGHT_ANIMATION by turning [-180, 0, 0] signaling sig +wait for any clearing sig + +// Pivot Right Stop +animate entity corvus performing action PIVOTLEFTSTOP_ANIMATION signaling sig +wait for any clearing sig + + + +// Walk 1 +animate entity corvus performing action WALK1_ANIMATION by moving [200, 0, 0] signaling sig +wait for any clearing sig + +// Walk stop1 +animate entity corvus performing action WALKSTOP1_ANIMATION signaling sig +wait for any clearing sig + +// Walk start +animate entity corvus performing action WALKSTART_ANIMATION signaling sig +wait for any clearing sig + + + + +// Action 1 +animate entity corvus performing action ACTION1_ANIMATION signaling sig +wait for any clearing sig + + +// Idle 1 +animate entity corvus performing action IDLE1_ANIMATION + +use entity camera1 + +// The big switch back +corvus.origin = corvus.origin +player1.origin = player1.origin + +wait 2 seconds diff --git a/Toolkit/Designer/dsexamples/common/corvus4.ds b/Toolkit/Designer/dsexamples/common/corvus4.ds new file mode 100644 index 0000000..600c239 --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/corvus4.ds @@ -0,0 +1,122 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local int sig + +parameter entity corvus + + +corvus.yaw_speed = 15 + +// Idle2 +animate entity corvus performing action IDLE2_ANIMATION repeating for 4 times signaling sig +wait for any clearing sig + + +// Action 2 +animate entity corvus performing action ACTION2_ANIMATION signaling sig +wait for any clearing sig + +// Action 2 +animate entity corvus performing action ACTION2_ANIMATION signaling sig +wait for any clearing sig + +// Walk start +animate entity corvus performing action WALKSTART_ANIMATION signaling sig +wait for any clearing sig + +// Walk 1 +animate entity corvus performing action WALK1_ANIMATION by moving [240, 0, 0] signaling sig +wait for any clearing sig + +// Walk stop1 +animate entity corvus performing action WALKSTOP1_ANIMATION signaling sig +wait for any clearing sig + +// Walk start +animate entity corvus performing action WALKSTART_ANIMATION signaling sig +wait for any clearing sig + +// Walk 1 +animate entity corvus performing action WALK1_ANIMATION by moving [140, 0, 0] signaling sig +wait for any clearing sig + +// Walk stop2 +animate entity corvus performing action WALKSTOP2_ANIMATION signaling sig +wait for any clearing sig + +// Idle 1 +animate entity corvus performing action IDLE1_ANIMATION repeating for 2 times signaling sig +wait for any clearing sig + + +// Pivot Left Go +animate entity corvus performing action PIVOTLEFTGO_ANIMATION signaling sig +wait for any clearing sig + +// Pivot Left +animate entity corvus performing action PIVOTLEFT_ANIMATION by turning [180, 0, 0] signaling sig +wait for any clearing sig + +// Pivot Left Stop +animate entity corvus performing action PIVOTLEFTSTOP_ANIMATION signaling sig +wait for any clearing sig + + +// Idle 1 +animate entity corvus performing action IDLE1_ANIMATION repeating for 2 times signaling sig +wait for any clearing sig + +// Pivot Right Go +animate entity corvus performing action PIVOTRIGHTGO_ANIMATION signaling sig +wait for any clearing sig + +// Pivot Right +animate entity corvus performing action PIVOTRIGHT_ANIMATION by turning [-180, 0, 0] signaling sig +wait for any clearing sig + +// Pivot Right Stop +animate entity corvus performing action PIVOTLEFTSTOP_ANIMATION signaling sig +wait for any clearing sig + + +// Action 1 +animate entity corvus performing action ACTION1_ANIMATION signaling sig +wait for any clearing sig + +// Action 2 +animate entity corvus performing action ACTION2_ANIMATION signaling sig +wait for any clearing sig + +// Action 3 +animate entity corvus performing action ACTION3_ANIMATION signaling sig +wait for any clearing sig + +// Action 4 +animate entity corvus performing action ACTION4_ANIMATION signaling sig +wait for any clearing sig + +// Action 5 +animate entity corvus performing action ACTION5_ANIMATION signaling sig +wait for any clearing sig + +// Idle 2 +animate entity corvus performing action IDLE2_ANIMATION by turning [180, 0, 0] repeating for 4 times signaling sig +wait for any clearing sig + +// Walk start +animate entity corvus performing action WALKSTART_ANIMATION signaling sig +wait for any clearing sig + +// Walk 2 +animate entity corvus performing action WALK2_ANIMATION by moving [240, 0, 0] signaling sig +wait for any clearing sig + + + + +// Idle 1 +animate entity corvus performing action IDLE1_ANIMATION diff --git a/Toolkit/Designer/dsexamples/common/dranor.ds b/Toolkit/Designer/dsexamples/common/dranor.ds new file mode 100644 index 0000000..b368d1e --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/dranor.ds @@ -0,0 +1,206 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local int sig + +parameter entity dranor + + +dranor.yaw_speed = 15 + + +cache sound "cinematics/dranor/19-316.wav" +cache sound "cinematics/dranor/20-314.wav" +cache sound "cinematics/dranor/21-319.wav" +cache sound "cinematics/dranor/22-314.wav" +cache sound "cinematics/dranor/23-315.wav" +cache sound "cinematics/dranor/24-316.wav" +cache sound "cinematics/dranor/25-316.wav" +cache sound "cinematics/dranor/26-319.wav" +cache sound "cinematics/dranor/27-315.wav" +cache sound "cinematics/dranor/28-317.wav" +cache sound "cinematics/dranor/29-317.wav" +cache sound "cinematics/dranor/30-314.wav" +cache sound "cinematics/dranor/31-314.wav" +cache sound "cinematics/dranor/32-317.wav" + + +// Idle 1 +animate entity dranor performing action IDLE1_ANIMATION repeating for 2 times signaling sig +wait for any clearing sig + + +// Action 12 +animate entity dranor performing action ACTION12_ANIMATION repeating for 20 times signaling sig +wait for any clearing sig + + +// Action 1 +animate entity dranor performing action ACTION1_ANIMATION signaling sig +wait for any clearing sig + +play sound "cinematics/dranor/19-316.wav" for entity dranor + +// Action 2 +animate entity dranor performing action ACTION2_ANIMATION signaling sig +wait for any clearing sig + + + + +play sound "cinematics/dranor/20-314.wav" for entity dranor + +// Idle 2 +animate entity dranor performing action IDLE2_ANIMATION signaling sig +wait for any clearing sig + + + + +play sound "cinematics/dranor/21-319.wav" for entity dranor + +// Action 3 +animate entity dranor performing action ACTION3_ANIMATION signaling sig +wait for any clearing sig + + + + +play sound "cinematics/dranor/22-314.wav" for entity dranor + +// Idle 3 +animate entity dranor performing action IDLE3_ANIMATION repeating for 2 times signaling sig +wait for any clearing sig + + + + +play sound "cinematics/dranor/23-315.wav" for entity dranor + +// Action 4 +animate entity dranor performing action ACTION4_ANIMATION signaling sig +wait for any clearing sig + +// Action 5 +animate entity dranor performing action ACTION5_ANIMATION signaling sig +wait for any clearing sig + + + + +play sound "cinematics/dranor/24-316.wav" for entity dranor + +// Idle 3 +animate entity dranor performing action IDLE3_ANIMATION signaling sig +wait for any clearing sig + + + +play sound "cinematics/dranor/25-316.wav" for entity dranor + +// Action 7 +animate entity dranor performing action ACTION7_ANIMATION signaling sig +wait for any clearing sig + +// Action 6 +animate entity dranor performing action ACTION6_ANIMATION signaling sig +wait for any clearing sig + + + + +play sound "cinematics/dranor/26-319.wav" for entity dranor + + +// Action 8 +animate entity dranor performing action ACTION8_ANIMATION signaling sig +wait for any clearing sig + +// Action 9 +animate entity dranor performing action ACTION9_ANIMATION signaling sig +wait for any clearing sig + + + + + +play sound "cinematics/dranor/27-315.wav" for entity dranor + +// Idle 3 +animate entity dranor performing action IDLE3_ANIMATION signaling sig +wait for any clearing sig + + + +play sound "cinematics/dranor/28-317.wav" for entity dranor + +// Action 4 +animate entity dranor performing action ACTION4_ANIMATION signaling sig +wait for any clearing sig + +// Action 5 +animate entity dranor performing action ACTION5_ANIMATION signaling sig +wait for any clearing sig + +// Action 10 +animate entity dranor performing action ACTION10_ANIMATION signaling sig +wait for any clearing sig + + + +play sound "cinematics/dranor/29-317.wav" for entity dranor + +// Action 8 +animate entity dranor performing action ACTION8_ANIMATION signaling sig +wait for any clearing sig + +// Action 4 +animate entity dranor performing action ACTION4_ANIMATION signaling sig +wait for any clearing sig + +// Action 5 +animate entity dranor performing action ACTION5_ANIMATION signaling sig +wait for any clearing sig + + +// Action 11 +animate entity dranor performing action ACTION11_ANIMATION signaling sig +wait for any clearing sig + + +play sound "cinematics/dranor/30-314.wav" for entity dranor + +// Idle 3 +animate entity dranor performing action IDLE3_ANIMATION repeating for 3 times signaling sig +wait for any clearing sig + + + + +play sound "cinematics/dranor/31-314.wav" for entity dranor + +// Action 4 +animate entity dranor performing action ACTION4_ANIMATION signaling sig +wait for any clearing sig + +// Action 11 +animate entity dranor performing action ACTION11_ANIMATION signaling sig +wait for any clearing sig + +// Action 5 +animate entity dranor performing action ACTION5_ANIMATION signaling sig +wait for any clearing sig + + + +play sound "cinematics/dranor/32-317.wav" for entity dranor + +// Death 1 +animate entity dranor performing action DEATH1_ANIMATION signaling sig +wait for any clearing sig + + + diff --git a/Toolkit/Designer/dsexamples/common/header.ds b/Toolkit/Designer/dsexamples/common/header.ds new file mode 100644 index 0000000..d289dea --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/header.ds @@ -0,0 +1,134 @@ +field vector "origin" +field int "movetype" +field vector "start_origin" +field vector "start_angles" +field int "state" +field float "distance" +field entity "owner" +field float "wait" +field vector "velocity" +field vector "angle_velocity" +field entity "team_chain" +field float "yaw_speed" +field int "modelindex" +field int "count" +field int "solid" +field vector "angles" +field vector "delta_angles" +field int "skinnum" +field int "c_mode" +field float "ideal_yaw" +field vector "p_origin" +field int "takedamage" + + + +// Defines for print level +#define PRINT_LOW 0 // pickup messages +#define PRINT_MEDIUM 1 // death messages +#define PRINT_HIGH 2 // critical messages +#define PRINT_CHAT 3 // chat messages + + + +// Physic movetypes +#define PHYSICSTYPE_NONE 0 // MOVETYPE_NONE +#define PHYSICSTYPE_STATIC 1 +#define PHYSICSTYPE_NOCLIP 2 // MOVETYPE_NOCLIP +#define PHYSICSTYPE_FLY 3 // MOVETYPE_FLY, MOVETYPE_FLYMISSILE, MOVETYPE_BOUNCE +#define PHYSICSTYPE_STEP 4 // MOVETYPE_WALK, MOVETYPE_STEP, MOVETYPE_TOSS, MOVETYPE_BOUNCE +#define PHYSICSTYPE_PUSH 5 // MOVETYPE_PUSH +#define PHYSICSTYPE_STOP 6 // MOVETYPE_STOP +#define MOVETYPE_FLYMISSILE 7 +#define PHYSICSTYPE_SCRIPT_ANGULAR 8 +#define NUM_PHYSICSTYPES 9 + +#define MOVETYPE_NONE 10 // never moves +#define MOVETYPE_NOCLIP 11 // origin and angles change with no interaction +#define MOVETYPE_PUSH 12 // no clip to world, push on box contact +#define MOVETYPE_STOP 13 // no clip to world, stops on box contact +#define MOVETYPE_WALK 14 // gravity +#define MOVETYPE_STEP 15 // gravity, special edge handling +#define MOVETYPE_FLY 16 +#define MOVETYPE_TOSS 17 // gravity +#define MOVETYPE_BOUNCE 18 +#define MOVETYPE_SCRIPT_ANGULAR 19 // moves with the rotation of another entity + + +// Defines for animation sequences + +#define ACTION1_ANIMATION 0 +#define ACTION2_ANIMATION 1 +#define ACTION3_ANIMATION 2 +#define ACTION4_ANIMATION 3 +#define ACTION5_ANIMATION 4 +#define ACTION6_ANIMATION 5 +#define ACTION7_ANIMATION 6 +#define ACTION8_ANIMATION 7 +#define ACTION9_ANIMATION 8 +#define ACTION10_ANIMATION 9 +#define ACTION11_ANIMATION 10 +#define ACTION12_ANIMATION 11 +#define ACTION13_ANIMATION 12 +#define ACTION14_ANIMATION 13 +#define ACTION15_ANIMATION 14 +#define ACTION16_ANIMATION 15 +#define ACTION17_ANIMATION 16 +#define ACTION18_ANIMATION 17 +#define ACTION19_ANIMATION 18 +#define ACTION20_ANIMATION 19 +#define ATTACK1_ANIMATION 20 +#define ATTACK2_ANIMATION 21 +#define ATTACK3_ANIMATION 22 +#define BACKPEDAL1_ANIMATION 23 +#define DEATH1_ANIMATION 24 +#define DEATH2_ANIMATION 25 +#define DEATH3_ANIMATION 26 +#define DEATH4_ANIMATION 27 +#define GIB1_ANIMATION 28 +#define IDLE1_ANIMATION 29 +#define IDLE2_ANIMATION 30 +#define IDLE3_ANIMATION 31 +#define IDLE4_ANIMATION 32 +#define IDLE5_ANIMATION 33 +#define IDLE6_ANIMATION 34 +#define JUMP1_ANIMATION 35 +#define PAIN1_ANIMATION 36 +#define PAIN2_ANIMATION 37 +#define PAIN3_ANIMATION 38 +#define PIVOTLEFTGO_ANIMATION 39 +#define PIVOTLEFT_ANIMATION 40 +#define PIVOTLEFTSTOP_ANIMATION 41 +#define PIVOTRIGHTGO_ANIMATION 42 +#define PIVOTRIGHT_ANIMATION 43 +#define PIVOTRIGHTSTOP_ANIMATION 44 +#define RUN1_ANIMATION 45 +#define STEPLEFT_ANIMATION 46 +#define STEPRIGHT_ANIMATION 47 +#define THINKAGAIN_ANIMATION 48 +#define TRANS1_ANIMATION 49 +#define TRANS2_ANIMATION 50 +#define TRANS3_ANIMATION 51 +#define TRANS4_ANIMATION 52 +#define TRANS5_ANIMATION 53 +#define TRANS6_ANIMATION 54 +#define WALKSTART_ANIMATION 55 +#define WALK1_ANIMATION 56 +#define WALK2_ANIMATION 57 +#define WALK3_ANIMATION 58 +#define WALK4_ANIMATION 59 +#define WALKSTOP1_ANIMATION 60 +#define WALKSTOP2_ANIMATION 61 +#define ATTACK4_ANIMATION 62 +#define ATTACK5_ANIMATION 63 + + +#define SOLID_NOT 0 +#define SOLID_SOLID 2 + + +#define DAMAGE_NO 0 // Won't take damage +#define DAMAGE_YES 1 // Takes damage +#define DAMAGE_AIM 2 // Can be autotargeted??? +#define DAMAGE_NO_RADIUS 3 // Will not take damage from radius blasts + diff --git a/Toolkit/Designer/dsexamples/common/highpriestess.ds b/Toolkit/Designer/dsexamples/common/highpriestess.ds new file mode 100644 index 0000000..92b4427 --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/highpriestess.ds @@ -0,0 +1,116 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local int sig + +parameter entity highpriestess + + +highpriestess.yaw_speed = 2 + + +cache sound "cinematics/Fallen Priestess/107-454.wav" +cache sound "cinematics/Fallen Priestess/108-450.wav" +cache sound "cinematics/Fallen Priestess/109-450.wav" +cache sound "cinematics/Fallen Priestess/110-455.wav" +cache sound "cinematics/Fallen Priestess/112-458.wav" +cache sound "cinematics/Fallen Priestess/113-455.wav" +cache sound "cinematics/Fallen Priestess/99-450.wav" +cache sound "cinematics/Fallen Priestess/100-451.wav" +cache sound "cinematics/Fallen Priestess/101-454.wav" +cache sound "cinematics/Fallen Priestess/102-454.wav" +cache sound "cinematics/Fallen Priestess/103-454.wav" +cache sound "cinematics/Fallen Priestess/104-454.wav" +cache sound "cinematics/Fallen Priestess/105-450.wav" +cache sound "cinematics/Fallen Priestess/106-454.wav" +cache sound "cinematics/Fallen Priestess/114-458.wav" +cache sound "cinematics/Fallen Priestess/115-458.wav" + +animate entity highpriestess performing action IDLE2_ANIMATION repeating for 100 times signaling sig +wait for any clearing sig + +// Action7 +//play sound "cinematics/Fallen Priestess/99-450.wav" for entity highpriestess +//animate entity highpriestess performing action ACTION7_ANIMATION signaling sig +//wait for any clearing sig + +// Action8 +//play sound "cinematics/Fallen Priestess/100-451.wav" for entity highpriestess +//animate entity highpriestess performing action ACTION8_ANIMATION signaling sig +//wait for any clearing sig + +// Action9 +//play sound "cinematics/Fallen Priestess/101-454.wav" for entity highpriestess +//animate entity highpriestess performing action ACTION9_ANIMATION signaling sig +//wait for any clearing sig + +// Action10 +//play sound "cinematics/Fallen Priestess/102-454.wav" for entity highpriestess +//animate entity highpriestess performing action ACTION10_ANIMATION signaling sig +//wait for any clearing sig + +// Action11 +//play sound "cinematics/Fallen Priestess/103-454.wav" for entity highpriestess +//animate entity highpriestess performing action ACTION11_ANIMATION signaling sig +//wait for any clearing sig + +// Action12 +//play sound "cinematics/Fallen Priestess/104-454.wav" for entity highpriestess +//animate entity highpriestess performing action ACTION12_ANIMATION signaling sig +//wait for any clearing sig + +// Action13 +//play sound "cinematics/Fallen Priestess/105-450.wav" for entity highpriestess +//animate entity highpriestess performing action ACTION13_ANIMATION signaling sig +//wait for any clearing sig + +// Action14 +//play sound "cinematics/Fallen Priestess/106-454.wav" for entity highpriestess +//animate entity highpriestess performing action ACTION14_ANIMATION signaling sig +//wait for any clearing sig + +// Action1 +//play sound "cinematics/Fallen Priestess/107-454.wav" for entity highpriestess +//animate entity highpriestess performing action ACTION1_ANIMATION signaling sig +//wait for any clearing sig + + +// Action2 +play sound "cinematics/Fallen Priestess/108-450.wav" for entity highpriestess +animate entity highpriestess performing action ACTION2_ANIMATION signaling sig +wait for any clearing sig + + +// Action3 +play sound "cinematics/Fallen Priestess/109-450.wav" for entity highpriestess +animate entity highpriestess performing action ACTION3_ANIMATION signaling sig +wait for any clearing sig + +// Action4 +play sound "cinematics/Fallen Priestess/110-455.wav" for entity highpriestess +animate entity highpriestess performing action ACTION4_ANIMATION signaling sig +wait for any clearing sig + +// Action5 +play sound "cinematics/Fallen Priestess/112-458.wav" for entity highpriestess +animate entity highpriestess performing action ACTION5_ANIMATION signaling sig +wait for any clearing sig + +// Action6 +play sound "cinematics/Fallen Priestess/113-455.wav" for entity highpriestess +animate entity highpriestess performing action ACTION6_ANIMATION signaling sig +wait for any clearing sig + +// Action15 +play sound "cinematics/Fallen Priestess/114-458.wav" for entity highpriestess +animate entity highpriestess performing action ACTION15_ANIMATION signaling sig +wait for any clearing sig + +// Action16 +play sound "cinematics/Fallen Priestess/115-458.wav" for entity highpriestess +animate entity highpriestess performing action ACTION16_ANIMATION signaling sig +wait for any clearing sig + diff --git a/Toolkit/Designer/dsexamples/common/plagueelf.ds b/Toolkit/Designer/dsexamples/common/plagueelf.ds new file mode 100644 index 0000000..388132a --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/plagueelf.ds @@ -0,0 +1,78 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local int sig + +parameter entity plagueelf + +// Idle 3 +animate entity plagueelf performing action IDLE3_ANIMATION repeating for 2 times signaling sig +wait for any clearing sig + +// Pain 1 +animate entity plagueelf performing action PAIN1_ANIMATION by turning [180, 0, 0] repeating for 4 times signaling sig +wait for any clearing sig + +// DEATH 1 +animate entity plagueelf performing action DEATH1_ANIMATION signaling sig + + +// DEATH 2 +//animate entity plagueelf performing action DEATH2_ANIMATION signaling sig +//wait for any clearing sig + +// DEATH 3 +//animate entity plagueelf performing action DEATH3_ANIMATION signaling sig +//wait for any clearing sig + +// Idle 3 +//animate entity plagueelf performing action IDLE3_ANIMATION by turning [180, 0, 0] repeating for 2 times signaling sig +//wait for any clearing sig + + +// Idle 1 +//animate entity plagueelf performing action IDLE1_ANIMATION by turning [180, 0, 0] repeating for 4 times signaling sig +//wait for any clearing sig + +// Idle 2 +//animate entity plagueelf performing action IDLE2_ANIMATION by turning [-180, 0, 0] repeating for 2 times signaling sig +//wait for any clearing sig + + +// Run 1 +//animate entity plagueelf performing action RUN1_ANIMATION by moving [200, 0, 0] by turning [180, 0, 0] signaling sig +//wait for any clearing sig + + +// Walk 1 +//animate entity plagueelf performing action WALK2_ANIMATION by moving [200, 0, 0] by turning [180, 0, 0] signaling sig +//wait for any clearing sig + + +// Walk 2 +//animate entity plagueelf performing action WALK1_ANIMATION by moving [200, 0, 0] by turning [180, 0, 0] signaling sig +//wait for any clearing sig + + +// ATTACK1 +//animate entity plagueelf performing action ATTACK1_ANIMATION by moving [100, 0, 0] signaling sig +//wait for any clearing sig + + +// ATTACK2 +//animate entity plagueelf performing action ATTACK2_ANIMATION repeating for 3 times signaling sig +//wait for any clearing sig + +// ATTACK3 +//animate entity plagueelf performing action ATTACK3_ANIMATION signaling sig +//wait for any clearing sig + + +// DEATH 4 +//animate entity plagueelf performing action DEATH4_ANIMATION + +// GIB 1 +//animate entity plagueelf performing action GIB1_ANIMATION diff --git a/Toolkit/Designer/dsexamples/common/pushogle.ds b/Toolkit/Designer/dsexamples/common/pushogle.ds new file mode 100644 index 0000000..ffb8fc5 --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/pushogle.ds @@ -0,0 +1,17 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local entity ogle1 +local entity push1 +local int sig +local int sig1 + +ogle1 = find entity with targetname ogle1 +push1 = find entity with targetname push1 + +animate entity ogle1 performing action WALK3_ANIMATION by moving [704, 0, 0] signaling sig +move entity push1 by [0, -704, 0] at 40 speed signaling sig1 +wait for all clearing sig, sig1 diff --git a/Toolkit/Designer/dsexamples/common/shifty.ds b/Toolkit/Designer/dsexamples/common/shifty.ds new file mode 100644 index 0000000..11aaf7f --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/shifty.ds @@ -0,0 +1,14 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local entity break1 +local entity break2 + +break1 = find entity with targetname "break1" +break2 = find entity with targetname "break2" + +use entity break1 +use entity break2 diff --git a/Toolkit/Designer/dsexamples/common/soundy.ds b/Toolkit/Designer/dsexamples/common/soundy.ds new file mode 100644 index 0000000..c38937a --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/soundy.ds @@ -0,0 +1,15 @@ +//This is the super blasto surround sound wave playing test script! + +#include "../common/header.ds" + +output "r:/base/ds/common" + +//define variables + + +//playing wave + +play sound "ambient/kidcry1.wav" at volume 1.0 at attenuation 1 after 1.0 seconds + + + diff --git a/Toolkit/Designer/dsexamples/common/ssithravictim.ds b/Toolkit/Designer/dsexamples/common/ssithravictim.ds new file mode 100644 index 0000000..16f3f01 --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/ssithravictim.ds @@ -0,0 +1,35 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds/common" + +local int sig + +parameter entity ssithravictim + + +ssithravictim.yaw_speed = 5 + +// Action 2 +animate entity ssithravictim performing action ACTION2_ANIMATION signaling sig +wait for any clearing sig + +// Action 3 +animate entity ssithravictim performing action ACTION3_ANIMATION signaling sig +wait for any clearing sig + +// Action 4 +animate entity ssithravictim performing action ACTION4_ANIMATION signaling sig +wait for any clearing sig + +// Action 5 +animate entity ssithravictim performing action ACTION5_ANIMATION signaling sig +wait for any clearing sig + +// Action 6 +animate entity ssithravictim performing action ACTION6_ANIMATION signaling sig +wait for any clearing sig + +// Idle 1 +animate entity ssithravictim performing action IDLE1_ANIMATION diff --git a/Toolkit/Designer/dsexamples/common/test1.ds b/Toolkit/Designer/dsexamples/common/test1.ds new file mode 100644 index 0000000..2879f55 --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/test1.ds @@ -0,0 +1,30 @@ +//Beginning of game + +#include "../common/header.ds" +output "r:/base/ds/common" + +local entity player1 + +player1 = get entity activator + +enable cinematics + +print 28 + +wait 5 seconds + +print 28 centered + +wait 5 seconds + +print 28 centered to entity player1 + +wait 5 seconds + +print 28 captioned to entity player1 + +wait 5 seconds + +disable cinematics + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/common/test2.ds b/Toolkit/Designer/dsexamples/common/test2.ds new file mode 100644 index 0000000..a48615c --- /dev/null +++ b/Toolkit/Designer/dsexamples/common/test2.ds @@ -0,0 +1,26 @@ +//Beginning of game + +#include "../common/header.ds" +output "r:/base/ds/common" + +local entity player1 + +player1 = get entity activator + +print 28 + +wait 5 seconds + +print 28 centered + +wait 5 seconds + +print 28 centered to entity player1 + +wait 5 seconds + +print 28 captioned to entity player1 + +wait 5 seconds + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/dungeon/cage.ds b/Toolkit/Designer/dsexamples/dungeon/cage.ds new file mode 100644 index 0000000..6a7f292 --- /dev/null +++ b/Toolkit/Designer/dsexamples/dungeon/cage.ds @@ -0,0 +1,142 @@ +// the cage that dips down into the lava. killing poor fred. + +#include "../common/header.ds" + +output "r:/base/ds/dungeon" + +local entity cage +local entity light +local entity fred +local entity lavadoor1 +local entity lavadoor2 + +local int sig +local int sig1 +local int sig2 + +cage = find entity with targetname "cage" +light = find entity with targetname "light" +fred = find entity with targetname "fred" +lavadoor1 = find entity with targetname "lavadoor1" +lavadoor2 = find entity with targetname "lavadoor2" + +// start + + label beginning + + play sound "doors/gendoorstart.wav" for entity lavadoor1 + move entity lavadoor1 by [-120, 0, 0] over 2 seconds signaling sig + + play sound "doors/gendoorstart.wav" for entity lavadoor2 + move entity lavadoor2 by [120, 0, 0] over 2 seconds signaling sig1 + wait for all clearing sig, sig1 + + play sound "doors/gendoorstop.wav" for entity lavadoor1 + play sound "doors/gendoorstop.wav" for entity lavadoor2 + + fred.movetype = PHYSICSTYPE_NOCLIP + light.movetype = PHYSICSTYPE_PUSH + + play sound "doors/gendoorstart.wav" for entity cage + + move entity cage by [0, 0, -380] at 50 speed signaling sig + + move entity light by [0, 0, -380] at 50 speed signaling sig2 + + move entity fred by [0, 0, -380] at 50 speed signaling sig1 + wait for all clearing sig, sig2 + + play sound "doors/gendoorstop.wav" for entity cage + + fred.movetype = PHYSICSTYPE_STEP + + wait 3 seconds + + fred.movetype = PHYSICSTYPE_NOCLIP + + play sound "doors/gendoorstart.wav" for entity cage + + move entity cage by [0, 0, 380] at 50 speed signaling sig + + move entity light by [0, 0, 380] at 50 speed signaling sig2 + wait for all clearing sig, sig2 + + play sound "doors/gendoorstop.wav" for entity cage + + play sound "doors/gendoorstart.wav" for entity lavadoor1 + move entity lavadoor1 by [120, 0, 0] over 2 seconds signaling sig + + play sound "doors/gendoorstart.wav" for entity lavadoor2 + move entity lavadoor2 by [-120, 0, 0] over 2 seconds signaling sig1 + wait for all clearing sig, sig1 + + play sound "doors/gendoorstop.wav" for entity lavadoor1 + play sound "doors/gendoorstop.wav" for entity lavadoor2 + + fred.modelindex = 0 + + suspend + + goto beginning + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/dungeon/start.ds b/Toolkit/Designer/dsexamples/dungeon/start.ds new file mode 100644 index 0000000..6ee537d --- /dev/null +++ b/Toolkit/Designer/dsexamples/dungeon/start.ds @@ -0,0 +1,127 @@ +// the beginnign script with corvus and the tome of power. + +#include "../common/header.ds" + +output "r:/base/ds/dungeon" + +local entity corvus1 +local entity tome +local entity scamera +local entity player1 +local entity sickcam + +local int sig + +corvus1 = find entity with targetname "corvus1" +tome = find entity with targetname "tome" +scamera = find entity with targetname "scamera" +sickcam = find entity with targetname "sickcam" +player1 = get entity activator + +// tome starts talking. + + copy player attributes from entity player1 to entity corvus1 + corvus1.modelindex = corvus1.count + corvus1.solid = SOLID_SOLID + corvus1.movetype = 4 + + tome.modelindex = tome.count + tome.solid = SOLID_SOLID + + enable cinematics + + use entity scamera + + animate entity tome performing action IDLE1_ANIMATION + + print 74 captioned + + play sound "player/corvussick.wav" for entity corvus1 + + animate entity corvus1 performing action ACTION4_ANIMATION signaling sig + wait 2 seconds + move entity sickcam by [90, 200, -75] over 4 seconds + wait for all clearing sig + + animate entity corvus1 performing action IDLE1_ANIMATION + + wait 4 seconds + + disable cinematics + + player1.origin = corvus1.origin + player1.p_origin = corvus1.origin + set view angles of entity player1 to corvus1.angles + + corvus1.modelindex = 0 + corvus1.solid = SOLID_NOT + + tome.modelindex = 0 + tome.solid = SOLID_NOT + + use entity scamera + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/dungeon/trap.ds b/Toolkit/Designer/dsexamples/dungeon/trap.ds new file mode 100644 index 0000000..63c645f --- /dev/null +++ b/Toolkit/Designer/dsexamples/dungeon/trap.ds @@ -0,0 +1,109 @@ +// the big bad trap right before the level change + +#include "../common/header.ds" + +output "r:/base/ds/dungeon" + + +local entity trapdoor1 +local entity trapdoor2 + +local int sig +local int sig1 + +trapdoor1 = find entity with targetname "trapdoor1" +trapdoor2 = find entity with targetname "trapdoor2" + +// dropping your drawers. ah hem, i mean doors. + + move entity trapdoor1 by [0, 0, -200] at 1000 speed signaling sig + + move entity trapdoor2 by [0, 0, -200] at 1000 speed signaling sig1 + wait for all clearing sig, sig1 + +// start coming together + + move entity trapdoor1 by [100, 0, 0] over 3 seconds signaling sig + + move entity trapdoor2 by [-100, 0, 0] over 3 seconds signaling sig1 + wait for all clearing sig, sig1 + + + + + move entity trapdoor1 by [100, 0, 0] over 3 seconds signaling sig + + move entity trapdoor2 by [-100, 0, 0] over 3 seconds signaling sig1 + wait for all clearing sig, sig1 + + + + + move entity trapdoor1 by [75, 0, 0] over 3 seconds signaling sig + + move entity trapdoor2 by [-75, 0, 0] over 3 seconds signaling sig1 + wait for all clearing sig, sig1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/dungeon/victim.ds b/Toolkit/Designer/dsexamples/dungeon/victim.ds new file mode 100644 index 0000000..c402d41 --- /dev/null +++ b/Toolkit/Designer/dsexamples/dungeon/victim.ds @@ -0,0 +1,164 @@ +// This hopefully will be the cinematic with the Ssithera victim in the Dungeon level. +// Starring Rick Johnson as the Hero and Eric Biessman as the Victim. + +#include "../common/header.ds" + +output "r:/base/ds/dungeon" + +local entity camera1 +local entity camera2 +local entity camera3 +local entity camera4 +local entity camera5 +local entity zoom +local entity zoom2 +local entity spawner +local entity victim +local entity dungeonkey +local entity player1 +parameter entity hero + +local int sig +local int sig1 + +cache sound "cinematics/torture victim/117-345.wav" +cache sound "cinematics/torture victim/117a-344.wav" +cache sound "cinematics/torture victim/117a-345.wav" +cache sound "cinematics/torture victim/118-350.wav" +cache sound "cinematics/torture victim/119-345.wav" +cache sound "cinematics/torture victim/wheel.wav" + +hero.yaw_speed = 6 + +camera1 = find entity with targetname "camera1" +camera2 = find entity with targetname "camera2" +camera3 = find entity with targetname "camera3" +camera4 = find entity with targetname "camera4" +camera5 = find entity with targetname "camera5" +zoom = find entity with targetname "zoom" +zoom2 = find entity with targetname "zoom2" +spawner = find entity with targetname "spawner" +victim = find entity with targetname "victim" +player1 = get entity activator + +// its a start + + copy player attributes from entity player1 to entity hero + hero.modelindex = hero.count + hero.solid = SOLID_SOLID + hero.movetype = 4 + + enable cinematics + + +// Our story starts out with a lovely camrea shot. + + play sound "cinematics/torture victim/117a-344.wav" for entity victim + + use entity camera1 + +// Let's make our hero walk forward shall we? Victim in pain. + + animate entity hero performing action WALK2_ANIMATION by moving [140, 0, 0] by turning [0, 0, 0] signaling sig + wait for all clearing sig + +// At last our hero speaks + + move entity zoom2 by [0, 100, 0] over 3 seconds + + print 259 captioned + play sound "cinematics/torture victim/117-345.wav" for entity hero + + animate entity hero performing action WALK2_ANIMATION by moving [60, 0, 0] by turning [-45, 0, 0] signaling sig + wait for all clearing sig + + animate entity hero performing action WALK2_ANIMATION by moving [27, 0, 0] by turning [-45, 0, 0] signaling sig + wait for all clearing sig + +// Our Hero releases the poor victim + + animate entity hero performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + play sound "cinematics/torture victim/wheel.wav" for entity hero + + animate entity hero performing action ACTION2_ANIMATION signaling sig1 + + animate entity victim performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig, sig1 + + animate entity hero performing action IDLE1_ANIMATION + +// Our story continues with this magnificent camera change. (up high looking down) + + use entity camera1 + + use entity camera4 + + play sound "cinematics/torture victim/117a-345.wav" for entity hero + + animate entity victim performing action ACTION3_ANIMATION + + wait 3 seconds + +// Camera (high, looking down in hero and victim) + + print 260 captioned + play sound "cinematics/torture victim/118-350.wav" for entity victim + + animate entity victim performing action ACTION4_ANIMATION + + animate entity hero performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity hero performing action IDLE2_ANIMATION repeating for 18 times + + use entity camera4 + + use entity camera5 + + wait 9 seconds + +// Camera (medium shot, zooms in) + + use entity camera5 + + use entity camera2 + + wait 4 seconds + + dungeonkey = spawn entity with fields "classname" = "item_puzzle_dungeonkey" , "angle" = 0 , "origin" = [-2391, -2758, 793] + + animate entity victim performing action ACTION5_ANIMATION + + print 261 captioned + play sound "cinematics/torture victim/119-345.wav" for entity victim + + wait 10 seconds + + animate entity victim performing action ACTION6_ANIMATION + + move entity zoom by [30, 30, 0] over 10 seconds signaling sig + wait for all clearing sig + + wait 2 seconds + +// The final shot. + + use entity camera2 + + use entity camera3 + + wait 2 seconds + + player1.origin = hero.origin + player1.p_origin = hero.origin + set view angles of entity player1 to hero.angles + + hero.modelindex = 0 + hero.solid = SOLID_NOT + + disable cinematics + + use entity camera3 + diff --git a/Toolkit/Designer/dsexamples/hive/biteme.ds b/Toolkit/Designer/dsexamples/hive/biteme.ds new file mode 100644 index 0000000..bc42b7a --- /dev/null +++ b/Toolkit/Designer/dsexamples/hive/biteme.ds @@ -0,0 +1,51 @@ +// The most awful and brain racking BearTrap from hell! + +#include "../common/header.ds" + +output "r:/base/ds/hive" + +parameter entity parm1 +parameter entity parm2 +parameter entity parm3 + + +local int sig1 +local int sig2 + + + +parm1.movetype = PHYSICSTYPE_NOCLIP +parm2.movetype = PHYSICSTYPE_NOCLIP + +//this better fucking work + +label start + +rotate entity parm1 by [0, 0, 45] at 600 speed signaling sig1 +rotate entity parm2 by [0, 0, -45] at 600 speed signaling sig2 +wait for all clearing sig1, sig2 + +enable trigger entity parm3 + +rotate entity parm1 by [0, 0, 45] at 600 speed signaling sig1 +rotate entity parm2 by [0, 0,-45] at 600 speed signaling sig2 +wait for all clearing sig1, sig2 + +play sound "objects/klang.wav" for entity parm1 on channel 10 + +wait .2 seconds + +disable trigger entity parm3 +rotate entity parm1 by [0, 0, -45] at 600 speed signaling sig1 +rotate entity parm2 by [0, 0, 45] at 600 speed signaling sig2 +wait for all clearing sig1, sig2 + + + +rotate entity parm1 by [0, 0, -45] at 600 speed signaling sig1 +rotate entity parm2 by [0, 0, 45] at 600 speed signaling sig2 +wait for all clearing sig1, sig2 + +suspend + +goto start \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hive/brbr.ds b/Toolkit/Designer/dsexamples/hive/brbr.ds new file mode 100644 index 0000000..f67f733 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hive/brbr.ds @@ -0,0 +1,10 @@ +//Sounds for falling bridge + +#include "../common/header.ds" +output "r:/base/ds/hive" + + +//define variables +parameter entity break + +play sound "misc/breakstone.wav" for entity break diff --git a/Toolkit/Designer/dsexamples/hive/captured.ds b/Toolkit/Designer/dsexamples/hive/captured.ds new file mode 100644 index 0000000..ecb6409 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hive/captured.ds @@ -0,0 +1,360 @@ +// Captured by the T'Chekrik! + +#include "../common/header.ds" + +output "r:/base/ds/hive" + + +local entity cam1 +local entity cam2 +local entity cam3 +local entity cam4 +local entity cam5 +local entity cam6 +local entity cam7 +local entity cam8 +local entity cam9 +local entity cam10 +local entity cam11 + +local entity dolly10 +local entity dolly7 +local entity dolly1 +local entity dolly2 +local entity dolly6 + +local entity cam1train +local entity cam6train +local entity cam10train + +local entity tome +local entity corvus +local entity player1 + +local entity spawn3 +local entity spawn4 +local entity spawn5 +local entity spawn6 + +local entity sbug +local entity sbug1 +local entity sbug2 +local entity sbug3 + +local entity door +local entity door1 +local entity fourdoors +local entity stardoor + +local entity mainbug +local entity bugright +local entity bugleft + +local entity levelchange +local entity objective +local entity objective7 + +local int sig +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int sig6 +local int sigrj + + +corvus.yaw_speed = 5 + +door = find entity with targetname "door" +door1 = find entity with targetname "door1" +fourdoors = find entity with targetname "floordoors" +stardoor = find entity with targetname "floorlift" + + +cam1 = find entity with targetname "shot1" +cam2 = find entity with targetname "shot2" +cam3 = find entity with targetname "shot3" +cam4 = find entity with targetname "shot4" +cam5 = find entity with targetname "shot5" +cam6 = find entity with targetname "shot6" +cam7 = find entity with targetname "shot7" +cam8 = find entity with targetname "shot8" +cam9 = find entity with targetname "shot9" +cam10 = find entity with targetname "shot10" +cam11 = find entity with targetname "shot11" + +dolly1 = find entity with targetname "pan1" +dolly6 = find entity with targetname "t97" +dolly2 = find entity with targetname "pan2" +dolly7 = find entity with targetname "pan7" +dolly10 = find entity with targetname "pan10" + +cam1train = find entity with targetname "train1" +cam6train = find entity with targetname "cam6base" +cam10train = find entity with targetname "train10" + +levelchange = find entity with targetname "t5" +objective = find entity with targetname "take5" +objective = find entity with targetname "objective7" + +tome = find entity with targetname "tome" +corvus = find entity with targetname "corvus" + +enable cinematics + +//Switching player +player1 = get entity activator // Get player who set off trigger +copy player attributes from entity player1 to entity corvus // copies players appearance +corvus.modelindex = corvus.count // Turn on cinematic corvus +corvus.solid = SOLID_NOT // Make him block +corvus.movetype = PHYSICSTYPE_STEP + + // Create the bugs + sbug = spawn entity with fields "classname" = "monster_tcheckrik_male", "origin" = [-1824, -192, 184], "angle" = 180 + sbug1 = spawn entity with fields "classname" = "monster_tcheckrik_male", "origin" = [-2200, -480, 168], "angle" = 90 + sbug2 = spawn entity with fields "classname" = "monster_tcheckrik_male", "origin" = [-2152, -480, 168], "angle" = 90 + sbug3 = spawn entity with fields "classname" = "monster_tcheckrik_male", "origin" = [-2176, -520, 188], "angle" = 90 + mainbug = spawn entity with fields "classname" = "monster_tcheckrik_male", "origin" = [-2176, 208, 168], "angle" = 270 + bugright = spawn entity with fields "classname" = "monster_tcheckrik_male", "origin" = [-2152, 160, 168], "angle" = 270 + bugleft = spawn entity with fields "classname" = "monster_tcheckrik_male", "origin" = [-2200, 160, 168], "angle" = 270 + + // Let them know they are cinematic creatures + sbug.c_mode = 1; + sbug1.c_mode = 1; + sbug2.c_mode = 1; + sbug3.c_mode = 1; + mainbug.c_mode = 1; + bugright.c_mode = 1; + bugleft.c_mode = 1; + +//Opening shot of Corvus placing amulet and backing up seeing that he's surrounded by bugs. + + use entity cam1 + + move entity cam1train by [128, -32, -16] over 5 seconds + dolly1.movetype = PHYSICSTYPE_PUSH + move entity dolly1 by [200, 0, 0] over 5 seconds + + animate entity corvus performing action WALK2_ANIMATION by moving [-176, 0, 0] signaling sig + wait for all clearing sig + + move entity door by [48, 0, 0] at 100 speed + + move entity door1 by [-48, 0, 0] at 100 speed + + animate entity corvus performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + animate entity corvus performing action ACTION9_ANIMATION by turning [-90, 0, 0] signaling sig + wait for all clearing sig + +//Panning across the room as the bugs run out. + + use entity cam2 + + dolly2.movetype = PHYSICSTYPE_PUSH + move entity dolly2 by [0, 200, 0] over 8 seconds + + animate entity sbug performing action RUN1_ANIMATION by moving [242, 0, 0] signaling sig + wait .8 seconds + animate entity sbug3 performing action RUN1_ANIMATION by moving [148, 0, 0] signaling sig1 + animate entity sbug2 performing action RUN1_ANIMATION by moving [148, 0, 0] signaling sig2 + animate entity sbug1 performing action RUN1_ANIMATION by moving [148, 0, 0] signaling sig3 + wait for all clearing sig, sig1, sig2, sig3 + + + + animate entity sbug performing action IDLE1_ANIMATION //signaling sig + animate entity sbug2 performing action RUN1_ANIMATION by turning [-45, 0, 0] signaling sig1 + animate entity sbug1 performing action RUN1_ANIMATION by turning [45, 0, 0] signaling sig2 + wait for all clearing sig1, sig2 + + play sound "cinematics/t'chekrik/kchektalk3.wav" for entity mainbug + animate entity sbug3 performing action RUN1_ANIMATION by moving [64, 0, 0] signaling sig3 + animate entity sbug2 performing action RUN1_ANIMATION by moving [78, 0, 0] signaling sig1 + animate entity sbug1 performing action RUN1_ANIMATION by moving [78, 0, 0] signaling sig2 + wait for all clearing sig1, sig2, sig3 + + animate entity sbug3 performing action IDLE1_ANIMATION //signaling sig + animate entity sbug2 performing action IDLE1_ANIMATION //signaling sig1 + animate entity sbug1 performing action IDLE1_ANIMATION //signaling sig2 + + animate entity bugleft performing action RUN1_ANIMATION by moving [238, -32, 0] signaling sig3 + animate entity bugright performing action RUN1_ANIMATION by moving [238, -32, 0] signaling sig4 + animate entity mainbug performing action RUN1_ANIMATION by moving [178, 0, 0] signaling sig5 + wait for all clearing sig3, sig4, sig5 + + animate entity mainbug performing action IDLE3_ANIMATION + + move entity door by [-48, 0, 0] at 50 speed + + move entity door1 by [48, 0, 0] at 50 speed + + +// Clicking bugs, Corvus doesn't understand. Camera close up on the Mainbug. + + use entity cam5 + + animate entity bugleft performing action WALK1_ANIMATION by moving [80, 0, 0] by turning [-60, 0, 0] signaling sig + animate entity bugright performing action WALK1_ANIMATION by moving [80, 0, 0] by turning [60, 0, 0] signaling sig1 + wait for all clearing sig, sig1 + + animate entity mainbug performing action WALK1_ANIMATION by moving [88, 0, 0] signaling sig + wait for all clearing sig + + print 218 captioned + play sound "cinematics/t'chekrik/kchektalk1.wav" for entity mainbug + + animate entity mainbug performing action IDLE3_ANIMATION signaling sig + animate entity sbug1 performing action IDLE3_ANIMATION by turning [-90, 0, 0] signaling sig1 + animate entity sbug2 performing action IDLE3_ANIMATION by turning [90, 0, 0] signaling sig2 + animate entity sbug3 performing action IDLE3_ANIMATION signaling sig3 + animate entity bugright performing action IDLE3_ANIMATION by turning [-90, 0, 0] signaling sig4 + animate entity bugleft performing action IDLE3_ANIMATION by turning [90, 0, 0] signaling sig5 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5 + +// Main bug does his speech and the cracks Corvus on the head. + + use entity cam6 + + move entity cam6train by [24, -24, 16] over 12 seconds + dolly6.movetype = PHYSICSTYPE_PUSH + move entity dolly6 by [0, -24, 0] over 12 seconds + animate entity mainbug performing action RUN1_ANIMATION by moving [64,0,0] signaling sig + wait for all clearing sig + animate entity mainbug performing action ATTACK3_ANIMATION signaling sig + wait .5 seconds + play sound "monster/insect/swipe.wav" for entity mainbug + play sound "Weapons/staffhit.wav" for entity mainbug + wait .2 seconds + play sound "Player/corvuspain1.wav" for entity corvus + animate entity corvus performing action ACTION7_ANIMATION signaling sig1 + wait for all clearing sig + animate entity mainbug performing action IDLE3_ANIMATION + wait for all clearing sig1 + + print 220 captioned + play sound "cinematics/t'chekrik/85-404.wav" for entity corvus + animate entity corvus performing action ACTION2_ANIMATION signaling sig1 + wait for all clearing sig1 + animate entity corvus performing action IDLE2_ANIMATION signaling sig + wait for all clearing sig + +// Tome comes out and speaks + + use entity cam7 + + tome.solid = SOLID_NOT + tome.modelindex = tome.count + + print 221 captioned + play sound "cinematics/t'chekrik/86-405.wav" for entity tome + + dolly7.movetype = PHYSICSTYPE_PUSH + move entity dolly7 by [0,40,16] over 8 seconds + tome.movetype = PHYSICSTYPE_PUSH + move entity tome by [-16, 32, 20] over 8 seconds + + animate entity corvus performing action IDLE2_ANIMATION signaling sig + wait for all clearing sig + animate entity corvus performing action IDLE2_ANIMATION signaling sig + wait for all clearing sig + animate entity corvus performing action IDLE2_ANIMATION signaling sig + wait for all clearing sig +//wait 8 seconds + +// Corvus tells about amulet + + use entity cam8 + + print 222 captioned + play sound "cinematics/t'chekrik/87-403.wav" for entity corvus + animate entity corvus performing action ACTION3_ANIMATION signaling sig + animate entity mainbug performing action BACKPEDAL1_ANIMATION by moving [-64, 0, 0] signaling sig1 + wait for all clearing sig, sig1 + animate entity mainbug performing action IDLE3_ANIMATION + print 223 captioned + play sound "cinematics/t'chekrik/88-408.wav" for entity tome + animate entity corvus performing action IDLE2_ANIMATION signaling sig + wait for all clearing sig + print 224 captioned + play sound "cinematics/t'chekrik/tomekchek.wav" for entity tome + + wait 2 seconds + + +// T'chekrik click, close up of main bug man. + + use entity cam9 + + wait 1 seconds + print 225 captioned + play sound "cinematics/t'chekrik/kchektalk2.wav" for entity mainbug + animate entity mainbug performing action IDLE3_ANIMATION signaling sig + wait for all clearing sig + + wait 4 seconds + +// Tome translates + + use entity cam10 + print 226 captioned + play sound "cinematics/t'chekrik/90-406.wav" for entity tome + + move entity cam10train by [-66, 48, 24] over 8 seconds + + dolly10.movetype = PHYSICSTYPE_PUSH + move entity dolly10 by [-34,16,32] over 8 seconds + animate entity corvus performing action ACTION4_ANIMATION signaling sig1 + move entity tome by [32, -48, 0] over 4 seconds signaling sig + wait for all clearing sig, sig1 + + //wait 8 seconds + print 227 captioned + play sound "cinematics/t'chekrik/91-406.wav" for entity corvus + animate entity corvus performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + animate entity corvus performing action IDLE3_ANIMATION signaling sig + wait for all clearing sig + +// door opens for Corvus + + use entity cam11 + + //wait 1 seconds + + //animate entity mainbug performing action BACKPEDAL1_ANIMATION by moving [-36, 0, 0] signaling sig + animate entity bugright performing action BACKPEDAL1_ANIMATION by moving [-48, 0, 0] signaling sig1 + animate entity bugleft performing action BACKPEDAL1_ANIMATION by moving [-48, 0, 0] signaling sig2 + animate entity sbug performing action BACKPEDAL1_ANIMATION by moving [-48, 0, 0] signaling sig3 + animate entity sbug1 performing action BACKPEDAL1_ANIMATION by moving [-48, 0, 0] signaling sig4 + animate entity sbug2 performing action BACKPEDAL1_ANIMATION by moving [-48, 0, 0] signaling sig5 + animate entity sbug3 performing action BACKPEDAL1_ANIMATION by moving [-48, 0, 0] signaling sig6 + wait for all clearing sig1, sig2, sig3, sig4, sig5, sig6 + + animate entity mainbug performing action IDLE3_ANIMATION signaling sig + animate entity bugright performing action IDLE3_ANIMATION signaling sig1 + animate entity bugleft performing action IDLE3_ANIMATION signaling sig2 + animate entity sbug performing action IDLE3_ANIMATION signaling sig3 + animate entity sbug1 performing action IDLE3_ANIMATION signaling sig4 + animate entity sbug2 performing action IDLE3_ANIMATION signaling sig5 + animate entity sbug3 performing action IDLE3_ANIMATION signaling sig6 + play sound "cinematics/t'chekrik/kchektalk3.wav" for entity mainbug + + use entity objective + + use entity objective7 + + use entity fourdoors + + wait 1.5 seconds + + move entity stardoor by [0, 0, -320] at 500 speed signaling sig + + wait .6 seconds + move entity tome by [0, 0, -320] at 500 speed signaling sig1 + wait for all clearing sig, sig1 + +disable cinematics + +use entity levelchange \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hive/fallenprts.ds b/Toolkit/Designer/dsexamples/hive/fallenprts.ds new file mode 100644 index 0000000..efa744c --- /dev/null +++ b/Toolkit/Designer/dsexamples/hive/fallenprts.ds @@ -0,0 +1,244 @@ +// The Fallen High Priestess. + + +#include "../common/header.ds" + +output "r:/base/ds/hive" + +local entity send +local entity camnot +local entity camthere +local entity cam22 +local entity camera1 +local entity camera2 +local entity camera3 +local entity camera4 +local entity camera4base +local entity camera5 +local entity camera6 +local entity portal +local entity portalcam +local entity fallen +local entity corvus +local entity levelchange + +local entity player1 +local entity watcher +local entity monster + +local int sig +local int sig1 + +send = find entity with targetname "send" +camnot = find entity with targetname "not" +camthere = find entity with targetname "there" +cam22 = find entity with targetname "cam22" +camera1 = find entity with targetname "fcam1" +camera2 = find entity with targetname "fcam2" +camera3 = find entity with targetname "fcam3" +camera4 = find entity with targetname "fcam4" +camera4base = find entity with targetname "fcam4b" +camera5 = find entity with targetname "fcam5" +camera6 = find entity with targetname "fcam6" +portal = find entity with targetname "portal" +portalcam = find entity with targetname "portalcam" +levelchange = find entity with targetname "t129" +fallen = find entity with targetname "fallen" +corvus = find entity with targetname "corvus" +monster = find entity with targetname "monster" + +cache sound "cinematics/fallen priestess/107-454.wav" +cache sound "cinematics/fallen priestess/108-450.wav" +cache sound "cinematics/fallen priestess/109-450.wav" +cache sound "cinematics/fallen priestess/110-455.wav" +cache sound "cinematics/fallen priestess/112-458.wav" +cache sound "cinematics/fallen priestess/113-455.wav" +cache sound "cinematics/fallen priestess/99-450.wav" +cache sound "cinematics/fallen priestess/100-451.wav" +cache sound "cinematics/fallen priestess/101-454.wav" +cache sound "cinematics/fallen priestess/102-454.wav" +cache sound "cinematics/fallen priestess/103-454.wav" +cache sound "cinematics/fallen priestess/104-454.wav" +cache sound "cinematics/fallen priestess/105-450.wav" +cache sound "cinematics/fallen priestess/106-454.wav" +cache sound "cinematics/fallen priestess/114-458.wav" +cache sound "cinematics/fallen priestess/115-458.wav" + + + +//Switching Priestess +player1 = get entity activator // Get player who set off trigger + +copy player attributes from entity player1 to entity corvus // copies players appearance +player1.solid = SOLID_NOT // Player won't block now + +corvus.modelindex = corvus.count // Turn on cinematic corvus +corvus.solid = SOLID_NOT // Make him block +corvus.movetype = PHYSICSTYPE_STEP + +//monster = get entity activator // Get player who set off trigger +monster.modelindex = 0 // Make players model disappear +monster.solid = SOLID_NOT // Player won't block now +fallen.modelindex = fallen.count // Turn on cinematic priestess +fallen.solid = SOLID_SOLID // Make her block +fallen.movetype = PHYSICSTYPE_STEP +fallen.origin = [2292, 2108, 504] +fallen.angles = [0, 270, 0] + + +enable cinematics + + +//Camera1, behind fallen looking at corvus. + + use entity camera1 + + play sound "cinematics/fallen priestess/99-450.wav" for entity fallen + animate entity fallen performing action ACTION7_ANIMATION signaling sig + animate entity corvus performing action ACTION7_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + print 237 captioned + play sound "cinematics/fallen priestess/100-451.wav" for entity corvus + animate entity fallen performing action ACTION8_ANIMATION signaling sig + animate entity corvus performing action ACTION8_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + + print 238 captioned + play sound "cinematics/fallen priestess/101-454.wav" for entity fallen + animate entity fallen performing action ACTION9_ANIMATION signaling sig + animate entity corvus performing action ACTION9_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + +//Camera2, on the side looking at both the fallen and corvus. + + animate entity fallen performing action ACTION10_ANIMATION signaling sig1 + + use entity camera2 + print 239 captioned + play sound "cinematics/fallen priestess/102-454.wav" for entity corvus + animate entity corvus performing action ACTION10_ANIMATION signaling sig + wait for all clearing sig, sig1 + print 240 captioned + play sound "cinematics/fallen priestess/103-454.wav" for entity fallen + animate entity corvus performing action ACTION11_ANIMATION signaling sig + animate entity fallen performing action ACTION11_ANIMATION signaling sig1 + wait 9 seconds + print 241 captioned + use entity camera2 + +//Close up shots, one of Priestess, one of Corvus + + use entity camnot + + wait for all clearing sig, sig1 + + use entity camnot + + use entity camthere + + print 242 captioned + play sound "cinematics/fallen priestess/104-454.wav" for entity corvus + animate entity corvus performing action ACTION12_ANIMATION signaling sig + animate entity fallen performing action ACTION12_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + + use entity camthere + +//back to profile shot of the two + + use entity cam22 + print 243 captioned + play sound "cinematics/fallen priestess/105-450.wav" for entity fallen + animate entity corvus performing action ACTION13_ANIMATION signaling sig + animate entity corvus performing action ACTION13_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + print 244 captioned + play sound "cinematics/fallen priestess/106-454.wav" for entity corvus + animate entity corvus performing action ACTION14_ANIMATION signaling sig + animate entity fallen performing action ACTION14_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + print 245 captioned + play sound "cinematics/fallen priestess/107-454.wav" for entity fallen + animate entity corvus performing action ACTION1_ANIMATION signaling sig + animate entity fallen performing action ACTION1_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + use entity cam22 + + +//Camera3, close up of corvus. + + use entity camera3 + print 246 captioned + play sound "cinematics/fallen priestess/108-450.wav" for entity corvus + animate entity corvus performing action ACTION2_ANIMATION signaling sig + animate entity fallen performing action ACTION2_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + +//Camera4, looking over corvus's shoulder + + use entity camera4 + print 247 captioned + play sound "cinematics/fallen priestess/109-450.wav" for entity fallen + animate entity corvus performing action ACTION3_ANIMATION signaling sig + animate entity fallen performing action ACTION3_ANIMATION signaling sig1 + wait 6 seconds + print 248 captioned + wait for all clearing sig, sig1 + +//Camera4, camera pulls back looking at both the fallen and corvus + + move entity camera4base by [-56, 72, 0] over 37 seconds + print 249 captioned + play sound "cinematics/fallen priestess/110-455.wav" for entity fallen + animate entity corvus performing action ACTION4_ANIMATION signaling sig + animate entity fallen performing action ACTION4_ANIMATION signaling sig1 + wait 4 seconds + print 250 captioned + wait 6 seconds + print 251 captioned + wait for all clearing sig, sig1 + print 252 captioned + play sound "cinematics/fallen priestess/112-458.wav" for entity fallen + animate entity corvus performing action ACTION5_ANIMATION signaling sig + animate entity fallen performing action ACTION5_ANIMATION signaling sig1 + wait 8 seconds + print 253 captioned to entity player1 + wait for all clearing sig, sig1 + +//Camera5, low looking up at corvus + + use entity camera5 + print 254 captioned + play sound "cinematics/fallen priestess/113-455.wav" for entity corvus + animate entity corvus performing action ACTION6_ANIMATION signaling sig + animate entity fallen performing action ACTION6_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + +//Camera6, behind corvus looking at the fallen. + + use entity camera6 + print 255 captioned + play sound "cinematics/fallen priestess/114-458.wav" for entity fallen + animate entity corvus performing action ACTION15_ANIMATION signaling sig + animate entity fallen performing action ACTION15_ANIMATION signaling sig1 + wait 6 seconds + print 256 captioned + wait for all clearing sig, sig1 + use entity camera6 + use entity send + print 257 captioned + play sound "cinematics/fallen priestess/115-458.wav" for entity corvus + animate entity fallen performing action ACTION16_ANIMATION signaling sig + animate entity corvus performing action ACTION16_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + + use entity send +// animate entity fallen performing action IDLE1_ANIMATION signaling sig +// animate entity corvus performing action IDLE4_ANIMATION signaling sig1 +// wait for all clearing sig + + use entity send + + disable cinematics + + use entity levelchange \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hive/firstprts.ds b/Toolkit/Designer/dsexamples/hive/firstprts.ds new file mode 100644 index 0000000..8bda962 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hive/firstprts.ds @@ -0,0 +1,149 @@ +// The Frist time Corvus encounters the High Priestess. + +#include "../common/header.ds" + +output "r:/base/ds/hive" + +local entity oneshot +local entity onetarget +local entity cam1a +local entity cam2a +local entity cam3a +local entity base1a +local entity cam3target +local entity testcam + +local entity fallen1 +local entity corvus1 +local entity player1 +local entity monster + +local int sig +local int sig1 + +oneshot = find entity with targetname "oneshot" +onetarget = find entity with targetname "t175" +testcam = find entity with targetname "testcam" +cam1a = find entity with targetname "camera1a" +cam2a = find entity with targetname "camera2a" +cam3a = find entity with targetname "camera3a" +base1a = find entity with targetname "cam1abase" +cam3target = find entity with targetname "t131" +fallen1 = find entity with targetname "fallen1" +corvus1 = find entity with targetname "corvus1" +monster = find entity with targetname "monster" + +//Switching player + +player1 = get entity activator // Get player who set off trigger +copy player attributes from entity player1 to entity corvus1 // copies players appearance +//corvus1.modelindex = corvus1.count // Turn on cinematic corvus +corvus1.solid = SOLID_NOT // Make him block +corvus1.movetype = PHYSICSTYPE_STEP + +fallen1.yaw_speed = .5 + +enable cinematics +cache sound "cinematics/first priestess/92-448.wav" +cache sound "cinematics/first priestess/93-445.wav" +cache sound "cinematics/first priestess/94-447.wav" +cache sound "cinematics/first priestess/95-448.wav" +cache sound "cinematics/first priestess/96-446.wav" +cache sound "cinematics/first priestess/97-446.wav" +cache sound "cinematics/first priestess/98-447.wav" + +//Opening shot of Corvus walking into scene. + + use entity oneshot + + wait .1 seconds + +// corvus1.modelindex = corvus1.count // Turn on cinematic corvus + onetarget.movetype = PHYSICSTYPE_PUSH + move entity onetarget by [0, 72, 0] over 3 seconds signaling sig + animate entity corvus1 performing action WALK3_ANIMATION by moving [72, 0, 0] signaling sig1 + wait for all clearing sig1 + animate entity corvus1 performing action IDLE2_ANIMATION + wait for all clearing sig + + use entity oneshot + +//Cam1a, behind corvus1 looking at fallen1 as she walks toward him. + + use entity cam1a + + wait 1 seconds + print 229 captioned + play sound "cinematics/first priestess/92-448.wav" for entity fallen1 + animate entity fallen1 performing action ACTION1_ANIMATION signaling sig + animate entity corvus1 performing action ACTION17_ANIMATION + wait for all clearing sig + print 230 captioned + play sound "cinematics/first priestess/93-445.wav" for entity corvus1 + animate entity corvus1 performing action ACTION18_ANIMATION signaling sig + animate entity fallen1 performing action ACTION2_ANIMATION signaling sig1 + wait for all clearing sig, sig1 + animate entity corvus1 performing action ACTION17_ANIMATION + print 231 captioned + play sound "cinematics/first priestess/94-447.wav" for entity fallen1 + animate entity fallen1 performing action ACTION3_ANIMATION by turning [-20, 0, 0] signaling sig + wait for all clearing sig + + use entity cam1a + +//Cam2a, low on the left of corvus1 looking up at the fallen1 as she walks around him. + + use entity cam2a + + move entity base1a by [80, -112, 0] over 21 seconds + print 232 captioned + play sound "cinematics/first priestess/95-448.wav" for entity corvus1 + animate entity corvus1 performing action ACTION19_ANIMATION signaling sig + animate entity fallen1 performing action ACTION4_ANIMATION by turning [20, 0, 0] signaling sig1 + wait for all clearing sig, sig1 + animate entity corvus1 performing action ACTION17_ANIMATION + + fallen1.yaw_speed = 2 + print 233 captioned + play sound "cinematics/first priestess/96-446.wav" for entity fallen1 + animate entity fallen1 performing action ACTION5_ANIMATION by turning [-180, 0, 0] signaling sig + wait for all clearing sig + + fallen1.yaw_speed = 2 + print 234 captioned + play sound "cinematics/first priestess/97-446.wav" for entity corvus1 + animate entity corvus1 performing action ACTION20_ANIMATION signaling sig + animate entity fallen1 performing action ACTION6_ANIMATION by turning [-200, 0, 0] signaling sig1 + wait for all clearing sig, sig1 + animate entity corvus1 performing action ACTION17_ANIMATION + +//Cam3a, close up of corvus. + + //use entity cam3a + + fallen1.yaw_speed = 1 + print 235 captioned + play sound "cinematics/first priestess/98-447.wav" for entity fallen1 + animate entity fallen1 performing action ACTION7_ANIMATION by turning [100, 0, 0] signaling sig + animate entity corvus1 performing action ACTION17_ANIMATION + wait for all clearing sig + + //use entity cam3a + use entity cam2a + +//Switching back + +player1.origin = corvus1.origin // Put player where Cinematic corvus is +player1.p_origin = corvus1.origin // Put player where Cinematic corvus is set view angles of entity player1 to hero.angles +corvus1.modelindex = 0 // Turn off the cinematic corvus model +corvus1.solid = SOLID_NOT // Make him not solid + +//Switching Priestess + +monster.origin = fallen1.origin // Put Monster where Cinematic Priestess is +monster.angles = fallen1.angles // Make Monster angles like Cinematic Watcher +monster.solid = SOLID_SOLID // Make the monster solid +fallen1.modelindex = 0 // Turn off the cinematic Priestess model +fallen1.solid = SOLID_NOT // Make her not solid + +disable cinematics diff --git a/Toolkit/Designer/dsexamples/hive/spear.ds b/Toolkit/Designer/dsexamples/hive/spear.ds new file mode 100644 index 0000000..1053460 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hive/spear.ds @@ -0,0 +1,42 @@ +// Hive2 tomb script + +#include "../common/header.ds" + +output "r:/base/ds/hive" + +local entity spearcam +local entity amdoor1 +local entity amdoor2 +local entity speartrain +local entity t118 +local int sig +local int sig2 +local int sig3 + +spearcam = find entity with targetname "t115" +amdoor1 = find entity with targetname "amdoor1" +amdoor2 = find entity with targetname "amdoor2" +speartrain = find entity with targetname "spearcam" +t118 = find entity with targetname "t118" + +//Gunga-ga-lunga + + +use entity spearcam + +move entity speartrain by [0, 0, 24] at 25 speed signaling sig +wait for all clearing sig + +use entity t118 + +move entity speartrain by [0, -64, 0] at 10 speed signaling sig +play sound "doors/kchunk6.wav" for entity amdoor1 +move entity amdoor1 by [-32, 0, 0] at 50 speed signaling sig2 +move entity amdoor2 by [32, 0, 0] at 50 speed signaling sig3 +wait for all clearing sig, sig2, sig3 +play sound "doors/kchunk7.wav" for entity amdoor1 +wait 2.5 seconds + +use entity spearcam + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hive/tomber.ds b/Toolkit/Designer/dsexamples/hive/tomber.ds new file mode 100644 index 0000000..7632b19 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hive/tomber.ds @@ -0,0 +1,79 @@ +// Hive2 tomb script + +#include "../common/header.ds" + +output "r:/base/ds/hive" + +local entity bug1 +local entity bug2 +local entity tomb +local entity base1 +local entity base2 +local entity tombguy +local entity clampleft +local entity clampright +local entity steps +local entity cam +local entity camerabase +local entity rubbleleft +local entity rubbleright +local int sig +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int sig6 + +bug1 = find entity with targetname "bug1" +bug2 = find entity with targetname "bug2" +tomb = find entity with targetname "tomb" +base1 = find entity with targetname "base1" +base2 = find entity with targetname "base2" +tombguy = find entity with targetname "tombguy" +clampleft = find entity with targetname "clampleft" +clampright = find entity with targetname "clampright" +steps = find entity with targetname "steps" +cam = find entity with targetname "cam" +camerabase = find entity with targetname "camerabase" +rubbleleft = find entity with targetname "rubbleleft" +rubbleright = find entity with targetname "rubbleright" + + +//ohhhhh yeah! + +use entity cam +move entity camerabase by [-112, 160, -64] over 8 seconds + +use entity rubbleleft +use entity rubbleright + +play sound "doors/kchunk5.wav" for entity clampleft +play sound "doors/kchunk5.wav" for entity clampright +rotate entity clampleft by [80, 0, 0] at 50 speed signaling sig +rotate entity clampright by [-80, 0, 0] at 50 speed signaling sig2 +wait for all clearing sig, sig2 + +bug1.movetype = PHYSICSTYPE_NOCLIP +bug2.movetype = PHYSICSTYPE_NOCLIP +tombguy.movetype = PHYSICSTYPE_NOCLIP +play sound "doors/stoneloop.wav" for entity tomb on channel 10 +move entity base1 by [0, 0, -112] at 50 speed signaling sig +move entity base2 by [0, 0, -112] at 50 speed signaling sig2 +move entity bug1 by [0, 0, -112] at 50 speed signaling sig3 +move entity bug2 by [0, 0, -112] at 50 speed signaling sig4 +move entity tomb by [0, 0, -112] at 50 speed signaling sig5 +move entity tombguy by [0, 0, -112] at 50 speed signaling sig6 +wait for all clearing sig, sig2, sig3, sig4, sig5, sig6 +play sound "doors/stoneend.wav" for entity tomb on channel 10 + + +move entity steps by [0, 0, 16] at 50 speed signaling sig +wait for all clearing sig +play sound "doors/stoneend.wav" for entity steps +wait 1 seconds + +use entity cam + + + + diff --git a/Toolkit/Designer/dsexamples/hive/trapeze.ds b/Toolkit/Designer/dsexamples/hive/trapeze.ds new file mode 100644 index 0000000..c07aeed --- /dev/null +++ b/Toolkit/Designer/dsexamples/hive/trapeze.ds @@ -0,0 +1,28 @@ +// The fantabulous rotating lab table which has now been changed into the Gaunlet trapeze! + +#include "../common/header.ds" + +output "r:/base/ds/hive" + +local entity bucket +local entity arm +local int s1 +field int accel + +bucket = find entity with targetname "swingee" +arm = find entity with targetname "swinger" + +bucket.owner = arm +bucket.state = 0 +bucket.movetype = PHYSICSTYPE_SCRIPT_ANGULAR +arm.accel = 60 + +label schwingit + +rotate entity arm by [-80,0,0] at 20 speed signaling s1 +wait for all clearing s1 +wait 0.3 seconds +rotate entity arm by [80,0,0] at 20 speed signaling s1 +wait for all clearing s1 +wait 0.3 seconds +goto schwingit diff --git a/Toolkit/Designer/dsexamples/hive/trapezea.ds b/Toolkit/Designer/dsexamples/hive/trapezea.ds new file mode 100644 index 0000000..9188e99 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hive/trapezea.ds @@ -0,0 +1,34 @@ +// The fantabulous rotating lab table which has now been changed into the Gaunlet trapeze! + +#include "../common/header.ds" + +output "r:/base/ds/hive" + +local entity bucket +local entity arm + +local int s1 +field int accel + +bucket = find entity with targetname "swingee" +arm = find entity with targetname "swinger" + +bucket.owner = arm +bucket.state = 0 +bucket.distance = 464 +bucket.start_origin = [0, 0, 464] +bucket.movetype = PHYSICSTYPE_SCRIPT_ANGULAR + +rotate entity arm by [40,0,0] at 60 speed + +wait 2 seconds + + +label schwingit +rotate entity arm by [-80,0,0] at 20 speed signaling s1 +wait for all clearing s1 +wait 0.3 seconds +rotate entity arm by [80,0,0] at 20 speed signaling s1 +wait for all clearing s1 +wait 0.3 seconds +goto schwingit diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/closedoor.ds b/Toolkit/Designer/dsexamples/hivetrialpit/closedoor.ds new file mode 100644 index 0000000..bf3c44d --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/closedoor.ds @@ -0,0 +1,32 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity BigDoorN +local entity BigDoorS +local entity BigDoorPortal +local int s1 +local int s2 + +BigDoorN = find entity with targetname "bigdoorn" +BigDoorS = find entity with targetname "bigdoors" +BigDoorPortal = find entity with targetname "bigdoorportal" + +label beginning + +move entity BigDoorN by [0,-128,0] at 128 speed signaling s1 +move entity BigDoorS by [0,128,0] at 128 speed signaling s2 + +play sound "doors/slide2.wav" for entity BigDoorN +wait 0.1 seconds +play sound "doors/slide2.wav" for entity BigDoorS + +wait for all clearing s1, s2 + +use entity BigDoorPortal + +play sound "doors/stoneend.wav" for entity BigDoorN +play sound "doors/stoneend.wav" for entity BigDoorS + + +suspend +goto beginning \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/flare.ds b/Toolkit/Designer/dsexamples/hivetrialpit/flare.ds new file mode 100644 index 0000000..340bf9a --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/flare.ds @@ -0,0 +1,9 @@ +#include "../common/header.ds" + +output "r:/base/ds/hivetrialpit" + +parameter entity flare + +move entity flare by [256,256,0] at 200 speed + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/flare1.ds b/Toolkit/Designer/dsexamples/hivetrialpit/flare1.ds new file mode 100644 index 0000000..5e33382 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/flare1.ds @@ -0,0 +1,29 @@ +#include "../common/header.ds" + +output "r:/base/ds/hivetrialpit" + +local entity flare +local entity lights +local int s1 + +flare = find entity with targetname "flare1" +lights = find entity with targetname "f1" + +use entity flare + +move entity flare to [-704, 192, 4] at 400 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-768, 512, 132] at 400 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-768, 704, 132] at 400 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-896, 832, 132] at 400 speed signaling s1 +wait for any clearing s1 + +use entity flare +use entity lights + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/flare2.ds b/Toolkit/Designer/dsexamples/hivetrialpit/flare2.ds new file mode 100644 index 0000000..07d6e63 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/flare2.ds @@ -0,0 +1,29 @@ +#include "../common/header.ds" + +output "r:/base/ds/hivetrialpit" + +local entity flare +local entity lights +local int s1 + +flare = find entity with targetname "flare2" +lights = find entity with targetname "f2" + +use entity flare + +move entity flare to [-576, -384, 4] at 300 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-832, -704, 132] at 300 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-800, -896, 132] at 300 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-896, -1024, 132] at 300 speed signaling s1 +wait for any clearing s1 + +use entity flare +use entity lights + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/flare3.ds b/Toolkit/Designer/dsexamples/hivetrialpit/flare3.ds new file mode 100644 index 0000000..66c2f77 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/flare3.ds @@ -0,0 +1,32 @@ +#include "../common/header.ds" + +output "r:/base/ds/hivetrialpit" + +local entity flare +local entity lights +local int s1 + +flare = find entity with targetname "flare3" +lights = find entity with targetname "f3" + +use entity flare + +move entity flare to [-1024, -192, 4] at 500 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-1280, -160, 4] at 500 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-1600, -320, 132] at 500 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-1792, -320, 132] at 500 speed signaling s1 +wait for any clearing s1 + +move entity flare to [-1920, -192, 132] at 500 speed signaling s1 +wait for any clearing s1 + +use entity flare +use entity lights + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/killpillarn.ds b/Toolkit/Designer/dsexamples/hivetrialpit/killpillarn.ds new file mode 100644 index 0000000..08c2549 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/killpillarn.ds @@ -0,0 +1,40 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity pillartop +local entity pillarbottom +local entity pillarfirebase +local int s1 +local int s2 +local int spd +spd = 800 + +pillartop = find entity with scripttarget "NorthPillarTop" +pillarbottom = find entity with scripttarget "NorthPillarBottom" +pillarfirebase = find entity with targetname "npillarfirebase" + +pillartop.movetype = 5 +pillarbottom.movetype = 5 + +play sound "misc/breakstone.wav" for entity pillartop + +use entity pillarfirebase + +move entity pillartop by [-128,-32,-288] at spd speed signaling s1 +rotate entity pillartop by [-90,15,15] at 220 speed +move entity pillarbottom by [-384,32,-104] at spd speed signaling s2 +rotate entity pillarbottom by [-75,15,15] at 200 speed + +wait for all clearing s1, s2 + +play sound "misc/breakstone.wav" for entity pillartop + +pillartop.movetype = 0 +pillarbottom.movetype = 0 + +use entity pillartop +use entity pillarbottom + +exit + + diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/killpillars.ds b/Toolkit/Designer/dsexamples/hivetrialpit/killpillars.ds new file mode 100644 index 0000000..a29223e --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/killpillars.ds @@ -0,0 +1,39 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity pillartop +local entity pillarbottom +local entity pillarfirebase +local int s1 +local int s2 +local int spd +spd = 800 + +pillartop = find entity with scripttarget "SouthPillarTop" +pillarbottom = find entity with scripttarget "SouthPillarBottom" +pillarfirebase = find entity with targetname "spillarfirebase" + +pillartop.movetype = 5 +pillarbottom.movetype = 5 + +play sound "misc/breakstone.wav" for entity pillartop + +use entity pillarfirebase + +move entity pillartop by [-128,-32,-288] at spd speed signaling s1 +rotate entity pillartop by [-90,15,15] at 220 speed +move entity pillarbottom by [-384,32,-104] at spd speed signaling s2 +rotate entity pillarbottom by [-75,15,15] at 200 speed + +wait for all clearing s1, s2 + +play sound "misc/breakstone.wav" for entity pillartop + +pillartop.movetype = 0 +pillarbottom.movetype = 0 + +use entity pillartop +use entity pillarbottom + +exit + diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/killplatform.ds b/Toolkit/Designer/dsexamples/hivetrialpit/killplatform.ds new file mode 100644 index 0000000..ca2546e --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/killplatform.ds @@ -0,0 +1,32 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity platform +local entity beast +local int s1 + +beast = find entity with scripttarget "trialbeast" +platform = find entity with targetname "platform" + +play sound "misc/plattrem.wav" for entity platform +rotate entity platform by [1,3,2] at 50 speed + +suspend + +play sound "misc/plattrem.wav" for entity platform + +use entity beast + +move entity platform by [64,0,-256] at 800 speed signaling s1 +rotate entity platform by [0,3,2] at 50 speed + +wait for any clearing s1 + +play sound "misc/platimp.wav" for entity platform + +move entity platform by [-8,16,-64] at 200 speed signaling s1 +rotate entity platform by [4, 5, 3] at 50 speed + +wait for any clearing s1 + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/killrailne.ds b/Toolkit/Designer/dsexamples/hivetrialpit/killrailne.ds new file mode 100644 index 0000000..dbee5b4 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/killrailne.ds @@ -0,0 +1,19 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity Rail +local int s1 + +Rail = find entity with targetname "RailingNE" +Rail.movetype = 5 + +move entity Rail by [192,64,-128] at 800 speed signaling s1 +rotate entity Rail by [540, -600, 180] at 600 speed +wait for any clearing s1 + +move entity Rail by [128,64,-384] at 800 speed signaling s1 +wait for any clearing s1 + +use entity Rail + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/killrailse.ds b/Toolkit/Designer/dsexamples/hivetrialpit/killrailse.ds new file mode 100644 index 0000000..51909e0 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/killrailse.ds @@ -0,0 +1,19 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity Rail +local int s1 + +Rail = find entity with targetname "RailingSE" +Rail.movetype = 5 + +move entity Rail by [256,-32,-128] at 800 speed signaling s1 +rotate entity Rail by [-360, 600, 360] at 600 speed +wait for any clearing s1 + +move entity Rail by [192,-32,-384] at 800 speed signaling s1 +wait for any clearing s1 + +use entity Rail + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/killrailw.ds b/Toolkit/Designer/dsexamples/hivetrialpit/killrailw.ds new file mode 100644 index 0000000..e9fe4fe --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/killrailw.ds @@ -0,0 +1,20 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity RailW +local int s1 +local int s2 + +RailW = find entity with targetname "RailingW" +RailW.movetype = 5 + +move entity RailW by [-256,64,-128] at 800 speed signaling s1 +rotate entity RailW by [180, 600, 180] at 600 speed +wait for any clearing s1 + +move entity RailW by [-256,64,-256] at 800 speed signaling s1 +wait for any clearing s1 + +use entity RailW + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/opendoor.ds b/Toolkit/Designer/dsexamples/hivetrialpit/opendoor.ds new file mode 100644 index 0000000..6edb8b0 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/opendoor.ds @@ -0,0 +1,30 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity BigDoorN +local entity BigDoorS +local entity BigDoorPortal +local int s1 +local int s2 + +BigDoorN = find entity with targetname "bigdoorn" +BigDoorS = find entity with targetname "bigdoors" +BigDoorPortal = find entity with targetname "bigdoorportal" + +label beginning + +use entity BigDoorPortal +move entity BigDoorN by [0,128,0] at 128 speed signaling s1 +move entity BigDoorS by [0,-128,0] at 128 speed signaling s2 + +play sound "doors/slide2.wav" for entity BigDoorN +wait 0.1 seconds +play sound "doors/slide2.wav" for entity BigDoorS + +wait for all clearing s1, s2 + +play sound "doors/stoneend.wav" for entity BigDoorN +play sound "doors/stoneend.wav" for entity BigDoorS + +suspend +goto beginning \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/starttrial.ds b/Toolkit/Designer/dsexamples/hivetrialpit/starttrial.ds new file mode 100644 index 0000000..a336ae6 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/starttrial.ds @@ -0,0 +1,50 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity opener +local entity bug +local entity beast +local entity flare1t +local entity flare2t +local entity flare3t +local entity fire +local int s1 +local int s2 + +opener = find entity with targetname "opendoor" +bug = find entity with targetname "bug" +flare1t = find entity with targetname "flare1t" +flare2t = find entity with targetname "flare2t" +flare3t = find entity with targetname "flare3t" +fire = find entity with targetname "fire" +beast = find entity with scripttarget "trialbeast" + +wait 0.5 seconds + +animate entity bug performing action ATTACK3_ANIMATION signaling s1 +wait 0.4 seconds + +use entity fire +move entity fire to [-640, -64, 8] over 1 seconds signaling s2 + +wait for any clearing s1 +animate entity bug performing action IDLE2_ANIMATION + +wait for any clearing s2 + +use entity flare1t +use entity flare2t +use entity flare3t + +wait 1 seconds +use entity fire + +wait 4 seconds + +use entity opener + +wait .5 seconds + +use entity beast + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/tossbug.ds b/Toolkit/Designer/dsexamples/hivetrialpit/tossbug.ds new file mode 100644 index 0000000..42e5d3e --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/tossbug.ds @@ -0,0 +1,15 @@ +output "r:/base/ds/hivetrialpit" +#include "../common/header.ds" + +local entity bug +local int s1 + +bug = find entity with targetname "bug" + +bug.c_mode = 0 + +rotate entity bug by [360, 180, 360] at 300 speed +bug.velocity = [150, -100, 450] +use entity bug + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/trial1.ds b/Toolkit/Designer/dsexamples/hivetrialpit/trial1.ds new file mode 100644 index 0000000..b0214de --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/trial1.ds @@ -0,0 +1,56 @@ +#include "../common/header.ds" + +output "r:/base/ds/hivetrialpit" + +local vector v +local int spd + +local entity rubble1 +local entity rubble2 +local entity rubble3 +local entity rubble4 +local entity flame + +v = [500,500,500] +spd = 1000 + +rubble1 = find entity with scripttarget "rubble1" +rubble2 = find entity with scripttarget "rubble2" +rubble3 = find entity with scripttarget "rubble3" +rubble4 = find entity with scripttarget "rubble4" +flame = find entity with targetname "flame" + +rubble1.movetype = PHYSICSTYPE_NOCLIP +rubble2.movetype = PHYSICSTYPE_NOCLIP +rubble3.movetype = PHYSICSTYPE_NOCLIP +rubble4.movetype = PHYSICSTYPE_NOCLIP + +use entity flame +rotate entity rubble1 by v at spd speed +play sound "misc/breakstone.wav" for entity rubble1 +rotate entity rubble2 by v at spd speed +play sound "misc/breakstone.wav" for entity rubble2 +rotate entity rubble3 by v at spd speed +play sound "misc/breakstone.wav" for entity rubble3 +rotate entity rubble4 by v at spd speed +play sound "misc/breakstone.wav" for entity rubble4 + +move entity rubble1 to [-384,-320,12] at 600 speed +move entity rubble2 to [-430,-256,8] at 550 speed +move entity rubble3 to [-500,-192,16] at 540 speed +move entity rubble4 to [-320,-270,8] at 575 speed + +wait .3 seconds + +use entity rubble1 + +wait .1 seconds + +use entity rubble2 +use entity rubble4 + +wait .2 seconds + +use entity rubble3 + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/hivetrialpit/trial2.ds b/Toolkit/Designer/dsexamples/hivetrialpit/trial2.ds new file mode 100644 index 0000000..5e12241 --- /dev/null +++ b/Toolkit/Designer/dsexamples/hivetrialpit/trial2.ds @@ -0,0 +1,56 @@ +#include "../common/header.ds" + +output "r:/base/ds/hivetrialpit" + +local vector v +local int spd + +local entity rubble1 +local entity rubble2 +local entity rubble3 +local entity rubble4 +local entity flame + +v = [500,500,500] +spd = 800 + +rubble1 = find entity with scripttarget "rubble1n" +rubble2 = find entity with scripttarget "rubble2n" +rubble3 = find entity with scripttarget "rubble3n" +rubble4 = find entity with scripttarget "rubble4n" +flame = find entity with targetname "flamen" + +rubble1.movetype = PHYSICSTYPE_NOCLIP +rubble2.movetype = PHYSICSTYPE_NOCLIP +rubble3.movetype = PHYSICSTYPE_NOCLIP +rubble4.movetype = PHYSICSTYPE_NOCLIP + +use entity flame +rotate entity rubble1 by v at spd speed +play sound "misc/breakstone.wav" for entity rubble1 +rotate entity rubble2 by v at spd speed +play sound "misc/breakstone.wav" for entity rubble2 +rotate entity rubble3 by v at spd speed +play sound "misc/breakstone.wav" for entity rubble3 +rotate entity rubble4 by v at spd speed +play sound "misc/breakstone.wav" for entity rubble4 + +move entity rubble1 to [-384,16,12] at 600 speed +move entity rubble2 to [-430,100,8] at 550 speed +move entity rubble3 to [-500,64,16] at 540 speed +move entity rubble4 to [-320,128,8] at 575 speed + +wait .3 seconds + +use entity rubble1 + +wait .1 seconds + +use entity rubble2 +use entity rubble4 + +wait .2 seconds + +use entity rubble3 + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/kellcaves/bridge.ds b/Toolkit/Designer/dsexamples/kellcaves/bridge.ds new file mode 100644 index 0000000..dac81dc --- /dev/null +++ b/Toolkit/Designer/dsexamples/kellcaves/bridge.ds @@ -0,0 +1,62 @@ +//Earthquake, rock falls, bridge brakes. + +#include "../common/header.ds" + +output "r:/base/ds/kellcaves" + +//define variables + +//local entity earthquake +local entity rock +local entity dust1 +local entity rubble1 +local entity bridge +local int sig +local entity dam1 +local entity dam2 + +field vector "movetype" + +rock = find entity with targetname "rock" +dust1 = find entity with targetname "dust1" +rubble1 = find entity with targetname "rubble1" +bridge = find entity with targetname "bridge" +dam1 = find entity with targetname "dam1" +dam2 = find entity with targetname "dam2" + +//earthquake = find entity with targetname "quake" + +//Start earthquake + +//use entity earthquake + +//count 2 speed 50 on quake + +use entity dam1 + +rock.movetype = PHYSICSTYPE_PUSH + +wait .5 seconds use entity dust1 + +wait 1.2 seconds use entity rubble1 + +rotate entity rock to [30, 0, 0] at 600 speed signaling sig +wait for all clearing sig + +move entity rock by [0, 0, -656] at 800 speed + +wait .3 seconds use entity bridge + +play sound "misc/breakstone.wav" for entity rock + +rotate entity rock to [-50, 0, 0] at 600 speed signaling sig +wait for all clearing sig + +use entity dam2 + +use entity rock + + + + + diff --git a/Toolkit/Designer/dsexamples/kellcaves/cavein.ds b/Toolkit/Designer/dsexamples/kellcaves/cavein.ds new file mode 100644 index 0000000..fff499a --- /dev/null +++ b/Toolkit/Designer/dsexamples/kellcaves/cavein.ds @@ -0,0 +1,150 @@ +// This is the cave in, in one of the hallways. + +#include "../common/header.ds" + +output "r:/base/ds/kellcaves" + +local entity top +local entity bottom +local entity beam +local entity rubble1 +local entity rubble2 +local entity rocks1 +local entity rocks2 +local entity quake1 +local entity quake1a +local entity rockrt +local entity rocklt +local entity rockcam1 +local entity rockcam2 +local entity rockdmgon +local entity rockdmgoff +local entity rockclip + +global int dir + +local int sig +local int sig1 +local int sig2 +local int sig3 + +top = find entity with targetname "top" +bottom = find entity with targetname "bottom" +beam = find entity with targetname "beam" +rubble1 = find entity with targetname "rubble1" +rubble2 = find entity with targetname "rubble2" +rocks1 = find entity with targetname "rocks1" +rocks2 = find entity with targetname "rocks2" +quake1 = find entity with targetname "quake1" +quake1a = find entity with targetname "quake1a" +rockrt = find entity with targetname "rockrt" +rocklt = find entity with targetname "rocklt" +rockcam1 = find entity with targetname "rockcam1" +rockcam2 = find entity with targetname "rockcam2" +rockdmgon = find entity with targetname "rockdmgon" +rockdmgoff = find entity with targetname "rockdmgoff" +rockclip = find entity with targetname "rockclip" + +// In the begining + + +// enable cinematics + + if dir = 1 + use entity rockcam1 + + else + use entity rockcam2 + endif + + top.movetype = PHYSICSTYPE_PUSH + beam.movetype = PHYSICSTYPE_NOCLIP + + use entity quake1 + + wait .5 seconds + + use entity rocks1 + + wait .5 seconds + + use entity rubble1 + + move entity top by [35, 0, -25] at 460 speed signaling sig + wait for all clearing sig + + rotate entity beam by [-10, 0, 0] at 700 speed signaling sig + + move entity top by [0, 0, -15] at 700 speed signaling sig1 + wait for all clearing sig, sig1 + + rotate entity beam by [5, 0, 0] at 700 speed signaling sig + + rotate entity top by [0, 0, 90] at 700 speed signaling sig1 + wait for all clearing sig, sig1 + + use entity top + + rotate entity beam by [-5, 0, 0] at 700 speed signaling sig + + rotate entity rockrt by [9, 0, 0] at 700 speed signaling sig1 + + move entity rocklt by [-10, 0, -9] at 650 speed signaling sig2 + wait for all clearing sig, sig1, sig2 + + wait 1 seconds + + if dir = 1 + use entity rockcam1 + + else + use entity rockcam2 + endif + +// disable cinematics + + suspend + +// now for the actual cave in. + + use entity quake1a + + use entity rocks2 + + use entity rockdmgon + + move entity beam by [0, 0, -53] at 600 speed signaling sig + wait for all clearing sig + + use entity bottom + + move entity beam by [0, 0, -90] at 700 speed signaling sig + + rotate entity beam by [10, 0, 0] at 700 speed signaling sig1 + + rotate entity rockrt by [25, 0, 0] at 500 speed signaling sig2 + wait for all clearing sig, sig1, sig2 + + move entity rocklt by [-50, 0, 0] at 700 speed signaling sig + + move entity rockrt by [0, 0, -30] at 700 speed signaling sig1 + wait for all clearing sig, sig1 + + use entity beam + + rotate entity rockrt by [-15, 0, 0] at 500 speed signaling sig + + move entity rockrt by [0, 0, -110] at 500 speed signaling sig1 + + move entity rocklt by [90, 0, 0] at 700 speed signaling sig2 + + rotate entity rocklt by [85, 0, 0] at 600 speed signaling sig3 + wait for all clearing sig, sig1, sig2, sig3 + + move entity rocklt by [0, 0, -10] at 600 speed signaling sig + wait for all clearing sig + + use entity rockdmgoff + + use entity rockclip + diff --git a/Toolkit/Designer/dsexamples/kellcaves/cavein1.ds b/Toolkit/Designer/dsexamples/kellcaves/cavein1.ds new file mode 100644 index 0000000..3142e53 --- /dev/null +++ b/Toolkit/Designer/dsexamples/kellcaves/cavein1.ds @@ -0,0 +1,18 @@ +// This is first part of the cave in, in one of the hallways. +// this part decides which camera to use + +#include "../common/header.ds" + +output "r:/base/ds/kellcaves" + +global int dir + +parameter int parm1 + +local entity cavein + +dir = parm1 + +cavein = find entity with targetname "cavein" + +use entity cavein \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/kellcaves/levelchange.ds b/Toolkit/Designer/dsexamples/kellcaves/levelchange.ds new file mode 100644 index 0000000..d45a58c --- /dev/null +++ b/Toolkit/Designer/dsexamples/kellcaves/levelchange.ds @@ -0,0 +1,117 @@ +//level change for kell caves + +#include "../common/header.ds" + +output "r:/base/ds/kellcaves" + +//define variables + +local entity cam +local entity cl +local entity rock1 +local entity rock2 +local entity rock3 +local entity brock +local entity two +local entity rub1 +local entity rub2 +local entity rub3 +local entity dust +local entity dust1 +local entity c2 +local entity player1 +local entity quake9 + +local int sig +local int sig1 + +cl = find entity with targetname "t1" +cam = find entity with targetname "t68" +rock1 = find entity with targetname "rock1" +rock2 = find entity with targetname "rock2" +rock3 = find entity with targetname "rock3" +brock = find entity with targetname "backrock" +two = find entity with targetname "tworocks" +dust = find entity with targetname "smallrubble" +rub1 = find entity with targetname "rubble1" +rub2 = find entity with targetname "rubble2" +rub3 = find entity with targetname "rubble3" +dust1 = find entity with targetname "smallrubble2" +c2 = find entity with targetname "c2" +player1 = get entity activator +quake9 = find entity with targetname "quake9" + +//Cave-in and level change + + enable cinematics + + copy player attributes from entity player1 to entity c2 + c2.modelindex = c2.count + c2.solid = SOLID_SOLID + c2.movetype = 4 + + player1.takedamage = DAMAGE_NO + + c2.movetype = PHYSICSTYPE_NOCLIP + + animate entity c2 performing action IDLE1_ANIMATION + + use entity cam + + enable trigger entity quake9 + + use entity rub1 wait 1 seconds + play sound "Misc/gravel2.wav" for entity two + move entity two by [0, 0, -192] at 1100 speed signaling sig + wait for all clearing sig + + play sound "world/quake.wav" for entity c2 on channel 10 + use entity quake9 + + move entity brock by [0, 0, -160] at 1100 speed signaling sig + wait for all clearing sig + + use entity rub2 wait .5 seconds + + animate entity c2 performing action ACTION8_ANIMATION + + play sound "Misc/gravel2.wav" for entity rock3 + move entity rock3 by [0, 0, -136] at 1100 speed signaling sig + rotate entity rock3 by [0, 20, -60] at 1100 speed signaling sig1 + wait for all clearing sig, sig1 + + animate entity c2 performing action ACTION9_ANIMATION + + use entity dust1 + + move entity rock2 by [0, 0, -136] at 1200 speed signaling sig + rotate entity rock2 by [0, -10, 70] at 1200 speed signaling sig1 + wait for all clearing sig, sig1 + + use entity rub3 + + play sound "Misc/gravel2.wav" for entity rock1 + move entity rock1 by [0, 0, -160] at 1300 speed signaling sig + rotate entity rock1 by [0, 0, -60] at 1300 speed signaling sig1 + wait for all clearing sig, sig1 + + use entity dust + + disable trigger entity quake9 + + wait 2 second + + player1.origin = c2.origin + player1.p_origin = c2.origin + set view angles of entity player1 to c2.angles + player1.takedamage = DAMAGE_YES + + disable cinematics + + player1.modelindex = 0 + player1.solid = SOLID_NOT + + use entity cl + + + diff --git a/Toolkit/Designer/dsexamples/kellcaves/portal.ds b/Toolkit/Designer/dsexamples/kellcaves/portal.ds new file mode 100644 index 0000000..3717427 --- /dev/null +++ b/Toolkit/Designer/dsexamples/kellcaves/portal.ds @@ -0,0 +1,46 @@ +// The camera shot in the beginning of the kellcaves + +#include "../common/header.ds" + +output "r:/base/ds/kellcaves" + +local entity portalcam +local entity portal +local entity c1 +local entity player1 + +portalcam = find entity with targetname "portalcam" +portal = find entity with targetname "portal" +c1 = find entity with targetname "c1" +player1 = get entity activator + +// Lights, Camera, Action. + + enable cinematics + + copy player attributes from entity player1 to entity c1 + c1.modelindex = c1.count + c1.solid = SOLID_SOLID + c1.movetype = 4 + + animate entity c1 performing action IDLE1_ANIMATION + + use entity portal + play sound "items/teleport2.wav" for entity portal + use entity portalcam + + wait 4 seconds + use entity portal + + wait 3 seconds + + player1.origin = c1.origin + player1.p_origin = c1.origin + set view angles of entity player1 to c1.angles + + c1.modelindex = 0 + c1.solid = SOLID_NOT + + use entity portalcam + + disable cinematics \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/kellcaves/rubble.ds b/Toolkit/Designer/dsexamples/kellcaves/rubble.ds new file mode 100644 index 0000000..b203575 --- /dev/null +++ b/Toolkit/Designer/dsexamples/kellcaves/rubble.ds @@ -0,0 +1,69 @@ +//more rubble + +#include "../common/header.ds" + +output "r:/base/ds/kellcaves" + +//define entity + +local entity rockfall +local entity rockfall2 +local entity rockfall3 +local entity rockfall4 +local entity a1 +local entity a2 +local entity a3 +local entity a4 +local entity d1 +local entity d2 +local entity d3 +local entity d4 + +//local entity quake +local int sig + +//quake = find entity with targetname "quake" +rockfall = find entity with targetname "rockfall" +rockfall2 = find entity with targetname "rockfall2" +rockfall3 = find entity with targetname "rockfall3" +rockfall4 = find entity with targetname "rockfall4" +a1 = find entity with targetname "a1" +a2 = find entity with targetname "a2" +a3 = find entity with targetname "a3" +a4 = find entity with targetname "a4" +d1 = find entity with targetname "d1" +d2 = find entity with targetname "d2" +d3 = find entity with targetname "d3" +d4 = find entity with targetname "d4" + +//falling rubble + +//use entity quake + +use entity a1 +wait .2 seconds use entity rockfall + + +use entity a2 +wait .4 seconds use entity rockfall2 + + +use entity a3 +wait .5 seconds use entity rockfall3 +use entity d1 + +use entity d2 + +use entity a4 +wait .5 seconds use entity rockfall4 +use entity d3 + +wait .5 seconds +use entity d4 + + + + + + + diff --git a/Toolkit/Designer/dsexamples/kellcaves/steps.ds b/Toolkit/Designer/dsexamples/kellcaves/steps.ds new file mode 100644 index 0000000..cf89cbb --- /dev/null +++ b/Toolkit/Designer/dsexamples/kellcaves/steps.ds @@ -0,0 +1,101 @@ +// the breaking stairs. + +#include "../common/header.ds" + +output "r:/base/ds/kellcaves" + +local entity b1 +local entity b2 +local entity b3 +local entity step1 +local entity step2 +local entity step3 +local entity trig +local entity floor + +local int sig + +b1 = find entity with targetname "b1" +b2 = find entity with targetname "b2" +b3 = find entity with targetname "b3" +step1 = find entity with targetname "step1" +step2 = find entity with targetname "step2" +step3 = find entity with targetname "step3" +trig = find entity with targetname "trig" +floor = find entity with targetname "floor" + +// use the breakable brushes and their steps + + step1.movetype = PHYSICSTYPE_NOCLIP + step2.movetype = PHYSICSTYPE_NOCLIP + step3.movetype = PHYSICSTYPE_NOCLIP + + use entity b1 + + rotate entity step1 by [0, 0, 10] at 200 speed signaling sig + wait for all clearing sig + + use entity b2 + + rotate entity step2 by [0, 0, 10] at 200 speed signaling sig + wait for all clearing sig + + use entity b3 + + rotate entity step3 by [0, 0, 10] at 200 speed signaling sig + wait for all clearing sig + + use entity trig + + suspend + + + move entity step1 by [0, 0, -200] at 200 speed + wait .2 seconds + + move entity step2 by [0, 0, -200] at 200 speed + + wait .1 seconds + + use entity floor + + wait .1 seconds + + move entity step3 by [0, 0, -200] at 200 speed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/mines/cart.ds b/Toolkit/Designer/dsexamples/mines/cart.ds new file mode 100644 index 0000000..ce4cb2b --- /dev/null +++ b/Toolkit/Designer/dsexamples/mines/cart.ds @@ -0,0 +1,40 @@ +// an ogle pushing a cart + +#include "../common/header.ds" + +output "r:/base/ds/mines" + +local entity cart +local entity larry + +local int sig +local int sig1 + +cart = find entity with targetname "cart" +larry = find entity with targetname "larry" + +// start + + cart.movetype = PHYSICSTYPE_PUSH + + play sound "monsters/seraph/overlord/scold.wav" for entity larry + + wait 1 seconds + + move entity cart by [0, 186, 14] over 9 seconds signaling sig + + animate entity larry performing action WALK2_ANIMATION by moving [186, 0, 0] signaling sig1 + wait for all clearing sig, sig1 + + rotate entity cart by [0, 0, 8] at 200 speed signaling sig + wait for all clearing sig + + move entity cart by [0, 48, 0] over 2 seconds signaling sig + + animate entity larry performing action WALK2_ANIMATION by moving [48, 0, 0] signaling sig1 + wait for all clearing sig, sig1 + + animate entity larry performing action IDLE3_ANIMATION signaling sig + wait for all clearing sig + + animate entity larry performing action THINKAGAIN_ANIMATION \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/mines/flame.ds b/Toolkit/Designer/dsexamples/mines/flame.ds new file mode 100644 index 0000000..a57ab21 --- /dev/null +++ b/Toolkit/Designer/dsexamples/mines/flame.ds @@ -0,0 +1,31 @@ +// its the steam jet. coming out of a pipe. + +#include "../common/header.ds" + +output "r:/base/ds/mines" + + +local entity wheel +local entity flame +local entity flame1 +local entity flame2 + +local int sig + +wheel = find entity with targetname "wheel" +flame = find entity with targetname "flame" +flame1 = find entity with targetname "flame1" +flame2 = find entity with targetname "flame2" + +// the start. turning of the wheel + + wheel.movetype = PHYSICSTYPE_PUSH + + rotate entity wheel by [420, 0, 0] at 200 speed signaling sig + wait for all clearing sig + +// shutting off the steam + + use entity flame + use entity flame1 + use entity flame2 \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/mines/lift.ds b/Toolkit/Designer/dsexamples/mines/lift.ds new file mode 100644 index 0000000..562e8cd --- /dev/null +++ b/Toolkit/Designer/dsexamples/mines/lift.ds @@ -0,0 +1,74 @@ +// the lifts in the mine levels + + +#include "../common/header.ds" + +output "r:/base/ds/mines" + +parameter entity parm1 +parameter entity parm2 +parameter vector parm3 +parameter entity parm4 +parameter entity parm5 + +local int up = 1 + +local int sig +local int sig2 + + + label begining + +// using the lever + + parm1.movetype = PHYSICSTYPE_PUSH + + use entity parm1 + + wait 1 seconds + +// lets move this sucker + + play sound "doors/elevatormove.wav" for entity parm2 on channel 10 + + move entity parm1 by parm3 over 5 seconds signaling sig + + move entity parm2 by parm3 over 5 seconds signaling sig2 + + if up = 1 + wait 3.5 seconds + use entity parm4 + endif + + wait .5 seconds + + if up = 1 + use entity parm5 + up = 0 + else + up = 1 + endif + + wait for all clearing sig, sig2 + + play sound "doors/elevatorstop.wav" for entity parm2 on channel 10 + + + parm3 *=-1 + + suspend + + goto begining + + + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/mines/message.ds b/Toolkit/Designer/dsexamples/mines/message.ds new file mode 100644 index 0000000..962f45b --- /dev/null +++ b/Toolkit/Designer/dsexamples/mines/message.ds @@ -0,0 +1,23 @@ +// A little script that gives the player a message. I made this a script in the hopes that it will +// work a little better in coop. + +#include "../common/header.ds" + +output "r:/base/ds/mines" + +global entity last_player + +local entity dipshit + +label loop + + dipshit = get entity activator + + if dipshit != last_player + print 65 captioned + last_player = dipshit + endif + + suspend + +goto loop \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/mines/minecart.ds b/Toolkit/Designer/dsexamples/mines/minecart.ds new file mode 100644 index 0000000..0b2a9bc --- /dev/null +++ b/Toolkit/Designer/dsexamples/mines/minecart.ds @@ -0,0 +1,283 @@ +// Come and ride on my beautiful, my beautiful, Mine Cart. + +#include "../common/header.ds" + +output "r:/base/ds/mines" + +local entity wheel1 +local entity wheel2 +local entity main +local entity walls +local entity camera +local entity change +local entity corvus +local entity player1 +local entity break + +local int sig +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 +local int sig6 +local int sig7 +local int cor +local int cor1 + +cache sound "objects/spankers.wav" +cache sound "misc/breakstone.wav" + +wheel1 = find entity with targetname "wheel1" +wheel2 = find entity with targetname "wheel2" +main = find entity with targetname "main" +walls = find entity with targetname "walls" +camera = find entity with targetname "camera" +change = find entity with targetname "change" +corvus = find entity with targetname "corvus" +player1 = get entity activator +break = find entity with targetname "break" + + +// in the begining + + move entity wheel1 by [0, 0, 40] at 2000 speed signaling sig + wait for all clearing sig + + enable cinematics + +// let's get things rolling + + copy player attributes from entity player1 to entity corvus + corvus.modelindex = corvus.count + corvus.solid = SOLID_SOLID + corvus.movetype = 4 + +//-------------------------------- + + + use entity camera + + corvus.movetype = PHYSICSTYPE_NOCLIP + + animate entity corvus performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION9_ANIMATION repeating for 100 times + + play sound "objects/cartroll.wav" for entity main + + move entity wheel1 by [0, -100, 0] at 100 speed signaling sig + move entity wheel2 by [0, -100, 0] at 100 speed signaling sig1 + move entity main by [0, -100, 0] at 100 speed signaling sig2 + move entity walls by [0, -100, 0] at 100 speed signaling sig3 + move entity corvus by [0, -100, 0] at 100 speed signaling cor + wait for all clearing sig, sig1, sig2, sig3, cor + +// -------------------------------- + + move entity wheel1 by [0, -40, -6] at 150 speed signaling sig + move entity wheel2 by [0, -40, -6] at 150 speed signaling sig1 + move entity main by [0, -40, -6] at 150 speed signaling sig2 + move entity walls by [0, -40, -6] at 150 speed signaling sig3 + move entity corvus by [0, -40, -6] at 150 speed signaling cor + + rotate entity wheel1 by [0, 0, 18] at 200 speed signaling sig4 + rotate entity wheel2 by [0, 0, 18] at 200 speed signaling sig5 + rotate entity main by [0, 0, 18] at 200 speed signaling sig6 + rotate entity walls by [0, 0, 18] at 200 speed signaling sig7 + rotate entity corvus by [0, 0, 18] at 200 speed signaling cor1 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, sig6, sig7, cor, cor1 + +// -------------------------------- + + move entity wheel1 by [0, -690, -215] at 800 speed signaling sig + move entity wheel2 by [0, -690, -215] at 800 speed signaling sig1 + move entity main by [0, -690, -215] at 800 speed signaling sig2 + move entity walls by [0, -690, -215] at 800 speed signaling sig3 + move entity corvus by [0, -690, -215] at 800 speed signaling cor + wait for all clearing sig, sig1, sig2, sig3, cor + +//--------------------------------- + + move entity wheel1 by [0, -50, 0] at 800 speed signaling sig + move entity wheel2 by [0, -50, 0] at 800 speed signaling sig1 + move entity main by [0, -50, 0] at 800 speed signaling sig2 + move entity walls by [0, -50, 0] at 800 speed signaling sig3 + move entity corvus by [0, -50, 0] at 800 speed signaling cor + + rotate entity wheel1 by [0, 0, -10] at 800 speed signaling sig4 + rotate entity wheel2 by [0, 0, -10] at 800 speed signaling sig5 + rotate entity main by [0, 0, -10] at 800 speed signaling sig6 + rotate entity walls by [0, 0, -10] at 800 speed signaling sig7 + rotate entity corvus by [0, 0, -10] at 800 speed signaling cor1 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, sig6, sig7, cor, cor1 + +//--------------------------------- + + move entity wheel1 by [0, -65, -20] at 800 speed signaling sig + move entity wheel2 by [0, -65, -20] at 800 speed signaling sig1 + move entity main by [0, -65, -20] at 800 speed signaling sig2 + move entity walls by [0, -65, -20] at 800 speed signaling sig3 + move entity corvus by [0, -65, -20] at 800 speed signaling cor + + rotate entity wheel1 by [0, 0, -8] at 800 speed signaling sig4 + rotate entity wheel2 by [0, 0, -8] at 800 speed signaling sig5 + rotate entity main by [0, 0, -8] at 800 speed signaling sig6 + rotate entity walls by [0, 0, -8] at 800 speed signaling sig7 + rotate entity corvus by [0, 0, -8] at 800 speed signaling cor1 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, sig6, sig7, cor, cor1 + +//--------------------------------- + + move entity wheel1 by [0, -140, 0] at 800 speed signaling sig + move entity wheel2 by [0, -140, 0] at 800 speed signaling sig1 + move entity main by [0, -140, 0] at 800 speed signaling sig2 + move entity walls by [0, -140, 0] at 800 speed signaling sig3 + move entity corvus by [0, -140, 0] at 800 speed signaling cor + wait for all clearing sig, sig1, sig2, sig3, cor + +//--------------------------------- + + play sound "objects/spankers.wav" for entity main + + move entity wheel1 by [0, -50, 20] at 800 speed signaling sig + move entity wheel2 by [0, -50, 20] at 800 speed signaling sig1 + move entity main by [0, -50, 20] at 800 speed signaling sig2 + move entity walls by [0, -50, 20] at 800 speed signaling sig3 + move entity corvus by [0, -50, 20] at 800 speed signaling cor + + rotate entity wheel1 by [0, 0, -25] at 800 speed signaling sig4 + rotate entity wheel2 by [0, 0, -25] at 800 speed signaling sig5 + rotate entity main by [0, 0, -25] at 800 speed signaling sig6 + rotate entity walls by [0, 0, -25] at 800 speed signaling sig7 + rotate entity corvus by [0, 0, -25] at 800 speed signaling cor1 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, sig6, sig7, cor, cor1 + +// -------------------------------- + + move entity wheel1 by [0, -50, 50] at 800 speed signaling sig + move entity wheel2 by [0, -50, 50] at 800 speed signaling sig1 + move entity main by [0, -50, 50] at 800 speed signaling sig2 + move entity walls by [0, -50, 50] at 800 speed signaling sig3 + move entity corvus by [0, -50, 50] at 800 speed signaling cor + wait for all clearing sig, sig1, sig2, sig3, cor + +//--------------------------------- + + move entity wheel1 by [0, -50, 20] at 800 speed signaling sig + move entity wheel2 by [0, -50, 20] at 800 speed signaling sig1 + move entity main by [0, -50, 20] at 800 speed signaling sig2 + move entity walls by [0, -50, 20] at 800 speed signaling sig3 + move entity corvus by [0, -50, 20] at 800 speed signaling cor + + rotate entity wheel1 by [0, 0, 15] at 800 speed signaling sig4 + rotate entity wheel2 by [0, 0, 15] at 800 speed signaling sig5 + rotate entity main by [0, 0, 15] at 800 speed signaling sig6 + rotate entity walls by [0, 0, 15] at 800 speed signaling sig7 + rotate entity corvus by [0, 0, 15] at 800 speed signaling cor1 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, sig6, sig7, cor, cor1 + +// -------------------------------- + + move entity wheel1 by [0, -150, 0] at 800 speed signaling sig + move entity wheel2 by [0, -150, 0] at 800 speed signaling sig1 + move entity main by [0, -150, 0] at 800 speed signaling sig2 + move entity walls by [0, -150, 0] at 800 speed signaling sig3 + move entity corvus by [0, -150, 0] at 800 speed signaling cor + + rotate entity wheel1 by [0, 0, 10] at 800 speed signaling sig4 + rotate entity wheel2 by [0, 0, 10] at 800 speed signaling sig5 + rotate entity main by [0, 0, 10] at 800 speed signaling sig6 + rotate entity walls by [0, 0, 10] at 800 speed signaling sig7 + rotate entity corvus by [0, 0, 10] at 800 speed signaling cor1 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, sig6, sig7, cor, cor1 + +//--------------------------------- + + move entity wheel1 by [0, -150, 0] at 800 speed signaling sig + move entity wheel2 by [0, -150, 0] at 800 speed signaling sig1 + move entity main by [0, -150, 0] at 800 speed signaling sig2 + move entity walls by [0, -150, 0] at 800 speed signaling sig3 + move entity corvus by [0, -150, 0] at 800 speed signaling cor + + rotate entity wheel1 by [0, 0, 10] at 800 speed signaling sig4 + rotate entity wheel2 by [0, 0, 10] at 800 speed signaling sig5 + rotate entity main by [0, 0, 10] at 800 speed signaling sig6 + rotate entity walls by [0, 0, 10] at 800 speed signaling sig7 + rotate entity corvus by [0, 0, 10] at 800 speed signaling cor1 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, sig6, sig7, cor, cor1 + + +// --------------------------------- + + + move entity wheel1 by [0, -50, -20] at 800 speed signaling sig + move entity wheel2 by [0, -50, -20] at 800 speed signaling sig1 + move entity main by [0, -50, -20] at 800 speed signaling sig2 + move entity walls by [0, -50, -20] at 800 speed signaling sig3 + move entity corvus by [0, -50, -20] at 800 speed signaling cor + + rotate entity wheel1 by [0, 0, 15] at 800 speed signaling sig4 + rotate entity wheel2 by [0, 0, 15] at 800 speed signaling sig5 + rotate entity main by [0, 0, 15] at 800 speed signaling sig6 + rotate entity walls by [0, 0, 15] at 800 speed signaling sig7 + rotate entity corvus by [0, 0, 15] at 800 speed signaling cor1 + wait for all clearing sig, sig1, sig2, sig3, sig4, sig5, sig6, sig7, cor, cor1 + +//---------------------------------- + + move entity wheel1 by [0, -75, -50] at 800 speed signaling sig + move entity wheel2 by [0, -75, -50] at 800 speed signaling sig1 + move entity main by [0, -75, -50] at 800 speed signaling sig2 + move entity walls by [0, -75, -50] at 800 speed signaling sig3 + move entity corvus by [0, -75, -50] at 800 speed signaling cor + wait for all clearing sig, sig1, sig2, sig3, cor + + play sound "misc/metalbreak.wav" for entity main + + use entity break + +//--------------------------------- + + move entity wheel1 by [75, 25, 15] at 400 speed signaling sig + move entity wheel2 by [75, 0, 15] at 400 speed signaling sig1 + move entity main by [0, -10, -20] at 400 speed signaling sig2 + move entity corvus by [0, -10, -20] at 400 speed signaling cor + move entity walls by [30, -100, -40] at 400 speed signaling sig3 + + + rotate entity wheel1 by [90, 0, -25] at 400 speed signaling sig4 + rotate entity wheel2 by [90, 0, -25] at 400 speed signaling sig5 + rotate entity main by [0, 0, -25] at 400 speed signaling sig6 + rotate entity corvus by [0, 0, -25] at 400 speed signaling cor1 + rotate entity walls by [0, 0, -25] at 400 speed signaling sig7 + wait for any clearing sig, sig1, sig2, sig3, sig4, sig5, sig6, sig7, cor, cor1 + + corvus.movetype = PHYSICSTYPE_PUSH + animate entity corvus performing action ACTION11_ANIMATION by moving [-20, 0, 0] + +//---------------------------------- + + move entity main by [0, -10, 0] at 200 speed signaling sig + wait for all clearing sig + + move entity main by [0, -10, 0] at 100 speed signaling sig + wait for all clearing sig + + move entity main by [0, -10, 0] at 50 speed signaling sig + wait for all clearing sig + +// ---------------------------------- + + wait 1 seconds + + disable cinematics + + player1.modelindex = 0 + player1.solid = SOLID_NOT + + use entity change + + + diff --git a/Toolkit/Designer/dsexamples/mines/pipe.ds b/Toolkit/Designer/dsexamples/mines/pipe.ds new file mode 100644 index 0000000..4ebc28c --- /dev/null +++ b/Toolkit/Designer/dsexamples/mines/pipe.ds @@ -0,0 +1,92 @@ +// the big bad falling pipe. + +#include "../common/header.ds" + +output "r:/base/ds/mines" + +local entity pipe +local entity pipepiece +local entity pipefloor +local entity act1 +local entity deact1 + +local int sig + +pipe = find entity with targetname "pipe" +pipepiece = find entity with targetname "pipepiece" +pipefloor = find entity with targetname "pipefloor" +act1 = find entity with targetname "act1" +deact1 = find entity with targetname "deact1" + +// here we go + + use entity act1 + + rotate entity pipe by [0, 0, -28] at 150 speed signaling sig + wait for all clearing sig + + use entity pipepiece + + rotate entity pipe by [0, 0, -4] at 150 speed signaling sig + wait for all clearing sig + + use entity deact1 + + use entity pipefloor + + rotate entity pipe by [0, 0, 5] at 150 speed signaling sig + wait for all clearing sig + + rotate entity pipe by [0, 0, -8] at 150 speed signaling sig + wait for all clearing sig + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/mines/scoop.ds b/Toolkit/Designer/dsexamples/mines/scoop.ds new file mode 100644 index 0000000..0b79bbd --- /dev/null +++ b/Toolkit/Designer/dsexamples/mines/scoop.ds @@ -0,0 +1,99 @@ +// the place where you put the unrefined ore. + +#include "../common/header.ds" + +output "r:/base/ds/mines" + +local entity scoop +local entity pole +local entity ore +local entity wall +local entity bcam +local entity bcam2 +local entity relay +local entity cor +local entity player1 + +local int sig +local int sig1 +local int sig2 + +scoop = find entity with targetname "scoop" +pole = find entity with targetname "pole" +ore = find entity with targetname "ore" +wall = find entity with targetname "wall" +bcam = find entity with targetname "bcam" +bcam2 = find entity with targetname "bcam2" +relay = find entity with targetname "relay" +cor = find entity with targetname "cor" +player1 = get entity activator + +// place the ore in the bucket + + enable cinematics + + copy player attributes from entity player1 to entity cor + cor.modelindex = cor.count + cor.solid = SOLID_NOT + cor.movetype = PHYSICSTYPE_NOCLIP + + + use entity bcam + + use entity relay + + ore = spawn entity with fields "classname" = "item_puzzle_ore", "origin" = [2144, -88, -500], "targetname" = "ore" + + wait 2 seconds + + ore.movetype = PHYSICSTYPE_NOCLIP + + move entity scoop by [0, 0, 24] over 1 seconds signaling sig + + move entity pole by [0, 0, 24] over 1 seconds signaling sig1 + + move entity ore by [0, 0, 8] over 1 seconds signaling sig2 + wait for all clearing sig, sig1, sig2 + + rotate entity scoop by [0, 0, -110] over 2 seconds signaling sig + + move entity ore by [0, 40, 0] over 2 seconds signaling sig1 + wait for all clearing sig, sig1 + + move entity ore by [0, 250, 0] over 4 seconds signaling sig + + rotate entity scoop by [0, 0, 110] over 2 seconds signaling sig1 + wait for all clearing sig, sig1 + + move entity scoop by [0, 0, -24] over 1 seconds signaling sig + + move entity pole by [0, 0, -24] over 1 seconds signaling sig1 + + wait for all clearing sig, sig1 + + use entity bcam + + use entity bcam2 + + wait 2 seconds + + print 60 captioned + + use entity wall + + wait 3 seconds + + player1.origin = cor.origin + player1.p_origin = cor.origin // Put player where Cinematic corvus is + set view angles of entity player1 to cor.angles + + cor.modelindex = 0 + cor.solid = SOLID_NOT + + use entity bcam2 + + disable cinematics + + + + diff --git a/Toolkit/Designer/dsexamples/silverspring/ail.ds b/Toolkit/Designer/dsexamples/silverspring/ail.ds new file mode 100644 index 0000000..0871b9c --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/ail.ds @@ -0,0 +1,17 @@ +//Lever pushes crates out of doorway at bottom of SSDocks tower + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + + +//define variables + +local entity monster + +monster = get entity activator + +// print message then exit + +print 28 centered to entity monster + +exit diff --git a/Toolkit/Designer/dsexamples/silverspring/ambush.ds b/Toolkit/Designer/dsexamples/silverspring/ambush.ds new file mode 100644 index 0000000..05cec9b --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/ambush.ds @@ -0,0 +1,43 @@ +//SSwarehouse, I've been ambushed! + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + +//define variables + +local entity fallen +local entity ouch +local entity duster +local int sig1 +local int sig2 + +fallen = find entity with targetname "fallen" +ouch = find entity with targetname "ouch" +duster = find entity with targetname "duster" + +fallen.movetype = PHYSICSTYPE_PUSH + +//crate gets pushed + +move entity fallen by [0, 24, 0] at 20 speed signaling sig1 + +wait for all clearing sig1 + +move entity fallen by [0, 16, -216] at 400 speed signaling sig1 + +rotate entity fallen by [0, 0, -90] at 400 speed signaling sig2 + +wait for all clearing sig1, sig2 + +enable trigger entity ouch + +use entity duster + +use entity fallen + +wait .5 seconds + +disable trigger entity ouch + + + diff --git a/Toolkit/Designer/dsexamples/silverspring/begin.ds b/Toolkit/Designer/dsexamples/silverspring/begin.ds new file mode 100644 index 0000000..db32bb8 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/begin.ds @@ -0,0 +1,65 @@ +//Beginning of game + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + + +//define variables + +local entity camera +local entity portal +local entity message +local entity hero +local entity player1 + +local int sig + +camera = find entity with targetname "cam1" +portal = find entity with targetname "port" +message = find entity with targetname "mess" +hero = find entity with targetname "corv" + +//Switching player + +player1 = get entity activator // Get player who set off trigger +copy player attributes from entity player1 to entity hero +hero.modelindex = hero.count // Turn on cinematic corvus +hero.solid = SOLID_SOLID // Make him block + + +//Where is everyone? + +enable cinematics +disable ambient sounds +use entity camera +play sound "items/teleport2.wav" for entity portal +animate entity hero performing action WALK2_ANIMATION by moving [64, 0, 0] signaling sig + wait for all clearing sig +animate entity hero performing action ACTION6_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig +animate entity hero performing action ACTION7_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig +print 27 captioned +animate entity hero performing action ACTION7_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig +use entity portal +wait .5 seconds +animate entity hero performing action ACTION8_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig +animate entity hero performing action IDLE1_ANIMATION repeating for 10 times + +wait 1 seconds +use entity camera + +//Switching back +player1.origin = hero.origin // Put player where Cinematic corvus is +player1.p_origin = hero.origin // Put player where Cinematic corvus is +set view angles of entity player1 to hero.angles + +hero.modelindex = 0 // Turn off the cinematic corvus model +hero.solid = SOLID_NOT // Make him not solid + +disable cinematics + + +enable ambient sounds diff --git a/Toolkit/Designer/dsexamples/silverspring/bridge.ds b/Toolkit/Designer/dsexamples/silverspring/bridge.ds new file mode 100644 index 0000000..186dae1 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/bridge.ds @@ -0,0 +1,20 @@ +// This is the bridge in the Palace that collapses when Corvus jumps on it. + +output "r:/base/ds/silverspring" + +local entity bridge +local int sig + +bridge = find entity with targetname "bridge" + +rotate entity bridge by [0, 0, 5] at 800 speed signaling sig +wait for all clearing sig + +rotate entity bridge by [0, 0, -2] at 800 speed signaling sig +wait for all clearing sig + +rotate entity bridge by [0, 0, 7] over 0.5 seconds signaling sig +wait for all clearing sig + +rotate entity bridge by [0, 0, 34] at 250 speed signaling sig +wait for all clearing sig \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/cart.ds b/Toolkit/Designer/dsexamples/silverspring/cart.ds new file mode 100644 index 0000000..c7b8135 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/cart.ds @@ -0,0 +1,44 @@ +//SSwarehouse, an elf pushing a cart + +#include "../common/header.ds" + +output "R:base/ds/silverspring" + +local entity elf1 +local entity elf2 +local entity barrel +local entity cart + +local int sig + +elf1.yaw_speed = 3 + +elf1 = find entity with targetname "elf1" +elf2 = find entity with targetname "elf2" +barrel = find entity with targetname "barrel" +cart = find entity with targetname "cart" + +//Pushing the cart +//elf1.takedamage = DAMAGE_NO +//elf2.takedamage = DAMAGE_NO + +animate entity elf2 performing action WALK1_ANIMATION by moving [72, 0, 0] signaling sig + +cart.movetype = PHYSICSTYPE_NOCLIP +move entity cart by [64, 0, 0] at 30 speed signaling sig + +animate entity elf1 performing action WALK1_ANIMATION by moving [80, 0, 0] signaling sig + +barrel.movetype = PHYSICSTYPE_NOCLIP +move entity barrel by [72, 0, 0] at 30 speed signaling sig +wait for all clearing sig + +cart.movetype = PHYSICSTYPE_PUSH +barrel.movetype = PHYSICSTYPE_PUSH + +//elf1.takedamage = DAMAGE_YES +//elf2.takedamage = DAMAGE_YES + +animate entity elf1 performing action THINKAGAIN_ANIMATION +animate entity elf2 performing action THINKAGAIN_ANIMATION + diff --git a/Toolkit/Designer/dsexamples/silverspring/crane.ds b/Toolkit/Designer/dsexamples/silverspring/crane.ds new file mode 100644 index 0000000..a83b32b --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/crane.ds @@ -0,0 +1,71 @@ +//SSwarehouse, Elf breaking up crane + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + +//define variables + +local entity craneright +local entity craneleft +local entity cranerope +local entity cranebox +local entity dam +local entity e2 +local entity e1 +local int sig +local int sig1 +local int sig2 + +e2 = find entity with targetname "bybutton" +e1 = find entity with targetname "oncrane" +craneright = find entity with targetname "armright" +craneleft = find entity with targetname "armleft" +cranerope = find entity with targetname "rope" +cranebox = find entity with targetname "box" +dam = find entity with targetname "dam" + +craneleft.movetype = PHYSICSTYPE_NOCLIP +craneright.movetype = PHYSICSTYPE_NOCLIP + +//e1.takedamage = DAMAGE_NO +//e2.takedamage = DAMAGE_NO + +//Cut rope and drop crane + +animate entity e2 performing action ATTACK2_ANIMATION repeating for 2 times signaling sig +play sound "elves/diep.wav" for entity e2 +animate entity e1 performing action ATTACK2_ANIMATION repeating for 2 times signaling sig1 +wait for all clearing sig, sig1 + +use entity cranerope + +wait .2 seconds +enable trigger entity dam +move entity cranebox by [0, 0, -88] at 450 speed signaling sig +play sound "misc/metalbreak.wav" for entity craneright on channel 10 +move entity craneright by [0, 0, -116] at 350 speed signaling sig1 +play sound "misc/metalbreak.wav" for entity craneleft on channel 10 +move entity craneleft by [0, 0, -116] at 350 speed signaling sig2 +wait for all clearing sig, sig1, sig2 + +use entity cranebox +disable trigger entity dam + +rotate entity craneright to [90, 0, 0] at 300 speed signaling sig1 +rotate entity craneleft to [-90, -10, 0] at 300 speed signaling sig +wait for all clearing sig, sig1 + +use entity craneleft +use entity craneright + +animate entity e2 performing action IDLE1_ANIMATION by turning [90, 0, 0] repeating for 1 times signaling sig +animate entity e1 performing action IDLE1_ANIMATION by turning [-135, 0, 0] repeating for 1 times signaling sig1 + +wait for all clearing sig, sig1 + +//e1.takedamage = DAMAGE_YES +//e2.takedamage = DAMAGE_YES + +animate entity e1 performing action THINKAGAIN_ANIMATION +animate entity e2 performing action THINKAGAIN_ANIMATION +craneright.movetype = PHYSICSTYPE_NONE \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/crate.ds b/Toolkit/Designer/dsexamples/silverspring/crate.ds new file mode 100644 index 0000000..dd845b9 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/crate.ds @@ -0,0 +1,25 @@ +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +parameter entity crate + +local int sgnl +crate.movetype = PHYSICSTYPE_PUSH +rotate entity crate by [0,0,90] at 512 speed signaling sgnl +wait for any clearing sgnl + +move entity crate by [0,0,-8] at 256 speed signaling sgnl +wait for all clearing sgnl + +play sound "misc/brkwood2.wav" for entity crate + +move entity crate by [0,0,12] at 256 speed signaling sgnl +wait for all clearing sgnl + +move entity crate by [0,0,-11] at 256 speed signaling sgnl +wait for all clearing sgnl + +play sound "misc/brkwood2.wav" for entity crate + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/docklever.ds b/Toolkit/Designer/dsexamples/silverspring/docklever.ds new file mode 100644 index 0000000..329b6f0 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/docklever.ds @@ -0,0 +1,50 @@ +//Lever pushes crates out of doorway at bottom of SSDocks tower + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + +//define variables + +local entity lever1 +local entity lever2 +local entity jumper +local entity slammer +local int sig1 +local int sig2 +local int sig3 + +lever1 = find entity with targetname "bar1" +lever2 = find entity with targetname "bar2" +jumper = find entity with targetname "jumper" +slammer = find entity with targetname "slammer" + +//lever lifts crate and pushes it out of way + +jumper.takedamage = DAMAGE_NO +slammer.takedamage = DAMAGE_NO + +animate entity slammer performing action IDLE3_ANIMATION repeating for 10 times +animate entity jumper performing action WALK1_ANIMATION by moving [64, 0, 0] +wait 1.5 seconds + +slammer.movetype = PHYSICSTYPE_NOCLIP +rotate entity lever2 by [18, 0, 0] at 400 speed signaling sig1 +rotate entity lever1 by [18, 0, 0] at 400 speed signaling sig2 +move entity slammer by [-80, 0, 160] at 600 speed signaling sig3 +wait for any clearing sig1, sig2, sig3 + +slammer.movetype = PHYSICSTYPE_STEP +play sound "objects/planksnap.wav" for entity lever1 on channel 10 +animate entity slammer performing action GIB1_ANIMATION repeating for 1 times +rotate entity lever2 by [18, 0, 0] at 400 speed signaling sig1 +move entity lever2 by [-2, 0, 2] at 400 speed signaling sig2 +wait for all clearing sig1, sig2 +animate entity jumper performing action WALK1_ANIMATION by moving [64, 0, 0] signaling sig2 +rotate entity lever1 by [-19, 0, 0] at 200 speed signaling sig1 +wait for all clearing sig1, sig2 + +jumper.takedamage = DAMAGE_YES + +animate entity jumper performing action THINKAGAIN_ANIMATION + + diff --git a/Toolkit/Designer/dsexamples/silverspring/docklever2.ds b/Toolkit/Designer/dsexamples/silverspring/docklever2.ds new file mode 100644 index 0000000..4a030d1 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/docklever2.ds @@ -0,0 +1,55 @@ +//Lever pushes crates out of doorway at bottom of SSDocks tower + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + +//define variables + +local entity lever1 +local entity lever2 +local entity jumper +local entity slammer +local int sig1 +local int sig2 +local int sig3 + +lever1 = find entity with targetname "bar1" +lever2 = find entity with targetname "bar2" +jumper = find entity with targetname "jumper" +slammer = find entity with targetname "slammer" + +//lever lifts crate and pushes it out of way + +//jumper.takedamage = DAMAGE_NO +//slammer.takedamage = DAMAGE_NO +lever1.movetype = PHYSICSTYPE_PUSH +lever2.movetype = PHYSICSTYPE_PUSH +animate entity slammer performing action IDLE3_ANIMATION repeating for 10 times +animate entity jumper performing action WALK1_ANIMATION by moving [64, 0, 0] +wait 1.5 seconds + +slammer.movetype = PHYSICSTYPE_NOCLIP +rotate entity lever2 by [18, 0, 0] at 400 speed signaling sig1 +rotate entity lever1 by [20, 0, 0] at 400 speed signaling sig2 +move entity slammer by [-80, 0, 160] at 600 speed signaling sig3 +wait for any clearing sig1, sig2, sig3 +use entity lever1 +slammer.movetype = PHYSICSTYPE_STEP +play sound "objects/planksnap.wav" for entity lever1 on channel 10 +animate entity slammer performing action GIB1_ANIMATION repeating for 1 times +rotate entity lever2 by [18, 0, 0] at 400 speed signaling sig1 +move entity lever2 by [-2, 0, 2] at 400 speed signaling sig2 +wait for all clearing sig1, sig2 +animate entity jumper performing action WALK1_ANIMATION by moving [64, 0, 0] signaling sig2 +wait for any clearing sig2 +use entity lever2 + +animate entity jumper performing action IDLE1_ANIMATION signaling sig2 +wait for any clearing sig2 +//jumper.takedamage = DAMAGE_YES + +animate entity jumper performing action THINKAGAIN_ANIMATION +wait 1 seconds +exit + + diff --git a/Toolkit/Designer/dsexamples/silverspring/dockstair.ds b/Toolkit/Designer/dsexamples/silverspring/dockstair.ds new file mode 100644 index 0000000..ccb5978 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/dockstair.ds @@ -0,0 +1,99 @@ +//Plague Elves break stair in Inn + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + +//declare variables +local entity elf1 +local entity elf2 +local entity base +local entity break1 +local entity camera +local entity set1 +local entity set2 +local entity set3 +local entity set4 +local entity set5 +local entity set6 + +local int sig1 +local int sig2 +local int sig3 +local int sig4 +local int sig5 + +//define variables +elf1 = find entity with targetname "stairelf1" +elf2 = find entity with targetname "stairelf2" +base = find entity with targetname "stairbase" +break1 = find entity with targetname "breakstair1" +camera = find entity with targetname "staircam" +set1 = find entity with targetname "stairset1" +set2 = find entity with targetname "stairset2" +set3 = find entity with targetname "stairset3" +set4 = find entity with targetname "stairset4" +set5 = find entity with targetname "stairset5" +set6 = find entity with targetname "stairset6" + +//Elves break stair and it crashes down + +elf1.takedamage = DAMAGE_NO +elf2.takedamage = DAMAGE_NO + +animate entity elf1 performing action ATTACK4_ANIMATION repeating for 10 times +animate entity elf2 performing action ATTACK3_ANIMATION repeating for 10 times +set1.movetype = PHYSICSTYPE_NOCLIP +set2.movetype = PHYSICSTYPE_NOCLIP +set3.movetype = PHYSICSTYPE_NOCLIP +set4.movetype = PHYSICSTYPE_NOCLIP +set5.movetype = PHYSICSTYPE_NOCLIP +set6.movetype = PHYSICSTYPE_NOCLIP +use entity camera +wait 2.0 seconds + +use entity base +use entity break1 +play sound "objects/planksnap.wav" for entity set3 on channel 10 +rotate entity set3 by [-15, 0, 0] at 90 speed signaling sig1 +wait for all clearing sig1 +move entity set3 by [0, 0, -104] at 400 speed signaling sig1 +rotate entity set3 by [15, 0, 0] at 90 speed signaling sig2 +wait for all clearing sig1, sig2 +set3.movetype = PHYSICSTYPE_PUSH + +use entity set6 +play sound "objects/planksnap.wav" for entity set2 on channel 10 +rotate entity set2 by [25, 0, 0] at 90 speed signaling sig1 +move entity set2 by [0, 0, -32] at 300 speed signaling sig2 +play sound "objects/planksnap.wav" for entity set1 on channel 10 +rotate entity set1 by [-27, -15, 0] at 300 speed signaling sig3 +move entity set1 by [0, 0, -8] at 300 speed signaling sig4 +play sound "objects/planksnap.wav" for entity set4 on channel 10 +move entity set4 by [-16, 10, -80] at 300 speed signaling sig5 +wait for all clearing sig1, sig2, sig3, sig4, sig5 +use entity set1 +use entity set2 +use entity set4 + +set5.angle_velocity = [0, 200, 0] +play sound "objects/planksnap.wav" for entity set5 on channel 10 +rotate entity set5 by [0, 30, 0] at 30 speed signaling sig1 +move entity set5 by [0, 0, -200] at 300 speed signaling sig2 +set5.movetype = PHYSICSTYPE_PUSH +set5.angle_velocity = [0, 0, 0] +wait for any clearing sig1, sig2 + +wait 1.0 seconds +use entity camera +animate entity elf1 performing action IDLE1_ANIMATION by turning [180, 0, 0] repeating for 3 times signaling sig1 +animate entity elf2 performing action IDLE1_ANIMATION repeating for 2 times signaling sig2 +wait for all clearing sig1, sig2 + +elf1.takedamage = DAMAGE_YES +elf2.takedamage = DAMAGE_YES + +animate entity elf1 performing action THINKAGAIN_ANIMATION +animate entity elf2 performing action THINKAGAIN_ANIMATION +wait 1 seconds +exit + diff --git a/Toolkit/Designer/dsexamples/silverspring/dranor.ds b/Toolkit/Designer/dsexamples/silverspring/dranor.ds new file mode 100644 index 0000000..bda5c8b --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/dranor.ds @@ -0,0 +1,282 @@ +// The Dranor Cinematic. Starring, Gina Garren as the hero, Corvus and +// Kim Lathrop as the old fart, Dranor. With guest appearances by Mike Gummelt +// and Josh Weier as the evil Plague Speader Twins. +// ....and all your troubles go down the drain. + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +local entity camera1 +local entity camera2 +local entity camera3 +local entity camera4 +local entity camera5 +local entity camera6 +local entity camera7 +local entity break1 +local entity chair +local entity dranor +local entity corvus +local entity player1 +local entity give + +local int sig +local int sig1 + +field vector "velocity" +field vector "movetype" + +cache sound "cinematics/dranor/19-316.wav" +cache sound "cinematics/dranor/20-314.wav" +cache sound "cinematics/dranor/21-319.wav" +cache sound "cinematics/dranor/22-314.wav" +cache sound "cinematics/dranor/23-315.wav" +cache sound "cinematics/dranor/24-316.wav" +cache sound "cinematics/dranor/25-316.wav" +cache sound "cinematics/dranor/26-319.wav" +cache sound "cinematics/dranor/27-315.wav" +cache sound "cinematics/dranor/28-317.wav" +cache sound "cinematics/dranor/29-317.wav" +cache sound "cinematics/dranor/30-314.wav" +cache sound "cinematics/dranor/31-314.wav" +cache sound "cinematics/dranor/32-317.wav" + +camera1 = find entity with targetname "camera1" +camera2 = find entity with targetname "camera2" +camera3 = find entity with targetname "camera3" +camera4 = find entity with targetname "camera4" +camera5 = find entity with targetname "camera5" +camera6 = find entity with targetname "camera6" +camera7 = find entity with targetname "camera7" +break1 = find entity with targetname "break1" +chair = find entity with targetname "chair" +dranor = find entity with targetname "dranor" +corvus = find entity with targetname "corvus" +give = find entity with targetname "give" +player1 = get entity activator + +corvus.yaw_speed = 5 + + copy player attributes from entity player1 to entity corvus + corvus.modelindex = corvus.count + corvus.solid = SOLID_SOLID + corvus.movetype = 4 + + dranor.movetype = 4 + + enable cinematics + +// Corvus walks in and notices Dranor + + use entity camera1 + print 138 captioned + play sound "cinematics/dranor/19-316.wav" for entity dranor + + animate entity dranor performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action IDLE2_ANIMATION + print 139 captioned + play sound "cinematics/dranor/20-314.wav" for entity corvus + + animate entity corvus performing action ACTION1_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE1_ANIMATION + print 140 captioned + play sound "cinematics/dranor/21-319.wav" for entity dranor + + animate entity dranor performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action IDLE3_ANIMATION repeating for 6 times + + animate entity corvus performing action WALK2_ANIMATION by moving [120, 0, 0] by turning [15, 0, 0] signaling sig + wait for all clearing sig + + use entity camera1 + +// Corvus walks up to Dranor + + use entity camera2 + print 141 captioned + play sound "cinematics/dranor/22-314.wav" for entity corvus + + animate entity corvus performing action ACTION2_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE3_ANIMATION repeating for 5 times + print 142 captioned + play sound "cinematics/dranor/23-315.wav" for entity dranor + + animate entity dranor performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + print 143 captioned + play sound "cinematics/dranor/24-316.wav" for entity corvus + + animate entity dranor performing action IDLE3_ANIMATION + + animate entity corvus performing action ACTION3_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE3_ANIMATION repeating for 10 times + + use entity camera2 + +// Dranor's close-up speech. + + use entity camera3 + print 144 captioned + play sound "cinematics/dranor/25-316.wav" for entity dranor + + animate entity dranor performing action ACTION7_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action ACTION6_ANIMATION signaling sig + wait for all clearing sig + wait .5 seconds + print 145 captioned + play sound "cinematics/dranor/26-319.wav" for entity dranor + + animate entity dranor performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action ACTION9_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action IDLE3_ANIMATION repeating for 2 times + + use entity camera3 + +// Side shot as Corvus speaks + + use entity camera7 + print 146 captioned + play sound "cinematics/dranor/27-315.wav" for entity corvus + + animate entity corvus performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE3_ANIMATION repeating for 14 times + + use entity camera7 + +// Shot behind Corvus looking at Dranor has he gives his long speech. + + use entity camera4 + print 147 captioned + play sound "cinematics/dranor/28-317.wav" for entity dranor + + animate entity dranor performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + print 148 captioned + animate entity dranor performing action ACTION10_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action IDLE3_ANIMATION signaling sig + wait for all clearing sig + print 149 captioned + play sound "cinematics/dranor/29-317.wav" for entity dranor + + animate entity dranor performing action ACTION8_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + print 150 captioned + animate entity dranor performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action ACTION11_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action IDLE3_ANIMATION signaling sig + wait for all clearing sig + + use entity camera4 + +// Shot behind Dranor looking at Corvus + + use entity camera5 + print 151 captioned + play sound "cinematics/dranor/30-314.wav" for entity corvus + + animate entity corvus performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity corvus performing action IDLE3_ANIMATION repeating for 5 times + + use entity camera5 + +// Medium shot of both charators. + + use entity camera6 + print 152 captioned + play sound "cinematics/dranor/31-314.wav" for entity dranor + + animate entity dranor performing action ACTION4_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action ACTION11_ANIMATION signaling sig + wait for all clearing sig + + animate entity dranor performing action ACTION5_ANIMATION signaling sig + wait for all clearing sig + play sound "misc/breakstone.wav" for entity break1 on channel 10 + use entity break1 + + play sound "cinematics/dranor/32-317.wav" for entity dranor + + animate entity dranor performing action DEATH1_ANIMATION + + chair. movetype = PHYSICSTYPE_PUSH + chair.velocity = [0, 200, 30] + + rotate entity chair by [0, 0, 95] at 400 speed signaling sig + wait for all clearing sig + + move entity chair by [0, 20, -25] at 400 speed signaling sig + wait for all clearing sig + + chair.velocity = [0, 0, 0] + + wait 3 seconds + + use entity give + + disable cinematics + + player1.origin = corvus.origin + player1.p_origin = corvus.origin + set view angles of entity player1 to corvus.angles + corvus.modelindex = 0 + corvus.solid = SOLID_NOT + + dranor.solid = SOLID_NOT + + use entity camera6 + + + + + + + + + + + + \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/elfbangers.ds b/Toolkit/Designer/dsexamples/silverspring/elfbangers.ds new file mode 100644 index 0000000..3437cd5 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/elfbangers.ds @@ -0,0 +1,36 @@ +//Starts elves banging heads in courtyard + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + +//define variables + +local entity bang1 +local entity bang2 + +local int e1 +local int e2 + +bang1 = find entity with targetname "bangelf1" +bang2 = find entity with targetname "bangelf2" + + + + +//Elves bang their heads +label looper + + animate entity bang1 performing action IDLE1_ANIMATION repeating for 1 times signaling e1 + animate entity bang2 performing action IDLE1_ANIMATION repeating for 1 times signaling e2 + +wait for any clearing e1, e2 + + if bang1 = -1 + exit + endif + + if bang2 = -1 + exit + endif +wait 2.0 seconds +goto looper \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/elfonstick.ds b/Toolkit/Designer/dsexamples/silverspring/elfonstick.ds new file mode 100644 index 0000000..ef28020 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/elfonstick.ds @@ -0,0 +1,24 @@ +// the elf turning on a stick in the docks + + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +local entity ralf + +local int sig + +field vector "movetype" +field vector "angle_velocity" + +ralf = find entity with targetname "ralf" + +// lets get cooking + + ralf.movetype = PHYSICSTYPE_PUSH + ralf.angles = [0, 0, 90] + ralf.angle_velocity = [50, 0, 0] + +// rotate entity ralf by [0, 360, 0] over 10 seconds signaling sig +// wait for all clearing sig \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/endlevel.ds b/Toolkit/Designer/dsexamples/silverspring/endlevel.ds new file mode 100644 index 0000000..66d8825 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/endlevel.ds @@ -0,0 +1,36 @@ +//Level change, push crate + +#include "../common/header.ds" + +output "R:base/ds/silverspring" + +//Define variables + +local entity box +local entity boards +local entity cam +local int sig + +box = find entity with targetname "b1" +boards = find entity with targetname "b2" +cam = find entity with targetname "c1" + +//Pushing crate over edge + + use entity cam + + rotate entity box to [-30, 0, 0] at 250 speed signaling sig + wait for all clearing sig + + //move entity box by [0, 0, -272] at 500 speed signaling sig + wait for all clearing sig + + rotate entity box to [-60, 0, 0] at 250 speed signaling sig + + use entity boards + +exit + + + + \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/jump1.ds b/Toolkit/Designer/dsexamples/silverspring/jump1.ds new file mode 100644 index 0000000..7d83a22 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/jump1.ds @@ -0,0 +1,23 @@ +//Lever pushes crates out of doorway at bottom of SSDocks tower + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + + +//define variables + +local entity trigs +global int jumpyboy + +trigs = find entity with targetname "jump1" + +// print message then exit + +if jumpyboy != 1 + jumpyboy = 1 + print 77 +endif + +disable trigger entity trigs +exit + diff --git a/Toolkit/Designer/dsexamples/silverspring/lust.ds b/Toolkit/Designer/dsexamples/silverspring/lust.ds new file mode 100644 index 0000000..d7e56fa --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/lust.ds @@ -0,0 +1,18 @@ +//Lever pushes crates out of doorway at bottom of SSDocks tower + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + + +//define variables + +global int blood + +// print message then exit + +blood += 1 +if blood = 4 + print 31 + exit +endif + diff --git a/Toolkit/Designer/dsexamples/silverspring/magic.ds b/Toolkit/Designer/dsexamples/silverspring/magic.ds new file mode 100644 index 0000000..4b27919 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/magic.ds @@ -0,0 +1,34 @@ +// spinning color blocks + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +local entity spin1 + +local int sig1 +local int sig2 + +spin1 = find entity with targetname "spin1" + +spin1.movetype = PHYSICSTYPE_NOCLIP +spin1.solid = SOLID_NOT +label hi +rotate entity spin1 by [720, 720, 720] at 800 speed +move entity spin1 by [0, 2, -6] at 300 speed signaling sig1 +wait for all clearing sig1 +move entity spin1 by [0, 6, -2] at 300 speed signaling sig1 +wait for all clearing sig1 +move entity spin1 by [0, 6, 2] at 300 speed signaling sig1 +wait for all clearing sig1 +move entity spin1 by [0, 2, 6] at 300 speed signaling sig1 +wait for all clearing sig1 +move entity spin1 by [0, -2, 6] at 300 speed signaling sig1 +wait for all clearing sig1 +move entity spin1 by [0, -6, 2] at 300 speed signaling sig1 +wait for all clearing sig1 +move entity spin1 by [0, -6, -2] at 300 speed signaling sig1 +wait for all clearing sig1 +move entity spin1 by [0, -2, -6] at 300 speed signaling sig1 +wait for all clearing sig1 +goto hi \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/magic2.ds b/Toolkit/Designer/dsexamples/silverspring/magic2.ds new file mode 100644 index 0000000..a0e683e --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/magic2.ds @@ -0,0 +1,36 @@ +// spinning color blocks + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +local entity rock1 +local entity player1 + +local int sig3 +local int sig4 + +rock1 = find entity with targetname "rock1" +player1 = get entity activator + +rock1.movetype = PHYSICSTYPE_NOCLIP +rock1.solid = SOLID_NOT +label bye +rotate entity rock1 by [720, 720, 720] at 800 speed +move entity rock1 by [2, -6, 6] at 300 speed signaling sig3 +wait for any clearing sig3 +move entity rock1 by [6, -2, 2] at 300 speed signaling sig3 +wait for any clearing sig3 +move entity rock1 by [6, -2, -2] at 300 speed signaling sig3 +wait for any clearing sig3 +move entity rock1 by [2, -6, -6] at 300 speed signaling sig3 +wait for any clearing sig3 +move entity rock1 by [-2, 6, -6] at 300 speed signaling sig3 +wait for any clearing sig3 +move entity rock1 by [-6, 2, -2] at 300 speed signaling sig3 +wait for any clearing sig3 +move entity rock1 by [-6, 2, 2] at 300 speed signaling sig3 +wait for any clearing sig3 +move entity rock1 by [-2, 6, 6] at 300 speed signaling sig3 +wait for all clearing sig3 +goto bye \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/magic3.ds b/Toolkit/Designer/dsexamples/silverspring/magic3.ds new file mode 100644 index 0000000..6bd85b8 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/magic3.ds @@ -0,0 +1,35 @@ +// spinning color blocks + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +local entity spin3 + +local int sig5 +local int sig6 + +spin3 = find entity with targetname "spin3" + +wait .5 seconds +spin3.movetype = PHYSICSTYPE_NOCLIP +spin3.solid = SOLID_NOT +label hi +rotate entity spin3 by [720, 720, 720] at 800 speed +move entity spin3 by [-2, -6, -6] at 300 speed signaling sig5 +wait for all clearing sig5 +move entity spin3 by [-6, -2, -2] at 300 speed signaling sig5 +wait for all clearing sig5 +move entity spin3 by [-6, -2, 2] at 300 speed signaling sig5 +wait for all clearing sig5 +move entity spin3 by [-2, -6, 6] at 300 speed signaling sig5 +wait for all clearing sig5 +move entity spin3 by [2, 6, 6] at 300 speed signaling sig5 +wait for all clearing sig5 +move entity spin3 by [6, 2, 2] at 3000speed signaling sig5 +wait for all clearing sig5 +move entity spin3 by [6, 2, -2] at 300 speed signaling sig5 +wait for all clearing sig5 +move entity spin3 by [2, 6, -6] at 300 speed signaling sig5 +wait for all clearing sig5 +goto hi \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/rollingbox.ds b/Toolkit/Designer/dsexamples/silverspring/rollingbox.ds new file mode 100644 index 0000000..f09ee4e --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/rollingbox.ds @@ -0,0 +1,77 @@ +//Thing drops, box rolls, wall blows up. + + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +//define variables + +local entity crate +local entity cam +local entity targ +local entity plat +local entity door +local entity ropes +local entity gono +local int sig +local int sig2 + +field vector "velocity" + +plat = find entity with targetname "plat" +crate = find entity with targetname "broke" +cam = find entity with targetname "platcam" +targ = find entity with targetname "camtarg" +door = find entity with targetname "breakdoor" +ropes = find entity with targetname "whousedoor" +gono = find entity with targetname "nogo" + +crate.movetype = PHYSICSTYPE_PUSH +targ.movetype = PHYSICSTYPE_PUSH + +//Drop box and slide + +use entity cam +wait 0.5 seconds +use entity ropes +wait 0.1 seconds + +rotate entity plat by [0, 0, -40] at 150 speed +move entity crate by [0, 0, -2] at 150 speed signaling sig +move entity targ by [0, 0, -2] at 150 speed signaling sig2 +wait for all clearing sig, sig2 + +play sound "doors/objectdrop.wav" for entity crate + +rotate entity crate by [0, 0, -40] at 200 speed signaling sig +wait for all clearing sig + +move entity crate by [0, 90, -130] at 250 speed signaling sig +move entity targ by [0, 124, -110] at 250 speed signaling sig2 +wait for all clearing sig, sig2 + +crate.velocity = [0, 380, 0] + +rotate entity crate by [0, 30, -20] at 250 speed signaling sig +wait for all clearing sig + +move entity crate by [0, 20, -10] at 300 speed signaling sig +move entity targ by [0, 20, -10] at 300 speed signaling sig2 +wait for all clearing sig, sig2 + +crate.velocity = [0, 500, 200] + +rotate entity crate by [0, 0, -140] at 150 speed + +use entity door +wait 0.1 seconds +use entity crate +wait 1 seconds +use entity cam +disable trigger entity gono + + + + + diff --git a/Toolkit/Designer/dsexamples/silverspring/runningelf.ds b/Toolkit/Designer/dsexamples/silverspring/runningelf.ds new file mode 100644 index 0000000..c8948f0 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/runningelf.ds @@ -0,0 +1,70 @@ +//SSwarehouse level Scared running elf! + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +parameter entity wus +parameter entity bully1 +parameter entity bully2 + +local int sig +local int sig1 +local int sig2 + +bully1.yaw_speed = 8 +bully2.yaw_speed = 8 + +//Chief Running Elf + +//wus.takedamage = DAMAGE_NO +//bully1.takedamage = DAMAGE_NO +//bully2.takedamage = DAMAGE_NO + +animate entity wus performing action RUN1_ANIMATION by moving [700, 0, 0] + +play sound "ambient/scream2.wav" at attenuation 0 for entity wus + +wait 1 seconds + +//two elves chase + +animate entity bully1 performing action RUN1_ANIMATION by moving [765, 0, 0] + +animate entity bully2 performing action RUN1_ANIMATION by moving [832, 0, 0] signaling sig +wait for all clearing sig + +animate entity bully1 performing action ATTACK3_ANIMATION repeating for 4 times + +play sound "monsters/plagueElf/hookhit.wav" for entity bully1 + +animate entity bully2 performing action ATTACK2_ANIMATION repeating for 4 times signaling sig + +play sound "monsters/plagueElf/hamhit.wav" for entity bully2 + +animate entity wus performing action PAIN1_ANIMATION by turning [180, 0, 0] repeating for 2 times signaling sig1 + +play sound "monsters/plagueElf/pain1.wav" for entity wus +wait for all clearing sig, sig1 + +animate entity wus performing action DEATH1_ANIMATION signaling sig + +animate entity bully1 performing action IDLE1_ANIMATION by turning [180, 0, 0] repeating for 1 times signaling sig1 + +animate entity bully2 performing action IDLE1_ANIMATION by turning [180, 0, 0] repeating for 1 times signaling sig2 + +play sound "monsters/plagueElf/death1.wav" +wait for all clearing sig, sig1, sig2 + +animate entity wus performing action GIB1_ANIMATION + +//bully1.takedamage = DAMAGE_YES +//bully2.takedamage = DAMAGE_YES + +animate entity bully1 performing action THINKAGAIN_ANIMATION signaling sig1 + +animate entity bully2 performing action THINKAGAIN_ANIMATION signaling sig2 + +wait for all clearing sig1, sig2 + +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/scroll.ds b/Toolkit/Designer/dsexamples/silverspring/scroll.ds new file mode 100644 index 0000000..c926bd9 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/scroll.ds @@ -0,0 +1,44 @@ +// This is one of the secret doors that leads into +// the area behind the scroll cases in the Palace level. + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +parameter entity parm1 +parameter entity parm2 +parameter vector parm3 + +local int sig + +label beginning + +play sound "doors/slide2.wav" for entity parm1 on channel 10 +move entity parm1 by parm3 over 1 seconds signaling sig +wait for all clearing sig +wait 0.5 seconds + +play sound "doors/slide2.wav" for entity parm2 on channel 10 +move entity parm2 by [0, 0, 64] over 1 seconds signaling sig +wait for all clearing sig +wait 0.5 seconds + +wait 4 seconds + +play sound "doors/slide2.wav" for entity parm2 on channel 10 +move entity parm2 by [0, 0, -64] over 1 seconds signaling sig +wait for all clearing sig +wait 0.5 seconds + +parm3 *=-1 + +play sound "doors/slide2.wav" for entity parm1 on channel 10 +move entity parm1 by parm3 over 1 seconds signaling sig +wait for all clearing sig +wait 0.5 seconds + +parm3 *=-1 + +suspend + +goto beginning \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/shriner.ds b/Toolkit/Designer/dsexamples/silverspring/shriner.ds new file mode 100644 index 0000000..d6efc70 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/shriner.ds @@ -0,0 +1,18 @@ +//Lever pushes crates out of doorway at bottom of SSDocks tower + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + + +//define variables + +global int firstshrine + +// print message then exit + +if firstshrine != 66 + print 73 + firstshrine = 66 +endif +exit + diff --git a/Toolkit/Designer/dsexamples/silverspring/smallcrate.ds b/Toolkit/Designer/dsexamples/silverspring/smallcrate.ds new file mode 100644 index 0000000..83140ad --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/smallcrate.ds @@ -0,0 +1,32 @@ +output "r:/base/ds/silverspring" + +#include "../common/header.ds" + +parameter entity smallcrate + +local int sgnl +local int sgnl2 + +smallcrate.movetype = PHYSICSTYPE_PUSH +smallcrate.angle_velocity = [0,0,94] +move entity smallcrate by [0,-80,-24] at 512 speed signaling sgnl +wait for all clearing sgnl + +smallcrate.angle_velocity = [0,0,94] +move entity smallcrate by [0,-32,-32] at 512 speed signaling sgnl +wait for all clearing sgnl + +smallcrate.angle_velocity = [0,0,190] +move entity smallcrate by [0,-16,-48] at 512 speed signaling sgnl +wait for all clearing sgnl + +rotate entity smallcrate by [0,0,135] at 640 speed signaling sgnl +move entity smallcrate by [0,-4,-24] at 448 speed signaling sgnl2 +wait for any clearing sgnl, sgnl2 + +play sound "misc/brkwood2.wav" at volume 1 +smallcrate.angle_velocity = [0,0,0] + +smallcrate.movetype = PHYSICSTYPE_PUSH +use entity smallcrate +exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/spike.ds b/Toolkit/Designer/dsexamples/silverspring/spike.ds new file mode 100644 index 0000000..0be73f5 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/spike.ds @@ -0,0 +1,61 @@ +//SSwarehouse, Spiky thing swings + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + +//define variables + +local entity spiky +local entity richard + +local int sig1 + +spiky = find entity with targetname "spiky" +richard = find entity with targetname "richard" +spiky.movetype = PHYSICSTYPE_PUSH +//spike goes up + +rotate entity spiky by [0, 0, -60] at 200 speed signaling sig1 + +wait for all clearing sig1 + +suspend + +//...and spike comes down +enable trigger entity richard + +play sound "doors/creak4.wav" for entity spiky on channel 10 + +rotate entity spiky by [0, 0, 90] at 225 speed signaling sig1 + +wait for all clearing sig1 + +rotate entity spiky by [0, 0, -50] at 200 speed signaling sig1 + +wait for all clearing sig1 + +play sound "doors/creak4.wav" for entity spiky on channel 10 + +rotate entity spiky by [0, 0, 40] at 175 speed signaling sig1 + +wait for all clearing sig1 + +rotate entity spiky by [0, 0, -30] at 150 speed signaling sig1 + +wait for all clearing sig1 + +rotate entity spiky by [0, 0, 20] at 125 speed signaling sig1 + +wait for all clearing sig1 + +rotate entity spiky by [0, 0, -15] at 125 speed signaling sig1 + +wait for all clearing sig1 + +rotate entity spiky by [0, 0, 5] at 100 speed signaling sig1 + +wait for all clearing sig1 + +disable trigger entity richard + + diff --git a/Toolkit/Designer/dsexamples/silverspring/spike2.ds b/Toolkit/Designer/dsexamples/silverspring/spike2.ds new file mode 100644 index 0000000..aed295c --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/spike2.ds @@ -0,0 +1,21 @@ +//SSwarehouse, Spiky thing swings + +#include "../common/header.ds" +output "r:/base/ds/silverspring" + +//define variables + +local entity spiky +local entity richard + +spiky = find entity with targetname "spiky" +richard = find entity with targetname "richard" +spiky.movetype = PHYSICSTYPE_PUSH + +//poor spiky + +use entity spiky + +disable trigger entity richard + + diff --git a/Toolkit/Designer/dsexamples/silverspring/spit.ds b/Toolkit/Designer/dsexamples/silverspring/spit.ds new file mode 100644 index 0000000..62f2782 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/spit.ds @@ -0,0 +1,24 @@ +// Spit with a frying elf + + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +local entity spinman +local entity spit +local int sig +local int sig1 + +spinman = find entity with targetname "spinman" +spit = find entity with targetname "spit" +spinman.movetype = PHYSICSTYPE_PUSH +spinman.origin = spit.origin + +label top + +rotate entity spit by [360, 0, 0] at 30 speed signaling sig +rotate entity spinman by [0, 0, 360] at 30 speed signaling sig1 +wait for all clearing sig, sig1 + +goto top \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/swinger.ds b/Toolkit/Designer/dsexamples/silverspring/swinger.ds new file mode 100644 index 0000000..f1c522a --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/swinger.ds @@ -0,0 +1,37 @@ +output "r:/base/ds/silverspring" + +parameter entity thing +parameter vector distance +parameter float time_var + +local vector tvec +local int sgnl +local float ttime +local float counter + +counter = 0 + +label begin + +counter += 9 +ttime = sin counter +ttime += 1 +ttime /= 4 +ttime += time_var +tvec = distance +tvec *= -1 + +rotate entity thing to tvec over ttime seconds signaling sgnl +wait for any clearing sgnl + +counter += 17 +ttime = sin counter +ttime += 1 +ttime /= 4 +ttime += time_var +tvec = distance + +rotate entity thing to tvec over ttime seconds signaling sgnl +wait for any clearing sgnl + +goto begin \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/tombox.ds b/Toolkit/Designer/dsexamples/silverspring/tombox.ds new file mode 100644 index 0000000..02ea67c --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/tombox.ds @@ -0,0 +1,226 @@ +//SSwarehouse, opening the exit to the town level. + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +local entity right +local entity left +local entity rope +local entity box +local entity one +local entity two +local entity camera +local entity target +local entity corvus +local entity player1 + +local int sig +local int sig1 +local int sig2 +local int sig3 + +field vector "velocity" + +right = find entity with targetname "righttom" +left = find entity with targetname "lefttom" +rope = find entity with targetname "ropetom" +box = find entity with targetname "boxtom" +one = find entity with targetname "one" +two = find entity with targetname "two" +camera = find entity with targetname "cameratom" +target = find entity with targetname "targetcamtom" +corvus = find entity with targetname "corvus" + +player1 = get entity activator + + copy player attributes from entity player1 to entity corvus + corvus.modelindex = corvus.count + corvus.solid = SOLID_SOLID + corvus.movetype = 4 + +enable cinematics + +// clamping down on the box + + use entity camera + + rotate entity right by [0, 0, -15] over 1 seconds signaling sig + + rotate entity left by [0, 0, 15] over 1 seconds signaling sig1 + play sound "doors/elevatorstart.wav" for entity rope on channel 10 + wait for all clearing sig, sig1 + + +// picking up the box + + move entity right by [0, 0, 30] over 1 seconds + + move entity left by [0, 0, 30] over 1 seconds + + move entity rope by [0, 0, 30] over 1 seconds + + move entity box by [0, 0, 30] over 1 seconds + + play sound "doors/elevatorstop.wav" for entity rope on channel 10 + +// move it to the right + + wait 1.5 seconds + + play sound "objects/winch2.wav" for entity rope on channel 10 + + target.movetype = PHYSICSTYPE_NOCLIP + + move entity target by [0, 220, 0] at 50 speed + + move entity right by [0, 220, 0] at 50 speed + + move entity left by [0, 220, 0] at 50 speed + + move entity rope by [0, 220, 0] at 50 speed + + move entity box by [0, 220, 0] at 50 speed + wait 2 seconds + play sound "objects/winch2.wav" for entity left on channel 10 + +// spin it around + + wait 4 seconds + + play sound "doors/elevatorstop.wav" for entity rope on channel 10 + + right.velocity = [10, -9, 0] + left.velocity = [-10, 9, 0] + + play sound "objects/oilpump.wav" for entity left on channel 10 + + rotate entity right by [0, -90, 0] over 1 seconds signaling sig + + rotate entity left by [0, -90, 0] over 1 seconds signaling sig1 + + rotate entity rope by [0, -90, 0] over 1 seconds signaling sig2 + + rotate entity box by [0, -90, 0] over 1 seconds signaling sig3 + wait for all clearing sig, sig1, sig2, sig3 + + right.velocity = [0, 0, 0] + left.velocity = [0, 0, 0] + +// move it down + play sound "doors/elevatormove.wav" for entity rope on channel 10 + + move entity target by [0, 0, -200] over 10 seconds + + one.movetype = PHYSICSTYPE_NOCLIP + move entity one by [-20, 0, 0] over 7 seconds + + two.movetype = PHYSICSTYPE_NOCLIP + move entity two by [20, 0, 0] over 7 seconds + + move entity right by [0, 0, -100] at 30 speed signaling sig + + move entity left by [0, 0, -100] at 30 speed signaling sig1 + + move entity rope by [0, 0, -100] at 30 speed signaling sig2 + + move entity box by [0, 0, -100] at 30 speed signaling sig3 + wait for all clearing sig, sig1, sig2, sig3 + + play sound "doors/elevatorstop.wav" for entity rope on channel 10 + +// oh oh we're in trouble + + + move entity right by [0, 0, 5] at 30 speed signaling sig + + move entity left by [0, 0, 5] at 30 speed signaling sig1 + + move entity rope by [0, 0, 5] at 30 speed signaling sig2 + + move entity box by [0, 0, 5] at 30 speed signaling sig3 + wait for all clearing sig, sig1, sig2, sig3 + + play sound "doors/thud3.wav" for entity rope on channel 10 + wait 1 seconds + + play sound "misc/brkwood2.wav" for entity box on channel 10 + move entity box by [0, 0, -5] at 10 speed signaling sig + wait for all clearing sig + + wait 1 seconds + + play sound "misc/brkwood2.wav" for entity box on channel 10 + move entity box by [0, 0, -5] at 10 speed signaling sig + wait for all clearing sig + + +// bombs away + + rotate entity right by [0, 0, 10] at 50 speed signaling sig + + rotate entity left by [0, 0, -10] at 50 speed signaling sig1 + + move entity box by [0, 0, -420] at 400 speed + wait .5 seconds + play sound "misc/breakwood.wav" for entity one on channel 10 + play sound "misc/breakwood.wav" for entity two on channel 10 + use entity one + use entity two + + wait for all clearing sig, sig1 + +//--------- + + rotate entity right by [0, 0, -15] at 20 speed signaling sig + + rotate entity left by [0, 0, 15] at 20 speed signaling sig1 + wait for all clearing sig, sig1 + +//--------- + + rotate entity right by [0, 0, 7] at 20 speed signaling sig + + rotate entity left by [0, 0, -7] at 20 speed signaling sig1 + wait for all clearing sig, sig1 + +//--------- + + rotate entity right by [0, 0, -2] at 20 speed signaling sig + + rotate entity left by [0, 0, 2] at 20 speed signaling sig1 + wait for all clearing sig, sig1 + + use entity camera + +disable cinematics + + player1.origin = corvus.origin + player1.p_origin = corvus.origin // Put player where Cinematic corvus is + set view angles of entity player1 to corvus.angles + + corvus.modelindex = 0 + corvus.solid = SOLID_NOT + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Toolkit/Designer/dsexamples/silverspring/watchercinema.ds b/Toolkit/Designer/dsexamples/silverspring/watchercinema.ds new file mode 100644 index 0000000..d31831d --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/watchercinema.ds @@ -0,0 +1,137 @@ +// The Watcher Cinematic with Spam-O-Vision. + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +local entity cam1 +local entity cam2 +local entity cam3 +local entity dolly +local entity dolly2 +local entity dolly3 +local entity cam1train +local entity cam2train +local entity cam3train +local entity watcher +local entity player1 +local entity fire1 +local entity fire2 +local entity light1 +local entity light2 +local entity light3 +local entity monster +parameter entity hero + +local int sig +local int sig1 +local int sig2 + +cam1 = find entity with targetname "shot1" +cam1train = find entity with scripttarget "train1" +cam2 = find entity with targetname "shot2" +cam2train = find entity with scripttarget "train2" +cam3 = find entity with targetname "shot3" +cam3train = find entity with scripttarget "train3" +dolly = find entity with scripttarget "pan" +dolly2 = find entity with scripttarget "pan2" +dolly3 = find entity with scripttarget "pan3" +watcher = find entity with targetname "lord" +fire1 = find entity with targetname "fire1" +fire2 = find entity with targetname "fire2" +light1 = find entity with targetname "light1" +light2 = find entity with targetname "light2" +light3 = find entity with targetname "light3" +monster = find entity with targetname "monster" + +//Switching player + +player1 = get entity activator // Get player who set off trigger +copy player attributes from entity player1 to entity hero +hero.modelindex = hero.count // Turn on cinematic corvus +hero.solid = SOLID_SOLID // Make him block +hero.movetype = PHYSICSTYPE_STEP + +enable cinematics +cache sound "cinematics/watcher/33-33.wav" +cache sound "cinematics/watcher/34-36.wav" +cache sound "cinematics/watcher/35-33.wav" + +// Corvus enters the Watcher's Throne Room and says, Nice Digs. + animate entity watcher performing action IDLE2_ANIMATION repeating for 10 times + use entity cam1 + dolly.movetype = PHYSICSTYPE_NOCLIP + animate entity hero performing action WALK2_ANIMATION by moving [64, 0, 0] by turning [0, 0, 0] signaling sig + wait for any clearing sig + animate entity hero performing action IDLE2_ANIMATION repeating for 10 times + print 154 captioned + play sound "cinematics/watcher/33-33.wav" for entity watcher + wait .2 seconds + animate entity watcher performing action ACTION1_ANIMATION signaling sig2 + move entity cam1train by [0, 0, 128] over 2.5 seconds signaling sig1 + wait for any clearing sig1 + wait 1 seconds + use entity fire1 + use entity fire2 + use entity light1 + use entity light2 + use entity light3 + move entity dolly by [0, 300, 0] over 10.5 seconds signaling sig + move entity cam1train by [0, 300, 0] over 12.5 seconds signaling sig1 + wait for all clearing sig, sig1, sig2 + use entity cam1 + animate entity watcher performing action IDLE2_ANIMATION + + +// Corvus walks into room, Watcher floats down and they shake hands. + use entity cam2 + dolly2.movetype = PHYSICSTYPE_NOCLIP + print 155 captioned + play sound "cinematics/watcher/34-36.wav" for entity hero + wait .2 seconds + animate entity hero performing action ACTION1_ANIMATION signaling sig + move entity dolly2 by [0, 200, 64] over 6.5 seconds signaling sig1 + move entity cam2train by [0, 0, -64] over 6.5 seconds signaling sig2 + wait for all clearing sig, sig1, sig2 + animate entity hero performing action IDLE3_ANIMATION repeating for 15 times + wait 1.0 seconds + //animate entity watcher performing action IDLE_ANIMATION + use entity cam2 + +// Corvus is tired of the blather. + use entity cam3 + wait .5 seconds + dolly3.movetype = PHYSICSTYPE_NOCLIP + animate entity hero performing action WALK2_ANIMATION by moving [96, 0, 0] by turning [0, 0, 0] + print 156 captioned + play sound "cinematics/watcher/35-33.wav" for entity watcher + wait .4 seconds + animate entity watcher performing action ACTION2_ANIMATION + move entity cam3train by [0, 128, 0] over 10.4 seconds signaling sig + wait for all clearing sig + move entity cam3train by [0, 65, 32] over 10 seconds signaling sig + move entity dolly3 by [0, 0, 48] over 10 seconds signaling sig1 + wait for all clearing sig, sig1 + animate entity watcher performing action IDLE2_ANIMATION + use entity cam3 + +//Switching back + +player1.origin = hero.origin // Put player where Cinematic corvus is +player1.p_origin = hero.origin // Put player where Cinematic corvus is +set view angles of entity player1 to hero.angles +hero.modelindex = 0 // Turn off the cinematic corvus model +hero.solid = SOLID_NOT // Make him not solid + +//Switching Watcher + +monster.origin = watcher.origin // Put Monster where Cinematic Watcher is +monster.angles = watcher.angles // Make Monster angles like Cinematic Watcher +monster.solid = SOLID_SOLID // Make the monster solid +watcher.modelindex = 0 // Turn off the cinematic Watcher model +watcher.solid = SOLID_NOT // Make him not solid + +disable cinematics + + + \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/silverspring/watcherdies.ds b/Toolkit/Designer/dsexamples/silverspring/watcherdies.ds new file mode 100644 index 0000000..375a8d2 --- /dev/null +++ b/Toolkit/Designer/dsexamples/silverspring/watcherdies.ds @@ -0,0 +1,194 @@ +// The Watcher dies + +#include "../common/header.ds" + +output "r:/base/ds/silverspring" + +local entity lpillar +local entity lpilltp +local entity lpillbt +local entity rpillar +local entity rpillarside +local entity camera +local entity camdolly +local entity camtarget +local entity floor1 +local entity floor2 +local entity floor3 +local entity floor4 +local entity floor5 +local entity topbeam +local entity topbeambar +local entity tbeamst +local entity taker +parameter entity hero1 +local entity player1 +local entity watcher +local entity monster +local entity change +local entity quaker +local entity rubble +local entity killer + +local int sig +local int sig1 + +lpillar = find entity with targetname "t116" +lpilltp = find entity with targetname "pilltop" +lpillbt = find entity with targetname "t117" +rpillar = find entity with targetname "pillar" +rpillarside = find entity with targetname "t133" +camera = find entity with targetname "t162" +camdolly = find entity with targetname "end" +camtarget = find entity with targetname "t167" +floor1 = find entity with targetname "floor1" +floor2 = find entity with targetname "floor2" +floor3 = find entity with targetname "floor3" +floor4 = find entity with targetname "floor4" +floor5 = find entity with targetname "floor5" +topbeam = find entity with targetname "t123" +topbeambar = find entity with targetname "bar" +tbeamst = find entity with targetname "t128" +taker = find entity with targetname "taker" +monster = find entity with targetname "monster" +watcher = find entity with targetname "lord" +change = find entity with targetname "change" +quaker = find entity with targetname "quaker" +rubble = find entity with targetname "rubble" +killer = find entity with targetname "killer" +player1 = get entity activator + +//start the end + +copy player attributes from entity player1 to entity hero1 +hero1.modelindex = hero1.count +hero1.solid = SOLID_SOLID +hero1.movetype = PHYSICSTYPE_STEP + +monster = find entity with targetname "monster" +monster.modelindex = 0 +monster.solid = SOLID_NOT +watcher.modelindex = watcher.count +watcher.solid = SOLID_SOLID +watcher.movetype = PHYSICSTYPE_STEP + + // Give monster elflord a chance to go away + wait .4 seconds + +//here we go + + enable cinematics + + use entity camera + + animate entity watcher performing action DEATH2_ANIMATION signaling sig + + wait for all clearing sig + + animate entity watcher performing action DEATH1_ANIMATION signaling sig + + wait for all clearing sig + + animate entity watcher performing action DEATH2_ANIMATION signaling sig + + wait for all clearing sig + + animate entity watcher performing action GIB1_ANIMATION + + enable trigger entity quaker + + play sound "world/quake.wav" for entity quaker on channel 10 + + use entity killer + +//place goes to hell + + rubble.movetype = PHYSICSTYPE_NOCLIP + + wait .5 seconds + +//break left pillar + + move entity camdolly by [-320, 0, 32] over 8 seconds + + move entity camtarget by [128,0,-32] over 8 seconds + + lpillar.movetype = PHYSICSTYPE_NOCLIP + + use entity lpilltp + + wait 1 seconds + + move entity lpillar by [0, 0, -256] at 400 speed signaling sig + rotate entity lpillar by [120, 0, 0] at 400 speed signaling sig1 + + wait for all clearing sig, sig1 + + use entity lpillar + use entity lpillbt + +//break right pillar + + wait 4.5 seconds + + use entity rpillarside + + wait .5 seconds + + rpillar.movetype = PHYSICSTYPE_NOCLIP + + move entity rubble by [0, 0, -384] at 1000 speed + + rotate entity rpillar by [-110, 0, 0] at 150 speed signaling sig + move entity rpillar by [ -16, 0, 0 ] at 150 speed signaling sig1 + + wait for all clearing sig, sig1 + + use entity rubble + use entity rpillar + use entity floor3 + use entity floor2 + +//break top crossbeam + + use entity topbeambar + + wait 1 seconds + + use entity tbeamst + + topbeam.movetype = PHYSICSTYPE_NOCLIP + + move entity topbeam by [0, -64, -64] at 300 speed signaling sig + rotate entity topbeam by [0, 0, 30] at 75 speed signaling sig1 + + wait for all clearing sig, sig1 + + move entity topbeam by [0, -32, -368] at 500 speed signaling sig + rotate entity topbeam by [0, 15, 60] at 100 speed signaling sig1 + + wait for all clearing sig, sig1 + + move entity camdolly by [160, 160, -64] over 3 seconds + + move entity camtarget by [0,0,-384] over 3 seconds + + use entity floor5 + + move entity topbeam by [0, -16, -448] at 500 speed signaling sig + rotate entity topbeam by [-5, 75, 90] at 100 speed signaling sig1 + + use entity floor1 + + wait for all clearing sig, sig1 + + use entity floor4 + +//the rest + disable trigger entity quaker + use entity taker + use entity camera + wait .5 seconds + use entity change + disable cinematics + exit \ No newline at end of file diff --git a/Toolkit/Designer/dsexamples/swamp/exit.ds b/Toolkit/Designer/dsexamples/swamp/exit.ds new file mode 100644 index 0000000..e87c3bf --- /dev/null +++ b/Toolkit/Designer/dsexamples/swamp/exit.ds @@ -0,0 +1,58 @@ +// Corvus is plagued! + +#include "../common/header.ds" + +output "r:/base/ds/swamp" + +local entity exitcorv +local entity cendoor +local entity topdoor +local entity botdoor +local entity camdoor +local entity player1 + +local int sig +local int sig1 +local int sig2 + +exitcorv = find entity with targetname "exitcorv" +cendoor = find entity with targetname "cendoor" +botdoor = find entity with targetname "botdoor" +topdoor = find entity with targetname "topdoor" +camdoor = find entity with targetname "camdoor" + +//Switching player + +player1 = get entity activator +copy player attributes from entity player1 to entity exitcorv +exitcorv.modelindex = exitcorv.count +exitcorv.solid = SOLID_SOLID +exitcorv.movetype = PHYSICSTYPE_STEP + +enable cinematics + +// door closes + + use entity camdoor + + use entity cendoor + + wait 2 seconds + + use entity topdoor + use entity botdoor + + wait 3 seconds + + use entity camdoor + +//Switching back + +player1.origin = exitcorv.origin +player1.p_origin = exitcorv.origin // Put player where Cinematic corvus is +set view angles of entity player1 to exitcorv.angles +exitcorv.modelindex = 0 +exitcorv.solid = SOLID_NOT + +disable cinematics + diff --git a/Toolkit/Designer/dsexamples/swamp/tomesewer.ds b/Toolkit/Designer/dsexamples/swamp/tomesewer.ds new file mode 100644 index 0000000..99fb2f5 --- /dev/null +++ b/Toolkit/Designer/dsexamples/swamp/tomesewer.ds @@ -0,0 +1,151 @@ +// Corvus is plagued! + +#include "../common/header.ds" + +output "r:/base/ds/swamp" + +local entity mission +local entity cam1 +local entity cam2 +local entity cam3 +local entity dolly1 +local entity dolly2 +local entity dolly3 +local entity cam1train +local entity cam2train +local entity cam3train +local entity tome +local entity player1 +parameter entity hero + +local int sig +local int sig1 +local int sig2 + +mission = find entity with targetname "mission" +cam1 = find entity with targetname "shot1" +cam1train = find entity with scripttarget "train1" +cam2 = find entity with targetname "shot2" +cam2train = find entity with scripttarget "train2" +cam3 = find entity with targetname "shot3" +cam3train = find entity with scripttarget "train3" +dolly1 = find entity with scripttarget "pan1" +dolly2 = find entity with scripttarget "pan2" +dolly3 = find entity with scripttarget "pan3" +tome = find entity with targetname "tome" + +//Switching player + +player1 = get entity activator // Get player who set off trigger +copy player attributes from entity player1 to entity hero +hero.modelindex = hero.count // Turn on cinematic corvus +hero.solid = SOLID_SOLID // Make him block +hero.movetype = PHYSICSTYPE_STEP + +tome.modelindex = tome.count // Turn on cinematic corvus +tome.solid = SOLID_SOLID // Make him block +tome.movetype = PHYSICSTYPE_STEP + +enable cinematics +cache sound "cinematics/sewer/39-395.wav" +cache sound "cinematics/sewer/40-399.wav" +cache sound "cinematics/sewer/41-392.wav" +cache sound "cinematics/sewer/42-395.wav" +cache sound "cinematics/sewer/43-392.wav" +cache sound "cinematics/sewer/44-392.wav" +cache sound "cinematics/sewer/45-394.wav" +cache sound "cinematics/sewer/46-392.wav" + +// Corvus wakes up + + use entity cam1 + move entity cam1train by [16, 16, -96] over 6 seconds + play sound "cinematics/sewer/39-395.wav" for entity hero + animate entity tome performing action IDLE1_ANIMATION repeating for 20 times + animate entity hero performing action ACTION1_ANIMATION repeating for 1 times signaling sig + wait for any clearing sig + animate entity hero performing action ACTION2_ANIMATION repeating for 1 times signaling sig + wait for any clearing sig + animate entity hero performing action ACTION3_ANIMATION repeating for 1 times signaling sig + wait for any clearing sig + print 158 captioned + animate entity hero performing action ACTION2_ANIMATION repeating for 1 times signaling sig + wait for any clearing sig + animate entity hero performing action ACTION4_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig + use entity cam1 + +// The tome speaks + + use entity cam2 + dolly2.movetype = PHYSICSTYPE_NOCLIP + cam1train.movetype = PHYSICSTYPE_NOCLIP + move entity cam2train by [64, -64, 0] over 20 seconds + move entity dolly2 by [0, 0, -48] over 20 seconds + print 159 captioned + play sound "cinematics/sewer/40-399.wav" for entity tome + animate entity hero performing action IDLE2_ANIMATION repeating for 2 times signaling sig + wait for all clearing sig + animate entity hero performing action IDLE4_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig + wait 1.5 seconds + print 160 captioned + play sound "cinematics/sewer/41-392.wav" for entity hero + animate entity hero performing action ACTION5_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig + print 161 captioned + play sound "cinematics/sewer/42-395.wav" for entity tome + animate entity hero performing action IDLE2_ANIMATION repeating for 2 times signaling sig + wait for all clearing sig + animate entity hero performing action IDLE4_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig + wait 1 seconds + print 162 captioned + play sound "cinematics/sewer/43-392.wav" for entity tome + animate entity hero performing action IDLE2_ANIMATION repeating for 3 times signaling sig + wait for all clearing sig + use entity cam2 + +// Corvus gets pissed! + + use entity cam3 + move entity cam3train by [96, 96, -32] over 24 seconds + print 163 captioned + play sound "cinematics/sewer/44-392.wav" for entity hero + animate entity hero performing action ACTION6_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig + print 164 captioned + play sound "cinematics/sewer/45-394.wav" for entity tome + animate entity hero performing action ACTION7_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig + animate entity hero performing action IDLE3_ANIMATION repeating for 3 times signaling sig + wait for all clearing sig + print 165 captioned + animate entity hero performing action IDLE3_ANIMATION repeating for 4 times signaling sig + wait for all clearing sig + wait 1 seconds + print 166 captioned + play sound "cinematics/sewer/46-392.wav" for entity hero + animate entity hero performing action ACTION8_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig + animate entity hero performing action ACTION9_ANIMATION repeating for 1 times signaling sig + wait for all clearing sig + animate entity hero performing action IDLE5_ANIMATION signaling sig + wait for all clearing sig + +use entity mission + +use entity cam3 +//Switching back + +player1.origin = hero.origin // Put player where Cinematic corvus is +player1.p_origin = hero.origin // Put player where Cinematic corvus is +set view angles of entity player1 to hero.angles +hero.modelindex = 0 // Turn off the cinematic corvus model +hero.solid = SOLID_NOT // Make him not solid + +tome.modelindex = 0 // Turn off the cinematic corvus model +tome.solid = SOLID_NOT // Make him not solid + +disable cinematics + diff --git a/Toolkit/Designer/dsexamples/template.ds b/Toolkit/Designer/dsexamples/template.ds new file mode 100644 index 0000000..9da3fd3 --- /dev/null +++ b/Toolkit/Designer/dsexamples/template.ds @@ -0,0 +1,7 @@ +// template file for scripts + +#include "../common/header.ds" + +output "r:/base/ds" + + diff --git a/Toolkit/Designer/makeqdt.exe b/Toolkit/Designer/makeqdt.exe new file mode 100755 index 0000000..7803ac6 Binary files /dev/null and b/Toolkit/Designer/makeqdt.exe differ diff --git a/Toolkit/Designer/paker.exe b/Toolkit/Designer/paker.exe new file mode 100755 index 0000000..4df15e5 Binary files /dev/null and b/Toolkit/Designer/paker.exe differ diff --git a/Toolkit/Designer/qMView.lnk b/Toolkit/Designer/qMView.lnk new file mode 100644 index 0000000..b565ce4 Binary files /dev/null and b/Toolkit/Designer/qMView.lnk differ diff --git a/Toolkit/Designer/qdata.exe b/Toolkit/Designer/qdata.exe new file mode 100755 index 0000000..be2c6ba Binary files /dev/null and b/Toolkit/Designer/qdata.exe differ diff --git a/Toolkit/Designer/qmview/!skin.m8 b/Toolkit/Designer/qmview/!skin.m8 new file mode 100644 index 0000000..b488c4d Binary files /dev/null and b/Toolkit/Designer/qmview/!skin.m8 differ diff --git a/Toolkit/Designer/qmview/!skin.pcx b/Toolkit/Designer/qmview/!skin.pcx new file mode 100644 index 0000000..95ccc9c Binary files /dev/null and b/Toolkit/Designer/qmview/!skin.pcx differ diff --git a/Toolkit/Designer/qmview/!test.m8 b/Toolkit/Designer/qmview/!test.m8 new file mode 100644 index 0000000..a843ded Binary files /dev/null and b/Toolkit/Designer/qmview/!test.m8 differ diff --git a/Toolkit/Designer/qmview/MFC42.DLL b/Toolkit/Designer/qmview/MFC42.DLL new file mode 100644 index 0000000..bf61c90 Binary files /dev/null and b/Toolkit/Designer/qmview/MFC42.DLL differ diff --git a/Toolkit/Designer/qmview/backup/qMView.exe b/Toolkit/Designer/qmview/backup/qMView.exe new file mode 100755 index 0000000..52a30fd Binary files /dev/null and b/Toolkit/Designer/qmview/backup/qMView.exe differ diff --git a/Toolkit/Designer/qmview/backup/qMView_back.exe b/Toolkit/Designer/qmview/backup/qMView_back.exe new file mode 100755 index 0000000..456af5e Binary files /dev/null and b/Toolkit/Designer/qmview/backup/qMView_back.exe differ diff --git a/Toolkit/Designer/qmview/backup/qmview-NEW.exe b/Toolkit/Designer/qmview/backup/qmview-NEW.exe new file mode 100755 index 0000000..c427d9b Binary files /dev/null and b/Toolkit/Designer/qmview/backup/qmview-NEW.exe differ diff --git a/Toolkit/Designer/qmview/dll/MFC40.DLL b/Toolkit/Designer/qmview/dll/MFC40.DLL new file mode 100644 index 0000000..c32c52d Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MFC40.DLL differ diff --git a/Toolkit/Designer/qmview/dll/MFC40D.DLL b/Toolkit/Designer/qmview/dll/MFC40D.DLL new file mode 100644 index 0000000..6df94d3 Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MFC40D.DLL differ diff --git a/Toolkit/Designer/qmview/dll/MFC42D.DLL b/Toolkit/Designer/qmview/dll/MFC42D.DLL new file mode 100644 index 0000000..e91daf1 Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MFC42D.DLL differ diff --git a/Toolkit/Designer/qmview/dll/MFCD42D.DLL b/Toolkit/Designer/qmview/dll/MFCD42D.DLL new file mode 100644 index 0000000..8694efb Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MFCD42D.DLL differ diff --git a/Toolkit/Designer/qmview/dll/MFCN42D.DLL b/Toolkit/Designer/qmview/dll/MFCN42D.DLL new file mode 100644 index 0000000..b1431aa Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MFCN42D.DLL differ diff --git a/Toolkit/Designer/qmview/dll/MSVCP50.DLL b/Toolkit/Designer/qmview/dll/MSVCP50.DLL new file mode 100644 index 0000000..07c9dc3 Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MSVCP50.DLL differ diff --git a/Toolkit/Designer/qmview/dll/MSVCP50D.DLL b/Toolkit/Designer/qmview/dll/MSVCP50D.DLL new file mode 100644 index 0000000..2790552 Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MSVCP50D.DLL differ diff --git a/Toolkit/Designer/qmview/dll/MSVCR40D.DLL b/Toolkit/Designer/qmview/dll/MSVCR40D.DLL new file mode 100644 index 0000000..80807a0 Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MSVCR40D.DLL differ diff --git a/Toolkit/Designer/qmview/dll/MSVCRT.DLL b/Toolkit/Designer/qmview/dll/MSVCRT.DLL new file mode 100644 index 0000000..db64ef9 Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MSVCRT.DLL differ diff --git a/Toolkit/Designer/qmview/dll/MSVCRTD.DLL b/Toolkit/Designer/qmview/dll/MSVCRTD.DLL new file mode 100644 index 0000000..9ca21c1 Binary files /dev/null and b/Toolkit/Designer/qmview/dll/MSVCRTD.DLL differ diff --git a/Toolkit/Designer/qmview/dll/mfc42.dll b/Toolkit/Designer/qmview/dll/mfc42.dll new file mode 100644 index 0000000..f0365be Binary files /dev/null and b/Toolkit/Designer/qmview/dll/mfc42.dll differ diff --git a/Toolkit/Designer/qmview/dll/msvcrt40.dll b/Toolkit/Designer/qmview/dll/msvcrt40.dll new file mode 100644 index 0000000..6796061 Binary files /dev/null and b/Toolkit/Designer/qmview/dll/msvcrt40.dll differ diff --git a/Toolkit/Designer/qmview/qMView.exe b/Toolkit/Designer/qmview/qMView.exe new file mode 100755 index 0000000..6754db1 Binary files /dev/null and b/Toolkit/Designer/qmview/qMView.exe differ diff --git a/Toolkit/Designer/qmview/skin.pcx b/Toolkit/Designer/qmview/skin.pcx new file mode 100644 index 0000000..8624f26 Binary files /dev/null and b/Toolkit/Designer/qmview/skin.pcx differ diff --git a/Toolkit/Designer/qmview/test.pcx b/Toolkit/Designer/qmview/test.pcx new file mode 100644 index 0000000..e6601f3 Binary files /dev/null and b/Toolkit/Designer/qmview/test.pcx differ diff --git a/Toolkit/Designer/qmview/tris.fm b/Toolkit/Designer/qmview/tris.fm new file mode 100644 index 0000000..6c7b43b Binary files /dev/null and b/Toolkit/Designer/qmview/tris.fm differ diff --git a/Toolkit/Designer/qmview/tris.md2 b/Toolkit/Designer/qmview/tris.md2 new file mode 100644 index 0000000..a36f578 Binary files /dev/null and b/Toolkit/Designer/qmview/tris.md2 differ diff --git a/Toolkit/Designer/qmview/worklog.txt b/Toolkit/Designer/qmview/worklog.txt new file mode 100644 index 0000000..80b6597 --- /dev/null +++ b/Toolkit/Designer/qmview/worklog.txt @@ -0,0 +1,122 @@ +qMView ver 1.5 Work Log (c) 1998, Josh Weier +---------------------------------------------- + +TODO: +---------------------------------------------- + + ground plane + axis + drag and drop frame placement (insert before / after) + scale (scoped) + translate (scoped) + rotate (scoped) + file save (Quake) + file save (Quake2) + model bitfield editing + label editing (frame) + undo / redo + import frame (3DS / DXF / COB) + export frame (3DS / DXF / COB) + export skin (BMP / PCX / RAW) + skin view + on model painting + dodge tool + burn tool + on skin page painting + palette swatches + other paint tools + dynamic interpolation + frame rate locking (clamping / acceling) + preferences dialog + palette on status bar + on the fly frame import and model colallation + optimize Quake2 frame updates (vert paths) + add tri-outline skin + frame sequencing + snap to vertex + +---------------------------------------------- + +[1/24/98] + + * surrenders processor time when not active (minimized, not visible) + * 'z' spin toggle + * fix model loading error + * fix Quake models + * frame rate display (in status bar) + * updated to DirectX v5.0 (SDK / End User) + - Fixed ambient light problem + - Fixed transparency error (has palette error now) + - Minor speed increase + * ambient lighting mode + * removed Quake2 model light normal calculations (4 FPS opt) + * re-added frame interpolation (manditory 4 IFPF) + + +[1/25/98] + + * added interpolation toggle to menu and toolbar + +[1/26/98] + + * fix Quake texture vertex loss bug + * fix palette import bug + +[1/29/98] + + * Models are loadable from command line or double click + * fix Quake model scale bug + * fix Quake frame group bug + * fix interpolation error (interpolating to next frame in full list) + * moved to version 1.4ß + * tweaked splash screen + +[1/31/98] + + * really fixed z-spin + * re-did dialog bar + +[2/14/98] + + * spent Valentine's day coding + * added multi-selection + * fixed Quake model mirroring + +[2/20/98] + + * fixed Quake model Skin import + * fixed ping-pong in punch select + * added normal ping-pong + * fixed scaling system + * fixed SHIFT and CTRL key captures (unless focus to treectrl) + * add smooth scale + * hacked workable tree updates + * fixed Z rotation (really!) + * added tweaks to throw code to prevent slow moving + * hack fixed Microsoft's weird texture transparency problem + +[2/21/98] + + * made h2 palette the default + * fixed up Quake model preset positions + +[2/22/98] + + * added multi-skin support + * added icon art + * optimized skin loading + * added group filling to multi-select frames + * FIXME! Don't group select backwards! + * FIXME! Don't think about doing it with Quake2! + * FIXME! Don't switch internal skins after loading a new one! + * fixed keydown capture on skin tree + +[3/17/98] + + * Hexen2 MP finished up, added qMView to SourceSafe + +[2/23/98] + + * Basic FM support + * Load M8 as a skin + * Added double click disk load to skin tree diff --git a/Toolkit/Designer/unpak.bat b/Toolkit/Designer/unpak.bat new file mode 100644 index 0000000..4f1b6a5 --- /dev/null +++ b/Toolkit/Designer/unpak.bat @@ -0,0 +1 @@ +paker -extract ..\..\base\Htic2-0.pak textures ..\..\base\ \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/Final/H2Common.lib b/Toolkit/Programming/GameCode/Final/H2Common.lib new file mode 100644 index 0000000..809fca5 Binary files /dev/null and b/Toolkit/Programming/GameCode/Final/H2Common.lib differ diff --git a/Toolkit/Programming/GameCode/Final/Player.lib b/Toolkit/Programming/GameCode/Final/Player.lib new file mode 100644 index 0000000..3c9407e Binary files /dev/null and b/Toolkit/Programming/GameCode/Final/Player.lib differ diff --git a/Toolkit/Programming/GameCode/Final/SndDll.lib b/Toolkit/Programming/GameCode/Final/SndDll.lib new file mode 100644 index 0000000..c2e60b1 Binary files /dev/null and b/Toolkit/Programming/GameCode/Final/SndDll.lib differ diff --git a/Toolkit/Programming/GameCode/Final/quake2.lib b/Toolkit/Programming/GameCode/Final/quake2.lib new file mode 100644 index 0000000..034fabc Binary files /dev/null and b/Toolkit/Programming/GameCode/Final/quake2.lib differ diff --git a/Toolkit/Programming/GameCode/Final/ref_gl.lib b/Toolkit/Programming/GameCode/Final/ref_gl.lib new file mode 100644 index 0000000..f50ab16 Binary files /dev/null and b/Toolkit/Programming/GameCode/Final/ref_gl.lib differ diff --git a/Toolkit/Programming/GameCode/Final/ref_soft.lib b/Toolkit/Programming/GameCode/Final/ref_soft.lib new file mode 100644 index 0000000..467e915 Binary files /dev/null and b/Toolkit/Programming/GameCode/Final/ref_soft.lib differ diff --git a/Toolkit/Programming/GameCode/Player/p_newmove.h b/Toolkit/Programming/GameCode/Player/p_newmove.h new file mode 100644 index 0000000..1aa7695 --- /dev/null +++ b/Toolkit/Programming/GameCode/Player/p_newmove.h @@ -0,0 +1,8 @@ +#ifndef P_NEW_MOVE_H +#define P_NEW_MOVE_H + +#if 1 +#define P_NEW_MOVE +#endif + +#endif // P_NEW_MOVE \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/Ambient Effects.c b/Toolkit/Programming/GameCode/client effects/Ambient Effects.c new file mode 100644 index 0000000..cfcba08 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Ambient Effects.c @@ -0,0 +1,162 @@ +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" + +void DoWaterSplash(client_entity_t *effect, paletteRGBA_t color, int count) +{ + client_particle_t *p; + int i; + + if (count>500) + count=500; + for(i = 0; i < count; i++) + { + p = ClientParticle_new(PART_16x16_WATERDROP, color, 1000); + + p->d_alpha = 0; + p->d_scale = -1.0; + p->velocity[0] = flrand(-20.0F, 20.0F); + p->velocity[1] = flrand(-20.0F, 20.0F); + p->velocity[2] = flrand(20.0F, 30.0F); + + AddParticleToList(effect, p); + } +} + +void WaterSplash(centity_t *owner, int type, int flags, vec3_t origin) +{ + int cnt; + client_entity_t *effect; + paletteRGBA_t color; + + fxi.GetEffect(owner, flags, "b", &cnt); + + effect = ClientEntity_new(type, flags, origin, NULL, 500); + effect->flags |= CEF_NO_DRAW | CEF_NOMOVE; + + AddEffect(NULL, effect); + + color.c = 0xffffffff; + DoWaterSplash(effect, color, cnt); +} + +#define FLY_EFFECT_THINK_TIME 100 // creates new flies every 0.1 sec + +// This needs work. . . +qboolean CreateFlyParticles(client_entity_t *this, centity_t *owner) +{ +#define NUMVERTEXNORMALS 162 +#define BEAMLENGTH 16 +// int n; + int count; +// int starttime; + +// int fly_stoptime; + + int i; + client_particle_t *p; + float angle; + float sr, sp, sy, cr, cp, cy; + vec3_t forward; + float dist = 64; + float ltime; + static float avertexnormals [NUMVERTEXNORMALS][3] = + { + #include "anorms.h" + }; + static vec3_t avelocities [NUMVERTEXNORMALS]; + +/* fly_stoptime = this->startTime + this->duration; + + if (fly_stoptime < fxi.cl->time) + { + starttime = fxi.cl->time; + fly_stoptime = fxi.cl->time + 60000; + } + else + { + starttime = fly_stoptime - 60000; + } + + n = fxi.cl->time - starttime; + if (n < 20000) + count = n * 162 / 20000.0; + else + { + n = fly_stoptime - fxi.cl->time; + if (n < 20000) + count = n * 162 / 20000.0; + else + count = 162; + }*/ + + // + +// if (count > NUMVERTEXNORMALS) + count = NUMVERTEXNORMALS; + + if (!avelocities[0][0]) + { + for (i=0 ; itime / 1000.0; + for (i=0 ; ip_root)); + + AddParticleToList(this, p); + + angle = ltime * avelocities[i][0]; + sy = sin(angle); + cy = cos(angle); + angle = ltime * avelocities[i][1]; + sp = sin(angle); + cp = cos(angle); + angle = ltime * avelocities[i][2]; + sr = sin(angle); + cr = cos(angle); + + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + + p->startTime = fxi.cl->time; + p->duration = 50; + + dist = sin(ltime + i)*64; + p->origin[0] = avertexnormals[i][0]*dist + forward[0]*BEAMLENGTH; + p->origin[1] = avertexnormals[i][1]*dist + forward[1]*BEAMLENGTH; + p->origin[2] = avertexnormals[i][2]*dist + forward[2]*BEAMLENGTH; + + VectorClear (p->velocity); + VectorClear (p->acceleration); + + p->color.c = 0x000000FF; + + p->d_alpha = -100; + + p->scale = 1.0; + p->d_scale = 0.0; + } + + return true; // never goes away. . . +} + +void FlyEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *effect; + + effect = ClientEntity_new(type, flags, origin, NULL, FLY_EFFECT_THINK_TIME); + + effect->flags |= CEF_NO_DRAW; + + effect->Update = CreateFlyParticles; + + AddEffect(owner, effect); +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/Client Effects.c b/Toolkit/Programming/GameCode/client effects/Client Effects.c new file mode 100644 index 0000000..52c2697 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Client Effects.c @@ -0,0 +1,231 @@ +#include "Client Effects.h" +#include "Client Entities.h" +#include "FX.h" + +// NB. The assassin tport go is not precached + +ClientEffect_t clientEffectSpawners[NUM_FX] = +{ // ***NOTE*** We currently have 113 client effects, and we don't want to exceed 32768! Ha! + { RemoveEffects, NULL }, + { FXflametest, NULL}, + { GenericExplosion1, NULL }, + { GenericExplosion2, NULL }, + { WaterSplash, PreCacheWaterSplash }, + { GenericGibTrail, NULL }, + { FXBlood, PreCacheSplat }, + { FXBloodTrail, PreCacheSplat }, + { FXLinkedBlood, NULL }, + { FXGenericSparks, PreCacheSparks }, + { PlayerTeleportin, PreCacheTeleport }, + { FXHealthPickup, PreCacheHealth }, + { FXWeaponPickup, PreCacheItemWeapons }, + { FXDefensePickup, PreCacheItemDefense }, + { FXPuzzlePickup, PreCachePuzzleItems }, + { FXAmmoPickup, PreCacheItemAmmo }, + { FXFlyingFist, PreCacheFist }, + { FXFlyingFistExplode, NULL }, + { FXBlueRing, PreCacheBluering }, + { FXMeteorBarrier, PreCacheMeteor }, // see fx.h for an explanation of this + { FXMeteorBarrier, PreCacheMeteor }, + { FXMeteorBarrier, PreCacheMeteor }, + { FXMeteorBarrier, PreCacheMeteor }, + { FXMeteorBarrierTravel, PreCacheMeteor }, + { FXMeteorBarrierExplode, NULL }, + { FXLightningShield, PreCacheShield }, + { FXSphereOfAnnihilation, PreCacheSphere }, + { FXSphereOfAnnihilationGlowballs, NULL }, + { FXSphereOfAnnihilationExplode, NULL }, + { FXSphereOfAnnihilationPower, NULL}, + { FXSpherePlayerExplode, NULL }, + { FXMagicMissile, PreCacheArray }, + { FXMagicMissileExplode, NULL }, + { FXBlast, NULL }, + { FXRedRainMissile, PreCacheRedrain }, + { FXRedRain, NULL }, + { FXRedRainGlow, NULL }, + { FXMaceball, PreCacheMaceball }, + { FXMaceballBounce, NULL }, + { FXMaceballExplode, NULL }, + { FXPhoenixMissile, PreCachePhoenix }, + { FXPhoenixExplode, NULL }, + { FXMorphMissile, PreCacheMorph }, + { FXMorphMissile_initial, NULL }, + { FXMorphExplode, NULL }, + { FXFireWave, PreCacheWall }, + { FXFireWaveWorm, PreCacheWall }, + { FXFireBurst, NULL }, + { FXRipperExplode, NULL}, + { FXWaterEntrySplash, NULL }, + { FXWaterRipples, PreCacheRipples }, + { FXWaterWake, PreCacheWake }, + { FXBubbler, PreCacheBubbler }, + { FXScorchmark, PreCacheScorch }, + { FXDebris, PreCacheDebris }, + { FXFleshDebris, PreCacheDebris }, + { FXShadow, PrecacheShadow }, + { FXAnimate, PreCacheFXAnimate }, + { FXFountain, NULL }, + { FXWaterfallBase, NULL }, + { FXDripper, PreCacheDripper }, + { FXMist, PreCacheMist }, + { FXPlagueMist, NULL }, + { FXPlagueMistExplode, NULL }, + { FXSpellHands, PreCacheHands }, + { FXLensFlare, PreCacheFlare }, + { FXStaff, PreCacheStaff }, + { FXSpoo, PreCacheSpoo }, + { FXHalo, PreCacheHalos }, + { FXRemoteCamera, NULL }, + { FXHellbolt, PreCacheHellstaff }, + { FXHellboltExplode, NULL }, + { FXHellstaffPower, PreCacheHellstaff }, + { FXHellstaffPowerBurn, NULL }, + { FXSpellChange, NULL }, + { FXStaffCreate, NULL }, + { FXStaffCreatePoof, NULL }, + { FXStaffRemove, NULL }, + { FXDustPuffOnGround, NULL }, + { FXFire, NULL }, + { FXSound, NULL }, + { FXPickup, PreCachePickup }, + { FXGenericHitPuff, NULL }, + { FXDust, PreCacheRockchunks }, + { FXEnvSmoke, PreCacheSmoke }, + { FXSpooSplat, NULL }, + { FXBodyPart, NULL }, + { PlayerTeleportout, NULL }, + { FXPlayerPersistant, NULL }, + { FXplayertorch, PreCacheTorch }, + { FXTomeOfPower, NULL }, + { FXFireOnEntity, NULL }, + { FXFlareup, PreCacheFlareup }, + { FXShrinePlayerEffect, PreCacheShrine }, + { FXShrineManaEffect, NULL }, + { FXShrineLungsEffect, NULL }, + { FXShrineLightEffect, NULL }, + { FXShrineReflectEffect, NULL }, + { FXShrineArmorEffect, NULL }, + { FXShrineHealthEffect, NULL }, + { FXShrineStaffEffect, NULL }, + { FXShrineGhostEffect, NULL }, + { FXShrineSpeedEffect, NULL }, + { FXShrinePowerUpEffect, NULL }, + { FXRope, PreCacheRope }, + { FXFireHands, NULL }, + { FXShrineBall, NULL }, + { FXShrineBallExplode, NULL }, + { FXOgleHitPuff, PrecacheOgleHitPuff }, + { FXHPMissile, PreCacheHPMissile }, + { FXIEffects, PreCacheIEffects }, + { FXChickenExplode, NULL}, + { FXFlamethrower, NULL}, + { FXTeleportPad, NULL}, // 110 fx to here + { FXQuake, NULL }, //FX_QUAKE + { FXLightning, PreCacheLightning}, + { FXPowerLightning, PreCacheLightning}, + { FXBubble, PreCacheBubbler}, + { FXTPortSmoke, PreCacheTPortSmoke }, //FX_TPORTSMOKE - 117 + { FXWaterParticles, PreCacheWaterParticles }, //FX_WATER_PARTICLES - 119 + { FXMEffects, PreCacheMEffects}, //FX_M_EFFECTS - 120 - all of Morcalavin's effects + { FXHPStaff, PreCacheHPStaff}, //FX_HP_STAFF - 121 - staff effects for the high priestess + { FXRandWaterBubble, NULL}, + { FXMagicPortal, PreCachePortal}, + { FXTBEffects, PreCacheTB}, //FX_TB_EFFECTS - 124 + { FXTestBBox, NULL}, + { FXBodyPart, NULL },//FX_THROWWEAPON - uses body part, which just detects type for certain things - 126!!! + { FXSsithraArrow, PrecacheSsithraArrow }, + { FXPESpell, PrecachePESpell }, + { FXLightningHit, PreCacheHitPuff }, // FX_LIGHTNING_HIT + { NullEffect, NULL }, // FX_FOOTSTEP, //114// Unimplemented fx + { NullEffect, NULL }, // FX_FALLSHORT, //115// Unimplemented fx + { FXStaffStrike, PreCacheStaffHit }, + { FXCreateArmorHit, PreCacheArmorHit}, + { FXBarrelExplode, PreCacheObjects}, + { FXCWatcherEffects, PreCacheCWModels}, + { FXCorpseRemove, PreCacheCrosshair}, // naughty little hack here, crosshair has nothing to do with corpse removal + { FXLeader, NULL}, +}; + +CE_ClassStatics_t classStatics[NUM_CLASSIDS]; + +void (*classStaticsInits[NUM_CLASSIDS])()= +{ + InitDebrisStatics +}; + +void NullEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ +} + +void RemoveEffects(centity_t *owner, int type, int flags, vec3_t origin) +{ + short fx; + + assert(owner); +// assert(owner->effects); // FIXME: This assert fires, but it should not. We shouldn't be here anyway. + + fxi.GetEffect(owner, flags, "s", &fx); + RemoveEffectTypeList(&owner->effects, fx, owner); +} + +// *************************************************************************************** +// Client Sounds +// *************************************************************************************** + +void RegisterSounds() +{ +} + +// *************************************************************************************** +// Client Models +// *************************************************************************************** + +void RegisterModels() +{ + int i; + + for(i = 0; i < NUM_FX; i++) + { + if(clientEffectSpawners[i].PrecacheCFX) + { + clientEffectSpawners[i].PrecacheCFX(); + } + } +} + +float cl_turbsin[] = +{ + 0, 0.19633, 0.392541, 0.588517, 0.784137, 0.979285, 1.17384, 1.3677, + 1.56072, 1.75281, 1.94384, 2.1337, 2.32228, 2.50945, 2.69512, 2.87916, + 3.06147, 3.24193, 3.42044, 3.59689, 3.77117, 3.94319, 4.11282, 4.27998, + 4.44456, 4.60647, 4.76559, 4.92185, 5.07515, 5.22538, 5.37247, 5.51632, + 5.65685, 5.79398, 5.92761, 6.05767, 6.18408, 6.30677, 6.42566, 6.54068, + 6.65176, 6.75883, 6.86183, 6.9607, 7.05537, 7.14579, 7.23191, 7.31368, + 7.39104, 7.46394, 7.53235, 7.59623, 7.65552, 7.71021, 7.76025, 7.80562, + 7.84628, 7.88222, 7.91341, 7.93984, 7.96148, 7.97832, 7.99036, 7.99759, + 8, 7.99759, 7.99036, 7.97832, 7.96148, 7.93984, 7.91341, 7.88222, + 7.84628, 7.80562, 7.76025, 7.71021, 7.65552, 7.59623, 7.53235, 7.46394, + 7.39104, 7.31368, 7.23191, 7.14579, 7.05537, 6.9607, 6.86183, 6.75883, + 6.65176, 6.54068, 6.42566, 6.30677, 6.18408, 6.05767, 5.92761, 5.79398, + 5.65685, 5.51632, 5.37247, 5.22538, 5.07515, 4.92185, 4.76559, 4.60647, + 4.44456, 4.27998, 4.11282, 3.94319, 3.77117, 3.59689, 3.42044, 3.24193, + 3.06147, 2.87916, 2.69512, 2.50945, 2.32228, 2.1337, 1.94384, 1.75281, + 1.56072, 1.3677, 1.17384, 0.979285, 0.784137, 0.588517, 0.392541, 0.19633, + 9.79717e-16, -0.19633, -0.392541, -0.588517, -0.784137, -0.979285, -1.17384, -1.3677, + -1.56072, -1.75281, -1.94384, -2.1337, -2.32228, -2.50945, -2.69512, -2.87916, + -3.06147, -3.24193, -3.42044, -3.59689, -3.77117, -3.94319, -4.11282, -4.27998, + -4.44456, -4.60647, -4.76559, -4.92185, -5.07515, -5.22538, -5.37247, -5.51632, + -5.65685, -5.79398, -5.92761, -6.05767, -6.18408, -6.30677, -6.42566, -6.54068, + -6.65176, -6.75883, -6.86183, -6.9607, -7.05537, -7.14579, -7.23191, -7.31368, + -7.39104, -7.46394, -7.53235, -7.59623, -7.65552, -7.71021, -7.76025, -7.80562, + -7.84628, -7.88222, -7.91341, -7.93984, -7.96148, -7.97832, -7.99036, -7.99759, + -8, -7.99759, -7.99036, -7.97832, -7.96148, -7.93984, -7.91341, -7.88222, + -7.84628, -7.80562, -7.76025, -7.71021, -7.65552, -7.59623, -7.53235, -7.46394, + -7.39104, -7.31368, -7.23191, -7.14579, -7.05537, -6.9607, -6.86183, -6.75883, + -6.65176, -6.54068, -6.42566, -6.30677, -6.18408, -6.05767, -5.92761, -5.79398, + -5.65685, -5.51632, -5.37247, -5.22538, -5.07515, -4.92185, -4.76559, -4.60647, + -4.44456, -4.27998, -4.11282, -3.94319, -3.77117, -3.59689, -3.42044, -3.24193, + -3.06147, -2.87916, -2.69512, -2.50945, -2.32228, -2.1337, -1.94384, -1.75281, + -1.56072, -1.3677, -1.17384, -0.979285, -0.784137, -0.588517, -0.392541, -0.19633, +}; +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/Client Effects.def b/Toolkit/Programming/GameCode/client effects/Client Effects.def new file mode 100644 index 0000000..02afe6f --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Client Effects.def @@ -0,0 +1,2 @@ +EXPORTS + GetfxAPI diff --git a/Toolkit/Programming/GameCode/client effects/Client Effects.dsp b/Toolkit/Programming/GameCode/client effects/Client Effects.dsp new file mode 100644 index 0000000..4e15684 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Client Effects.dsp @@ -0,0 +1,699 @@ +# Microsoft Developer Studio Project File - Name="Client Effects" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=Client Effects - 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 "Client Effects.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 "Client Effects.mak" CFG="Client Effects - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Client Effects - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Client Effects - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Client Effects - Win32 Final" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Heretic2/Code/Client Effects", TNFAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Client Effects - 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 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /Zi /O2 /I "../client" /I "../qcommon" /I "../game" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_HERETIC2_" /D "_DEVEL" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /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 /dll /machine:I386 +# ADD LINK32 winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib H2Common.lib quake2.lib /nologo /base:"0x110e0000" /version:1.0 /subsystem:windows /dll /profile /debug /machine:I386 /libpath:"../Release" + +!ELSEIF "$(CFG)" == "Client Effects - 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 /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /Gi /Zi /Od /I "../client" /I "../qcommon" /I "../game" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_HERETIC2_" /D "_DEVEL" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /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 /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib H2Common.lib quake2.lib /nologo /base:"0x110e0000" /version:1.0 /subsystem:windows /dll /debug /machine:I386 /libpath:"../Debug" +# SUBTRACT LINK32 /pdb:none /incremental:no /map + +!ELSEIF "$(CFG)" == "Client Effects - Win32 Final" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Client_Effects___Win32_Final" +# PROP BASE Intermediate_Dir "Client_Effects___Win32_Final" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\Final" +# PROP Intermediate_Dir ".\Final" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /Zi /O2 /I "../client" /I "../qcommon" /I "../game" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_HERETIC2_" /FR /YX /FD /c +# ADD CPP /nologo /MT /W3 /O2 /I "../client" /I "../qcommon" /I "../game" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_HERETIC2_" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /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 winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib H2Common.lib quake2.lib /nologo /version:1.0 /subsystem:windows /dll /profile /debug /machine:I386 /libpath:"../Release" +# ADD LINK32 winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib H2Common.lib quake2.lib /release /nologo /base:"0x110e0000" /version:1.0 /subsystem:windows /dll /machine:I386 /out:"..\base/Client Effects.dll" /libpath:"../Final" +# SUBTRACT LINK32 /profile /debug + +!ENDIF + +# Begin Target + +# Name "Client Effects - Win32 Release" +# Name "Client Effects - Win32 Debug" +# Name "Client Effects - Win32 Final" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c" +# Begin Source File + +SOURCE=".\Ambient Effects.c" +# End Source File +# Begin Source File + +SOURCE=.\ce_DefaultMessageHandler.c +# End Source File +# Begin Source File + +SOURCE=.\ce_DLight.c +# End Source File +# Begin Source File + +SOURCE=.\ce_Message.c +# End Source File +# Begin Source File + +SOURCE=".\Client Effects.c" +# End Source File +# Begin Source File + +SOURCE=".\Client Entities.c" +# End Source File +# Begin Source File + +SOURCE=.\fx_AmmoPickup.c +# End Source File +# Begin Source File + +SOURCE=.\fx_animate.c +# End Source File +# Begin Source File + +SOURCE=.\fx_assassin.c +# End Source File +# Begin Source File + +SOURCE=.\fx_blood.c +# End Source File +# Begin Source File + +SOURCE=.\fx_BlueRing.c +# End Source File +# Begin Source File + +SOURCE=.\fx_bubbler.c +# End Source File +# Begin Source File + +SOURCE=.\fx_crosshair.c +# End Source File +# Begin Source File + +SOURCE=.\fx_cwatcher.c +# End Source File +# Begin Source File + +SOURCE=.\fx_debris.c +# End Source File +# Begin Source File + +SOURCE=.\fx_DefensePickup.c +# End Source File +# Begin Source File + +SOURCE=.\fx_Dripper.c +# End Source File +# Begin Source File + +SOURCE=.\fx_dust.c +# End Source File +# Begin Source File + +SOURCE=.\fx_dustpuff.c +# End Source File +# Begin Source File + +SOURCE=.\fx_fire.c +# End Source File +# Begin Source File + +SOURCE=.\fx_firehands.c +# End Source File +# Begin Source File + +SOURCE=.\fx_flamethrow.c +# End Source File +# Begin Source File + +SOURCE=.\fx_flyingfist.c +# End Source File +# Begin Source File + +SOURCE=.\fx_Fountain.c +# End Source File +# Begin Source File + +SOURCE=.\fx_halo.c +# End Source File +# Begin Source File + +SOURCE=.\fx_HealthPickup.c +# End Source File +# Begin Source File + +SOURCE=.\fx_HellStaff.c +# End Source File +# Begin Source File + +SOURCE=.\fx_hitpuff.c +# End Source File +# Begin Source File + +SOURCE=.\fx_hpproj.c +# End Source File +# Begin Source File + +SOURCE=.\fx_insectstaff.c +# End Source File +# Begin Source File + +SOURCE=.\fx_lensflare.c +# End Source File +# Begin Source File + +SOURCE=.\fx_lightning.c +# End Source File +# Begin Source File + +SOURCE=.\fx_Maceball.c +# End Source File +# Begin Source File + +SOURCE=.\fx_magicmissile.c +# End Source File +# Begin Source File + +SOURCE=.\fx_meteorbarrier.c +# End Source File +# Begin Source File + +SOURCE=.\fx_mist.c +# End Source File +# Begin Source File + +SOURCE=.\fx_mork.c +# End Source File +# Begin Source File + +SOURCE=.\fx_Morph.c +# End Source File +# Begin Source File + +SOURCE=.\fx_objects.c +# End Source File +# Begin Source File + +SOURCE=.\fx_pespell.c +# End Source File +# Begin Source File + +SOURCE=.\fx_Phoenix.c +# End Source File +# Begin Source File + +SOURCE=.\fx_pickup.c +# End Source File +# Begin Source File + +SOURCE=.\fx_pickuppuzzle.c +# End Source File +# Begin Source File + +SOURCE=.\fx_PlagueMist.c +# End Source File +# Begin Source File + +SOURCE=.\fx_PlagueMistExplode.c +# End Source File +# Begin Source File + +SOURCE=.\fx_portal.c +# End Source File +# Begin Source File + +SOURCE=.\fx_quake.c +# End Source File +# Begin Source File + +SOURCE=.\fx_RedRain.c +# End Source File +# Begin Source File + +SOURCE=.\fx_redrainglow.c +# End Source File +# Begin Source File + +SOURCE=.\fx_remotecamera.c +# End Source File +# Begin Source File + +SOURCE=.\fx_Ripples.c +# End Source File +# Begin Source File + +SOURCE=.\fx_rope.c +# End Source File +# Begin Source File + +SOURCE=.\fx_scorchmark.c +# End Source File +# Begin Source File + +SOURCE=.\fx_shadow.c +# End Source File +# Begin Source File + +SOURCE=.\fx_Shield.c +# End Source File +# Begin Source File + +SOURCE=.\fx_shrine.c +# End Source File +# Begin Source File + +SOURCE=.\fx_smoke.c +# End Source File +# Begin Source File + +SOURCE=.\fx_sound.c +# End Source File +# Begin Source File + +SOURCE=.\fx_sparks.c +# End Source File +# Begin Source File + +SOURCE=.\fx_spellchange.c +# End Source File +# Begin Source File + +SOURCE=.\fx_spellhands.c +# End Source File +# Begin Source File + +SOURCE=.\fx_sphereofannihlation.c +# End Source File +# Begin Source File + +SOURCE=.\fx_spoo.c +# End Source File +# Begin Source File + +SOURCE=.\fx_ssarrow.c +# End Source File +# Begin Source File + +SOURCE=.\fx_ssithra.c +# End Source File +# Begin Source File + +SOURCE=.\fx_staff.c +# End Source File +# Begin Source File + +SOURCE=.\fx_tbeast.c +# End Source File +# Begin Source File + +SOURCE=.\fx_teleport.c +# End Source File +# Begin Source File + +SOURCE=.\fx_tome.c +# End Source File +# Begin Source File + +SOURCE=.\fx_Wall.c +# End Source File +# Begin Source File + +SOURCE=.\fx_waterentrysplash.c +# End Source File +# Begin Source File + +SOURCE=.\fx_waterwake.c +# End Source File +# Begin Source File + +SOURCE=.\fx_WeaponPickup.c +# End Source File +# Begin Source File + +SOURCE=".\Generic Character Effects.c" +# End Source File +# Begin Source File + +SOURCE=".\Generic Weapon Effects.c" +# End Source File +# Begin Source File + +SOURCE=".\Item Effects.c" +# End Source File +# Begin Source File + +SOURCE=.\LevelMaps.c +# End Source File +# Begin Source File + +SOURCE=.\LightStyles.c +# End Source File +# Begin Source File + +SOURCE=.\Main.c +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Message.c +# End Source File +# Begin Source File + +SOURCE=".\Monster Weapon Effects.c" +# End Source File +# Begin Source File + +SOURCE="..\qcommon\NetMsg Read.c" +# End Source File +# Begin Source File + +SOURCE=.\Particle.c +# End Source File +# Begin Source File + +SOURCE=".\Player Effects.c" +# End Source File +# Begin Source File + +SOURCE=.\TestEffect.c +# End Source File +# Begin Source File + +SOURCE=.\Utilities.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h" +# Begin Source File + +SOURCE=".\ambient effects.h" +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Angles.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\anorms.h +# End Source File +# Begin Source File + +SOURCE=..\client\cdaudio.h +# End Source File +# Begin Source File + +SOURCE=.\ce_DefaultMessageHandler.h +# End Source File +# Begin Source File + +SOURCE=.\ce_DLight.h +# End Source File +# Begin Source File + +SOURCE=.\ce_Message.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\cl_strings.h +# End Source File +# Begin Source File + +SOURCE=".\Client Effects.h" +# End Source File +# Begin Source File + +SOURCE=".\Client Entities.h" +# End Source File +# Begin Source File + +SOURCE=..\client\client.h +# End Source File +# Begin Source File + +SOURCE=..\client\console.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\EffectFlags.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\FX.h +# End Source File +# Begin Source File + +SOURCE=.\fx_debris.h +# End Source File +# Begin Source File + +SOURCE=.\fx_dustpuff.h +# End Source File +# Begin Source File + +SOURCE=..\game\g_items.h +# End Source File +# Begin Source File + +SOURCE=..\game\g_itemstats.h +# End Source File +# Begin Source File + +SOURCE=..\game\g_PhysicsInfo.h +# End Source File +# Begin Source File + +SOURCE=..\game\g_playstats.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\GenericUnions.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\H2Common.h +# End Source File +# Begin Source File + +SOURCE=..\client\input.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\items.h +# End Source File +# Begin Source File + +SOURCE=..\client\keys.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\LevelMaps.h +# End Source File +# Begin Source File + +SOURCE=..\game\m_elf.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Matrix.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Message.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\motion.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_types.h +# End Source File +# Begin Source File + +SOURCE=.\Particle.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Placement.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\PrimitiveDisplayHack.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_ClientServer.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_Physics.h +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_Sprite.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_Surface.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_Typedef.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\random.h +# End Source File +# Begin Source File + +SOURCE=..\client\ref.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Reference.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\ResourceManager.h +# End Source File +# Begin Source File + +SOURCE=..\client\screen.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\SinglyLinkedList.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Skeletons.h +# End Source File +# Begin Source File + +SOURCE=..\client\sound.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\timing.h +# End Source File +# Begin Source File + +SOURCE=.\Utilities.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Vector.h +# End Source File +# Begin Source File + +SOURCE=..\client\vid.h +# End Source File +# End Group +# Begin Group "Resources" + +# PROP Default_Filter "def" +# Begin Source File + +SOURCE=".\Client Effects.def" +# End Source File +# End Group +# End Target +# End Project diff --git a/Toolkit/Programming/GameCode/client effects/Client Effects.h b/Toolkit/Programming/GameCode/client effects/Client Effects.h new file mode 100644 index 0000000..31e3297 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Client Effects.h @@ -0,0 +1,255 @@ +#ifndef CLIENT_H +#define CLIENT_H +#include "client.h" +#endif + +extern client_fx_import_t fxi; + +extern cvar_t *r_farclipdist; +extern cvar_t *r_nearclipdist; +extern cvar_t *r_detail; +extern cvar_t *clfx_gravity; +extern cvar_t *fxTest1; +extern cvar_t *fxTest2; +extern cvar_t *fxTest3; +extern cvar_t *fxTest4; +extern cvar_t *cl_timedemo; +extern cvar_t *compass; + +extern qboolean fx_FreezeWorld; + +typedef struct ClientEffect_s +{ + void (*SpawnCFX)(centity_t *owner, int type, int flags, vec3_t origin); + void (*PrecacheCFX)(void); +} ClientEffect_t; + +extern ClientEffect_t clientEffectSpawners[]; + +// *************************************************************************************** +// Client Sounds +// *************************************************************************************** + +extern struct sfx_s *cl_sfx_ric1; +extern struct sfx_s *cl_sfx_ric2; +extern struct sfx_s *cl_sfx_ric3; + +// *************************************************************************************** +// Initialisers for ClassStatics used by client-effects. +// *************************************************************************************** + +extern void InitDebrisStatics(void); +extern void InitWallStatics(void); + +extern float cl_turbsin[]; +// *************************************************************************************** +// Client-effect functions. +// *************************************************************************************** + +void RemoveEffects(centity_t *owner, int type, int flags, vec3_t origin); +void GenericExplosion1(centity_t *owner, int type, int flags, vec3_t origin); +void GenericExplosion2(centity_t *owner, int type, int flags, vec3_t origin); +void WaterSplash(centity_t *owner, int type, int flags, vec3_t origin); +void GenericGibTrail(centity_t *owner, int type, int flags, vec3_t origin); +void FXBlood(centity_t *owner, int type, int flags, vec3_t origin); +void FXBloodTrail(centity_t *owner, int type, int flags, vec3_t origin); +void FXLinkedBlood(centity_t *owner, int type, int flags, vec3_t origin); +void FXGenericSparks(centity_t *owner, int type, int flags, vec3_t origin); +void PlayerTeleportin(centity_t *owner, int type, int flags, vec3_t origin); +void FXHealthPickup(centity_t *owner, int type, int flags, vec3_t origin); +void FXWeaponPickup(centity_t *owner, int type, int flags, vec3_t origin); +void FXDefensePickup(centity_t *owner, int type, int flags, vec3_t origin); +void FXPuzzlePickup(centity_t *owner, int type, int flags, vec3_t origin); +void FXAmmoPickup(centity_t *owner, int type, int flags, vec3_t origin); +void FXFlyingFist(centity_t *owner, int type, int flags, vec3_t origin); +void FXFlyingFistExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXBlueRing(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMeteorBarrier(centity_t *owner, int type, int flags, vec3_t origin); +void FXMeteorBarrierTravel(centity_t *owner, int type, int flags, vec3_t origin); +void FXMeteorBarrierExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXLightningShield(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXSphereOfAnnihilation(centity_t *owner, int type, int flags, vec3_t origin); +void FXSphereOfAnnihilationGlowballs(centity_t *owner, int type, int flags, vec3_t origin); +void FXSphereOfAnnihilationExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXSphereOfAnnihilationPower(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXSpherePlayerExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMagicMissile(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMagicMissileExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXBlast(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXRedRainMissile(centity_t *Owner, int Type, int Flags, vec3_t Origin); +void FXRedRain(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXRedRainGlow(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMaceball(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMaceballBounce(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMaceballExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXPhoenixMissile(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXPhoenixExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMorphMissile(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMorphMissile_initial(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMorphExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXFireWave(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXFireWaveWorm(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXFireBurst(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXRipperExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXWaterEntrySplash(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXWaterRipples(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXWaterWake(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXBubbler(centity_t *Owner, int Type, int Flags, vec3_t Origin); +void FXScorchmark(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXDebris(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXFleshDebris(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShadow(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXAnimate(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXFountain(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXWaterfallBase(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXDripper(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMist(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXPlagueMist(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXPlagueMistExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXSpellHands(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXLensFlare(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXStaff(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXSpoo(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXHalo(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXRemoteCamera(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXHellbolt(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXHellboltExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXHellstaffPower(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXHellstaffPowerBurn(centity_t *owner, int type, int flags, vec3_t origin); +void FXSpellChange(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXStaffCreate(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXStaffCreatePoof(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXStaffRemove(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXDustPuffOnGround(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXFire(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXSound(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXPickup(centity_t *owner, int type, int flags, vec3_t origin); +void FXGenericHitPuff(centity_t *owner, int type, int flags, vec3_t origin); +void FXDust(centity_t *owner, int type, int flags, vec3_t origin); +void FXEnvSmoke(centity_t *owner, int type, int flags, vec3_t origin); +void FXSpooSplat(centity_t *owner, int type, int flags, vec3_t origin); +//void FXSpooSneeze(centity_t *owner, int type, int flags, vec3_t origin); +void FXBodyPart(centity_t *owner,int type,int flags,vec3_t origin); +void PlayerTeleportout(centity_t *owner, int type, int flags, vec3_t origin); +void FXPlayerPersistant(centity_t *owner, int type, int flags, vec3_t origin); +void FXSsithraArrowGlow(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXSsithraArrowMissile(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXSsithraArrowExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXplayertorch(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXTomeOfPower(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXFireOnEntity(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXFlareup(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrinePlayerEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineManaEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineLungsEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineLightEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineSpeedEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineArmorEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineHealthEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineStaffEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineGhostEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineReflectEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrinePowerUpEffect(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXRope(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXFireHands(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXShrineBall(centity_t *owner, int type, int flags, vec3_t origin); +void FXShrineBallExplode(centity_t *owner, int type, int flags, vec3_t origin); +void FXOgleHitPuff(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXHPMissile(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXIEffects(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXChickenExplode(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXTeleportPad(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXTPortSmoke(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXWaterParticles(centity_t *owner, int type, int flags, vec3_t origin); +void FXMEffects(centity_t *owner,int type,int flags,vec3_t origin); +void FXFlamethrower(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXflametest(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXQuake(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXLightning(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXPowerLightning(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXHPStaff(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXRandWaterBubble(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXBubble(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXMagicPortal(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXTBEffects(centity_t *owner,int type,int flags, vec3_t org); +void FXTestBBox(centity_t *Owner,int Type,int Flags,vec3_t Origin); +void FXSsithraArrow(centity_t *owner,int type,int flags, vec3_t org); +void FXPESpell(centity_t *owner,int type,int flags, vec3_t org); +void FXLightningHit(centity_t *owner,int type,int flags, vec3_t org); +void NullEffect(centity_t *owner, int type, int flags, vec3_t origin); +void FXStaffStrike(centity_t *owner, int type, int flags, vec3_t origin); +void FXCreateArmorHit(centity_t *owner,int Type,int Flags,vec3_t Origin); +void FXBarrelExplode(centity_t *owner,int Type,int Flags,vec3_t Origin); +void FXCWatcherEffects(centity_t *owner,int Type,int Flags,vec3_t Origin); +void FXCorpseRemove(centity_t *Owner, int Type, int Flags, vec3_t Origin); +void FXLeader(centity_t *Owner, int Type, int Flags, vec3_t Origin); + + +// client effect used by another client effect - needs its own wrapper +void FXClientScorchmark(vec3_t origin, vec3_t dir); +void FXCrosshair(centity_t *owner, int type, int flags, vec3_t origin); + +void PreCacheDebris(void); +void PreCacheHalos(void); +void PreCacheMist(void); +void PreCacheBluering(void); +void PreCacheDripper(void); +void PreCacheBubbler(void); +void PreCacheHealth(void); +void PreCacheItemWeapons(void); +void PreCacheItemDefense(void); +void PreCachePuzzleItems(void); +void PreCacheItemAmmo(void); +void PreCacheHellstaff(void); +void PreCacheMorph(void); +void PreCachePhoenix(void); +void PreCacheRedrain(void); +void PreCacheRipples(void); +void PreCacheSparks(void); +void PreCacheMaceball(void); +void PreCacheTeleport(void); +void PreCacheSsithraArrow(void); +void PreCacheTorch(void); +void PreCacheFlareup(void); +void PreCacheRockchunks(void); +void PreCacheFist(void); +void PreCacheWall(void); +void PreCacheFlare(void); +void PreCacheArray(void); +void PreCacheMeteor(void); +void PreCacheShield(void); +void PreCachePickup(void); +void PreCacheScorch(void); +void PreCacheSmoke(void); +void PreCacheHands(void); +void PreCacheSphere(void); +void PreCacheSpoo(void); +void PreCacheStaff(void); +void PreCacheWaterSplash(void); +void PreCacheWake(void); +void PreCacheShrine(void); +void PreCacheRope(void); +void PreCacheFXAnimate(void); +void PreCacheHPMissile(void); +void PreCacheIEffects(void); +void PrecacheShadow(void); +void PrecacheOgleHitPuff(void); +void PreCacheTPortSmoke(void); +void PreCacheWaterParticles(void); +void PreCacheMEffects(void); +void PreCacheLightning(void); +void PreCacheHPStaff(void); +void PreCacheTB(void); +void PreCacheSplat(void); +void PrecacheSsithraArrow(void); +void PrecachePESpell(void); +void PreCachePortal(void); +void PreCacheCrosshair(void); +void PreCacheStaffHit(void); +void PreCacheArmorHit(void); +void PreCacheHitPuff(void); +void PreCacheObjects(void); +void PreCacheCWModels(void); + +// end diff --git a/Toolkit/Programming/GameCode/client effects/Client Entities.c b/Toolkit/Programming/GameCode/client effects/Client Entities.c new file mode 100644 index 0000000..64cce57 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Client Entities.c @@ -0,0 +1,644 @@ +// +// Client Entities.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#include "Client Entities.h" +#include "Client Effects.h" +#include "ResourceManager.h" +#include "Particle.h" +#include "FX.h" +#include "Vector.h" +#include "Matrix.h" +#include "Angles.h" +#include "ce_Message.h" +#include "Utilities.h" +#include "Reference.h" +#include "ce_DLight.h" +#include "q_Sprite.h" +#include "g_playstats.h" + +extern int numprocessedparticles; +extern int numrenderedparticles; + +ResourceManager_t EntityMngr; + +void InitEntityMngr() +{ +#define ENTITY_BLOCK_SIZE 196 + + ResMngr_Con(&EntityMngr, sizeof(client_entity_t), ENTITY_BLOCK_SIZE); +} + +void ReleaseEntityMngr() +{ + ResMngr_Des(&EntityMngr); +} + +ResourceManager_t FMNodeInfoMngr; + +void InitFMNodeInfoMngr() +{ +#define FMNODEINFO_BLOCK_SIZE 16 + + ResMngr_Con(&FMNodeInfoMngr, sizeof(fmnodeinfo_t)*MAX_FM_MESH_NODES, FMNODEINFO_BLOCK_SIZE); +} + +void ReleaseFMNodeInfoMngr() +{ + ResMngr_Des(&FMNodeInfoMngr); +} + +client_entity_t *clientEnts = NULL; + +client_entity_t *ClientEntity_new(int type, int flags, vec3_t origin, vec3_t direction, int nextThinkTime) +{ + client_entity_t *newEnt; + + newEnt = ResMngr_AllocateResource(&EntityMngr, sizeof(*newEnt)); + + memset(newEnt, 0, sizeof(*newEnt)); + + SLList_DefaultCon(&newEnt->msgQ.msgs); + + VectorCopy(origin, newEnt->r.origin); + VectorCopy(origin, newEnt->origin); + + if(direction) + { + VectorCopy(direction, newEnt->direction); + + if(newEnt->direction[2] == 0) + { // vertical wall + newEnt->up[0] = 0; + newEnt->up[1] = 0; + newEnt->up[2] = 1; + } + else if(newEnt->direction[0] == 0 && newEnt->direction[1] == 0) + { //ceiling, floor + newEnt->up[0] = 1; + newEnt->up[1] = 0; + newEnt->up[2] = 0; + } + else + { + PerpendicularVector(newEnt->up, newEnt->direction); + } + } + else + { + newEnt->direction[0] = 1.0; + newEnt->direction[1] = 0.0; + newEnt->direction[2] = 0.0; + + newEnt->up[0] = 0; + newEnt->up[1] = 0; + newEnt->up[2] = 1; + } + + // Currently either AnglesFromDirAndUp or PerpendicularVector isn't working properly + // This will need to be fixed at some point. + AnglesFromDirI(newEnt->direction, newEnt->r.angles); +// AnglesFromDirAndUp(newEnt->direction, newEnt->up, newEnt->r.angles); + + newEnt->r.scale = 1.0F; + newEnt->r.color.c = 0xffffffff; + newEnt->alpha = 1.0F; + newEnt->radius = 1.0F; + newEnt->effectID = type; + + newEnt->flags = flags | CEF_CULLED; //added this cos we need to assume every client effect is culled before we do addeffectstoview for the first time + // to make sure the viewstatuschanged fires. + +// assert(nextThinkTime > 16); + newEnt->updateTime = nextThinkTime; + newEnt->nextThinkTime = fxi.cl->time + nextThinkTime; + newEnt->startTime = fxi.cl->time; + newEnt->Update = RemoveSelfAI; + + newEnt->r.swapFrame = -1; + return newEnt; +} + +void ClientEntity_delete(client_entity_t *toDelete, centity_t *owner) +{ + if(toDelete->p_root) + { + RemoveParticleList(&toDelete->p_root); + } + + if(toDelete->dlight) + { + CE_DLight_delete(toDelete->dlight); + } + + if(toDelete->r.fmnodeinfo) + { + ResMngr_DeallocateResource(&FMNodeInfoMngr, toDelete->r.fmnodeinfo, sizeof(fmnodeinfo_t)*MAX_FM_MESH_NODES); + } + + if(owner && toDelete->refMask) + { + DisableRefPoints(owner->referenceInfo, toDelete->refMask); + } + + if(toDelete->r.spriteType == SPRITE_VARIABLE) + { + if(toDelete->r.verts_p) + { + free(toDelete->r.verts_p); + } + } + + ClearMessageQueue(toDelete); + + SLList_Des(&toDelete->msgQ.msgs); + + ResMngr_DeallocateResource(&EntityMngr, toDelete, sizeof(*toDelete)); +} + +fmnodeinfo_t *FMNodeInfo_new() +{ + return ResMngr_AllocateResource(&FMNodeInfoMngr, sizeof(fmnodeinfo_t)*MAX_FM_MESH_NODES); +} + +void AddEffectToList(client_entity_t **root, client_entity_t *fx) +{ + assert(root); + + fx->next = *root; + *root = fx; +} + +void RemoveEffectFromList(client_entity_t **root, centity_t *owner) +{ + client_entity_t *toFree; + + assert(root); + assert(*root); + + toFree = *root; + + assert(toFree); + + *root = toFree->next; + + ClientEntity_delete(toFree, owner); +} + +void RemoveEffectList(client_entity_t **root) +{ + assert(root); + assert(*root); + + while(*root) + { + RemoveEffectFromList(root, NULL); + } +} + +void RemoveOwnedEffectList(centity_t *owner) +{ + client_entity_t **root; + + root = &owner->effects; + assert(root); + assert(*root); + + while(*root) + { + RemoveEffectFromList(root, owner); + } +} + +// fx = type of effect to remove +// = 0, remove all effects + +void RemoveEffectTypeList(client_entity_t **root, FX_Type_t fx, centity_t *owner) +{ + client_entity_t **prev; + client_entity_t *current; + + assert(root); +// assert(*root); // FIXME: This shouldn't fire, but it does. The result is more or less harmless. + + for(prev = root, current = *root; current; current = current->next) + { + if(!fx || (current->effectID == fx)) + { + RemoveEffectFromList(prev, owner); + continue; + } + prev = &(*prev)->next; + } +} + +vec3_t viewDir; +float viewFOV; + +void PrepAddEffectsToView() +{ + refdef_t *refDef; + + refDef = &fxi.cl->refdef; + + if(refDef->fov_x > refDef->fov_y) + { + viewFOV = cos(refDef->fov_x*0.5*ANGLE_TO_RAD*1.2); + } + else + { + viewFOV = cos(refDef->fov_y*0.5*ANGLE_TO_RAD*1.2); + } + + AngleVectors (refDef->viewangles, viewDir, NULL, NULL); +} + +int AddEffectsToView(client_entity_t **root, centity_t *owner) +{ + client_entity_t *current; + vec3_t dir; + int numFX = 0; + + cl_camera_under_surface = Cvar_Get( "cl_camera_under_surface", "0", 0 ); + + assert(root); + assert(*root); + + for(current = *root; current; current = current->next) + { + float dot; + float dist; + + current->flags |= CEF_CULLED; + // if we have a light, particles, a model, a potential routine that will change our think function, and we aren't disappeared, + // determing if we should be culled or not. + if(current->dlight || current->p_root || current->r.model + || (!(current->flags & (CEF_DISAPPEARED ))) || (current->flags & CEF_VIEWSTATUSCHANGED)) + { + // do this here since we do have an owner, and most probably we are tied to its origin, and we need that to do the proper culling routines + if(owner && current->AddToView) + { + current->AddToView(current, owner); + } + + VectorSubtract(current->r.origin, fxi.cl->refdef.vieworg, dir); + + current->r.depth = dist = VectorNormalize(dir); + + if(dist > r_farclipdist->value) + { + continue; + } + + if(r_detail->value == DETAIL_LOW && dist < r_nearclipdist->value && !current->p_root && !current->dlight)//not a particle thing and not a dlight thing + { + continue; + } + dot = DotProduct(dir, viewDir); + } + else + { + continue; // has nothing to add to view + } + + if(current->dlight) + { + CE_DLight_t *ce_dlight = current->dlight; + + if (fxi.cls->r_numdlights < MAX_DLIGHTS) + { + if(ce_dlight->intensity > 0.0) + { + if((dot + (ce_dlight->intensity*ce_dlight->intensity)/(dist*300.0f)) > viewFOV) // 300.0 was determined by trial and error with intensities of 200 and 400 + { + dlight_t *dl; + + dl = &fxi.cls->r_dlights[fxi.cls->r_numdlights++]; + + VectorCopy (current->r.origin, dl->origin); + + dl->intensity = ce_dlight->intensity; + + dl->color.r = ce_dlight->color.r; + dl->color.g = ce_dlight->color.g; + dl->color.b = ce_dlight->color.b; + } + } + } + } + + // if no part of our radius is in the field of view or we aren't within the current PVS, cull us. + if(((dot + (current->radius/dist)) < viewFOV) || !(fxi.InCameraPVS(current->r.origin)) || + // if we have an owner, and its server culled, and we want to check against it then do so + (owner && (owner->flags & CF_SERVER_CULLED) && (current->flags & CEF_CHECK_OWNER))) + { + continue; + } + + // we do this here cos we don't have an owner - only do the update if we haven't already been culled. + if(!owner && current->AddToView) + { + current->AddToView(current, owner); + } + + ++numFX; + current->flags &= ~CEF_CULLED; + + if(current->p_root) // add any particles + { + numrenderedparticles += AddParticlesToView(current); + } + + if(!(current->flags & (CEF_NO_DRAW | CEF_DISAPPEARED))) + { + if(current->alpha < 0) + { // wacky all colors at minimum, but drawn at max instead for addative transparent sprites + current->alpha = 0.0F; + } + + current->r.color.a = Q_ftol(current->alpha * 255.0); + + if(current->r.color.a && (current->r.scale > 0.0)) + { + if(!AddEntityToView(¤t->r)) + { + current->flags |= CEF_DROPPED; + } + } + else + { + current->flags |= CEF_DISAPPEARED; + } + } + } + return numFX; +} + +void AddEffect(centity_t *owner, client_entity_t *fx) +{ + if(owner) + { + AddEffectToList(&owner->effects, fx); + if(owner->referenceInfo && fx->refMask) + { + EnableRefPoints(owner->referenceInfo, fx->refMask); + } + } + else + { + AddEffectToList(&clientEnts, fx); + } + + // copy up the scale on a model so it can be culled properly + fx->r.cl_scale = fx->r.scale; +} + +#define NUM_TRACES 100 // I really, really hope we don't ever see more than this + +int UpdateEffects(client_entity_t **root, centity_t *owner) +{ + extern int ParticleUpdateTime; + + client_entity_t **prev; + client_entity_t *current; + entity_t *r; + float d_time = fxi.cls->frametime; + float d_time2 = d_time * d_time * 0.5; + static trace_t traces[NUM_TRACES]; + static trace_t traces2[NUM_TRACES]; + static qboolean useOtherTraces = false; + trace_t *trace; + int curTrace = 0; + int numFX = 0; + int curTime = fxi.cl->time; + + assert(root); + assert(*root); + + // If the world is frozen then add the particles, just don't update the world time. + // Always update the particle timer + if (!fx_FreezeWorld) + { + ParticleUpdateTime = fxi.cl->time; + } + + if(!useOtherTraces) + { + trace = traces; + } + else + { + trace = traces2; + } + + useOtherTraces = !useOtherTraces; + + for(prev = root, current = *root; current; current = current->next) + { + numFX++; + + if(current->msgHandler) + { + ProcessMessages(current); + } + + if(current->Update) + { + if(current->nextThinkTime <= curTime) + { + // Only think when not culled and not think culled + if(!((current->flags & CEF_VIEWSTATUSCHANGED) && (current->flags & CEF_CULLED))) + { + if(!current->Update(current, owner)) + { + RemoveEffectFromList(prev, owner); + // current = current->next is still valid in the for loop. + // a deallocated resource is guaranteed not to be changed until it is + // reallocated, when the mananger is not shared between threads + continue; + } + } + assert(current->updateTime > 16); + current->nextThinkTime = curTime + current->updateTime; + } + } + + r = ¤t->r; + + if(!(current->flags & (CEF_NO_DRAW|CEF_DISAPPEARED))) + { + float d_size; + + d_size = d_time * current->d_scale; + + current->radius *= (1 + d_size/r->scale); + + r->scale += d_size; + + // Apply scale to spritelines as appropriate. + if (current->r.spriteType == SPRITE_LINE) + { + // Either copy the scale to scale2, or use the d_scale2. + if (current->flags & CEF_USE_SCALE2) + { // Use the second scale + d_size = d_time * current->d_scale2; + r->scale2 += d_size; + } + else + { // Otherwise the second scale is copied from the first. + r->scale2 = r->scale; + } + } + + current->alpha += d_time * current->d_alpha; + + if (current->d_alpha > 0 && current->alpha >= 1.0) + { + current->alpha = 0.99; + if (current->flags & CEF_PULSE_ALPHA) + { // If these effects are increasing alpha, reverse and decrease with the PULSE_ALPHA flag. + current->d_alpha = -current->d_alpha; + } + else + { + current->d_alpha = 0.0; + } + } + } + + if(current->dlight) + { + current->dlight->intensity += (d_time * current->dlight->d_intensity); + } + if(current->p_root) + { + numprocessedparticles += UpdateParticles(current); + } + + if(!(current->flags & CEF_NOMOVE)) + { + if(!owner || (current->flags&CEF_DONT_LINK)) + { + if(current->flags & CEF_CLIP_TO_WORLD) + { + if(curTrace < NUM_TRACES - 1) // leave one at the end to continue checking collisions + { + if(Physics_MoveEnt(current, d_time, d_time2, trace)) + { // collided with something + ++trace; + ++curTrace; + } + } + else + { + Com_DPrintf("Max Client Collisions exceeded by %d\n", curTrace - (NUM_TRACES - 1)); + ++curTrace; + } + } + else + { + if (current->r.spriteType != SPRITE_LINE) + { // Update origin velocity based on acceleration. + r->origin[0] += current->velocity[0] * d_time + current->acceleration[0] * d_time2; + r->origin[1] += current->velocity[1] * d_time + current->acceleration[1] * d_time2; + r->origin[2] += current->velocity[2] * d_time + current->acceleration[2] * d_time2; + + current->velocity[0] += current->acceleration[0] * d_time; + current->velocity[1] += current->acceleration[1] * d_time; + current->velocity[2] += current->acceleration[2] * d_time; + } + else + { // Update the startpos and endpos velocity, then worry about the entity origin. + vec3_t dpos, dvel, d2vel; + + VectorScale(current->velocity, d_time, dpos); // velocity*dt + VectorScale(current->acceleration, d_time, dvel); // acceleration*dt + VectorScale(current->acceleration, d_time2, d2vel); // acceleration*dt^2 + + VectorAdd(r->startpos, dpos, r->startpos); + VectorAdd(r->startpos, d2vel, r->startpos); // Calculate change in startpos + VectorAdd(current->velocity, dvel, current->velocity); // Calculate change in velocity + + // First, if we don't have auto origin flagged, we want to apply the velocity & such to the origin. + if (!(current->flags & CEF_AUTO_ORIGIN)) + { + VectorAdd(r->origin, dpos, r->origin); + VectorAdd(r->origin, d2vel, r->origin); // Calculate change in origin. Sync with startpos. + } + // else wait until the endpos is calculated, then update the origin. + + // Now, check to see if the endpos should use the same information, or maintain its own velocity. + if (!(current->flags & CEF_USE_VELOCITY2)) + { + VectorAdd(r->endpos, dpos, r->endpos); + VectorAdd(r->endpos, d2vel, r->endpos); // Calculate change in endpos + } + else + { // Figure out totally seperate changes + VectorScale(current->velocity2, d_time, dpos); // velocity2*dt + VectorScale(current->acceleration2, d_time, dvel); // acceleration2*dt + VectorScale(current->acceleration2, d_time2, d2vel); // acceleration2*dt^2 + + VectorAdd(r->endpos, dpos, r->endpos); + VectorAdd(r->endpos, d2vel, r->endpos); // Calculate change in endpos + VectorAdd(current->velocity2, dvel, current->velocity2); // Calculate change in velocity2 + } + + // Now, if the AUTOORIGIN flag was set, then we haven't updated the origin yet. Do it now. + if (current->flags & CEF_AUTO_ORIGIN) + { + VectorAdd(r->startpos, r->endpos, r->origin); // Get a midpoint by + VectorScale(r->origin, 0.5, r->origin); // averaging out the startpos and endpos. + } + } + } + } + } + + prev = &(*prev)->next; + } + + return numFX; +} + +qboolean AddEntityToView(entity_t *ent) +{ + if (!ent->model || !*ent->model) + { + Com_DPrintf ("AddEntityToView: NULL Model\n"); + } + if((ent->flags & RF_TRANS_ADD) && (ent->flags & RF_ALPHA_TEXTURE)) + { + Com_DPrintf ("AddEntityToView: Cannot have additive alpha mapped image. UNSUPPORTED !!\n"); + } + + if((ent->flags & RF_TRANS_ANY) || (ent->color.a != 255)) + { + if(fxi.cls->r_num_alpha_entities < MAX_ALPHA_ENTITIES) + { + fxi.cls->r_alpha_entities[fxi.cls->r_num_alpha_entities++] = ent; + } + else + { + return false; + } + } + else + { + if(fxi.cls->r_numentities < MAX_ENTITIES) + { + fxi.cls->r_entities[fxi.cls->r_numentities++] = ent; + } + else + { + return false; + } + } + + return true; +} +// end diff --git a/Toolkit/Programming/GameCode/client effects/Client Entities.h b/Toolkit/Programming/GameCode/client effects/Client Entities.h new file mode 100644 index 0000000..2d76b8b --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Client Entities.h @@ -0,0 +1,170 @@ +#ifndef CLIENT_ENTITIES_H +#define CLIENT_ENTITIES_H + +#ifndef CLIENT_H +#define CLIENT_H +#include "client.h" +#endif + +#include "Message.h" +#include "ce_Message.h" + +typedef enum ClassID_e +{ + CID_DEBRIS = 0, + NUM_CLASSIDS +} ClassID_t; + +typedef struct CE_ClassStatics_s +{ + CE_MsgReceiver_t msgReceivers[NUM_MESSAGES]; +} CE_ClassStatics_t; + +typedef qboolean (*UpdateEffect_t)(struct client_entity_s *this, centity_t *owner); + +typedef struct client_entity_s +{ + MsgQueue_t msgQ; + CE_MessageHandler_t msgHandler; + + int classID; + + entity_t r; // ends up being sent to the renderer + + struct client_entity_s *next; // next client entity, if any + + // Note: Since a client_entity's origin (inside the entity e field) is + // controled soley by it's velocity and acceleration, it doesn't need to + // have it's orign lerped by the renderer. + + vec3_t origin; // Used by (non-world) effects that + // have an owning centity_t. + + vec3_t velocity; + vec3_t acceleration; + + union { + vec3_t direction; + vec3_t startpos; + }; + + union { + vec3_t up; + vec3_t right; // This means you can't have a right AND up, but both usually aren't needed.. + vec3_t endpos; + }; + + float radius; // used to cull objects, 0 is a point object, values + // greater than 0 are increasing less likely to be culled + + float d_scale; // also affects the radius as well as r.scale + // if d_scale causes r.scale to become <= 0 + // the CEF_DISAPPEARED will be set, and the effect + // will no longer be added to the render list + // If at a later time, scale is set positive and + // CEF_DISAPPEARED is disabled, the radius will have to + // be reset as well. + + float alpha; // r.color.a is set directly from this + // a float is needed so small d_alpha at high frame + // rate aren't lost completly due to rounding + + float d_alpha; + + int effectID; + + int flags; + + int startTime; // time the client_entity_t was + // created + + int nextThinkTime; // next time Update will be run + int updateTime; + + UpdateEffect_t Update; // run every nextThinkTime, if it + // returns false the entity will be + // removed + + UpdateEffect_t AddToView; // run everytime the entity is added to the view + // if it returns false, the entity will not be added + // to the view (it won't be removed though) + + // light stuff + struct CE_DLight_s *dlight; + + // particle stuff + paletteRGBA_t color; // used to set the color of spawned particles in some cases + + struct client_particle_s *p_root; // root of particle list + + // For models only - NOTE - DO NOT UNION THESE - they are used internally + short refMask; // Current refpoints attached to client entity + short refPoint; // used for entites linked to one of another models + + // anim stuff // For CE spawners + + union { + int LifeTime; + int nextEventTime; // For user timed stuff. + }; + + union { + float Scale; + int SpawnDelay; + float elasticity; + float xscale; + }; + + union { + float AnimSpeed; + float SpawnData; + int lastThinkTime; // last time updated + float yscale; + }; + + union { + int NoOfAnimFrames; + int SpawnInfo; + float yaw; + }; + + // For spritelines + float d_scale2; // Delta Scale of the second line endpoint. Needs CEF_USE_SCALE2 flag. + + // sprite line data + union { + struct { // For lines that use interpolation + vec3_t startpos2; + vec3_t endpos2; + }; + struct { + vec3_t velocity2; // For lines that need seperate vel and acceleration on the second point + vec3_t acceleration2; + }; + }; + + void *extra; // extra whatever +} client_entity_t; + +extern client_entity_t *clientEnts; +extern CE_ClassStatics_t classStatics[NUM_CLASSIDS]; + +client_entity_t *ClientEntity_new(int type, int flags, vec3_t origin, vec3_t direction, int nextThinkTime); +fmnodeinfo_t *FMNodeInfo_new(); +void AddEffectToList(client_entity_t **root, client_entity_t *fx); +void RemoveEffectList(client_entity_t **root); +void RemoveOwnedEffectList(centity_t *owner); +void RemoveEffectTypeList(client_entity_t **root, enum FX_Type_e, centity_t *owner); +void RemoveEffectsFromCent(centity_t *cent); +void PrepAddEffectsToView(); +int AddEffectsToView(client_entity_t **root, centity_t *owner); +void AddEffect(centity_t *owner, client_entity_t *fx); +int UpdateEffects(client_entity_t **root, centity_t *owner); +qboolean AddEntityToView(entity_t *ent); +void InsertInCircularList(client_entity_t *self); + +#define MAX_ENTRIES_IN_CIRCLE_LIST 70 +extern client_entity_t *CircularList[MAX_ENTRIES_IN_CIRCLE_LIST + 1]; +extern int total_circle_entries; + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/Final/vc60.idb b/Toolkit/Programming/GameCode/client effects/Final/vc60.idb new file mode 100644 index 0000000..74e2584 Binary files /dev/null and b/Toolkit/Programming/GameCode/client effects/Final/vc60.idb differ diff --git a/Toolkit/Programming/GameCode/client effects/Generic Character Effects.c b/Toolkit/Programming/GameCode/client effects/Generic Character Effects.c new file mode 100644 index 0000000..bff9acd --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Generic Character Effects.c @@ -0,0 +1,668 @@ +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "ce_Dlight.h" +#include "Utilities.h" + +extern void MakeBubble(vec3_t loc, client_entity_t *spawner); + +#define NUM_GENFX_MODELS 6 +static struct model_s *genfx_models[NUM_GENFX_MODELS]; +void PrecacheOgleHitPuff() +{ + genfx_models[0] = fxi.RegisterModel("sprites/fx/steam_add.sp2"); + genfx_models[1] = fxi.RegisterModel("models/debris/stone/schunk1/tris.fm"); + genfx_models[2] = fxi.RegisterModel("models/debris/stone/schunk2/tris.fm"); + genfx_models[3] = fxi.RegisterModel("models/debris/stone/schunk3/tris.fm"); + genfx_models[4] = fxi.RegisterModel("models/debris/stone/schunk4/tris.fm"); + genfx_models[5] = fxi.RegisterModel("sprites/fx/halo.sp2"); +} + +#define NUM_WATERPART_MODELS 1 +static struct model_s *WaterParticle_models[NUM_WATERPART_MODELS]; +#define NUM_COMPASS_MODELS 1 +static struct model_s *compass_models[NUM_COMPASS_MODELS]; +void PreCacheWaterParticles() +{ + WaterParticle_models[0] = fxi.RegisterModel("sprites/lens/flare3.sp2"); + compass_models[0] = fxi.RegisterModel("sprites/fx/compass.sp2"); +} + +// ----------------------------------------------------------------------------------------- + +#define PARTICLE_TRAIL_PUFF_TIME 1000 // puff's last for 1 sec + +qboolean ParticleTrailAI(client_entity_t *this, centity_t *owner) +{ + client_entity_t *effect; + client_particle_t *p; + int i; + + assert(owner); + + effect = ClientEntity_new(FX_PUFF, CEF_NO_DRAW, owner->current.old_origin, NULL, PARTICLE_TRAIL_PUFF_TIME); + + effect->flags |= CEF_NO_DRAW; + + for(i = 0; i < 40; i++) + { + p = ClientParticle_new(PART_4x4_WHITE, this->color, PARTICLE_TRAIL_PUFF_TIME); + p->velocity[0] = flrand(-20.0F, 20.0F); + p->velocity[1] = flrand(-20.0F, 20.0F); + p->velocity[2] = flrand(30.0F, 80.0F); + AddParticleToList(effect, p); + } + + AddEffect(NULL, effect); // add the puff to the world + + return true;// actual puff spawner only goes away when it owner has a + // FX_REMOVE_EFFECTS sent on it +} + +void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, qboolean gib); + +void GenericGibTrail(centity_t *owner, int type, int flags, vec3_t origin) +{ + qboolean ParticleTrailAI(client_entity_t *this, centity_t *owner); + + client_entity_t *effect; + + effect = ClientEntity_new(type, flags, origin, NULL, PARTICLE_TRAIL_THINK_TIME); + + effect->flags |= CEF_NO_DRAW; + + effect->color.c = 0xFF2020FF; + + effect->Update = ParticleTrailAI; + + assert(owner); + + AddEffect(owner, effect); + + ParticleTrailAI(effect, owner); // think once right away, to spawn the first puff +} + +qboolean PebbleUpdate(struct client_entity_s *self, centity_t *owner) +{ + int curTime = fxi.cl->time; + float d_time = (curTime - self->lastThinkTime) / 1000.0f; + + self->acceleration[2] -= 75; + self->r.angles[0] += ANGLE_360*d_time; + self->r.angles[1] += ANGLE_360*d_time; + + self->lastThinkTime = fxi.cl->time; + + if (curTime > self->LifeTime) + return false; + + return true; +} +//Slight variation on the normal puff +void FXOgleHitPuff(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *effect; + vec3_t dir, work; + byte count; + int i, chance ; + float speed; + + fxi.GetEffect(owner, flags, "v", dir); // normalized direction vector + + speed = VectorNormalize(dir); + if(speed>1.0f) + count = irand(10,15); + else + count = irand(1,4); + + for(i = 0; i < count; i++) + {//puff! + effect = ClientEntity_new(type, flags, origin, NULL, 500); + + effect->r.model = genfx_models; + effect->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + if(speed>1.0f) + { + VectorRandomCopy(dir, work, 0.5); + VectorScale(work, speed, effect->velocity); + effect->acceleration[2] = flrand(10.0, 50.0); + } + else + { + VectorRandomCopy(dir, work, 0.5); + + if (flags & CEF_FLAG6) + { + VectorScale(work, flrand(8.0, 12.0), effect->velocity); + effect->acceleration[2] = flrand(10.0, 50.0); + } + else + { + VectorScale(work, 4.0, effect->velocity); + effect->acceleration[2] = flrand(10.0, 50.0); + } + } + + effect->alpha = 0.35; + if(speed>1) + effect->r.scale = flrand(0.3, 0.75); + else + effect->r.scale = 0.1; + effect->d_scale = 2.0; + effect->d_alpha = -2.0; + effect->color.c = 0xFFFFFFFF; + + AddEffect(NULL, effect); // add the effect as independent world effect + } + + for(i = 0; i < count; i++) + {//ROCK! + effect = ClientEntity_new(type, flags, origin, NULL, 50); + + chance = irand(0,3); + + switch(chance) + { + case 0: + effect->r.model = genfx_models + 1; + break; + case 1: + effect->r.model = genfx_models + 2; + break; + case 2: + effect->r.model = genfx_models + 3; + break; + case 3: + effect->r.model = genfx_models + 4; + break; + } + + if(speed>1.0f) + { + VectorRandomCopy(dir, work, 0.5); + VectorScale(work, speed, effect->velocity); + } + else + { + VectorRandomCopy(dir, work, 0.5); + VectorScale(work, flrand(8.0, 16.0), effect->velocity); + } + + if (flags & CEF_FLAG6 || speed > 1.0f) + { + effect->acceleration[0] += flrand(-75.0, 75.0); + effect->acceleration[1] += flrand(-75.0, 75.0); + effect->acceleration[2] = flrand(125.0, 250.0); + } + else + effect->acceleration[2] = flrand(-50.0, 50.0); + + effect->Update = PebbleUpdate; + effect->alpha = 1.0; + if(speed>1) + effect->r.scale = flrand(0.8, 1.5) * speed/100; + else + effect->r.scale = flrand(0.1, 0.25); + effect->d_scale = 0.0; + effect->d_alpha = 0.0; + effect->color.c = 0xFFFFFFFF; + effect->LifeTime = fxi.cl->time + 5000; + + AddEffect(NULL, effect); // add the effect as independent world effect + } +} + +void FXGenericHitPuff(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *effect; + vec3_t dir, work; + byte count; + int i; + + fxi.GetEffect(owner, flags, "db", dir, &count); // normalized direction vector + + if (count>40) + count=40; + + for(i = 0; i < count; i++) + { + effect = ClientEntity_new(type, flags, origin, NULL, 500); + + effect->r.model = genfx_models; + + effect->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + VectorRandomCopy(dir, work, 0.5); + VectorScale(work, 50.0, effect->velocity); + effect->acceleration[2] = -100.0; + effect->alpha = 0.5; + effect->r.scale = 0.1; + effect->d_scale = 1.0; + effect->d_alpha = -1.0; + effect->color.c = 0xFFFFFFFF; + + AddEffect(NULL, effect); // add the effect as independent world effect + } + + if (flags & CEF_FLAG6) + { // High-intensity impact point. + effect = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 250); + + effect->r.model = genfx_models + 5; + effect->r.frame = 0; + effect->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + effect->r.scale = 0.4; + effect->alpha = .95; + effect->d_scale = -1.6; + effect->d_alpha = -3.0; // Alpha goes up to 1, then down to zero. + effect->color.c = 0xc0ffffff; + effect->radius = 10.0; + effect->alpha = 0.8; + effect->r.origin[2] += 8.0; + + AddEffect(NULL, effect); + } +} + +// ----------------------------------------- + +#define SINEAMT 1 +#define SINESCALE (256.0 / (2 * M_PI)) +#define WATER_DENSITY 150.0 +#define WATER_DIST 100.0 +#define WATERPARTICLE_CLIPDIST (WATER_DIST * WATER_DIST) + +static qboolean water_particles_spawned; + +void SetupWaterParticle(client_particle_t *p, qboolean recycle) +{ + int ishade; + float shade; + vec3_t dist; + + ishade = irand(50, 150); + p->color.r = (byte)ishade; + p->color.g = (byte)ishade; + p->color.b = (byte)ishade; + p->color.a = irand(75, 150); + + shade = ((ishade * 0.04) - 3.1) * 0.35; + + p->velocity[0] = flrand(-1.0F, 1.0F); + p->velocity[1] = flrand(-1.0F, 1.0F); + p->velocity[2] = flrand(shade, 0.0); + + p->acceleration[2] = 0; + p->scale = flrand(0.3, 0.7); + + dist[0] = flrand(-WATER_DIST, WATER_DIST); + dist[1] = flrand(-WATER_DIST, WATER_DIST); + dist[2] = flrand(-WATER_DIST, WATER_DIST); + + // If we are recycling, we want to respawn as far away as possible + if(recycle) + { + VectorNormalize(dist); + Vec3ScaleAssign(WATER_DIST, dist); + } + VectorAdd(fxi.cl->refdef.vieworg, dist, p->origin); +} + +void CreateWaterParticles(client_entity_t *self) +{ + int i; + client_particle_t *p; + + // Scale number of particles by detail level + for(i = 0; i < (WATER_DENSITY * r_detail->value); i++) + { + p = ClientParticle_new(PART_4x4_WHITE | PFL_SOFT_MASK, self->color, 1000000); + + SetupWaterParticle(p, false); + + AddParticleToList(self, p); + } +} + +void UpdateWaterParticles(client_entity_t *self) +{ + client_particle_t *p; + vec3_t part_dist; + float addVal, dist; + + for(p = self->p_root; p; p = p->next) + { + VectorSubtract(p->origin, fxi.cl->refdef.vieworg, part_dist); + dist = VectorLengthSquared(part_dist); + if(dist >= WATERPARTICLE_CLIPDIST) + { + SetupWaterParticle(p, true); + continue; + } + + addVal = SINEAMT/128.0 * cl_turbsin[(int)((fxi.cl->time*0.001 + (self->origin[0] * 2.3 + p->origin[1])*.0015)*SINESCALE) & 255]; + addVal += SINEAMT/256.0 * cl_turbsin[(int)((fxi.cl->time*0.002 + (self->origin[1] * 2.3 + p->origin[0])*.0015)*SINESCALE) & 255]; + + p->origin[2] += addVal; + p->duration = fxi.cl->time + 10000000; + } +} + +qboolean WaterParticleGeneratorUpdate(client_entity_t *self, centity_t *owner) +{ + // Free up particles when we are not under water + if(!cl_camera_under_surface->value) + { + if(water_particles_spawned) + { + FreeParticles(self); + water_particles_spawned = false; + } + } + else + { + if(!water_particles_spawned) + { + CreateWaterParticles(self); + water_particles_spawned = true; + } + UpdateWaterParticles(self); + } + return(true); +} + +qboolean BubbleSpawner(client_entity_t *self, centity_t *owner) +{ + vec3_t org; + + if(!cl_camera_under_surface->value) + return(true); + + // Errr... what the hell, spawn some bubbles too. + VectorSet(org, flrand(-20.0, 20.0), flrand(-20.0 ,20.0), flrand(-20.0 ,20.0)); + VectorAdd(org, owner->origin, org); + MakeBubble(org, self); + + return(true); +} + +void FXWaterParticles(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *effect; + + assert(owner); + + // Spawn static water particle handler + effect = ClientEntity_new(type, flags | CEF_NO_DRAW | CEF_ABSOLUTE_PARTS| CEF_OWNERS_ORIGIN | CEF_VIEWSTATUSCHANGED, origin, NULL, PARTICLE_TRAIL_THINK_TIME); + + effect->AddToView = LinkedEntityUpdatePlacement; + effect->radius = 100.0; + effect->Update = WaterParticleGeneratorUpdate; + + AddEffect(owner, effect); + + // Spawn bubble spawner + effect = ClientEntity_new(type, flags | CEF_NO_DRAW | CEF_ABSOLUTE_PARTS| CEF_OWNERS_ORIGIN | CEF_VIEWSTATUSCHANGED, origin, NULL, PARTICLE_TRAIL_THINK_TIME); + + effect->AddToView = LinkedEntityUpdatePlacement; + effect->radius = 100.0; + effect->Update = BubbleSpawner; + + AddEffect(owner, effect); +} + +int DirectionalUpdate (client_entity_t *self, centity_t *owner) +{ + float addVal; + paletteRGBA_t color = {255, 128, 128, 128}; + client_particle_t *part; + + if(!compass->value) + { + self->updateTime = 2000; + self->flags |= CEF_NO_DRAW; + RemoveParticleList(&self->p_root); + return (true); + } + + self->flags &= ~CEF_NO_DRAW; + + VectorAdd(owner->lerp_origin, self->startpos, self->r.origin); + + addVal = SINEAMT/2.0 * cl_turbsin[(int)((fxi.cl->time*0.001 + (self->r.origin[0] * 2.3 + self->startpos[1])*.0015)*SINESCALE) & 255]; + addVal += SINEAMT/4.0 * cl_turbsin[(int)((fxi.cl->time*0.002 + (self->r.origin[1] * 2.3 + self->startpos[0])*.0015)*SINESCALE) & 255]; + + self->r.origin[2] += addVal; + + part = ClientParticle_new(self->classID, color, 100); + + VectorSet(part->origin, flrand(-12, 12), flrand(-12, 12), flrand(-8, 8)); + VectorAdd(self->r.origin, part->origin, part->origin); + + part->scale = flrand(1, 2); + VectorSet(part->velocity, flrand(-5.0, 5.0), flrand(-5, 5.0), flrand(15.0, 22.0)); + part->acceleration[2] = 2; + part->d_scale = flrand(-1.5, -2.0); + part->d_alpha = flrand(-100.0, -50.0); + part->duration = (color.a * 100.0) / -part->d_alpha; // time taken to reach zero alpha + + AddParticleToList(self, part); + + self->updateTime = 20; + + return (true); +} + +void FXCompass(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *effect; + int rflags; + + assert(owner); + + flags |= CEF_ABSOLUTE_PARTS | CEF_DONT_LINK | CEF_ADDITIVE_PARTS | CEF_NO_DRAW; + rflags = RF_GLOW | RF_TRANSLUCENT | RF_TRANS_ADD; + // Spawn each directional + //NORTH + effect = ClientEntity_new(type, flags, origin, NULL, 25); + + effect->r.model = compass_models; + effect->r.frame = 0; + effect->classID = PART_16x16_SPARK_C; + effect->r.flags = rflags; + effect->radius = 100.0; + VectorSet(effect->startpos, 0, 36, 0); + effect->Update = DirectionalUpdate; + + AddEffect(owner, effect); + + //EAST + effect = ClientEntity_new(type, flags, origin, NULL, 50); + + effect->r.model = compass_models; + effect->r.frame = 1; + effect->classID = PART_16x16_SPARK_Y; + effect->r.flags = rflags; + effect->radius = 100.0; + VectorSet(effect->startpos, 36, 0, 0); + effect->Update = DirectionalUpdate; + + AddEffect(owner, effect); + + //SOUTH + effect = ClientEntity_new(type, flags, origin, NULL, 75); + + effect->r.model = compass_models; + effect->r.frame = 2; + effect->classID = PART_16x16_SPARK_G; + effect->r.flags = rflags; + effect->radius = 100.0; + VectorSet(effect->startpos, 0, -36, 0); + effect->Update = DirectionalUpdate; + + AddEffect(owner, effect); + + //WEST + effect = ClientEntity_new(type, flags, origin, NULL, 100); + + effect->r.model = compass_models; + effect->r.frame = 3; + effect->classID = PART_16x16_SPARK_R; + effect->r.flags = rflags; + effect->radius = 100.0; + VectorSet(effect->startpos, -36, 0, 0); + effect->Update = DirectionalUpdate; + + AddEffect(owner, effect); +} + +// ----------------------------------------- + +#define NUM_FLAME_ITEMS 20 +#define NUM_FLAME_PARTS 40 +#define FLAME_ABSVEL 120 + +void FXCorpseRemove(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *flameitem; + float curAng, vel, vel1; + int count, i; + client_particle_t *p; + paletteRGBA_t color; + + count = GetScaledCount(NUM_FLAME_ITEMS, 0.95); + // Bound this between 8 and 16 sprites. + if (count > 20) + count=20; + else if (count < 8) + count=8; + + // create main client entity + flameitem = ClientEntity_new(Type, Flags | CEF_NO_DRAW , Origin, NULL, 600); + flameitem->radius = 10.0F; + flameitem->color.c = 0xffffffff; + AddEffect(NULL, flameitem); + + // are we destroying a rat ? + if (Flags & CEF_FLAG6) + vel1 = FLAME_ABSVEL/2; + else + vel1 = FLAME_ABSVEL; + + // large particles + for(curAng = 0.0F; curAng < (M_PI * 2.0F); curAng += (M_PI * 2.0F) / count) + { + p = ClientParticle_new(PART_32x32_BLACKSMOKE, flameitem->color, 600); + + p->scale = 16.0; + p->d_scale = -25.0; + + VectorSet(p->velocity, vel1 * cos(curAng), vel1 * sin(curAng), 0); + VectorScale(p->velocity, -0.3, p->acceleration); +// p->type |= PFL_ADDITIVE; + + AddParticleToList(flameitem, p); + + } + + color.c = 0xff4f4f4f; + count = GetScaledCount(NUM_FLAME_PARTS, 0.1); + // small particles + for (i=0;iscale = 1.0; + p->d_scale = -1.0; + + curAng = flrand(0,(M_PI * 2.0F)); + vel = flrand(vel1,vel1*2.5); + VectorSet(p->velocity, vel * cos(curAng), vel * sin(curAng), 0); + VectorScale(p->velocity, -0.3, p->acceleration); + p->type |= PFL_ADDITIVE | PFL_SOFT_MASK; + + AddParticleToList(flameitem, p); + + } + +} + + +/* +---------------------------------------- + +Leader effect routines + +---------------------------------------- +*/ + +#define LEADER_RAD 12 +#define TOTAL_LEADER_EFFECTS 30 +#define LEADER_EFFECTS_HEIGHT 30 + +// create the two circles that ring the player +static qboolean FXLeaderThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + paletteRGBA_t color; + + if (!(--self->LifeTime)) + { + self->LifeTime = TOTAL_LEADER_EFFECTS; + } + + // if we are ghosted, don't do the effect + if ((owner->current.renderfx & RF_TRANS_GHOST) || (owner->current.effects & EF_CLIENT_DEAD)) + return(true); + + // create the ring of particles that goes up + color.c = 0x7fffffff; + + // figure out how many particles we are going to use + + ce = ClientParticle_new(PART_16x16_SPARK_Y, color, 800); + ce->acceleration[2] = 0.0; + VectorSet(ce->origin, LEADER_RAD * cos(self->Scale), LEADER_RAD * sin(self->Scale), 4); + ce->scale = 8.0F; + AddParticleToList(self, ce); + // create the ring of particles that goes down + + ce = ClientParticle_new(PART_16x16_SPARK_Y, color, 800); + ce->acceleration[2] = 0.0; + VectorSet(ce->origin, LEADER_RAD * cos(self->Scale+3.14), LEADER_RAD * sin(self->Scale+3.14), 4); + ce->scale = 8.0F; + AddParticleToList(self, ce); + + // move the rings up/down next frame + self->Scale += 0.17; + + return(true); +} + +// create the entity the flight loops are on +void FXLeader(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + glow = ClientEntity_new(type, flags | CEF_NO_DRAW | CEF_ADDITIVE_PARTS, origin, 0, 60); + + VectorClear(glow->origin); + glow->Update = FXLeaderThink; + glow->LifeTime = TOTAL_LEADER_EFFECTS; + glow->AddToView = LinkedEntityUpdatePlacement; + glow->Scale = 0; + + AddEffect(owner, glow); + +} + + +// end + + diff --git a/Toolkit/Programming/GameCode/client effects/Generic Weapon Effects.c b/Toolkit/Programming/GameCode/client effects/Generic Weapon Effects.c new file mode 100644 index 0000000..00d2b3d --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Generic Weapon Effects.c @@ -0,0 +1,118 @@ +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "q_Sprite.h" + +#define NUM_EXPLODE_PARTS 256 +#define EXP_RANGE 16.0 +#define EXP_SPEED 192.0 + +static struct model_s *armorhit_models[1]; + +void PreCacheArmorHit(void) +{ + armorhit_models[0] = fxi.RegisterModel("sprites/fx/firestreak.sp2"); +} + + +// we hit someone with armor - do a pretty effect +// ripped off unashamedly from Josh's extremely cool streak effect. One of the coolest effects I've seen in a long time Josh. Good work Dude. +void FXCreateArmorHit(centity_t *owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *TrailEnt; + vec3_t dir; + int i; + + fxi.GetEffect(owner,Flags,"d", &dir); + + //Spawn a hit explosion of lines + i = GetScaledCount(6, 0.85); + + while (i--) + { + TrailEnt=ClientEntity_new(Type, Flags & ~CEF_NO_DRAW, Origin, 0, 500); + + TrailEnt->r.model = armorhit_models; + + TrailEnt->r.spriteType = SPRITE_LINE; + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.color.c = 0xFFFFFFFF; + TrailEnt->r.scale = flrand(1.0, 2.5); + TrailEnt->alpha = flrand(1.0, 0.75); + TrailEnt->d_alpha = -2.0; + TrailEnt->d_scale = -1.0; + + TrailEnt->r.color.r = irand(128, 255); + TrailEnt->r.color.g = irand(64, 255); + TrailEnt->r.color.b = irand(64, 255); + TrailEnt->r.color.a = 64 + irand(16, 128); + + VectorRandomCopy(dir, TrailEnt->velocity, 1.0); + + VectorCopy(Origin, TrailEnt->r.endpos); + VectorMA(TrailEnt->r.endpos, irand(6,8), TrailEnt->velocity, TrailEnt->r.startpos); + + VectorScale(TrailEnt->velocity, irand(50,100), TrailEnt->velocity); + + AddEffect(NULL, TrailEnt); + } + +} + +void CreateExplosionParticles(client_entity_t *this) +{ + int i, count; + client_particle_t *p; + paletteRGBA_t color; + + count = GetScaledCount(NUM_EXPLODE_PARTS, 0.9); + for(i = 0; i < count; i++) + { + color.r = irand(127, 255); + color.g = irand(127, 255); + color.b = 0; + color.a = 255; + + p = ClientParticle_new(PART_4x4_WHITE, color, 500); + + VectorSet(p->origin, flrand(-EXP_RANGE, EXP_RANGE), flrand(-EXP_RANGE, EXP_RANGE), flrand(-EXP_RANGE, EXP_RANGE)); + VectorSet(p->velocity, flrand(-EXP_SPEED, EXP_SPEED), flrand(-EXP_SPEED, EXP_SPEED), flrand(-EXP_SPEED, EXP_SPEED)); + + AddParticleToList(this, p); + } +} + +void GenericExplosion1(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *effect; + + effect = ClientEntity_new(type, flags, origin, NULL, 500); + + effect->alpha = 0.75; + effect->flags |= CEF_NO_DRAW; + + AddEffect(NULL, effect); // add the effect as independent world effect + + CreateExplosionParticles(effect); +} + +void GenericExplosion2(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *effect; + + effect = ClientEntity_new(type, flags, origin, NULL, 500); + + effect->flags |= CEF_NO_DRAW; + + AddEffect(NULL, effect); // add the effect as independent world effect + + CreateExplosionParticles(effect); +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/Item Effects.c b/Toolkit/Programming/GameCode/client effects/Item Effects.c new file mode 100644 index 0000000..5380db4 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Item Effects.c @@ -0,0 +1,32 @@ +#include "Client Effects.h" +#include "Client Entities.h" +#include "FX.h" +#include "Particle.h" +#include "Random.h" + +void ItemRespawn(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *effect; + client_particle_t *p; + paletteRGBA_t color; + int i; + + effect = ClientEntity_new(type, flags, origin, NULL, 750); + + effect->flags |= CEF_NO_DRAW; + + color.c = 0xFF00FFFF; + + AddEffect(NULL, effect); // add the effect as independent world effect + + for(i = 0; i < 32; i++) + { + p = ClientParticle_new(PART_4x4_WHITE, color, 750); + p->velocity[0] = flrand(-20.0F, 20.0F); + p->velocity[1] = flrand(-20.0F, 20.0F); + p->velocity[2] = flrand(30.0F, 80.0F); + AddParticleToList(effect, p); + } +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/LightStyles.c b/Toolkit/Programming/GameCode/client effects/LightStyles.c new file mode 100644 index 0000000..f0abd45 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/LightStyles.c @@ -0,0 +1,142 @@ +#include "Client Effects.h" + +/* +============================================================== + +LIGHT STYLE MANAGEMENT + +============================================================== +*/ + +typedef struct +{ + int length; + float value[3]; + float map[MAX_QPATH]; +} clightstyle_t; + +clightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; +int lastofs; + +/* +===================== +V_AddLightStyle + +Uses: +1 - 2 int comp +1 OR +4 offsets +2 additions +4 Assignments +===================== +*/ +void V_AddLightStyle (int style, float r, float g, float b) +{ + lightstyle_t *ls; + + if (style < 0 || style > MAX_LIGHTSTYLES) + { + assert(0); + Com_Error (ERR_DROP, "Bad light style %i", style); + } + else + { + ls = &fxi.cls->r_lightstyles[style]; + + ls->white = r+g+b; + ls->rgb[0] = r; + ls->rgb[1] = g; + ls->rgb[2] = b; + } +} + +/* +================ +CL_ClearLightStyles +================ +*/ +void CL_ClearLightStyles (void) +{ + memset (cl_lightstyle, 0, sizeof(cl_lightstyle)); + lastofs = -1; +} + +/* +================ +CL_RunLightStyles +================ +*/ +void CL_RunLightStyles (void) +{ + int ofs; + int i; + clightstyle_t *ls; + + ofs = fxi.cl->time / 100; + + if(ofs == lastofs) + { + return; + } + + lastofs = ofs; + + for(i = 0, ls = cl_lightstyle; i < MAX_LIGHTSTYLES ; ++i, ++ls) + { + if (!ls->length) + { + ls->value[0] = ls->value[1] = ls->value[2] = 1.0; + continue; + } + + if (ls->length == 1) + { + ls->value[0] = ls->value[1] = ls->value[2] = ls->map[0]; + } + else + { + ls->value[0] = ls->value[1] = ls->value[2] = ls->map[ofs%ls->length]; + } + } +} + + +void CL_SetLightstyle (int i) +{ + char *s; + int j, k; + + s = fxi.cl->configstrings[i+CS_LIGHTS]; + + j = strlen (s); + + if (j >= MAX_QPATH) + { + assert(0); + fxi.Com_Error (ERR_DROP, "svc_lightstyle length=%i", j); + } + + cl_lightstyle[i].length = j; + + for (k=0 ; kvalue[0], ls->value[1], ls->value[2]); + } +} + diff --git a/Toolkit/Programming/GameCode/client effects/Main.c b/Toolkit/Programming/GameCode/client effects/Main.c new file mode 100644 index 0000000..947932b --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Main.c @@ -0,0 +1,769 @@ +// +// Main.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +// #include + + + +#include "Client Effects.h" +#include "FX.h" +#include "ResourceManager.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ce_DLight.h" +#include "SinglyLinkedList.h" +#include "ce_Message.h" +#include "Angles.h" +#include "Vector.h" +#include "Skeletons.h" +#include "q_Physics.h" +#include "g_playstats.h" + +client_fx_import_t fxi; + +cvar_t *cl_camera_under_surface; +cvar_t *r_farclipdist; +cvar_t *r_nearclipdist; +cvar_t *r_detail; +cvar_t *fx_numinview; +cvar_t *fx_numactive; +cvar_t *clfx_gravity; +cvar_t *vid_ref; +cvar_t *fxTest1; +cvar_t *fxTest2; +cvar_t *fxTest3; +cvar_t *fxTest4; +cvar_t *cl_lerpdist2; +cvar_t *cl_timedemo; +cvar_t *crosshair; +cvar_t *compass; + +int ref_soft; +int numprocessedparticles; +int numrenderedparticles; + +qboolean fx_FreezeWorld=false; + +void CL_SetLightstyle(int i); + +void Init(); +void Clear(); +void ShutDown(); +void RegisterSounds(); +qboolean RegisterModels(int idx); +void AddEffects(qboolean freeze); +void PostRenderUpdate(); +void PreRenderUpdate(); +struct level_map_info_s *GetLMI(); +int GetLMIMax(); + +void AddServerEntities(frame_t *frame); +void ParseEffects(centity_t *cent); +static void RemoveEffectsFromCent(centity_t *cent); + +/* +============== +GetRefAPI + +============== +*/ +client_fx_export_t GetfxAPI (client_fx_import_t import) +{ + client_fx_export_t export; + + fxi = import; + + export.api_version = API_VERSION; + + export.Init = Init; + + export.ShutDown = ShutDown; + + export.Clear=Clear; + + export.RegisterSounds = RegisterSounds; + export.RegisterModels = RegisterModels; + + // In the client code in the executable the following functions are called + // First + export.AddPacketEntities = AddServerEntities; + // Second + export.AddEffects = AddEffects; + // Next (if any independent effects exist) + export.ParseClientEffects = ParseEffects; + // Last + export.UpdateEffects = PostRenderUpdate; + + export.SetLightstyle = CL_SetLightstyle; + + export.GetLMI = GetLMI; + export.GetLMIMax = GetLMIMax; + + export.RemoveClientEffects = RemoveEffectsFromCent; + + return export; +} + +void Init() +{ + extern void (*classStaticsInits[NUM_CLASSIDS])(); + void InitEntityMngr(); + void InitFMNodeInfoMngr(); + + int i; + + InitParticleMngrMngr(); + InitFMNodeInfoMngr(); + InitEntityMngr(); + InitMsgMngr(); + InitDLightMngr(); + + for(i = 0; i < NUM_CLASSIDS; ++i) + { + classStaticsInits[i](); + } + + clientEnts = NULL; + + cl_camera_under_surface = Cvar_Get( "cl_camera_under_surface", "0", 0 ); + r_farclipdist = Cvar_Get("r_farclipdist", FAR_CLIP_DIST, 0); + r_nearclipdist = Cvar_Get("r_nearclipdist", NEAR_CLIP_DIST, 0); + r_detail = Cvar_Get("r_detail", DETAIL_DEFAULT, CVAR_ARCHIVE); + fx_numinview = Cvar_Get("fx_numinview", "0", 0); + fx_numactive = Cvar_Get("fx_numactive", "0", 0); + clfx_gravity = Cvar_Get("clfx_gravity", GRAVITY_STRING, 0); + cl_timedemo = Cvar_Get("timedemo","0",0); + compass = Cvar_Get("compass", "0", CVAR_ARCHIVE); + + fxTest1 = Cvar_Get("fxTest1", "0", 0); + fxTest2 = Cvar_Get("fxTest2", "0", 0); + fxTest3 = Cvar_Get("fxTest3", "0", 0); + fxTest4 = Cvar_Get("fxTest4", "0", 0); + + cl_lerpdist2 = Cvar_Get("cl_lerpdist2", "10000", 0); + vid_ref = Cvar_Get( "vid_ref", "soft", CVAR_ARCHIVE ); + crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE); + + Clear(); +} + +void Clear() +{ + void CL_ClearLightStyles(); + int i; + centity_t *owner; + + if(clientEnts) + { + RemoveEffectList(&clientEnts); + } + + for(i = 0, owner = fxi.server_entities; i < MAX_NETWORKABLE_EDICTS; ++i, ++owner) + { + if(owner->effects) + { + RemoveOwnedEffectList(owner); + } + + if(owner->current.clientEffects.buf) + { + ResMngr_DeallocateResource(fxi.FXBufMngr, owner->current.clientEffects.buf, sizeof(char[ENTITY_FX_BUF_SIZE])); + owner->current.clientEffects.buf=0; + } + } + + CL_ClearLightStyles(); + + memset(&CircularList[0],0,sizeof(CircularList)); + if (r_detail->value == DETAIL_LOW) + total_circle_entries = 30; + else + if (r_detail->value == DETAIL_NORMAL) + total_circle_entries = 50; + else + total_circle_entries = MAX_ENTRIES_IN_CIRCLE_LIST; +} + +void ShutDown() +{ + void ReleaseEntityMngr(); + void ReleaseFMNodeInfoMngr(); + + Clear(); + + ReleaseParticleMngrMngr(); + ReleaseEntityMngr(); + ReleaseFMNodeInfoMngr(); + ReleaseDLightMngr(); + ReleaseMsgMngr(); +} + +/* +============== +AddEffects + +============== +*/ +static int num_owned_inview; + +void AddEffects(qboolean freeze) +{ + void CL_AddLightStyles(void); + + int i; + centity_t *owner; + int num_free_inview = 0; + + // If the world is frozen then the client effects, particularly the particles shouldn't update. + fx_FreezeWorld = freeze; + + if(clientEnts) + { + num_free_inview += AddEffectsToView(&clientEnts, NULL); + } + + // Add all effects which are attatched to entities, that have no model. + + for(i = 0, owner = fxi.server_entities; i < MAX_NETWORKABLE_EDICTS; ++i, ++owner) // gak, think something else need to be done + { // maybe a list of centities with effects. . . + if(owner->effects && (owner->current.effects & EF_ALWAYS_ADD_EFFECTS)) + { + num_owned_inview += AddEffectsToView(&owner->effects, owner); + } + } + + CL_AddLightStyles(); + + if(fx_numinview->value) + { + Com_DPrintf("Active CE : free %d, owned %d. Particles : processed %d, rendered %d\n", + num_free_inview, num_owned_inview, numprocessedparticles, numrenderedparticles); + } +} + +/* +============== +PostRenderUpdate + +============== +*/ +void PostRenderUpdate(void) +{ + void CL_RunLightStyles(void); + + int i; + centity_t *owner; + int num_free_active = 0; + int num_owned_active = 0; + + numprocessedparticles = 0; + numrenderedparticles = 0; + + if(clientEnts) + { + num_free_active += UpdateEffects(&clientEnts, NULL); + } + + for(i = 0, owner = fxi.server_entities; i < MAX_NETWORKABLE_EDICTS; ++i, ++owner) // gak, think something else need to be done + { // maybe a list of centities with effects. . . + if(owner->effects) + { + num_owned_active += UpdateEffects(&owner->effects, owner); + } + } + + CL_RunLightStyles(); + + if(fx_numactive->value) + { + Com_DPrintf("Active CE : free %d, owned %d\n", num_free_active, num_owned_active); + } +} + +/* +============== +ParseClientEffects + +============== +*/ +// Insert the logic in this could use a good cleaning. . . +void ParseEffects(centity_t *owner) +{ + int i, index; + int num,flags = 0; + unsigned short effect; + vec3_t position; + sizebuf_t *msg_read; + sizebuf_t tempBuf; + EffectsBuffer_t *fxBuf; + centity_t *tempOwner; + int last_effect = -1; + + tempOwner = owner; + + if(owner) + { + fxBuf = &owner->current.clientEffects; + + num = fxBuf->numEffects; + + msg_read = &tempBuf; + + memset (msg_read, 0, sizeof(*msg_read)); + + msg_read->data = fxBuf->buf; + msg_read->cursize = msg_read->maxsize = fxBuf->bufSize; + } + else + { + msg_read = fxi.net_message; + + num = MSG_ReadByte(msg_read); + } + + assert(num >= 0); + + if(num < 0) + { + fxi.Com_Error(ERR_DROP, "ParseClientEffects: number of effects < 0"); + return; + } + + for(i = 0; i < num; ++i) + { + if(owner) + { + msg_read->readcount = fxBuf->freeBlock; + } + + effect = MSG_ReadShort(msg_read); +#if _DEVEL + Cvar_Set("cfxpl", MSG_ReadString(msg_read)); +#endif + if(effect & 0x8000) + { + effect &= ~0x8000; + + flags = MSG_ReadByte(msg_read); + } + else + { + flags = 0; + } + + if(flags & (CEF_BROADCAST|CEF_MULTICAST)) + { + if(flags & CEF_ENTNUM16) + { + index = MSG_ReadShort(msg_read); + } + else + { + index = MSG_ReadByte(msg_read); + } + + if(index) // 0 should indicate the world + { + assert(index > 0); + assert(index < MAX_NETWORKABLE_EDICTS); + + tempOwner = fxi.server_entities + index; + } + } + + if(flags & CEF_OWNERS_ORIGIN) + { + if(tempOwner) + { + VectorCopy(tempOwner->origin, position); + } + else + { + position[0] = position[1] = position[2] = 0; + } + } + else + { + MSG_ReadPos(msg_read, position); + + if(tempOwner && !(flags & CEF_BROADCAST)) + { + position[0] += tempOwner->origin[0]; + position[1] += tempOwner->origin[1]; + position[2] += tempOwner->origin[2]; + } + } + + assert(effect < NUM_FX); + + if(!(effect >= 0 && effect < NUM_FX)) + { + fxi.Com_Error(ERR_DROP, "ParseClientEffects: bad effect %d last effect %d", effect, last_effect); + return; + } + +// Com_Printf("Client Effect %d unbuffered\n", effect); + + if(owner && !(flags & (CEF_BROADCAST|CEF_MULTICAST))) + { + fxBuf->freeBlock = msg_read->readcount; + } + + clientEffectSpawners[effect].SpawnCFX(tempOwner, effect, flags, position); + + if(flags & (CEF_BROADCAST|CEF_MULTICAST)) + { + tempOwner = NULL; + } + last_effect = effect; + } + + if(owner) // free the buffer allocated in CL_ParseDelta and passed onto owner->current + { + fxBuf->freeBlock = 0; + ResMngr_DeallocateResource(fxi.FXBufMngr, fxBuf->buf, sizeof(char[ENTITY_FX_BUF_SIZE])); + fxBuf->buf = NULL; + fxBuf->numEffects = 0; + fxBuf->bufSize = 0; + } +} + +static void RemoveEffectsFromCent(centity_t *cent) +{ + if(cent->effects) + { + RemoveOwnedEffectList(cent); + } +} + +/* +=============== +AddServerEntities + +=============== +*/ + +void AddServerEntities(frame_t *frame) +{ + entity_t *ent; + static entity_t sv_ents[MAX_SERVER_ENTITIES]; + static fmnodeinfo_t sv_ents_fmnodeinfos[MAX_SERVER_ENTITIES][MAX_FM_MESH_NODES]; + entity_state_t *s1; + float autorotate, macerotate; + int i; + int pnum; + centity_t *cent; + int autoanim; + int effects, renderfx; + int numEntsToAdd; + vec3_t dist; + int maxclients = atoi(fxi.cl->configstrings[CS_MAXCLIENTS]); + + // have to do this here, since the init is loaded once, and the graphics dll might be reloaded. + ref_soft = (strcmp("soft", vid_ref->string)) ? 0 : 1; + + fxi.cl->PIV = 0; + + PrepAddEffectsToView(); + num_owned_inview = 0; + + // Bonus items rotate at a fixed rate. + autorotate = anglemod(fxi.cl->time / 10.0); + macerotate = anglemod(fxi.cl->time / 700.0); + + // Brush models can auto animate their frames. + autoanim = 2*fxi.cl->time/1000; + + memset (sv_ents, 0, sizeof(sv_ents)); + + numEntsToAdd = frame->num_entities; + + if(numEntsToAdd > MAX_SERVER_ENTITIES) + { + Com_Printf("Overflow: Too many (%d : %d) server entities to add to view\n", numEntsToAdd, MAX_SERVER_ENTITIES); + numEntsToAdd = MAX_SERVER_ENTITIES; + } + + for(pnum = 0, ent = sv_ents; pnumparse_entities+pnum)&(MAX_PARSE_ENTITIES-1)); + + cent = fxi.server_entities + s1->number; + + // Setup skin and stuff. + + if((fxi.cl_predict->value)&&(s1->number==fxi.cl->playernum+1)) + { + // Prediction is active... + + effects = cent->Effects; + renderfx = cent->renderfx; + ent->skinnum = cent->skinnum; + } + else + { + // Prediction is not active... + + effects = s1->effects; + renderfx = s1->renderfx; + ent->skinnum = s1->skinnum; + } + + // Set frame. + + if (effects & EF_ANIM_ALL) + ent->frame = autoanim; + else if (effects & EF_ANIM_ALLFAST) + ent->frame = fxi.cl->time / 100; + else + ent->frame = s1->frame; + + // Handle flex-model nodes. + + ent->fmnodeinfo = sv_ents_fmnodeinfos[pnum]; + + if((fxi.cl_predict->value)&&(s1->number==fxi.cl->playernum+1)) + { + // Prediction is active. + + memcpy(ent->fmnodeinfo,fxi.predictinfo->fmnodeinfo,sizeof(s1->fmnodeinfo)); + } + else + { + // Prediction is not active. + + memcpy(ent->fmnodeinfo,s1->fmnodeinfo,sizeof(s1->fmnodeinfo)); + } + + // What's going on here? + + if((fxi.cl_predict->value)&&(s1->number==fxi.cl->playernum+1)) + { + // Deal with predicted origin. + + ent->backlerp = 1.0 - cent->playerlerp; + VectorCopy(cent->origin, ent->origin); + + } + else + { + ent->oldframe = cent->prev.frame; + ent->backlerp = 1.0 - fxi.cl->lerpfrac; + + // Interpolate origin. + + VectorSubtract(cent->current.origin, cent->prev.origin, dist); + + if(DotProduct(dist, dist) <= cl_lerpdist2->value) + VectorMA(cent->prev.origin, 1.0f - ent->backlerp, dist, ent->origin); + else + VectorCopy(cent->current.origin, ent->origin); + VectorCopy(ent->origin, cent->origin); + } + + VectorCopy(ent->origin, ent->oldorigin); + VectorCopy(cent->origin, cent->lerp_origin); + + // Set model. + + ent->skin = NULL; + + if (s1->modelindex == 255) + ent->model = fxi.cl->baseclientinfo.model; + else + ent->model = &fxi.cl->model_draw[s1->modelindex]; + + ent->scale = s1->scale; + + if(s1->color.c) + { + ent->color.c = s1->color.c; + } + else + { + ent->color.c = 0xFFFFFFFF; + } + + ent->absLight.r = s1->absLight.r; + ent->absLight.g = s1->absLight.g; + ent->absLight.b = s1->absLight.b; + + // Render effects (fullbright, translucent, etc). + + ent->flags = renderfx; + + // Calculate angles. + + if (effects & EF_MACE_ROTATE) + { + // Some bonus items auto-rotate. + + ent->angles[0] = macerotate * 2; + ent->angles[1] = macerotate; + ent->angles[2] = 0; + } + else + if (effects & EF_ROTATE) + { + // Some bonus items auto-rotate. + + ent->angles[0] = 0; + ent->angles[1] = autorotate; + ent->angles[2] = 0; + } + else + { + // Interpolate angles. + + float a1, a2; + + if((fxi.cl_predict->value)&&(s1->number==fxi.cl->playernum+1)) + { + // Prediction is active and we are dealing with the player's entity. The corect angle + // values have already been generated by prediction and written into the player's centity_t. + + for (i=0 ; i<3 ; i++) + { + a1 = cent->current.angles[i]; + a2 = cent->prev.angles[i]; + ent->angles[i] = LerpAngle (a2, a1, cent->playerlerp); + } + } + else + { + // Prediction is not active, so always get the angle values from the usual source, for + // all entities, including the player. + + for (i=0 ; i<3 ; i++) + { + a1 = cent->current.angles[i]; + a2 = cent->prev.angles[i]; + ent->angles[i] = LerpAngle (a2, a1, fxi.cl->lerpfrac); + } + } + + VectorDegreesToRadians(ent->angles, ent->angles); + VectorCopy(ent->angles, cent->lerp_angles); + } + + if(effects & EF_JOINTED) + { + ent->rootJoint = s1->rootJoint; + } + else + { + ent->rootJoint = NULL_ROOT_JOINT; + } + + if((fxi.cl_predict->value)&&(s1->number==fxi.cl->playernum+1)) + { + // Prediction is active and we are dealing with the player's entity. The corect frame + // swapframe values have already been generated by prediction and written into the + // player's centity_t. + + ent->oldframe = cent->prev.frame; + ent->frame=cent->current.frame; + + if((effects & EF_SWAPFRAME)&&(cent->current.swapFrame!=cent->current.frame)) + { + ent->swapFrame=cent->current.swapFrame; + ent->oldSwapFrame=cent->prev.swapFrame; + + // Yuck... but need to stop crashes for the demo. + + if(ent->oldSwapFrame==NO_SWAP_FRAME) + ent->oldSwapFrame=ent->oldframe; + } + else + { + ent->swapFrame=cent->prev.swapFrame=NO_SWAP_FRAME; + } + } + else + { + // Prediction is not active, so always get the frame and swapframe values from the usual + // source, for all entities, including the player. + + if((effects & EF_SWAPFRAME) && (s1->swapFrame != s1->frame)) + { + ent->swapFrame = s1->swapFrame; + ent->oldSwapFrame = cent->prev.swapFrame; + + // Yuck... but need to stop crashes for the demo. + + if(ent->oldSwapFrame==NO_SWAP_FRAME) + ent->oldSwapFrame=ent->oldframe; + } + else + { + ent->swapFrame = cent->prev.swapFrame = NO_SWAP_FRAME; + } + + } + + ent->referenceInfo = cent->referenceInfo; + + if(cent->current.clientEffects.numEffects) + { + ParseEffects(cent); + } + + if((s1->number > 0) && (s1->number <= maxclients)) + { + fxi.cl->PIV |= 1 << (s1->number - 1); + VectorCopy(ent->origin, fxi.cl->clientinfo[s1->number - 1].origin); + } + + // Add player's packet_entity_t to refresh list of entity_t's and save the entity_t pointer + // in PlayerEntPtr. + + if(s1->number==fxi.cl->playernum+1) + { + if(s1->modelindex) + { + AddEntityToView(ent); + } + *(fxi.PlayerEntPtr) = ent; + + // So client effects can play with owners entity. + cent->entity = ent; + + if(cent->effects && !(effects&(EF_DISABLE_ALL_CFX|EF_ALWAYS_ADD_EFFECTS))) + { + num_owned_inview += AddEffectsToView(¢->effects, cent); + } + + ++ent; + continue; + } + + // Cull (any elegible) entire models before they get rendered + // Don't ask me--I just commented what this does - MW). + + if(s1->modelindex) + { + vec3_t dir; + + VectorSubtract(ent->origin, fxi.cl->refdef.vieworg, dir); + + ent->depth = VectorNormalize(dir); + + AddEntityToView(ent); + cent->entity = ent; // So client effects can play with owners entity + + ++ent; + } + + if(cent->effects && !(effects&(EF_DISABLE_ALL_CFX|EF_ALWAYS_ADD_EFFECTS))) + { + num_owned_inview += AddEffectsToView(¢->effects, cent); + } + } +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/Monster Weapon Effects.c b/Toolkit/Programming/GameCode/client effects/Monster Weapon Effects.c new file mode 100644 index 0000000..e69de29 diff --git a/Toolkit/Programming/GameCode/client effects/Particle.c b/Toolkit/Programming/GameCode/client effects/Particle.c new file mode 100644 index 0000000..33b4c56 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Particle.c @@ -0,0 +1,292 @@ +// +// Particle.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#include "Particle.h" +#include "Client Effects.h" +#include "FX.h" +#include "ResourceManager.h" +#include "Client Entities.h" +#include "Random.h" +#include "Vector.h" +#include "g_playstats.h" + +#define MAX_PARTS_PER_CE 2048 + +ResourceManager_t ParticleMngr; + +int ParticleUpdateTime=0; + +void InitParticleMngrMngr() +{ +#define PARTICLE_BLOCK_SIZE 256 + + ResMngr_Con(&ParticleMngr, sizeof(client_particle_t), PARTICLE_BLOCK_SIZE); +} + +void ReleaseParticleMngrMngr() +{ + ResMngr_Des(&ParticleMngr); +} + +void AddParticleToList(client_entity_t *ce, client_particle_t *fx) +{ + assert(ce); + assert(fx); + + fx->next = ce->p_root; + ce->p_root = fx; + +#if _DEBUG + // Check to see that a ce isn`t spawning particles + // while not in the view. This is a HUGE memory leak + // which is most likely responsible for the chug. + + // INSTRUCTIONS TO FIX + // Find the client effect that called this spawn function (one level up in call stack) + // Either (a) tell the person who wrote the bugged code in the first place to correct it + // or (b) emulate the ViewStatusChanged functionality of the fire or the fountain (this is a + // 5 minute fix at most) + { + int i = 0; + client_particle_t *p = ce->p_root; + + while(p) + { + i++; + p = p->next; + } + if(i > MAX_PARTS_PER_CE) + { + Com_DPrintf("Memory leak due to lack of CEF_VIEWSTATUSCHANGED\n"); + } + } +#endif +} + +void RemoveParticleList(client_particle_t **root) +{ + client_particle_t *next; + client_particle_t *toFree; + + assert(root); + + next = *root; + + while(next) + { + toFree = next; + + next = next->next; + + ResMngr_DeallocateResource(&ParticleMngr, toFree, sizeof(*toFree)); + } + + *root = NULL; +} + +int AddParticlesToView(client_entity_t *ce) +{ + client_particle_t *current; + client_particle_t **prev; + float d_time, d_time2; + int d_msec; + int alpha, ptype; + particle_t *r; + qboolean cull_parts; + int part_info; + float maxdepth2, mindepth2, depth; + int numparticles; + + assert(ce->p_root); + + numparticles = 0; + cull_parts = (r_detail->value == DETAIL_LOW); + maxdepth2 = r_farclipdist->value * r_farclipdist->value; + mindepth2 = r_nearclipdist->value * r_nearclipdist->value; + + for(prev = &ce->p_root, current = ce->p_root; current; current = current->next) + { + ptype = current->type & PFL_FLAG_MASK; + + d_msec = ParticleUpdateTime - current->startTime; + d_time = d_msec * 0.001f; + alpha = (int)current->color.a + Q_ftol(d_time * current->d_alpha); + + if (alpha > 255 && (ce->flags & CEF_PULSE_ALPHA)) + { // PULSE ALPHA means that once alpha is at max, reverse and head back down. + alpha = 255 - (alpha - 255); // A weird thing to do, but necessary because the alpha is + // based off a dtime from the CREATION of the particle + } + //add to additive particle list + if((ce->flags & CEF_ADDITIVE_PARTS) || (current->type & PFL_ADDITIVE)) + { + if (fxi.cls->r_anumparticles >= MAX_PARTICLES) + return(numparticles); + r = &fxi.cls->r_aparticles[fxi.cls->r_anumparticles]; + part_info = 1; + } + else + { + if (fxi.cls->r_numparticles >= MAX_PARTICLES) + return(numparticles); + + r = &fxi.cls->r_particles[fxi.cls->r_numparticles]; + part_info = 2; + } + + assert(ptype < NUM_PARTICLE_TYPES); + + r->type = current->type; + r->color.c = current->color.c; + + if(alpha > 255) + { + r->color.a = 255; + } + else + { + r->color.a = alpha; + } + + r->scale = current->scale + (d_time * current->d_scale); + + d_time2 = d_time * d_time * 0.5; + + if (ce->flags & CEF_ABSOLUTE_PARTS) + { + r->origin[0] = current->origin[0] + (current->velocity[0] * d_time) + (current->acceleration[0] * d_time2); + r->origin[1] = current->origin[1] + (current->velocity[1] * d_time) + (current->acceleration[1] * d_time2); + r->origin[2] = current->origin[2] + (current->velocity[2] * d_time) + (current->acceleration[2] * d_time2); + } + else + { + r->origin[0] = ce->r.origin[0] + current->origin[0] + (current->velocity[0] * d_time) + (current->acceleration[0] * d_time2); + r->origin[1] = ce->r.origin[1] + current->origin[1] + (current->velocity[1] * d_time) + (current->acceleration[1] * d_time2); + r->origin[2] = ce->r.origin[2] + current->origin[2] + (current->velocity[2] * d_time) + (current->acceleration[2] * d_time2); + } + + if(cull_parts || (current->type & PFL_NEARCULL)) + { + depth = VectorSeparationSquared(r->origin, fxi.cl->refdef.vieworg); + + if((depth > maxdepth2) || (depth < mindepth2)) + { + part_info = 0; + } + + } + switch(part_info) + { + case 0: + break; + case 1: + fxi.cls->r_anumparticles++; + break; + case 2: + fxi.cls->r_numparticles++; + break; + default: + assert(0); + break; + } + numparticles++; + prev = &(*prev)->next; + } + return(numparticles); +} + +int UpdateParticles(client_entity_t *ce) +{ + client_particle_t *current; + client_particle_t **prev; + float d_time; + int d_msec; + int alpha, ptype; + int numparticles; + + assert(ce->p_root); + numparticles = 0; + + for(prev = &ce->p_root, current = ce->p_root; current; current = current->next) + { + ptype = current->type & PFL_FLAG_MASK; + + d_msec = ParticleUpdateTime - current->startTime; + + if(d_msec > current->duration) + { + *prev = current->next; + + ResMngr_DeallocateResource(&ParticleMngr, current, sizeof(*current)); + // current = current->next is still valid in the for loop. + // a deallocated resource is guaranteed not to be changed until it is + // reallocated, when the mananger is not shared between threads + continue; + } + + d_time = d_msec * 0.001f; + + alpha = (int)current->color.a + Q_ftol(d_time * current->d_alpha); + + if (alpha > 255 && (ce->flags & CEF_PULSE_ALPHA)) + { // PULSE ALPHA means that once alpha is at max, reverse and head back down. + alpha = 255 - (alpha - 255); // A weird thing to do, but necessary because the alpha is + // based off a dtime from the CREATION of the particle + } + + if(alpha <= 0) + { + *prev = current->next; + + ResMngr_DeallocateResource(&ParticleMngr, current, sizeof(*current)); + // current = current->next is still valid in the for loop. + // a deallocated resource is guaranteed not to be changed until it is + // reallocated, when the mananger is not shared between threads + continue; + } + + prev = &(*prev)->next; + numparticles++; + } + return(numparticles); +} + +// This frees all particles attached to the client entity +void FreeParticles(client_entity_t *ce) +{ + client_particle_t *current; + client_particle_t **prev; + + for(prev = &ce->p_root, current = ce->p_root; current; current = current->next) + { + *prev = current->next; + ResMngr_DeallocateResource(&ParticleMngr, current, sizeof(*current)); + } +} + +client_particle_t *ClientParticle_new(int type, paletteRGBA_t color, int duration) +{ + client_particle_t *p; + + p = ResMngr_AllocateResource(&ParticleMngr, sizeof(client_particle_t)); + memset(p, 0, sizeof(client_particle_t)); + + p->acceleration[2] = -PARTICLE_GRAVITY; + + p->startTime = ParticleUpdateTime; + p->duration = duration; + + p->type = type; + p->scale = 1.0F; + p->color = color; + + p->d_alpha = -255.0 / (flrand(0.8F, 1.0F) * duration * (1.0F / 1000.0F)); + return(p); +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/Particle.h b/Toolkit/Programming/GameCode/client effects/Particle.h new file mode 100644 index 0000000..13d77bb --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Particle.h @@ -0,0 +1,155 @@ +#ifndef CLIENT_H +#define CLIENT_H +#include "client.h" +#endif + + +typedef enum ParticleTypes_e +{ + // Small 4x4 particles in the upper left (0,0) + PART_4x4_WHITE, + PART_4x4_BLUE, + PART_4x4_RED, + PART_4x4_GREEN, + + PART_4x4_CYAN, + PART_4x4_YELLOW, + PART_4x4_MAGENTA, + PART_4x4_ORANGE, + + PART_4x4_BLUE2, + PART_4x4_BLUE3, + PART_4x4_UNUSED1, + PART_4x4_UNUSED2, + + PART_4x4_BLOOD1, + PART_4x4_BLOOD2, + PART_4x4_GREENBLOOD1, + PART_4x4_GREENBLOOD2, + + // Unused 16x16 section, to right of above 16x16 section (1,0) + PART_8x8_BUBBLE, + PART_8x8_BLOOD, + PART_8x8_GLOBBIT1, + PART_8x8_GLOBBIT2, + + // Two sections, directly below the above two sections (0,1) and (1,1) + PART_16x16_MIST, + PART_16x16_GLOB, + + // Next 32x32 section, to the left of the above 32x32 section (2,0), (3,0), (2,1) and (3,1) + PART_16x16_STAR, + PART_16x16_WATERDROP, + PART_16x16_LIGHTNING, + PART_16x16_BLOOD, + + // Two 32x32 sections, below the above two 32x32 sections (0,2) and (2,2) + PART_32x32_STEAM, + PART_32x32_WFALL, + + // Three 32x32 sections, in the upper right 1/4 of the page (4,0) (6,0) (4,2) + PART_32x32_FIRE0, + PART_32x32_FIRE1, + PART_32x32_FIRE2, + + // The single remaining 32x32 section, in the lower right of the above one (6,2) + PART_16x16_SPARK_B, + PART_16x16_SPARK_R, + PART_16x16_SPARK_G, + PART_16x16_SPARK_Y, + + // The third 32x32 section down, on the left (0,4) + PART_32x32_FIREBALL, + PART_32x32_BLACKSMOKE, // The same spot, the fireball is additive, the smoke is not. + + // The next 32x32 section to the right of the above cell (2,4), (3,4), (2,5) and (3,5) + PART_16x16_SPARK_C, + // These are little 8x8 critters + PART_8x8_RED_X, + PART_8x8_RED_CIRCLE, + PART_8x8_GREEN_X, + PART_8x8_GREEN_CIRCLE, + + PART_8x8_BLUE_X, + PART_8x8_BLUE_CIRCLE, + PART_8x8_CYAN_X, + PART_8x8_CYAN_CIRCLE, + + PART_8x8_RED_DIAMOND, + PART_8x8_GREEN_DIAMOND, + PART_8x8_BLUE_DIAMOND, + PART_8x8_CYAN_DIAMOND, + + // Bottom two 32x32 sections, lower left (0,6) and (2,6) + PART_32x32_BUBBLE, + PART_32x32_ALPHA_GLOBE, + + // Upper left of lower right quadrant (4,4) + PART_16x16_SPARK_I, + PART_16x16_BLUE_PUFF, + PART_16x16_UNUSED, + PART_16x16_ORANGE_PUFF, + + // Two 32x32's in lower right quadrant (6,4) and (4,6) + PART_32x32_BLOOD, + PART_32x32_GREENBLOOD, + + // Remaining four 16x16's in lower right quadrant (6,6), (6, 7), (7, 6) and (7,7) + PART_16x16_FIRE1, + PART_16x16_FIRE2, + PART_16x16_FIRE3, + PART_16x16_GREENBLOOD, + + PART_MAX //total = 62 +} ParticleTypes_t; + +typedef struct client_particle_s +{ + struct client_particle_s *next; // next client particle, if any + + vec3_t origin; + vec3_t velocity; + vec3_t acceleration; + + paletteRGBA_t color; + float d_alpha; + + float scale; + float d_scale; + + int type; + + int startTime; // miliseconds + int duration; // miliseconds +} client_particle_t; + +#define PARTICLE_GRAVITY 80 +#define PARTICLE_TRAIL_THINK_TIME 100 // spawns a particle puff 10 times per sec + +//particle render flags, <127 is the type +#define PFL_FLAG_MASK 0x0000007f // Mask out any flags +#define PFL_SOFT_MASK 0x20000000 // For defining single point particles in software (unused in gl - here to stop + // people using this bit) +#define PFL_ADDITIVE 0x40000000 // Particle is added to additive particle list +#define PFL_NEARCULL 0x80000000 // Force near culling + +void InitParticleMngrMngr(); +void ReleaseParticleMngrMngr(); + +// should make a Particle_new to get rid of this +extern struct ResourceManager_s ParticleMngr; + +void AddParticleToList(struct client_entity_s *ce, client_particle_t *fx); +void RemoveParticleList(client_particle_t **root); +int AddParticlesToView(struct client_entity_s *ce); +int UpdateParticles(struct client_entity_s *ce); +void FreeParticles(struct client_entity_s *ce); +client_particle_t *ClientParticle_new(int type, paletteRGBA_t color, int duration); + +// Particle Creation Functions +void CreateParticles(struct client_entity_s *this, int numParticles, int originRand, + int velocityRand, paletteRGBA_t color, int type, int duration, int d_alpha, + float scale, vec3_t acceleration, float d_scale); +void CreateGenericParticles(struct client_entity_s *this, int numParticles, paletteRGBA_t color, + int type, int duration); + diff --git a/Toolkit/Programming/GameCode/client effects/Player Effects.c b/Toolkit/Programming/GameCode/client effects/Player Effects.c new file mode 100644 index 0000000..2a4b77b --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Player Effects.c @@ -0,0 +1,71 @@ +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Random.h" +#include "Reference.h" +#include "Utilities.h" +#include "g_playstats.h" + +void FXCompass(centity_t *owner, int type, int flags, vec3_t origin); + +qboolean PlayerFirstSeenInit(struct client_entity_s *self, centity_t *owner) +{ + void FXPlayerShadow(centity_t *owner, int type, int flags, vec3_t origin); + + // Is the modelindex valid? E.g. when a player is dead, his modelindex is 0, hence his + // referenceInfo will be invailid. + + if(owner->current.modelindex!=255) + return(false); + + // Enable all Corvus' reference points. + + self->refMask |= CORVUS_MASK; + + EnableRefPoints(owner->referenceInfo, self->refMask); + + self->AddToView = NULL; + self->Update = KeepSelfAI; + + // Spawn the shadow. + + if(r_detail->value >= DETAIL_NORMAL) + FXPlayerShadow(owner, FX_SHADOW, CEF_OWNERS_ORIGIN, owner->origin); + + if(r_detail->value > DETAIL_NORMAL) + FXWaterParticles(owner, FX_WATER_PARTICLES, 0, owner->origin); + + //This is a cheap, silly effect that probably could look better and doesn't use the viewstatuschanged flag... urg... + //if(compass->value) + // FXCompass(owner, FX_WATER_PARTICLES, 0, owner->origin); + + FXCrosshair(owner, -1, 0, owner->origin); + + return(true); +} + +void FXPlayerPersistant(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *self; + vec_t gravity; + + // FIXME : Comment this in when I can alter p_client.c + // I believe that gravity is contained somewhere in the player/client sturcture already -JKH + + gravity = 675.0; + + flags |= CEF_NO_DRAW; + + self = ClientEntity_new(type, flags, origin, NULL, 17); + + self->Update = NULL; + self->AddToView = PlayerFirstSeenInit; + + AddEffect(owner, self); + + fxi.Cvar_SetValue("clfx_gravity", gravity); +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/TestEffect.c b/Toolkit/Programming/GameCode/client effects/TestEffect.c new file mode 100644 index 0000000..bf1041c --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/TestEffect.c @@ -0,0 +1,56 @@ +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" + +void FXTestBBox(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *cent; + client_particle_t *part; + float radius, bottom, top; + paletteRGBA_t color={255, 255, 255, 255}; + vec3_t loc[8]; + int i, partid, max; + + fxi.GetEffect(owner, flags, "fff", &radius, &bottom, &top); + + cent = ClientEntity_new(type, CEF_NO_DRAW | CEF_ADDITIVE_PARTS, origin, NULL, 15000); + + AddEffect(NULL, cent); + + if (flags&CEF_FLAG6) + { // Diamond + VectorSet(loc[0], 0, -radius, 0); + VectorSet(loc[1], 0, radius, 0); + VectorSet(loc[2], -radius, 0, 0); + VectorSet(loc[3], radius, 0, 0); + VectorSet(loc[4], 0, 0, bottom); + VectorSet(loc[5], 0, 0, top); + max=6; + } + else + { // Square + VectorSet(loc[0], -radius, -radius, bottom); + VectorSet(loc[1], radius, -radius, bottom); + VectorSet(loc[2], -radius, radius, bottom); + VectorSet(loc[3], radius, radius, bottom); + VectorSet(loc[4], -radius, -radius, top); + VectorSet(loc[5], radius, -radius, top); + VectorSet(loc[6], -radius, radius, top); + VectorSet(loc[7], radius, radius, top); + max=8; + } + partid = PART_8x8_RED_X + irand(0,11); + + for (i=0; iorigin); + part->acceleration[2] = 0; + part->scale = 2.0; + AddParticleToList(cent, part); + } +} diff --git a/Toolkit/Programming/GameCode/client effects/Utilities.c b/Toolkit/Programming/GameCode/client effects/Utilities.c new file mode 100644 index 0000000..1772206 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Utilities.c @@ -0,0 +1,626 @@ +#include "Utilities.h" + +#include "Client Effects.h" +#include "FX.h" +#include "random.h" +#include "Matrix.h" +#include "Vector.h" +#include "Reference.h" +#include "motion.h" +#include "Particle.h" +#include "ce_DLight.h" +#include "g_playstats.h" +#include "Skeletons.h" + + +// setup for circular list +client_entity_t *CircularList[MAX_ENTRIES_IN_CIRCLE_LIST + 1]; +int CurrentCirclePointer = 0; +int total_circle_entries; +extern void RemoveEffectFromList(client_entity_t **root, centity_t *owner); + + +//------------------------------------------------------------------ +// Update funcs +//------------------------------------------------------------------ + +qboolean RemoveSelfAI(client_entity_t *this, centity_t *owner) +{ + return(false); // removed after one think (nextThinkTime is lifetime) +} +qboolean KeepSelfAI(client_entity_t *this, centity_t *owner) +{ + return(true); // Remain alive forever +} + +qboolean AttemptRemoveSelf(client_entity_t *self, centity_t *owner) +{ + if(self->flags & (CEF_NO_DRAW|CEF_DISAPPEARED|CEF_DROPPED)) + { + return false; + } + + if(self->flags & CEF_CULLED) + { + if(self->r.depth > CFX_CULLING_DIST) + { + return false; + } + } + else + { + if(self->r.depth > r_farclipdist->value) + { + return false; + } + } + + self->updateTime = 400; + + return true; +} + +//------------------------------------------------------------------ +// AddToView funcs +//------------------------------------------------------------------ + +qboolean LinkedEntityUpdatePlacement(client_entity_t *current, centity_t *owner) +{ + matrix3_t rotation; + vec3_t up, direction; + + if(current->r.flags & RF_FIXED) + { + Matrix3FromAngles(owner->lerp_angles, rotation); + + Matrix3MultByVec3(rotation, current->direction, direction); + Matrix3MultByVec3(rotation, current->up, up); + + AnglesFromDirAndUp(direction, up, current->r.angles); + } + + current->r.origin[0] = owner->origin[0]; + current->r.origin[1] = owner->origin[1]; + current->r.origin[2] = owner->origin[2]; + + return true; +} + +qboolean OffsetLinkedEntityUpdatePlacement(client_entity_t *current, centity_t *owner) +{ + matrix3_t rotation; + vec3_t up, direction; + vec3_t up2, direction2; + vec3_t origin; + + Matrix3FromAngles(owner->lerp_angles, rotation); + + Matrix3MultByVec3(rotation, current->origin, origin); + + if(current->r.flags & RF_FIXED) + { + VectorAdd(current->origin, current->direction, direction); + VectorAdd(current->origin, current->up, up); + + Matrix3MultByVec3(rotation, direction, direction2); + Matrix3MultByVec3(rotation, up, up2); + + Vec3SubtractAssign(origin, direction2); + Vec3SubtractAssign(origin, up2); + + AnglesFromDirAndUp(direction2, up2, current->r.angles); + } + + current->r.origin[0] = owner->origin[0] + origin[0]; + current->r.origin[1] = owner->origin[1] + origin[1]; + current->r.origin[2] = owner->origin[2] + origin[2]; + + return true; +} + +qboolean ReferenceLinkedEntityUpdatePlacement(struct client_entity_s *self, centity_t *owner) +{ + matrix3_t rotation; + vec3_t up, direction; + vec3_t up2, direction2; + vec3_t origin; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return true; + + VectorCopy(owner->referenceInfo->references[self->refPoint].placement.origin, self->origin); + + Matrix3FromAngles(owner->lerp_angles, rotation); + + Matrix3MultByVec3(rotation, self->origin, origin); + + if(self->r.flags & RF_FIXED) + { + VectorAdd(self->origin, self->direction, direction); + VectorAdd(self->origin, self->up, up); + + Matrix3MultByVec3(rotation, direction, direction2); + Matrix3MultByVec3(rotation, up, up2); + + Vec3SubtractAssign(origin, direction2); + Vec3SubtractAssign(origin, up2); + + AnglesFromDirAndUp(direction2, up2, self->r.angles); + } + + self->r.origin[0] = owner->origin[0] + origin[0]; + self->r.origin[1] = owner->origin[1] + origin[1]; + self->r.origin[2] = owner->origin[2] + origin[2]; + + return true; +} + +//------------------------------------------------------------------ +// Message Response Helper Funcs +//------------------------------------------------------------------ + +void BecomeStatic(client_entity_t *self) +{ + VectorClear(self->velocity); + VectorClear(self->acceleration); + + self->flags &= ~CEF_CLIP_TO_WORLD; +} + +//------------------------------------------------------------------ +// Physics Funcs +//------------------------------------------------------------------ + +// Returns whether solid world is there +// Sets dist to distance to solid or maxdist if no solid +// If maxdist < 0 - returns distance to floor +// If maxdist > 0 - returns distance to ceiling + +int GetSolidDist(vec3_t origin, vec_t radius, float maxdist, vec_t *dist) +{ + vec3_t mins, maxs, end; + trace_t trace; + + VectorSet(mins, -radius, -radius, -1.0F); + VectorSet(maxs, radius, radius, 1.0F); + VectorCopy(origin, end); + end[2] += maxdist; + fxi.Trace(origin, mins, maxs, end, MASK_DRIP, CEF_CLIP_TO_WORLD, &trace); + + if(trace.fraction == 1.0F) + { + *dist = maxdist; + return(false); + } + *dist = trace.endpos[2] - origin[2]; + return(true); +} + +// Gets time for a ce to fall to the ground + +int GetFallTime(vec3_t origin, vec_t veloc, vec_t accel, vec_t radius, float maxtime, trace_t *trace) +{ + vec3_t mins, maxs, end; + float time; + + VectorSet(mins, -radius, -radius, -1.0F); + VectorSet(maxs, radius, radius, 1.0F); + VectorCopy(origin, end); + end[2] += (veloc * maxtime) + accel * (maxtime * maxtime) * 0.5; // from s = ut + 0.5at^2 + + fxi.Trace(origin, mins, maxs, end, MASK_DRIP, CEF_CLIP_TO_WORLD, trace); + time = GetTimeToReachDistance(veloc, accel, trace->endpos[2] - origin[2]); + return(time); // in ms +} + +// Returns false if no plane found b4 maxdist travelled, or non water plane hit +// Returns true, the plane normal of plane hit and the distance to the plane if a plane hit + +int GetWaterNormal(vec3_t origin, float radius, float maxdist, vec3_t normal, vec_t *dist) +{ + vec3_t mins, maxs, start, end; + trace_t trace; + + VectorSet(mins, -radius, -radius, -1.0F); + VectorSet(maxs, radius, radius, 1.0F); + VectorCopy(origin, end); + VectorCopy(origin, start); + start[2] += maxdist; + end[2] -= maxdist; + + fxi.Trace(origin, mins, maxs, end, MASK_DRIP, CEF_CLIP_TO_WORLD, &trace); + if((trace.fraction == 1.0F) || (trace.contents & MASK_SOLID)) + return(false); + + VectorCopy(trace.plane.normal, normal); + *dist = (end[2] - origin[2]) * trace.fraction; + return(true); +} + +void FXDoWaterEntrySplash(centity_t *Owner,int Type,int Flags,vec3_t Origin, byte SplashSize, vec3_t Dir); +void FXWaterRipples(centity_t *Owner, int Type, int Flags, vec3_t Origin); +void FXBubble(centity_t *Owner, int Type, int Flags, vec3_t Origin); +void FireSparks(centity_t *owner, int type, int flags, vec3_t origin, vec3_t dir); +void FXDarkSmoke(vec3_t origin, float scale, float range); +qboolean FXDebris_Vanish(struct client_entity_s *self,centity_t *owner); +qboolean FXDebris_Remove(struct client_entity_s *self,centity_t *owner); + +void FizzleEffect (client_entity_t *self, vec3_t surface_top, vec3_t normal) +{ + vec3_t spot; + int num_puffs, i; + + if(self) + { + if(self->dlight) + self->dlight->intensity = 0;//lights out + } + if(irand(0, 3)) + { + fxi.S_StartSound(surface_top, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("ambient/lavadrop%c.wav", irand('1', '3'))), 1, ATTN_STATIC, 0); + } + else + { + fxi.S_StartSound(surface_top, -1, CHAN_AUTO, + fxi.S_RegisterSound("misc/lavaburn.wav"), 1, ATTN_STATIC, 0); + } + + num_puffs = GetScaledCount(irand(2, 5), 0.3); + for(i = 0; ir; + qboolean do_effect = false; + + if(Vec3IsZero(self->velocity)) + return false; + + if(Vec3IsZero(self->acceleration)) + return false; + + //BTW, make more debris leave particle trails, like dust for wood, pebbles for rock, etc. + if(self->SpawnInfo&SIF_INWATER) + { + //leave several bubbles? + d_time*=0.5; + d_time2*=0.5; + } + else if(self->SpawnInfo&SIF_INLAVA) + { + d_time*=0.01; + d_time2*=0.01; + } + else if(self->SpawnInfo&SIF_INMUCK) + { + //leave a ripple or two? + d_time*=0.05; + d_time2*=0.05; + } + + attempt[0] = self->velocity[0] * d_time + self->acceleration[0] * d_time2; + attempt[1] = self->velocity[1] * d_time + self->acceleration[1] * d_time2; + attempt[2] = self->velocity[2] * d_time + self->acceleration[2] * d_time2; + + // may need an individual mins and maxs, probably want to put into an optional + // physics_info struct + mins[0] = mins[1] = mins[2] = -(maxs[0] = maxs[1] = maxs[2] = self->radius); + + VectorAdd(r->origin, attempt, end); + + fxi.Trace(r->origin, mins, maxs, end, MASK_SHOT|MASK_WATER, self->flags, trace); + + if((trace->fraction < 1.0) && !trace->allsolid && !trace->startsolid && !Vec3IsZeroEpsilon(trace->plane.normal)) + { + if(trace->surface->flags&SURF_SKY) + {//remove it + self->Update = FXDebris_Remove; + self->updateTime = fxi.cl->time + 0.1; + return false; + } + + d_time *= trace->fraction; + + VectorScale(attempt, d_time, move); + + Vec3AddAssign(move, r->origin); + + self->velocity[0] += self->acceleration[0] * d_time; + self->velocity[1] += self->acceleration[1] * d_time; + self->velocity[2] += self->acceleration[2] * d_time; + + VectorCopy(attempt, dir); + VectorNormalize(dir); + + VectorMA(r->origin, self->radius*0.5, dir, surface_top); + + hit_angle = DotProduct(dir, trace->plane.normal); + + if(r_detail->value < DETAIL_UBERHIGH || !irand(0, 1)) + do_effect = true; + + if(trace->contents & CONTENTS_WATER && !(self->SpawnInfo&SIF_INWATER)) + { + if(self->flags&CEF_FLAG6) + { + self->flags &= ~CEF_FLAG6; + FizzleEffect(self, surface_top, trace->plane.normal); + } + + self->SpawnInfo |= SIF_INWATER;//in water now, sink a little slower + //spawn ripples, splash + if(do_effect) + { + FXDoWaterEntrySplash(NULL, FX_WATER_ENTRYSPLASH, 0, surface_top, 64, trace->plane.normal); + } + + + if(flrand(-0.5, 0) < hit_angle) + {//splash sound + if(do_effect) + { + fxi.S_StartSound(r->origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("misc/splish%c.wav", irand('2', '3'))), 1, ATTN_STATIC, 0); + } + QPostMessage(self, MSG_COLLISION, "g", trace); // this will be processed next + return true; + } + + material = self->SpawnInfo & SIF_FLAG_MASK; + if(material!=MAT_WOOD)//wood floats, everything else can keep sinking + {//bubbles and blurp sound + if(do_effect) + { + FXBubble(NULL, FX_BUBBLE, 0, surface_top); + fxi.S_StartSound(r->origin, -1, CHAN_AUTO, + fxi.S_RegisterSound("misc/splish1.wav"), 1, ATTN_STATIC, 0); + } + fxi.Trace(trace->endpos, mins, maxs, end, MASK_SHOT, self->flags, trace); + if(trace->fraction < 1.0) + { + d_time *= trace->fraction; + + VectorScale(attempt, d_time, move); + + Vec3AddAssign(move, r->origin); + + self->velocity[0] += self->acceleration[0] * d_time; + self->velocity[1] += self->acceleration[1] * d_time; + self->velocity[2] += self->acceleration[2] * d_time; + } + else + { + Vec3AddAssign(attempt, r->origin); + + self->velocity[0] += self->acceleration[0] * d_time; + self->velocity[1] += self->acceleration[1] * d_time; + self->velocity[2] += self->acceleration[2] * d_time; + } + } + else//sit on surface + {//splash sound + if(do_effect) + { + fxi.S_StartSound(r->origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("player/waterrun%c.wav", irand('1', '2'))), 1, ATTN_STATIC, 0); + } + VectorCopy(surface_top, r->origin); + VectorClear(self->velocity); + VectorClear(self->acceleration); + self->d_alpha = -0.2; + self->Update = FXDebris_Vanish; + self->updateTime = fxi.cl->time + 0.1; + } + return false;//no need to update trace counter if not sending collision + } + else if(trace->contents & CONTENTS_SLIME&& !(self->SpawnInfo&SIF_INMUCK)) + { + if(self->flags&CEF_FLAG6) + { + self->flags &= ~CEF_FLAG6; + if(do_effect) + { + FizzleEffect(self, surface_top, trace->plane.normal); + } + } + + self->SpawnInfo |= SIF_INMUCK;//in muck, sink really really slowly + //spawn ripples, splash + if(do_effect) + { + FXDoWaterEntrySplash(NULL, FX_WATER_ENTRYSPLASH, 0, surface_top, 64, trace->plane.normal); + } + + if(flrand(-0.75, 0) < hit_angle) + {//splash sound + if(do_effect) + { + fxi.S_StartSound(r->origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("player/waterrun%c.wav", irand('1', '2'))), 1, ATTN_STATIC, 0); + } + QPostMessage(self, MSG_COLLISION, "g", trace); // this will be processed next + return true; + } + + //bubbles and blurp sound + if(do_effect) + { + FXBubble(NULL, FX_BUBBLE, 0, surface_top); + fxi.S_StartSound(r->origin, -1, CHAN_AUTO, + fxi.S_RegisterSound("objects/submerge.wav"), 1, ATTN_STATIC, 0); + } + VectorCopy(surface_top, r->origin); + self->d_alpha = -0.01; + self->Update = FXDebris_Vanish; + self->updateTime = fxi.cl->time + 0.1; + + return false;//no need to update trace counter if not sending collision + } + else if(trace->contents & CONTENTS_LAVA && !(self->SpawnInfo&SIF_INLAVA)) + { + self->flags &= ~CEF_FLAG6; + self->SpawnInfo |= SIF_INLAVA;//in lava now, continue to burn + //smoke puffs and sizzle here + if(do_effect) + { + FizzleEffect(self, surface_top, trace->plane.normal); + } + VectorCopy(surface_top, r->origin); + self->d_scale = -0.2; + self->Update = FXDebris_Vanish; + self->updateTime = fxi.cl->time + 0.1; + return false; + } + + QPostMessage(self, MSG_COLLISION, "g", trace); // this will be processed next + // works just like a recursive call + return true; + } + else + { + Vec3AddAssign(attempt, r->origin); + + self->velocity[0] += self->acceleration[0] * d_time; + self->velocity[1] += self->acceleration[1] * d_time; + self->velocity[2] += self->acceleration[2] * d_time; + } + + return false; +} + +// ----------------------------------------------------------------- +// Takes desired count and scales it by the desired frame rates +// relationship with actual framerate +// Second parameter is the impact of this effect on the renderer (0.0 - 1.0) +// eg Huge transparent alpha mapped sprites should have a high refdepend. +// Due to the limits of cyrix processors, we have no way of accurately +// determining the time spent in the ref dll, so this feature is not +// implemented yet. + +int GetScaledCount(int count, float refdepend) +{ + float work; + + // if we are doing a time demo, we don't want scaleability + if (cl_timedemo->value) + work = count; + else + work = count * fxi.cls->framemodifier; + + if (r_detail->value == DETAIL_NORMAL) + work = work * 0.75; + else + if (r_detail->value == DETAIL_LOW) + work = work * 0.5; + + if(work < 1.0) + { + work = 1.0; + } + + + return(Q_ftol(work)); +} + +void AdvanceParticle(client_particle_t *p, int ms) +{ + GetPositionOverTime(p->origin, p->velocity, p->acceleration, ms * 0.001, p->origin); + GetVelocityOverTime(p->velocity, p->acceleration, ms * 0.001, p->velocity); +} + +// ----------------------------------------------------------------- +// We don`t have access to "sv_gravity" so we keep a local client fx +// copy. It is set to same default as on the server. + +float GetGravity() +{ + return(-clfx_gravity->value); +} + +// ----------------------------------------------------------------- + +// Tells if we have not rendered this reference point for a while. +qboolean RefPointsValid(centity_t *owner) +{ + if (owner->referenceInfo==NULL || + owner->renderfx & RF_IGNORE_REFS || // This one is necessary in case we're a chicken. + owner->referenceInfo->lastUpdate - fxi.cl->time > REF_MINCULLTIME) + return false; + else + return true; +} + + + +// FIXME Obsolete +qboolean ReferencesInitialized(centity_t *owner) +{ + if(!owner->referenceInfo) + { // this probably shouldn't happen, if it does, let me know, JKH +// assert(0); + return false; + } + + return true; +} + +// FIXME Obsolete +void EnableRefPoints(LERPedReferences_t *refInfo, int mask) +{ +// assert(refInfo); +} + +// FIXME Obsolete +void DisableRefPoints(LERPedReferences_t *refInfo, int mask) +{ +// assert(refInfo); +} + +// add a blood splat or a scorchmark to the circular list - removing an entity thats next in the list if there is one +void InsertInCircularList(client_entity_t *self) +{ + client_entity_t **root; + client_entity_t **prev; + client_entity_t *current; + + root = &clientEnts; + + // if we have an entry already - delete it + if(CircularList[CurrentCirclePointer]) + { + // search for this client entities entry in the client entity list + for(prev = root, current = *root; current; current = current->next) + { + if(current == CircularList[CurrentCirclePointer]) + { + RemoveEffectFromList(prev,NULL); + break; + } + prev = &(*prev)->next; + } + } + // add in new one + CircularList[CurrentCirclePointer] = self; + CurrentCirclePointer++; + // delimit the pointer + if (CurrentCirclePointer >= total_circle_entries) + CurrentCirclePointer = 0; +} + + +// ----------------------------------------------------------------- +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/Utilities.h b/Toolkit/Programming/GameCode/client effects/Utilities.h new file mode 100644 index 0000000..5621a7f --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/Utilities.h @@ -0,0 +1,45 @@ +#ifndef UTILITIES_H +#define UTILITIES_H + +#include "Client Entities.h" + +//------------------------------------------------------------------ +// Update funcs +//------------------------------------------------------------------ + +qboolean RemoveSelfAI(client_entity_t *this, centity_t *owner); // set by default in ClientEntity_new +qboolean KeepSelfAI(client_entity_t *this, centity_t *owner); +qboolean AttemptRemoveSelf(client_entity_t *self, centity_t *owner); + +//------------------------------------------------------------------ +// AddToView funcs +//------------------------------------------------------------------ + +qboolean LinkedEntityUpdatePlacement(client_entity_t *current, centity_t *owner); +qboolean OffsetLinkedEntityUpdatePlacement(client_entity_t *current, centity_t *owner); +qboolean ReferenceLinkedEntityUpdatePlacement(struct client_entity_s *self, centity_t *owner); + +//------------------------------------------------------------------ +// Message Response Helper Funcs +//------------------------------------------------------------------ + +void BecomeStatic(client_entity_t *self); + +//------------------------------------------------------------------ +// Physics Funcs +//------------------------------------------------------------------ + +int GetSolidDist(vec3_t origin, vec_t radius, float maxdist, vec_t *dist); +int GetFallTime(vec3_t origin, vec_t veloc, vec_t accel, vec_t radius, float, trace_t *); +void AdvanceParticle(struct client_particle_s *p, int ms); +int GetWaterNormal(vec3_t, float, float, vec3_t, vec_t *); +qboolean Physics_MoveEnt(client_entity_t *self, float d_time, float d_time2, trace_t *trace); + +int GetScaledCount(int count, float refdepend); +float GetGravity(); + +qboolean ReferencesInitialized(centity_t *owner); +qboolean RefPointsValid(centity_t *owner); + + +#endif diff --git a/Toolkit/Programming/GameCode/client effects/ambient effects.h b/Toolkit/Programming/GameCode/client effects/ambient effects.h new file mode 100644 index 0000000..8543162 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/ambient effects.h @@ -0,0 +1,5 @@ +// Protos for ambientfx + +void DoWaterSplash(client_entity_t *effect, paletteRGBA_t color, int count); + +// end diff --git a/Toolkit/Programming/GameCode/client effects/ce_DLight.c b/Toolkit/Programming/GameCode/client effects/ce_DLight.c new file mode 100644 index 0000000..06dee60 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/ce_DLight.c @@ -0,0 +1,36 @@ +#include "ce_Dlight.h" +#include "ResourceManager.h" + +ResourceManager_t DLightMngr; + +void InitDLightMngr() +{ +#define DLIGHT_BLOCK_SIZE 32 + + ResMngr_Con(&DLightMngr, sizeof(CE_DLight_t), DLIGHT_BLOCK_SIZE); +} + +void ReleaseDLightMngr() +{ + ResMngr_Des(&DLightMngr); +} + +struct CE_DLight_s *CE_DLight_new(paletteRGBA_t color, float intensity, float d_intensity) +{ + CE_DLight_t *newDLight; + + newDLight = ResMngr_AllocateResource(&DLightMngr, sizeof(*newDLight)); + + newDLight->color = color; + + newDLight->intensity = intensity; + + newDLight->d_intensity = d_intensity; + + return newDLight; +} + +void CE_DLight_delete(struct CE_DLight_s *toDelete) +{ + ResMngr_DeallocateResource(&DLightMngr, toDelete, sizeof(*toDelete)); +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/ce_DLight.h b/Toolkit/Programming/GameCode/client effects/ce_DLight.h new file mode 100644 index 0000000..75e720b --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/ce_DLight.h @@ -0,0 +1,22 @@ +#ifndef CLIENT_H +#define CLIENT_H +#include "client.h" +#endif + +typedef struct CE_DLight_s +{ + paletteRGBA_t color; + + float intensity; + float d_intensity; +} CE_DLight_t; + +void InitDLightMngr(); +void ReleaseDLightMngr(); + +struct CE_DLight_s *CE_DLight_new(paletteRGBA_t color, float intensity, float d_intensity); +void CE_DLight_delete(struct CE_DLight_s *toDelete); + +#if 0 +dlight = CE_DLight_new(, , ); +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/ce_DefaultMessageHandler.c b/Toolkit/Programming/GameCode/client effects/ce_DefaultMessageHandler.c new file mode 100644 index 0000000..391b346 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/ce_DefaultMessageHandler.c @@ -0,0 +1,31 @@ +#include "ce_DefaultMessageHandler.h" +#include "Client Entities.h" + +CE_MsgReceiver_t DefaultMessageReceivers[NUM_MESSAGES] = +{ + NULL, +}; + +void CE_DefaultMsgHandler(client_entity_t *self, CE_Message_t *msg) +{ + CE_MsgReceiver_t receiver; + + receiver = classStatics[self->classID].msgReceivers[msg->ID]; + + if(receiver) + { + receiver(self, msg); + } + else + { + // if and when there are a good number of defaults, change the NULL to be an Empty + // function, overall that should be faster to just always call the function then + // do the check + receiver = DefaultMessageReceivers[msg->ID]; + + if(receiver) + { + DefaultMessageReceivers[msg->ID](self, msg); + } + } +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/ce_DefaultMessageHandler.h b/Toolkit/Programming/GameCode/client effects/ce_DefaultMessageHandler.h new file mode 100644 index 0000000..b669c6b --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/ce_DefaultMessageHandler.h @@ -0,0 +1,9 @@ +#ifndef CE_DEFAULTMESSAGEHANDLER_H +#define CE_DEFAULTMESSAGEHANDLER_H + +#include "ce_Message.h" + +extern CE_MsgReceiver_t DefaultMessageReceivers[NUM_MESSAGES]; +extern void CE_DefaultMsgHandler(struct client_entity_s *self, CE_Message_t *msg); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/ce_Message.c b/Toolkit/Programming/GameCode/client effects/ce_Message.c new file mode 100644 index 0000000..36cdcbb --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/ce_Message.c @@ -0,0 +1,136 @@ +// +// ce_Message.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#include "ce_Message.h" +#include "Message.h" + +#include "Client Entities.h" +#include "ResourceManager.h" +#include "SinglyLinkedList.h" + +static ResourceManager_t MsgMngr; + +void InitMsgMngr() +{ + const int MESSAGE_BLOCK_SIZE = 256; + + ResMngr_Con(&MsgMngr, sizeof(CE_Message_t), MESSAGE_BLOCK_SIZE); +} + +void ReleaseMsgMngr() +{ + ResMngr_Des(&MsgMngr); +} + +void QPostMessage(client_entity_t *to, CE_MsgID_t ID, char *format, ...) +{ + CE_Message_t *newMsg; + qboolean append = false; + SinglyLinkedList_t *parms; + va_list marker; + + if(!to->msgHandler) // everything should really have one, but at this point everything + // doesn't so, the messages will never get popped of the queue + // so don't push them on in the first place + { + return; + } + + newMsg = ResMngr_AllocateResource(&MsgMngr, sizeof(CE_Message_t)); + + parms = &newMsg->parms; + + // Fix Me !!! + SLList_DefaultCon(parms); // whoops, need to port object manager to C + SLList_PushEmpty(parms); // should make a constructor fo CE_Message_t too + + newMsg->ID = ID; + + if(format) + { + va_start(marker, format); + + SetParms(parms, format, marker); + + va_end(marker); + } + + QueueMessage(&to->msgQ, newMsg); +} + +int ParseMsgParms(CE_Message_t *this, char *format, ...) +{ + SinglyLinkedList_t *parms; + va_list marker; + int args_filled; + + assert(this); + + parms = &this->parms; + + SLList_Front(parms); + + va_start(marker, format); + + args_filled = GetParms(parms, format, marker); + + va_end(marker); + + return args_filled; +} + +void ProcessMessages(client_entity_t *this) +{ + SinglyLinkedList_t *msgs; + SinglyLinkedList_t *parms; + CE_Message_t *msg; + + assert(this->msgHandler); + + msgs = &this->msgQ.msgs; + + while(!SLList_IsEmpty(msgs)) + { + msg = SLList_Pop(msgs).t_void_p; + + parms = &msg->parms; + + if(!SLList_AtLast(parms) && !SLList_AtEnd(parms)) + { + SLList_Chop(parms); + } + + this->msgHandler(this, msg); + + // Fix Me !!! + SLList_Des(parms); // whoops, need to port object manager to C + + ResMngr_DeallocateResource(&MsgMngr, msg, sizeof(CE_Message_t)); + } +} + +void ClearMessageQueue(client_entity_t *this) +{ + SinglyLinkedList_t *msgs; + SinglyLinkedList_t *parms; + CE_Message_t *msg; + + msgs = &this->msgQ.msgs; + + while(!SLList_IsEmpty(msgs)) + { + msg = SLList_Pop(msgs).t_void_p; + + parms = &msg->parms; + + // Fix Me !!! + SLList_Des(parms); // whoops, need to port object manager to C + + ResMngr_DeallocateResource(&MsgMngr, msg, sizeof(CE_Message_t)); + } +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/ce_Message.h b/Toolkit/Programming/GameCode/client effects/ce_Message.h new file mode 100644 index 0000000..2a198c4 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/ce_Message.h @@ -0,0 +1,29 @@ +#ifndef CE_MESSAGE_H +#define CE_MESSAGE_H + +#include "SinglyLinkedList.h" + +typedef enum CE_MsgID_e +{ + MSG_COLLISION = 0, // (parm1) trace_t *trace -- the trace matching the collision, valid only on the frame of collision + NUM_MESSAGES +} CE_MsgID_t; + +typedef struct Message_s +{ + CE_MsgID_t ID; + SinglyLinkedList_t parms; +} CE_Message_t; + +typedef void (*CE_MessageHandler_t)(struct client_entity_s *self, CE_Message_t *msg); +typedef void (*CE_MsgReceiver_t)(struct client_entity_s *self, CE_Message_t *msg); + +void InitMsgMngr(); +void ReleaseMsgMngr(); + +void QPostMessage(struct client_entity_s *to, CE_MsgID_t ID, char *format, ...); +int ParseMsgParms(CE_Message_t *this, char *format, ...); +void ProcessMessages(struct client_entity_s *this); +void ClearMessageQueue(struct client_entity_s *this); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_BlueRing.c b/Toolkit/Programming/GameCode/client effects/fx_BlueRing.c new file mode 100644 index 0000000..2da87ca --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_BlueRing.c @@ -0,0 +1,59 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Utilities.h" + +#define NUM_FLAME_ITEMS 20 +#define FLAME_ABSVEL 450 +#define FLAME_INIT_SCALE 0.1F +#define FLAME_DELTA_SCALE 6.0F +#define FLAME_DURATION 500 +#define FLAME_DELTA_ALPHA (1000/FLAME_DURATION) + +#define NUM_RING_MODELS 1 +static struct model_s *blue_models[NUM_RING_MODELS]; +void PreCacheBluering() +{ + blue_models[0] = fxi.RegisterModel("sprites/spells/bluering.sp2"); +} + +void FXBlueRing(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *flameitem; + float curAng; + int count; + + count = GetScaledCount(NUM_FLAME_ITEMS, 0.95); + // Bound this between 8 and 16 sprites. + if (count > 20) + count=20; + else if (count < 8) + count=8; + for(curAng = 0.0F; curAng < (M_PI * 2.0F); curAng += (M_PI * 2.0F) / count) + { + flameitem = ClientEntity_new(Type, Flags & ~CEF_OWNERS_ORIGIN, Origin, NULL, FLAME_DURATION); + + flameitem->r.model = blue_models; + flameitem->r.flags = RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + flameitem->r.frame = 0; + flameitem->r.scale = FLAME_INIT_SCALE; + flameitem->d_scale = FLAME_DELTA_SCALE; + + VectorSet(flameitem->velocity, FLAME_ABSVEL * cos(curAng), FLAME_ABSVEL * sin(curAng), 0); + flameitem->radius = 20.0F; + flameitem->d_alpha = -FLAME_DELTA_ALPHA; + + AddEffect(NULL, flameitem); + } + fxi.S_StartSound(Origin, -1, CHAN_AUTO, fxi.S_RegisterSound("weapons/Spell Blue Ring.wav"), 1, ATTN_NORM, 0); +} +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_Dripper.c b/Toolkit/Programming/GameCode/client effects/fx_Dripper.c new file mode 100644 index 0000000..c460518 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_Dripper.c @@ -0,0 +1,189 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// Created by JJS + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "Utilities.h" +#include "Ambient effects.h" + +#define DRIP_MAX_DURATION 2.0F +#define DRIP_RADIUS 2.0F +#define DRIP_NUM_SPLASHES 8 + +#define NUM_DRIP_MODELS 3 +static struct model_s *drip_models[NUM_DRIP_MODELS]; +void PreCacheDripper() +{ + drip_models[0] = fxi.RegisterModel("sprites/fx/steamhalf.sp2"); + drip_models[1] = fxi.RegisterModel("sprites/fx/steam.sp2"); + drip_models[2] = fxi.RegisterModel("sprites/fx/waterdrop.sp2"); +} + +// ----------------------------------------------------------------------------------------- + +qboolean FXDripThinkSolid(client_entity_t *drip, centity_t *owner) +{ + client_entity_t *mist; + vec3_t origin; + paletteRGBA_t color; + + VectorCopy(drip->r.origin, origin); + origin[2] = drip->SpawnData; + + mist = ClientEntity_new(-1, 0, origin, NULL, 500); + + mist->r.model = drip_models; + mist->r.scale = 0.5F; + mist->r.flags = RF_TRANSLUCENT; + + mist->alpha = 0.4F; + mist->d_alpha = -0.8F; + + color.c = 0xffffffff; + DoWaterSplash(mist, color, DRIP_NUM_SPLASHES); + + AddEffect(NULL, mist); + + fxi.S_StartSound(origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("ambient/soliddrop%c.wav", irand('1', '3'))), 1, ATTN_STATIC, 0); + + // FIXME : Returning false here doesn`t work + drip->Update = RemoveSelfAI; + return(true); +} + +qboolean FXDripThinkWater(client_entity_t *drip, centity_t *owner) +{ + client_entity_t *mist; + paletteRGBA_t color; + vec3_t origin; + + VectorCopy(drip->r.origin, origin); + origin[2] = drip->SpawnData; + + mist = ClientEntity_new(-1, 0, origin, NULL, 500); + + mist->r.model = drip_models; + mist->r.scale = 0.5F; + mist->r.flags = RF_TRANSLUCENT; + + mist->d_scale = -2.0; + mist->d_alpha = -8.0F; +// mist->velocity[0] = flrand(-20.0F, 20.0F); +// mist->velocity[1] = flrand(-20.0F, 20.0F); + AddEffect(NULL, mist); + + color.c = 0xffffffff; + DoWaterSplash(mist, color, DRIP_NUM_SPLASHES); + + FXWaterRipples(NULL, FX_WATER_RIPPLES, 0, drip->r.origin); + + fxi.S_StartSound(origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("ambient/waterdrop%c.wav", irand('1', '3'))), 1, ATTN_STATIC, 0); + + // FIXME : Returning false here doesn`t work + drip->Update = RemoveSelfAI; + return(true); +} + +qboolean FXDripThinkLava(client_entity_t *drip, centity_t *owner) +{ + client_entity_t *mist; + vec3_t origin; + + VectorCopy(drip->r.origin, origin); + origin[2] = drip->SpawnData; + + mist = ClientEntity_new(-1, 0, origin, NULL, 500); + + mist->r.model = drip_models + 1; + mist->r.scale = 0.5F; + mist->r.flags = RF_TRANSLUCENT; + + mist->alpha = 0.4F; + mist->d_alpha = -0.8F; + mist->velocity[0] = flrand(-10.0F, 10.0F); + mist->velocity[1] = flrand(-10.0F, 10.0F); + mist->velocity[2] = flrand(20.0F, 30.0F); + AddEffect(NULL, mist); + + fxi.S_StartSound(origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("ambient/lavadrop%c.wav", irand('1', '3'))), 1, ATTN_STATIC, 0); + + // FIXME : Returning false here doesn`t work + drip->Update = RemoveSelfAI; + return(true); +} + +static qboolean FXDripperParticleSpawner(client_entity_t *spawner, centity_t *owner) +{ + client_entity_t *drip; + + // Refresh time so it gets updated a random amount + spawner->updateTime = irand(spawner->LifeTime / 2, spawner->LifeTime * 2); + + // Spawn a drip to fall + drip = ClientEntity_new(-1, 0, spawner->r.origin, NULL, spawner->SpawnDelay); + + drip->r.model = drip_models + 2; + drip->r.scale = 0.1F; + drip->r.flags = RF_TRANSLUCENT | RF_ALPHA_TEXTURE; + drip->r.frame = spawner->r.frame; + + drip->radius = 2.0F; + drip->SpawnData = spawner->SpawnData; + VectorCopy(spawner->acceleration, drip->acceleration); + + switch(spawner->SpawnInfo & (CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_LAVA)) + { + case CONTENTS_WATER: + drip->Update = FXDripThinkWater; + break; + case CONTENTS_LAVA: + drip->Update = FXDripThinkLava; + break; + default: + drip->Update = FXDripThinkSolid; + break; + } + + AddEffect(NULL, drip); + return(true); +} + +// Spawn a water drop spawner + +void FXDripper(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *dripper; + byte dripspermin, frame; + trace_t trace; + + fxi.GetEffect(Owner, Flags, "bb", &dripspermin, &frame); + + Flags |= CEF_NO_DRAW | CEF_NOMOVE | CEF_VIEWSTATUSCHANGED; + dripper = ClientEntity_new(Type, Flags, Origin, NULL, 1000); + + dripper->r.frame = frame; + + dripper->LifeTime = (60 * 1000) / dripspermin; + dripper->Update = FXDripperParticleSpawner; + + dripper->acceleration[2] = GetGravity(); + dripper->radius = DRIP_RADIUS; + dripper->SpawnDelay = GetFallTime(Origin, 0, dripper->acceleration[2], DRIP_RADIUS, DRIP_MAX_DURATION, &trace); + dripper->SpawnData = trace.endpos[2] + 4.0F; + dripper->SpawnInfo = trace.contents; + + AddEffect(Owner, dripper); +} +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_Fountain.c b/Toolkit/Programming/GameCode/client effects/fx_Fountain.c new file mode 100644 index 0000000..df94159 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_Fountain.c @@ -0,0 +1,168 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "motion.h" +#include "Utilities.h" +#include "Matrix.h" +#include "g_playstats.h" + +void CreateFountainSplash(client_entity_t *owner, vec3_t origin, float xspread, float yspread, float angle) +{ + client_particle_t *mist; + vec3_t work, off; + matrix3_t mat; + paletteRGBA_t color; + + color.c = 0x40ffffff; + + CreateYawMatrix(mat, angle); + work[0] = flrand(-xspread, xspread); + work[1] = flrand(-yspread, yspread); + work[2] = 0; + Matrix3MultByVec3(mat, work, off); + + if (r_detail->value >= DETAIL_NORMAL) + mist = ClientParticle_new(PART_32x32_ALPHA_GLOBE, color, 500); + else + mist = ClientParticle_new(PART_32x32_ALPHA_GLOBE, color, 350); + + VectorCopy(off, mist->origin); + + mist->scale = 30.0F; + mist->d_scale = 3.0; + mist->d_alpha *= 0.5; + mist->acceleration[2] = 0.0F; + VectorSet(mist->velocity, flrand(-64.0, 64.0), flrand(-64.0, 64.0), 0.0); + + AddParticleToList(owner, mist); +} + +// ----------------------------------------------------------------------------------------- + +#define NUM_SPLASHES 0.005 + +static qboolean FXWaterfallBaseSpawner(client_entity_t *spawner, centity_t *owner) +{ + int i, count; + + VectorCopy(owner->current.origin, spawner->r.origin); + count = GetScaledCount(Q_ftol(spawner->xscale * spawner->yscale * NUM_SPLASHES), 0.8); + for(i = 0; i < count; i++) + { + CreateFountainSplash(spawner, spawner->r.origin, spawner->xscale, spawner->yscale, spawner->yaw); + } + return(true); +} + +void FXWaterfallBase(centity_t *owner, int type, int flags, vec3_t origin) +{ + byte xs, ys, yaw; + client_entity_t *wfb; + + fxi.GetEffect(owner, flags, "bbb", &xs, &ys, &yaw); + + flags |= CEF_NO_DRAW | CEF_NOMOVE | CEF_VIEWSTATUSCHANGED; + wfb = ClientEntity_new(type, flags, origin, NULL, 100); + + wfb->xscale = xs; + wfb->yscale = ys; + wfb->yaw = (yaw * ANGLE_360) / 256.0; + wfb->radius = wfb->xscale + wfb->yscale; + wfb->Update = FXWaterfallBaseSpawner; + + AddEffect(owner, wfb); +} + +// ----------------------------------------------------------------------------------------- + +qboolean FXWaterDropEnd(client_entity_t *waterdrop, centity_t *owner) +{ + CreateFountainSplash(waterdrop, waterdrop->r.origin, 10.0, 10.0, 0); + waterdrop->Update = RemoveSelfAI; + waterdrop->nextThinkTime = fxi.cl->time + 500; + return(true); +} + +#define FOUNTAIN_SCALE 80.0F +#define NUM_FOUNT_PARTS 20 + +static qboolean FXFountainParticleSpawner(client_entity_t *spawner, centity_t *owner) +{ + client_particle_t *drop; + client_entity_t *splash; + vec3_t origin; + vec3_t velocity; + vec_t accel; + int i, time, count; + float s; + + count = GetScaledCount(NUM_FOUNT_PARTS, 0.9); + for(i = 0; i < count; i++) + { + VectorSet(origin, flrand(-4.0F, 4.0F), flrand(-4.0F, 4.0F), flrand(-4.0F, 4.0F)); + VectorRandomCopy(spawner->direction, velocity, 16.0F); + + accel = GetGravity(); + s = spawner->SpawnData - origin[2]; + time = GetTimeToReachDistance(velocity[2], accel, s); + + drop = ClientParticle_new(PART_32x32_WFALL | PFL_NEARCULL, spawner->color, time); + + VectorCopy(origin, drop->origin); + VectorCopy(velocity, drop->velocity); + drop->acceleration[2] = accel; + drop->scale = 8.0F; + drop->d_scale = 16.0F; + drop->d_alpha *= 0.8; + drop->startTime += flrand(-50.0F, 0.0F); + + AddParticleToList(spawner, drop); + } + + GetPositionOverTime(spawner->r.origin, velocity, drop->acceleration, time * 0.001, origin); + splash = ClientEntity_new(-1, 0, origin, NULL, time); + splash->Update = FXWaterDropEnd; + splash->flags = CEF_NOMOVE | CEF_NO_DRAW; + AddEffect(NULL, splash); + + return(true); // Never go away +} + +// Could send the 'v' as a 'ds' but we would lose some accuracy. As it +// is a persistant effect, it doesn`t matter too much + +void FXFountain(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *fountain; + byte frame; + short drop; + + if (r_detail->value >= DETAIL_HIGH) + fountain = ClientEntity_new(Type, Flags, Origin, NULL, 50); + else + fountain = ClientEntity_new(Type, Flags, Origin, NULL, 90); + + fxi.GetEffect(Owner, Flags, "vsb", &fountain->direction, &drop, &frame); + + fountain->r.frame = frame; + + fountain->SpawnData = drop * 0.125; + fountain->color.c = 0xffffffff; + fountain->radius = 128.0F + Q_fabs(fountain->SpawnData); + fountain->Update = FXFountainParticleSpawner; + fountain->flags |= CEF_NO_DRAW | CEF_NOMOVE | CEF_CULLED | CEF_VIEWSTATUSCHANGED; // | CEF_ADDITIVE_PARTS; + + AddEffect(Owner, fountain); +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_HellStaff.c b/Toolkit/Programming/GameCode/client effects/fx_HellStaff.c new file mode 100644 index 0000000..097b1d2 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_HellStaff.c @@ -0,0 +1,255 @@ +// +// fx_hellstaff.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "Angles.h" +#include "Random.h" +#include "Utilities.h" +#include "q_sprite.h" +#include "g_playstats.h" + +#define NUM_HELL_MODELS 2 +static struct model_s *hell_models[NUM_HELL_MODELS]; +void PreCacheHellstaff() +{ + hell_models[0] = fxi.RegisterModel("sprites/spells/hellstafproj.sp2"); + hell_models[1] = fxi.RegisterModel("sprites/fx/helllaser.sp2"); +} + +// -------------------------------------------------------------- + +#define NUM_HELLBOLT_EXPLODES 8 + +// ************************************************************************************************ +// FXHellbolt +// ************************************************************************************************ + +void FXHellbolt(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t vel; + client_entity_t *hellbolt; + paletteRGBA_t lightcolor = {255, 128, 64, 255}; + + fxi.GetEffect(owner, flags, "t", vel); + + if (flags & CEF_FLAG6) + Vec3ScaleAssign(HELLBOLT_SPEED/2,vel); + else + Vec3ScaleAssign(HELLBOLT_SPEED,vel); + + hellbolt = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 10000); + + hellbolt->r.model = hell_models; + hellbolt->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + hellbolt->r.frame = irand(0, 1); + vectoangles(vel, hellbolt->r.angles); + VectorCopy(vel, hellbolt->velocity); + + hellbolt->r.scale = 0.5; + hellbolt->r.color = lightcolor; + hellbolt->d_alpha = 0.0; + hellbolt->radius = 10.0F; + + hellbolt->dlight = CE_DLight_new(lightcolor, 120.0f, 0.0f); + AddEffect(owner, hellbolt); +} + +// ************************************************************************************************ +// FXHellboltExplode +// --------------------- +// ************************************************************************************************ + +#define HELLBOLT_SPARK_VEL 64 +void HellboltExplode(vec3_t loc, vec3_t vel) +{ + client_entity_t *blast; + client_particle_t *spark; + int i; + paletteRGBA_t lightcolor = {255, 96, 48, 255}; + + blast = ClientEntity_new(-1, CEF_NO_DRAW | CEF_ADDITIVE_PARTS, loc, NULL, 500); + blast->radius = 32.0; + fxi.S_StartSound(blast->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/HellHit.wav"), 1, ATTN_NORM, 0); + blast->dlight = CE_DLight_new(lightcolor, 150.0f, -200.0f); + VectorClear(blast->velocity); + + AddEffect(NULL, blast); + + for(i = 0; i < NUM_HELLBOLT_EXPLODES; i++) + { + spark = ClientParticle_new(PART_16x16_SPARK_R, lightcolor, 500); + VectorRandomCopy(vel, spark->velocity, HELLBOLT_SPARK_VEL); + VectorSet(spark->acceleration, 0.0, 0.0, GetGravity() * 0.3); + spark->scale = flrand(12.0, 16.0); + spark->d_scale = -24.0; + spark->d_alpha = flrand(-640.0, -512.0); + AddParticleToList(blast, spark); + } +} + + +void FXHellboltExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t Dir; + + fxi.GetEffect(owner, flags, "d", Dir); + + Vec3ScaleAssign(32.0, Dir); + + if(flags & CEF_FLAG6) + { + FXClientScorchmark(origin, Dir); + } + + HellboltExplode(origin, Dir); +} + +#define HELLLASER_PARTS 9 +#define HELLLASER_SPEED 32.0 +void HellLaserBurn(vec3_t loc, vec3_t fwd, vec3_t right, vec3_t up) +{ + client_entity_t *blast; + client_particle_t *spark; + float curangle, dangle; + int i; + paletteRGBA_t lightcolor = {255, 96, 48, 255}, color = {255, 255, 255, 255}; + + blast = ClientEntity_new(-1, CEF_NO_DRAW | CEF_ADDITIVE_PARTS, loc, NULL, 1000); + blast->radius = 32.0; + + // We're not gonna put any sound on the laser impact. +// fxi.S_StartSound(blast->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/HellLaserHit.wav"), 1, ATTN_NORM, 0); + blast->dlight = CE_DLight_new(lightcolor, 150.0f, -300.0f); + VectorClear(blast->velocity); + + AddEffect(NULL, blast); + + dangle = (2.0*M_PI/(float)HELLLASER_PARTS); + curangle = flrand(0.0, dangle); + VectorScale(fwd, -0.25*HELLLASER_SPEED, fwd); + VectorScale(right, HELLLASER_SPEED, right); + VectorScale(up, HELLLASER_SPEED, up); + for(i = 0; i < HELLLASER_PARTS; i++) + { + spark = ClientParticle_new(PART_16x16_SPARK_R, color, 1000); + VectorMA(fwd, cos(curangle), right, spark->velocity); + VectorMA(spark->velocity, sin(curangle), up, spark->velocity); + spark->acceleration[2] = 64.0; + spark->scale = flrand(8.0, 24.0); + spark->d_scale = -12.0; + spark->d_alpha = flrand(-512.0, -256.0); + AddParticleToList(blast, spark); + curangle += dangle; + } +} + + +// Create Effect FX_WEAPON_HELLSTAFF_POWER_BURN +void FXHellstaffPowerBurn(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t angles, fwd, right, up, dir; + + VectorClear(angles); + fxi.GetEffect(owner, flags, "t", &dir); + vectoangles(dir, angles); + angles[PITCH] *= -1;// something's broken with angle signs somewhere ;( + + AngleVectors(angles, fwd, right, up); + + HellLaserBurn(origin, fwd, right, up); +} + + +// CreateEffect FX_WEAPON_HELLSTAFF_POWER +void FXHellstaffPower(centity_t *owner,int type,int flags, vec3_t origin) +{ + vec3_t endpos, curpos, dpos, angles; + vec3_t fwd, right, up, dir; + client_entity_t *beam, *beam2; + paletteRGBA_t lightcolor={255,255,255,255}; + int i; + client_particle_t *spark; + float len; + int count; + byte blen; + + VectorClear(angles); + fxi.GetEffect(owner,flags,"tb", &dir, &blen); + vectoangles(dir, angles); + angles[PITCH] *= -1;// something's broken with angle signs somewhere ;( + len = (float)blen * 8.0; + AngleVectors(angles, fwd, right, up); + + VectorMA(origin, len, fwd, endpos); + + //make the line beam + beam = ClientEntity_new(-1, CEF_DONT_LINK | CEF_ABSOLUTE_PARTS | CEF_ADDITIVE_PARTS, origin, NULL, 333); + beam->r.model = hell_models + 1; + beam->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + beam->r.scale = flrand(6.0, 10.0); + beam->r.tile = len/flrand(40.0, 48.0); + beam->r.tileoffset = flrand(0.0, 1.0); + beam->radius = 40.0; + beam->alpha = 0.95; + beam->d_alpha = -3.0; + VectorCopy(origin, beam->r.startpos); + VectorCopy(endpos, beam->r.endpos); + beam->r.spriteType = SPRITE_LINE; + AddEffect(NULL, beam); + + //make the line beam halo + beam2 = ClientEntity_new(-1, CEF_DONT_LINK, origin, NULL, 500); + beam2->r.model = hell_models + 1; + beam2->r.frame = 1; + beam2->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + beam2->r.scale = beam->r.scale * 1.4; + beam2->r.tile = beam->r.tile; + beam2->r.tileoffset = beam->r.tileoffset; + beam2->radius = 40.0; + beam2->alpha = 0.95; + beam2->d_alpha = -4.0; + VectorCopy(origin, beam2->r.startpos); + VectorCopy(endpos, beam2->r.endpos); + beam2->r.spriteType = SPRITE_LINE; + AddEffect(NULL, beam2); + + count = GetScaledCount((int)(len/16.0), 0.3); + VectorScale(fwd, len/(float)count, dpos); + + VectorCopy(origin, curpos); + //make the particles along the beam. + for(i=0; i < count;i++) + { + spark = ClientParticle_new(PART_16x16_SPARK_R, lightcolor, 500); + spark->scale=flrand(8.0, 12.0); + spark->d_scale = -2.0*spark->scale; + spark->acceleration[2] = 80.0; + VectorCopy(curpos, spark->origin); + VectorSet(spark->velocity, + flrand(-HELLLASER_SPEED, HELLLASER_SPEED), + flrand(-HELLLASER_SPEED, HELLLASER_SPEED), + flrand(-HELLLASER_SPEED, HELLLASER_SPEED)); + AddParticleToList(beam, spark); + VectorAdd(curpos, dpos, curpos); + } + + VectorSubtract(beam->r.endpos, beam->r.startpos, dir); + VectorNormalize(dir); + if (flags & CEF_FLAG7) + FXClientScorchmark(beam->r.endpos, dir); + + if (flags & CEF_FLAG6) + HellLaserBurn(endpos, fwd, right, up); +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_PlagueMist.c b/Toolkit/Programming/GameCode/client effects/fx_PlagueMist.c new file mode 100644 index 0000000..1ca65fb --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_PlagueMist.c @@ -0,0 +1,106 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// Created by JJS + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "g_playstats.h" + +#define NUM_MIST_PARTS 7 + +static qboolean FXPlagueMistParticleSpawner(client_entity_t *spawner, centity_t *owner) +{ + client_particle_t *p; + paletteRGBA_t color; + int i; + int count; + int duration; + float mist_scale, mist_d_scale; + + spawner->LifeTime -= 100; + if(spawner->LifeTime < 0) + return(false); + + count = (spawner->LifeTime - 1600) / 150; + if(count > NUM_MIST_PARTS) + count = NUM_MIST_PARTS; + if(count < 1) + return(true); + + if (r_detail->value >= DETAIL_HIGH) + { + duration = 1500; + mist_scale = 12.0; + mist_d_scale = 6.0; + } + else + if (r_detail->value == DETAIL_NORMAL) + { + duration = 1175; + mist_scale = 10.0; + mist_d_scale = 5.5; + } + else + { + duration = 900; + mist_scale = 8.0; + mist_d_scale = 5.0; + } + + + for(i = 0; i < count; i++) + { + color.r = irand(200, 255); + color.g = irand(200, 255); + color.b = irand(200, 255); + color.a = irand(200, 255); + + p = ClientParticle_new(PART_16x16_MIST | PFL_NEARCULL, color, duration); + VectorSet(p->origin, flrand(-2.0F, 2.0F), flrand(-2.0F, 2.0F), flrand(-2.0F, 2.0F)); + VectorRandomCopy(spawner->direction, p->velocity, 20.0F); + VectorScale(spawner->direction, -1.0F, p->acceleration); + p->acceleration[2] += flrand(20.0F, 30.0F); + p->scale = flrand(mist_scale, mist_scale+3.0); + p->d_scale = flrand(mist_d_scale, mist_d_scale+3.0); + AddParticleToList(spawner, p); + } + return(true); +} + +void FXPlagueMist(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *pm; + byte lifetime; + int mist_think_time; + + if (r_detail->value >= DETAIL_HIGH) + mist_think_time = 100; + else + if (r_detail->value == DETAIL_NORMAL) + mist_think_time = 125; + else + mist_think_time = 150; + + pm = ClientEntity_new(Type, Flags, Origin, NULL, mist_think_time); + fxi.GetEffect(Owner, Flags, "vb", pm->direction, &lifetime); + + pm->LifeTime = lifetime * 50; + pm->Update = FXPlagueMistParticleSpawner; + pm->flags |= CEF_NO_DRAW | CEF_NOMOVE; + + if(Owner) + AddEffect(Owner, pm); + else + AddEffect(NULL, pm); +} + +// end + diff --git a/Toolkit/Programming/GameCode/client effects/fx_PlagueMistExplode.c b/Toolkit/Programming/GameCode/client effects/fx_PlagueMistExplode.c new file mode 100644 index 0000000..53afe9d --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_PlagueMistExplode.c @@ -0,0 +1,115 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// Created by JJS + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "g_playstats.h" + +#define NUM_MIST_EXPLODE_PARTS 7 + +static qboolean FXPlagueMistExplodeSpawn(client_entity_t *spawner, centity_t *owner) +{ + int i, count; + client_particle_t *p; + paletteRGBA_t color; + int duration; + float mist_scale, mist_d_scale; + + spawner->LifeTime -= spawner->SpawnInfo; + if(spawner->LifeTime < 0) + return(false); + + count = (spawner->LifeTime - 1600) / 200; + if(count > NUM_MIST_EXPLODE_PARTS) + count = NUM_MIST_EXPLODE_PARTS; + if(count < 1) + return(true); + + if (r_detail->value >= DETAIL_HIGH) + { + duration = 1500; + mist_scale = 10.0; + mist_d_scale = 6.0; + } + else + if (r_detail->value == DETAIL_NORMAL) + { + duration = 1250; + mist_scale = 9.0; + mist_d_scale = 5.5; + } + else + { + duration = 1000; + mist_scale = 8.0; + mist_d_scale = 5.0; + } + + color.c = 0xffffffff; + for(i = 0; i < count; i++) + { + color.r = irand(140, 195); + color.g = irand(140, 195); + color.b = irand(140, 195); + color.a = irand(220, 255); + + p = ClientParticle_new(PART_16x16_MIST | PFL_NEARCULL, color, duration); + p->velocity[0] = flrand(-75.0F, 75.0F); + p->velocity[1] = flrand(-75.0F, 75.0F); + p->velocity[2] = flrand(-10.0F, 75.0F); + VectorScale(p->velocity, -1.1F, p->acceleration); + p->scale = mist_scale; + p->d_scale = mist_d_scale; + AddParticleToList(spawner, p); + } + + return(true); +} + +void FXPlagueMistExplode(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *spawner; + byte lifetime; + int mist_life; + int mist_think_time; + + if (r_detail->value >= DETAIL_HIGH) + { + mist_life = 50; + mist_think_time = 50; + } + else + if (r_detail->value == DETAIL_NORMAL) + { + mist_life = 38; + mist_think_time = 60; + } + else + { + mist_life = 33; + mist_think_time = 70; + } + + Flags = (Flags & ~CEF_OWNERS_ORIGIN) | CEF_NOMOVE | CEF_NO_DRAW; + spawner = ClientEntity_new(Type, Flags, Origin, NULL, mist_think_time); + fxi.GetEffect(Owner, Flags, "b", &lifetime); + spawner->LifeTime = lifetime * mist_life; + spawner->radius = 20.0F; + spawner->Update = FXPlagueMistExplodeSpawn; + spawner->SpawnInfo = mist_life; + + if(Owner) + AddEffect(Owner, spawner); + else + AddEffect(NULL, spawner); +} +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_RedRain.c b/Toolkit/Programming/GameCode/client effects/fx_RedRain.c new file mode 100644 index 0000000..b86a83b --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_RedRain.c @@ -0,0 +1,479 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "angles.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "motion.h" +#include "Reference.h" +#include "ce_Dlight.h" +#include "q_Sprite.h" +#include "g_playstats.h" + +#define MAX_REDRAINHEIGHT 200.0F +#define RED_RAIN_RADIUS 60.0F +#define POWER_RAIN_RADIUS 80.0F +#define DROP_RADIUS 2.0F +#define RAIN_INIT_VEL -600.0F +#define NUM_SPLASH_PARTS 4 +#define NUM_TAIL_PARTS 4 +#define NUM_DROPS 2 +#define MAX_FALL_DIST 1300 +#define RAIN_HEIGHT 32.0 +#define PART_OFF 5.0 +#define NUM_TRAIL_PARTS 6 +#define REDRAIN_EXPLODE_NUM 5 +#define RED_RAIN_DAMPFACTOR 0.5 +#define RED_RAIN_WIDTH 3.0 +#define POWER_RAIN_WIDTH 6.0 + +#define NUM_REDRAIN_MODELS 5 + +// Mutant Ssithra arrow- uses red-rain arrow +#define MSSITHRA_FX_ARROW_SPEED 750.0 + +static struct model_s *rain_models[NUM_REDRAIN_MODELS]; +void PreCacheRedrain() +{ + rain_models[0] = fxi.RegisterModel("sprites/spells/spark_red.sp2"); + rain_models[1] = fxi.RegisterModel("models/spells/redrainarrow/tris.fm"); + rain_models[2] = fxi.RegisterModel("sprites/spells/rsteam.sp2"); + rain_models[3] = fxi.RegisterModel("sprites/fx/redraindrop.sp2"); + rain_models[4] = fxi.RegisterModel("sprites/spells/spark_green.sp2"); +} + +void RedRainExplosion(vec3_t impactpos, vec3_t rainpos, int duration, qboolean powerup,centity_t *owner); +void DoLightning(vec3_t groundpos, vec3_t airpos); + + + + +// Things dropped by the red rain. + +// -------------------------------------------------------------- + +// This is a delayed effect which creates a splash out of red sparks. +//static +qboolean FXRedRainSplashThink(client_entity_t *splash, centity_t *owner) +{ + client_entity_t *mist; + client_particle_t *spark; + int i; + paletteRGBA_t pal; + int sparktype; + float grav; + + mist = ClientEntity_new(-1, CEF_NO_DRAW | CEF_ADDITIVE_PARTS, splash->r.origin, NULL, 500); + AddEffect(NULL, mist); + + pal.c = 0xffffffff; + if (splash->SpawnInfo) + { // Powered up rain + sparktype = PART_16x16_SPARK_G; + grav = PARTICLE_GRAVITY * 4.0; + } + else + { + sparktype = PART_16x16_SPARK_R; + grav = -PARTICLE_GRAVITY * 3.0; + } + + for (i=0; i<4; i++) + { + spark = ClientParticle_new(sparktype, pal, 500); + VectorSet(spark->velocity, flrand(-48.0, 48.0), flrand(-48.0, 48.0), flrand(48.0, 96.0)); + spark->acceleration[2] = -PARTICLE_GRAVITY*3.0; + spark->scale = 16.0; + spark->d_scale = -24.0; + AddParticleToList(mist, spark); + } + return(false); +} + + +// The drops need to update as they're added to the view, because velocity doesn't update the sprite line's start and endpoint. +//static +qboolean FXRedRainDropUpdate(client_entity_t *drop, centity_t *owner) +{ + drop->r.startpos[2] = drop->r.origin[2] + RAIN_HEIGHT; + if (drop->r.startpos[2] > drop->SpawnData) // Make sure that the top of the drop doesn't go higher that the spawn height + drop->r.startpos[2] = drop->SpawnData; + drop->r.endpos[2] = drop->r.origin[2] - RAIN_HEIGHT; + + return(false); +} + + +// Red Rain area + +// This constantly starts new drops up at the top. It also spawns a splash, which is set to go off at the appropriate fall time +static qboolean FXRedRainThink(client_entity_t *rain, centity_t *owner) +{ + client_entity_t *splash; + client_entity_t *drop; + vec3_t origin; //, top; + int j; + float duration, radius, width; + trace_t trace; + + if(rain->nextEventTime <= fxi.cl->time) + return (false);//in case we lose the packet that tells us to remove + + if (rain->SpawnInfo) + { // Powered up rain + radius = POWER_RAIN_RADIUS; + width = POWER_RAIN_WIDTH; + } + else + { // Unpowered + radius = RED_RAIN_RADIUS; + width = RED_RAIN_WIDTH; + } + + if (rain->SpawnData < 0.0) + { + rain->SpawnData += 8.0; + if (rain->SpawnData > 0.0) + rain->SpawnData = 0.0; + } + + if(owner->current.effects&EF_DISABLE_EXTRA_FX)//rain->LifeTime < 1000) + return(true); + + for(j = 0; j < NUM_DROPS; j++) + { + VectorSet(origin, + flrand(-radius, radius), + flrand(-radius, radius), + rain->SpawnData + flrand(-8.0F, 8.0F)); + VectorAdd(rain->origin, origin, origin); + duration = GetFallTime(origin, RAIN_INIT_VEL, -PARTICLE_GRAVITY, DROP_RADIUS, 3.0F, &trace); + drop = ClientEntity_new(-1, CEF_DONT_LINK, origin, NULL, duration); + drop->r.model = rain_models + 3; + drop->r.frame = rain->SpawnInfo; + drop->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + drop->alpha = 0.75; + drop->SpawnInfo = rain->SpawnInfo; + drop->r.scale = width; + drop->radius = RAIN_HEIGHT; + VectorCopy(origin, drop->r.startpos); + VectorCopy(origin, drop->r.endpos); + drop->r.endpos[2] -= RAIN_HEIGHT; + drop->velocity[2] = RAIN_INIT_VEL; + drop->r.spriteType = SPRITE_LINE; + drop->SpawnData = origin[2]; // This allows the drop to remember its top position, so the top doesn't go higher than it. + drop->AddToView = FXRedRainDropUpdate; + AddEffect(NULL, drop); + + if((duration > 20) && (r_detail->value > DETAIL_LOW)) + { + origin[2] += GetDistanceOverTime(RAIN_INIT_VEL, -PARTICLE_GRAVITY, (float)duration * 0.001F); + splash = ClientEntity_new(-1, CEF_NO_DRAW | CEF_NOMOVE, origin, NULL, duration); + splash->Update = FXRedRainSplashThink; + splash->SpawnInfo = rain->SpawnInfo; + AddEffect(NULL, splash); + } + } + return(true); +} + +// This is from creating the effect FX_RED_RAIN. +void FXRedRain(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *spawner; + vec_t ceiling; + vec_t floor; + vec3_t ceil_org; + float radius; + qboolean powerup; + + VectorCopy(Origin, ceil_org); + if (Flags & CEF_FLAG6) + { // powered up + radius = POWER_RAIN_RADIUS; + powerup = true; + } + else + { // unpowered + radius = RED_RAIN_RADIUS; + powerup = false; + } + GetSolidDist(Origin, radius * 0.5, MAX_REDRAINHEIGHT, &ceiling); + ceil_org[2] += ceiling; + GetSolidDist(Origin, 1, -MAX_FALL_DIST, &floor); + + Flags = (Flags | CEF_NO_DRAW | CEF_NOMOVE | CEF_CULLED | CEF_VIEWSTATUSCHANGED) & ~CEF_OWNERS_ORIGIN; + spawner = ClientEntity_new(Type, Flags, ceil_org, NULL, 200); + spawner->Update = FXRedRainThink; // FXRedRainThink; + spawner->radius = radius + MAX_REDRAINHEIGHT + (ceiling - floor); + + spawner->color.c = 0xffffffff; + spawner->nextEventTime = fxi.cl->time + (RED_RAIN_DURATION+1.0)*1000;//waits for EF_DISABLE from owner, but in case we miss the message, time out + + // The rain should start at the impact height, then move up to the target height. + spawner->SpawnData = -ceiling; + if (powerup) + spawner->SpawnInfo = 1; + + AddEffect(Owner, spawner); + + // Pass the explosion point as well as the rain generation point. + RedRainExplosion(Origin, ceil_org, (RED_RAIN_DURATION+1.0)*1000, powerup, Owner); +} + +// Red Rain Missile + + + +// --------------------------------------------------------------------------- + + +// The red rain projectile's trail of red sparks. +static qboolean FXRedRainMissileThink(client_entity_t *missile, centity_t *owner) +{ + int i; + client_entity_t *ce; + vec3_t diff, curpos, org; + + VectorSubtract(missile->r.origin, missile->origin, diff); + Vec3ScaleAssign((1.0 / NUM_TRAIL_PARTS), diff); + VectorClear(curpos); + + for(i = 0; i < NUM_TRAIL_PARTS; i++) + { + VectorRandomCopy(missile->origin, org, PART_OFF); + Vec3AddAssign(curpos, org); + ce = ClientEntity_new(-1, 0, org, NULL, 500); + if (missile->SpawnInfo) // Powered up + { + ce->r.model = rain_models+4; + } + else + { + ce->r.model = rain_models; + } + ce->r.scale = 1.0F; + ce->d_scale = 2.0F; + ce->r.frame = 0; + ce->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + ce->radius = 16.0F; + ce->d_alpha = -2.2F; + AddEffect(NULL, ce); + + Vec3AddAssign(diff, curpos); + } + // Remember for even spread of particles + VectorCopy(missile->r.origin, missile->origin); + return(true); +} + +// From creation of the effect FX_RED_RAIN_MISSILE +void FXRedRainMissile(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *missile; + vec3_t temp; + int dur; + + if (r_detail->value == DETAIL_LOW) + dur = 150; + else + if (r_detail->value == DETAIL_NORMAL) + dur = 125; + else + dur = 100; + + missile = ClientEntity_new(Type, Flags | CEF_DONT_LINK, Origin, NULL, dur); + fxi.GetEffect(Owner, Flags, "t", missile->velocity); + + if (Flags & CEF_FLAG7) + { + if (Flags & CEF_FLAG8) + Vec3ScaleAssign(MSSITHRA_FX_ARROW_SPEED/2,missile->velocity); + else + Vec3ScaleAssign(MSSITHRA_FX_ARROW_SPEED,missile->velocity); + } + + else + { + if (Flags & CEF_FLAG8) + Vec3ScaleAssign(RED_ARROW_SPEED/2,missile->velocity); + else + Vec3ScaleAssign(RED_ARROW_SPEED,missile->velocity); + } + + VectorCopy(missile->velocity, temp); + VectorNormalize(temp); + AnglesFromDir(temp, missile->r.angles); + + missile->r.model = rain_models + 1; + missile->Update = FXRedRainMissileThink; + missile->radius = 32.0F; + if (Flags & CEF_FLAG6) + { // Powered up rain + missile->SpawnInfo = 1; + missile->color.c = 0xff00ff80; // green + } + else + { + missile->color.c = 0xff0000ff; // Red + } + missile->dlight = CE_DLight_new(missile->color, 150.0F, 00.0F); + AddEffect(Owner, missile); +} + +// Red Rain Explosion + +// --------------------------------------------------------------------------- + + +// Thinker for the explosion, just fades the light +static qboolean FXRedRainDLightThink(client_entity_t *dlight, centity_t *owner) +{ + dlight->dlight->intensity -= 10.0F; + if(dlight->dlight->intensity < 0.0F) + return(false); + + return(true); +} + +static qboolean RedRainExplosionThink(client_entity_t *explosion, centity_t *owner) +{ // The explosion bit should be drawn to orbit the rain generation spot. + vec3_t targetpos, diffpos, dir, randomvect; + float radius; + + explosion->updateTime = 100; + explosion->LifeTime -= 100; + + if (explosion->LifeTime > 1000) + { // Vary intesity + explosion->alpha = 1.0 - explosion->r.scale*0.1; + } + else if(explosion->LifeTime == 1000) + { // Fade them out + explosion->d_alpha = -0.5; + explosion->d_scale = -2.0; + } + else if (explosion->LifeTime < 0) + return(false); + + explosion->r.angles[YAW] += 20.0; + + if (explosion->SpawnInfo) + { // Powered up rain + radius = POWER_RAIN_RADIUS; + } + else + { // Non-powered + radius = RED_RAIN_RADIUS; + } + + AngleVectors(explosion->r.angles, dir, NULL, NULL); + VectorMA(explosion->direction, radius*1.5, dir, targetpos); + VectorSet(randomvect, + flrand(-radius, radius), + flrand(-radius, radius), + flrand(-radius, radius)); + VectorAdd(targetpos, randomvect, targetpos); + + // This is the velocity it would need to reach the position in one second. + VectorSubtract(targetpos, explosion->r.origin, diffpos); + + // Average this velocity with the current one. + VectorAdd(explosion->velocity, diffpos, diffpos); + VectorScale(diffpos, 0.5, explosion->velocity); + + return(true); +} + +// This is similar to the FXRedRainMissileExplode, except that the explosion needs knowledge of the rainfall height. +void RedRainExplosion(vec3_t impactpos, vec3_t rainpos, int duration, qboolean powerup,centity_t *owner) +{ + client_entity_t *explo; + client_entity_t *dlight; + vec3_t org; + paletteRGBA_t color; + int i; + float degreeinc; + int count; + + dlight = ClientEntity_new(-1, CEF_NO_DRAW | CEF_NOMOVE, impactpos, NULL, 100); + if (powerup) + color.c = 0xff0080ff; // Orange when powered up + else + color.c = 0xff0000ff; // Red when not. + dlight->dlight = CE_DLight_new(color, 150.0F, 0.0F); + dlight->Update = FXRedRainDLightThink; + AddEffect(NULL, dlight); + + // always have at least 3 clouds + count = GetScaledCount(REDRAIN_EXPLODE_NUM, 0.3); + if (count < 3) + count = 3; + + degreeinc = (360.0)/(float)count; + for(i = 0; i < count; i++) + { + VectorRandomCopy(impactpos, org, RED_RAIN_RADIUS/3.0); + explo = ClientEntity_new(FX_WEAPON_REDRAIN, CEF_DONT_LINK, org, NULL, 100); + + explo->r.model = rain_models + 2; + explo->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + explo->radius = 16.0F; + VectorSet(explo->velocity, flrand(-128.0, 128.0), flrand(-128.0, 128.0), flrand(-128.0, 0.0)); + explo->r.angles[YAW] = (float)i*degreeinc; + VectorCopy(rainpos, explo->direction); + explo->alpha = 0.3; + explo->lastThinkTime = fxi.cl->time; + explo->LifeTime = duration; + explo->Update = RedRainExplosionThink; + if (powerup) + { + explo->SpawnInfo = 1; + explo->r.frame = 1; + explo->r.scale = 3; + } + else + { + explo->r.frame = 0; + explo->r.scale = 2.5; + } + + AddEffect(owner, explo); + } + + // Add a big red flash at impact of course. + explo = ClientEntity_new(-1, 0, impactpos, NULL, 500); + if (powerup) + { // Green flash + explo->r.model = rain_models+4; + } + else + { // Red flash + explo->r.model = rain_models; + } + explo->r.frame = 0; + explo->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + explo->radius = 16.0F; + explo->r.scale = 8.0F; + explo->d_scale = -16.0F; + explo->d_alpha = -2.0F; + AddEffect(NULL, explo); + + if (powerup) + fxi.S_StartSound(impactpos, -1, CHAN_AUTO, fxi.S_RegisterSound("weapons/RedRainPowerHit.wav"), 1, ATTN_NORM, 0); + else + fxi.S_StartSound(impactpos, -1, CHAN_AUTO, fxi.S_RegisterSound("weapons/RedRainHit.wav"), 1, ATTN_NORM, 0); +} + + + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_Ripples.c b/Toolkit/Programming/GameCode/client effects/fx_Ripples.c new file mode 100644 index 0000000..e04c99a --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_Ripples.c @@ -0,0 +1,73 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "Utilities.h" +#include "Ambient effects.h" + +#define SCALE 0.01F +#define DELTA_SCALE 1.0F + +#define NUM_RIPPLE_MODELS 1 +static struct model_s *ripple_models[NUM_RIPPLE_MODELS]; +void PreCacheRipples() +{ + ripple_models[0] = fxi.RegisterModel("sprites/fx/waterentryripple.sp2"); +} + +// -------------------------------------------------------------- + +static qboolean FXRippleSpawner(client_entity_t *spawner, centity_t *owner) +{ + client_entity_t *ripple; + float alpha; + + alpha = 1.0F / ((4 - spawner->SpawnInfo) * (4 - spawner->SpawnInfo)); + + ripple = ClientEntity_new(-1, 0, spawner->origin, spawner->direction, 1000); + + ripple->r.model = ripple_models; + ripple->r.flags |= RF_FIXED | RF_TRANSLUCENT | RF_ALPHA_TEXTURE; + ripple->r.scale = SCALE; + ripple->d_scale = DELTA_SCALE; + ripple->alpha = alpha; + ripple->d_alpha = -alpha; + + AddEffect(NULL, ripple); + + if(spawner->SpawnInfo-- < 0) + { + spawner->updateTime = 1000; + spawner->Update = RemoveSelfAI; + } + return(true); +} + +void FXWaterRipples(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *spawner; + vec3_t dir; + vec_t dist; + + if(GetWaterNormal(Origin, 1.0, 20.0F, dir, &dist)) + { + Origin[2] += dist; + spawner = ClientEntity_new(Type, Flags, Origin, dir, 200); + + spawner->SpawnInfo = 3; + spawner->Update = FXRippleSpawner; + spawner->flags |= CEF_NO_DRAW | CEF_NOMOVE; + + AddEffect(NULL, spawner); + } +} +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_ammopickup.c b/Toolkit/Programming/GameCode/client effects/fx_ammopickup.c new file mode 100644 index 0000000..856cb8b --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_ammopickup.c @@ -0,0 +1,135 @@ +// +// fx_AmmoPickup.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "ce_DefaultMessageHandler.h" +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "Angles.h" +#include "g_items.h" + +#define BOB_HEIGHT 6.0 +#define BOB_SPEED ANGLE_10 +#define HEALTH_RADIUS 6.0 + +#define NUM_AMMO_MODELS 9 +static struct model_s *ammomodels[NUM_AMMO_MODELS]; +void PreCacheItemAmmo() +{ + ammomodels[0] = fxi.RegisterModel("models/items/mana/half/tris.fm"); // ITEM_AMMO_MANA_DEFENSIVE_HALF + ammomodels[1] = fxi.RegisterModel("models/items/mana/full/tris.fm"); // ITEM_AMMO_MANA_DEFENSIVE_FULL + ammomodels[2] = fxi.RegisterModel("models/items/mana/half/tris.fm"); // ITEM_AMMO_MANA_OFFENSIVE_HALF + ammomodels[3] = fxi.RegisterModel("models/items/mana/full/tris.fm"); // ITEM_AMMO_MANA_OFFENSIVE_FULL + ammomodels[4] = fxi.RegisterModel("models/items/mana/combo/tris.fm"); // ITEM_AMMO_MANA_COMBO_QUARTER + ammomodels[5] = fxi.RegisterModel("models/items/mana/combo/tris.fm"); // ITEM_AMMO_MANA_COMBO_HALF + ammomodels[6] = fxi.RegisterModel("models/items/ammo/hellstaff/tris.fm"); // ITEM_AMMO_HELLSTAFF + ammomodels[7] = fxi.RegisterModel("models/items/ammo/redrain/tris.fm"); // ITEM_AMMO_REDRAIN + ammomodels[8] = fxi.RegisterModel("models/items/ammo/phoenix/tris.fm"); // ITEM_AMMO_PHOENIX +} + +// -------------------------------------------------------------- + +static qboolean FXAmmoPickupThink(struct client_entity_s *self, centity_t *owner) +{ + + client_particle_t *p; + paletteRGBA_t color; + + // Rotate and bob + self->r.angles[YAW] += ANGLE_5; + VectorCopy(owner->current.origin, self->r.origin); + self->r.origin[2] += (cos(self->SpawnData) * BOB_HEIGHT); + self->SpawnData += BOB_SPEED; + + switch(self->SpawnInfo) + { + + case 0: + case 1: + color.g = irand(50, 90); + color.b = irand(210, 255); + color.r = color.g; + break; + + case 2: + case 3: + color.r = irand(50, 90); + color.g = irand(210, 255); + color.b = color.r; + break; + + case 4: + case 5: + if (irand(0,1)) + { + color.g = irand(50, 90); + color.b = irand(210, 255); + color.r = color.g; + } + else + { + color.r = irand(50, 90); + color.g = irand(210, 255); + color.b = color.r; + } + break; + + } + + if (self->SpawnInfo < 6) + { + // spawn particles + color.a = 255; + p = ClientParticle_new(PART_4x4_WHITE | PFL_SOFT_MASK, color, 600); + + VectorSet(p->origin, flrand(-HEALTH_RADIUS, HEALTH_RADIUS), flrand(-HEALTH_RADIUS, HEALTH_RADIUS), 0.0); + VectorSet(p->velocity, 0.0, 0.0, flrand(20.0, 40.0)); + p->acceleration[2] = 20.0; + AddParticleToList(self, p); + } + return(true); +} + +void FXAmmoPickup(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *ce; + byte tag; + + fxi.GetEffect(owner, flags, "b", &tag); + + flags &= ~CEF_OWNERS_ORIGIN; + ce = ClientEntity_new(type, flags | CEF_DONT_LINK | CEF_CHECK_OWNER | CEF_VIEWSTATUSCHANGED, origin, NULL, 50); + + VectorCopy(ce->r.origin, ce->origin); + ce->r.model = ammomodels + tag; + + if (tag==0) // Blue stuff + ce->r.skinnum = 1; + if (tag==1) // Blue stuff + ce->r.skinnum = 1; + + ce->r.flags = RF_TRANSLUCENT | RF_GLOW; + + if ((tag == ITEM_AMMO_MANA_COMBO_HALF) || (tag == ITEM_AMMO_MANA_DEFENSIVE_FULL) || + (tag == ITEM_AMMO_MANA_OFFENSIVE_FULL)) + ce->r.scale = 1.25; + else + ce->r.scale = 1.0; + ce->radius = 10.0; + ce->alpha = 0.8; + ce->Update = FXAmmoPickupThink; + ce->SpawnInfo = tag; + + AddEffect(owner, ce); +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_animate.c b/Toolkit/Programming/GameCode/client effects/fx_animate.c new file mode 100644 index 0000000..db7ad2c --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_animate.c @@ -0,0 +1,129 @@ +// +// fx_animate.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "ce_DefaultMessageHandler.h" +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Utilities.h" +#include "Angles.h" +#include "random.h" + +typedef struct FXAnimModel +{ + char *ModelName; + struct model_s *model; + float radius; + float alpha; + int numframes; + int defaultframe; +} FXAnimModel_t; + +// ************************************************************************************************ +// Animating chunks +// ************************************************************************************************ + +FXAnimModel_t FXAnimModel[NUM_FX_ANIM]= +{ + "models/objects/banner/wall/tris.fm", NULL, 220.0, 1.0, 15, 1, // FX_ANIM_BANNER + "models/objects/lights/candelabrum/tris.fm",NULL, 100.0, 1.0, 7, 1, // FX_ANIM_CANDELABRUM + "models/objects/chandelier/chan2/tris.fm", NULL, 100.0, 1.0, 7, 7, // FX_ANIM_CHANDELIER2 + NULL, NULL, 100.0, 0.5, 1, 0, // FX_ANIM_FLAME - NEVER USED + NULL, NULL, 100.0, 0.5, 1, 0, // FX_ANIM_FIRE - NEVER USED + "models/objects/banner/onpole/tris.fm", NULL, 100.0, 1.0, 21, 0, // FX_ANIM_BANNERONPOLE + "models/objects/flags/onpole/tris.fm", NULL, 100.0, 1.0, 80, 0, // FX_ANIM_FLAGONPOLE + "models/objects/eggs/cocoon/tris.fm", NULL, 100.0, 1.0, 20, 0, // FX_ANIM_COCOON + "models/objects/labs/container1/tris.fm", NULL, 100.0, 1.0, 30, 0, // FX_ANIM_LABPARTSCONTAINER + "models/objects/labs/tray/tris.fm", NULL, 100.0, 1.0, 15, 0, // FX_ANIM_LABTRAY + "models/objects/labs/container2/tris.fm", NULL, 100.0, 1.0, 80, 0, // FX_ANIM_EYEBALLJAR + "models/objects/torture/ogle/tris.fm", NULL, 100.0, 1.0, 100, 0, // FX_ANIM_HANGING_OGLE +}; + +void PreCacheFXAnimate(void) +{ + int i; + + for(i = 0; i < NUM_FX_ANIM; ++i) + { + if (FXAnimModel[i].ModelName) + FXAnimModel[i].model = fxi.RegisterModel(FXAnimModel[i].ModelName); + } +} + +// ------------------------------------------------- + +static qboolean FXAnimateGo(struct client_entity_s *self, centity_t *owner) +{ + + self->r.frame++; + if(self->r.frame >= self->NoOfAnimFrames) + { + self->r.frame = 0; + } + return(true); +} + +static qboolean FXAnimateRandomGo(struct client_entity_s *self, centity_t *owner) +{ + self->updateTime = 100; + self->r.frame++; + + if(self->r.frame == self->NoOfAnimFrames) + { + self->r.frame = 0; + self->updateTime = irand(500, 5000); + } + return(true); +} + +void FXAnimate(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *self; + byte atype, scale, skinnum, anim; + + self = ClientEntity_new(type, flags, origin, 0, 100); + + fxi.GetEffect(owner, flags, "bbbv", &anim, &scale, &skinnum, self->r.angles); + VectorDegreesToRadians(self->r.angles, self->r.angles); + atype = anim & 0x7f; + + self->r.model = &FXAnimModel[atype].model; + self->r.scale = scale * 0.02; + self->r.skinnum = skinnum; + + self->alpha = FXAnimModel[atype].alpha; + self->radius = FXAnimModel[atype].radius; + self->NoOfAnimFrames = FXAnimModel[atype].numframes; + self->r.frame = FXAnimModel[atype].defaultframe; + + if(anim & 0x80) + { + // Animate (special animate for cocoon) + if(atype == FX_ANIM_COCOON) + { + self->Update = FXAnimateRandomGo; + } + else + { + self->Update = FXAnimateGo; + } + + self->nextThinkTime=fxi.cl->time + irand(40, 1600); // So they don't all start on frame 0 at the same time + + } + else + { + // Don`t animate and think less + self->Update = KeepSelfAI; + self->updateTime = 1000; + } + AddEffect(owner, self); +} +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_assassin.c b/Toolkit/Programming/GameCode/client effects/fx_assassin.c new file mode 100644 index 0000000..d7223d0 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_assassin.c @@ -0,0 +1,108 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// Created by JDW + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "Utilities.h" +#include "g_playstats.h" + +void PreCacheTPortSmoke() +{ +} + + +void FXTPortSmoke(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + int numPuffs, i; + client_entity_t *TPortSmoke; + client_particle_t *ce; + + TPortSmoke = ClientEntity_new(Type, Flags|CEF_NO_DRAW, Origin, NULL, 1650); + + TPortSmoke->r.color.r = 255; + TPortSmoke->r.color.g = 255; + TPortSmoke->r.color.b = 255; + TPortSmoke->r.color.a = 128; + + TPortSmoke->radius = 10.0F; + + AddEffect(NULL, TPortSmoke); + + if (r_detail->value >= DETAIL_HIGH) + numPuffs = irand(20,30); + else + if (r_detail->value == DETAIL_NORMAL) + numPuffs = irand(10,20); + else + numPuffs = irand(8,13); + + fxi.S_StartSound(Origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("monsters/assassin/smoke.wav"), 1, ATTN_NORM, 0); + for (i = 0; i < numPuffs; i++) + { + if (r_detail->value >= DETAIL_HIGH) + ce = ClientParticle_new(PART_32x32_BLACKSMOKE | PFL_NEARCULL, TPortSmoke->r.color, 1600); + else + if (r_detail->value == DETAIL_NORMAL) + ce = ClientParticle_new(PART_32x32_BLACKSMOKE | PFL_NEARCULL, TPortSmoke->r.color, 1500); + else + ce = ClientParticle_new(PART_32x32_BLACKSMOKE | PFL_NEARCULL, TPortSmoke->r.color, 1300); + + VectorClear(ce->origin); + ce->velocity[0] = flrand(-100.0F, 100.0F); + ce->velocity[1] = flrand(-100.0F, 100.0F); + ce->velocity[2] = flrand(50.0F, 250.0F); + + VectorScale(ce->velocity, -1.23F, ce->acceleration); + if (r_detail->value >= DETAIL_HIGH) + ce->scale = flrand(60.0, 70.0); + else + if (r_detail->value == DETAIL_NORMAL) + ce->scale = flrand(50.0, 60.0); + else + ce->scale = flrand(30.0, 45.0); + ce->d_scale = -20.0F; + ce->d_alpha = -77; + AddParticleToList(TPortSmoke, ce); + } +} + + +static qboolean FXAssSkinUpdaterThink(client_entity_t *assskinupdater, centity_t *owner) +{ + vec3_t sight_vec, endpos; + char string[MAX_QPATH]; + trace_t trace; + + if(owner->entity->skinnum!=100) + return (false); + + VectorSubtract(owner->origin, cl.camera_vieworigin, sight_vec); + VectorNormalize(sight_vec); + VectorMA(owner->origin, 1024, sight_vec, endpos); + //now look along that vector for first surface and take that texture + fxi.Trace(owner->origin, vec3_origin, vec3_origin, endpos, MASK_SHOT, CEF_CLIP_TO_WORLD, &trace); + strcpy(string, "textures/"); + strcat(string, trace.surface->name); + strcpy(owner->entity->skinname, string); + return(true); +} + +void FXAssassinUseWallSkin(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *assskinupdater; + + assskinupdater = ClientEntity_new(Type, CEF_NO_DRAW, Origin, NULL, 100); + + assskinupdater->Update = FXAssSkinUpdaterThink; + AddEffect(Owner, assskinupdater); +} +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_blood.c b/Toolkit/Programming/GameCode/client effects/fx_blood.c new file mode 100644 index 0000000..e8200e8 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_blood.c @@ -0,0 +1,614 @@ +// +// fx_staff.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Reference.h" +#include "Utilities.h" +#include "g_playstats.h" + +#define BLOOD_SPEED 40.0F +#define NUM_BLOOD_SPURT_PARTS 20 +#define NUM_INSECT_BLOOD_PARTICLES 12 + +extern int ref_soft; + +#define NUM_BLOOD_MODELS 2 +static struct model_s *splat_models[NUM_BLOOD_MODELS]; +void PreCacheSplat() +{ + splat_models[0] = fxi.RegisterModel("sprites/fx/bsplat.sp2"); + splat_models[1] = fxi.RegisterModel("sprites/fx/ysplat.sp2"); +} + +int InsectBloodParticle [NUM_INSECT_BLOOD_PARTICLES] = +{ + PART_4x4_GREEN, + PART_4x4_YELLOW, + PART_8x8_GLOBBIT1, + PART_8x8_GLOBBIT2, + PART_16x16_MIST, + PART_16x16_GLOB, + PART_16x16_SPARK_G, + PART_16x16_SPARK_Y, + PART_32x32_GREENBLOOD, + PART_16x16_GREENBLOOD, + PART_4x4_GREENBLOOD1, + PART_4x4_GREENBLOOD2 +}; + +client_entity_t *DoBloodSplash(vec3_t loc, int amount, qboolean yellow_blood) +{ + client_entity_t *splash; + client_particle_t *drop; + int i, j; + paletteRGBA_t pal; + paletteRGBA_t pal2; + float speed, grav; + int size; + int bpart; + + splash = ClientEntity_new(FX_BLOOD, CEF_NO_DRAW, loc, NULL, 1000); + AddEffect(NULL, splash); + + speed = 16 + 4*amount; + grav = GetGravity()*0.5; + pal.c = 0xffffffff; + pal2.c = 0xff0000ff; + if (amount>500) + amount=500; + for (i=0; ivelocity, flrand(-speed, speed), flrand(-speed, speed), flrand(speed*2.0, speed*4.0)); + drop->acceleration[2] = grav; + drop->d_alpha = 0.0; + drop->d_scale = -1.0; + AddParticleToList(splash, drop); + } + break; + case 1: // Some larger globs + for (j=0; j<3; j++) + { + if (ref_soft) + { + if(yellow_blood) + bpart = PART_8x8_GLOBBIT1; + else + bpart = PART_8x8_BLOOD; + drop = ClientParticle_new(bpart | PFL_SOFT_MASK, pal2, 650); + } + else + { + if(yellow_blood) + bpart = irand(PART_8x8_GLOBBIT1, PART_8x8_GLOBBIT2); + else + bpart = PART_8x8_BLOOD; + drop = ClientParticle_new(bpart, pal, 800); + } + VectorSet(drop->velocity, flrand(-speed, speed), flrand(-speed, speed), flrand(speed*2.0, speed*4.0)); + drop->acceleration[2] = grav; + drop->d_alpha = 0.0; + drop->scale = 2.0; + drop->d_scale = -2.0; + AddParticleToList(splash, drop); + } + break; + case 2: // Some big blobs + for (j=0; j<2; j++) + { + if(yellow_blood) + bpart = PART_16x16_GREENBLOOD; + else + bpart = PART_16x16_BLOOD; + drop = ClientParticle_new(bpart, pal, 1000); + VectorSet(drop->velocity, flrand(-speed, speed), flrand(-speed, speed), flrand(speed, speed*2.0)); + drop->acceleration[2] = grav*0.5; + drop->d_alpha = flrand(-512.0, -256.0); + drop->scale = 1.0; + drop->d_scale = flrand(4.0, 8.0); + AddParticleToList(splash, drop); + } + break; + case 3: // A big splash + if(yellow_blood) + bpart = PART_32x32_GREENBLOOD; + else + bpart = PART_32x32_BLOOD; + drop = ClientParticle_new(bpart, pal, 500); + VectorSet(drop->velocity, flrand(-speed, speed), flrand(-speed, speed), flrand(0, speed)); + drop->scale = 4.0; + drop->acceleration[2] = 0.0; + drop->d_scale = flrand(48.0, 64.0); + drop->d_alpha = flrand(-1024.0, -512.0); + AddParticleToList(splash, drop); + break; + } + } + + return splash; +} + +void DoBloodTrail(client_entity_t *spawner, int amount) +{ + client_particle_t *drop; + int i, j; + paletteRGBA_t pal; + paletteRGBA_t pal2; + float speed, grav, range; + int size; + qboolean yellow_blood = false; + + if((spawner->SpawnInfo&SIF_FLAG_MASK) == MAT_INSECT)//insect blood is yellow-green + yellow_blood = true; + + if(amount == -1) + speed = 0; + else + speed = 8 + 4*amount; + grav = GetGravity()*0.5; + range = (float)amount; + pal.c = 0xffffffff; + pal2.c = 0xff0000ff; + if (amount>500) + amount=500; + for (i=0; ivelocity, flrand(-speed, speed), flrand(-speed, speed), flrand(speed*2.0, speed*4.0)); + VectorMA(drop->velocity, 0.5, spawner->velocity, drop->velocity); + VectorSet(drop->origin, flrand(-range, range), flrand(-range, range), flrand(-range, range)); + VectorAdd(drop->origin, spawner->r.origin, drop->origin); + drop->acceleration[2] = grav; + drop->d_alpha = 0.0; + drop->d_scale = -1.0; + AddParticleToList(spawner, drop); + } + break; + case 1: // Some larger globs + if(yellow_blood) + drop = ClientParticle_new(InsectBloodParticle[irand(0, NUM_INSECT_BLOOD_PARTICLES - 1)], pal, 800); + else + drop = ClientParticle_new(PART_8x8_BLOOD, pal, 800); + VectorSet(drop->velocity, flrand(-speed, speed), flrand(-speed, speed), flrand(speed*2.0, speed*4.0)); + VectorMA(drop->velocity, 0.5, spawner->velocity, drop->velocity); + VectorSet(drop->origin, flrand(-range, range), flrand(-range, range), flrand(-range, range)); + VectorAdd(drop->origin, spawner->r.origin, drop->origin); + drop->acceleration[2] = grav; + drop->d_alpha = 0.0; + drop->scale = 2.0; + drop->d_scale = -2.0; + AddParticleToList(spawner, drop); + break; + } + } +} + +// -------------------------------------------------------------- +// Find exact plane to decal the bloodmark to + +static qboolean GetTruePlane(vec3_t origin, vec3_t direction) +{ + trace_t trace; + vec3_t end; + vec3_t mins, maxs; + + VectorClear(mins); + VectorClear(maxs); + + VectorMA(origin, 16.0, direction, end); + + fxi.Trace(origin, mins, maxs, end, MASK_DRIP, CEF_CLIP_TO_WORLD, &trace); + if(trace.fraction != 1.0) + { + // Set the new endpos and plane (should be exact) + VectorCopy(trace.endpos, origin); + VectorCopy(trace.plane.normal, direction); + + VectorMA(origin, 0.25, direction, origin); + return(true); + } + return(false); +} + +qboolean BloodSplatDripUpdate (client_entity_t *self, centity_t *owner); +qboolean BloodSplatSplishUpdate (client_entity_t *self, centity_t *owner) +{ + client_particle_t *p; + paletteRGBA_t color = {180, 140, 110, 160}; + vec3_t vel; + qboolean yellow_blood = false; + int bpart; + + if(self->flags&CEF_FLAG8) + yellow_blood = true; + + if (self->SpawnInfo>500) + return true; + while(self->SpawnInfo>0) + { + if (ref_soft) + { + if(yellow_blood) + bpart = InsectBloodParticle[irand(0, NUM_INSECT_BLOOD_PARTICLES - 1)]; + else + bpart = PART_4x4_BLOOD1; + p = ClientParticle_new(bpart|PFL_SOFT_MASK, color, 800); + } + else + { + if(yellow_blood) + bpart = InsectBloodParticle[irand(0, NUM_INSECT_BLOOD_PARTICLES - 1)]; + else + bpart = irand(PART_4x4_BLOOD1, PART_4x4_BLOOD2); + p = ClientParticle_new(bpart, color, 800); + } + p->acceleration[2] = GetGravity() * 0.2; + VectorRandomCopy(self->endpos2, vel, 10.0F); + VectorScale(vel, flrand(2, 5), p->velocity); + p->d_alpha = 0; + p->scale = flrand(0.4, 0.8); + VectorAdd(self->startpos2, self->startpos, p->origin); + AddParticleToList(self, p); + self->SpawnInfo--; + } + fxi.S_StartSound(p->origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("ambient/waterdrop%c.wav", irand('1', '3'))), flrand(0.5, 0.8), ATTN_STATIC, 0); + + if(!irand(0, 2)) + VectorSet(self->startpos, flrand(-1, 1), flrand(-1, 1), 0); + + self->Update = BloodSplatDripUpdate; + self->updateTime = irand(400, 1600); + + return (true); +} + +qboolean BloodSplatDripUpdate (client_entity_t *self, centity_t *owner) +{ + client_particle_t *p; + paletteRGBA_t color = {150, 140, 110, 160}; + int num_drips, i; + float scale, grav_mod, driptime; + qboolean yellow_blood = false; + int bpart; + + if(!AttemptRemoveSelf(self, owner)) + return (false); + + if(self->flags&CEF_FLAG8) + yellow_blood = true; + + //drip- fiXME: make p duration based on self->radius? + driptime = self->radius * 6; + scale = flrand(0.2, 0.4); + num_drips = irand(7, 15); + for(i = 0; i < num_drips; i++) + { + if (ref_soft) + { + if(yellow_blood) + bpart = InsectBloodParticle[irand(0, NUM_INSECT_BLOOD_PARTICLES - 1)]; + else + bpart = PART_4x4_BLOOD1; + p = ClientParticle_new(bpart | PFL_SOFT_MASK, color, 1600); + } + else + { + if(yellow_blood) + bpart = InsectBloodParticle[irand(0, NUM_INSECT_BLOOD_PARTICLES - 1)]; + else + bpart = irand(PART_4x4_BLOOD1, PART_4x4_BLOOD2); + p = ClientParticle_new(bpart, color, 3200); + } + grav_mod = (0.4 + (i * 0.025)); + p->acceleration[2] = GetGravity() * grav_mod; + p->d_alpha = 0; + p->scale = scale + (i * 0.08); + VectorCopy(self->startpos, p->origin); + + AdvanceParticle(p, 7 * i); + + AddParticleToList(self, p); + + if(driptime >= 17) + { + p->duration = driptime * 3 * grav_mod; + self->SpawnInfo++; + } + } + + if(self->SpawnInfo && driptime >= 17) + {//splash + self->Update = BloodSplatSplishUpdate; + self->updateTime = driptime; + } + else + { + if(!irand(0, 3)) + VectorSet(self->startpos, flrand(-1, 1), flrand(-1, 1), 0); + + self->updateTime = irand(400, 1600); + } + + return (true); +} + +void ThrowBlood(vec3_t origin, vec3_t tnormal, qboolean dark, qboolean yellow, qboolean trueplane) +{ + client_entity_t *bloodmark; + vec3_t normal; + int brightness; + + VectorCopy(tnormal, normal); + VectorScale(normal, -1, normal); + + if(trueplane || GetTruePlane(origin, normal)) + { + bloodmark = ClientEntity_new(FX_BLOOD, CEF_NOMOVE, origin, tnormal, 1000); + + bloodmark->r.angles[ROLL] = flrand(0, ANGLE_360); + + if(yellow) + bloodmark->r.model = splat_models + 1; + else + bloodmark->r.model = splat_models; + bloodmark->r.flags = 0; + bloodmark->r.flags |= RF_FIXED | RF_ALPHA_TEXTURE; + bloodmark->r.frame = irand(0,4); + + if(dark) + { + brightness = irand(32, 72); + bloodmark->r.color.r = brightness; + bloodmark->r.color.g = brightness; + bloodmark->r.color.b = brightness; + } + else + { + brightness = irand(72, 128); + bloodmark->r.color.r = brightness; + bloodmark->r.color.g = brightness; + bloodmark->r.color.b = brightness; + } + bloodmark->r.color.a = 255; + bloodmark->alpha = 1.0; + + bloodmark->radius = 10.0; + bloodmark->r.scale = flrand(0.2, 0.45); + + if(tnormal[2] <= -0.7 && !irand(0, 2) && bloodmark->r.frame != 2 && bloodmark->r.frame != 4) + { + trace_t extratrace; + vec3_t endpos; + + VectorMA(origin, 256, tnormal, endpos); + fxi.Trace(origin, vec3_origin, vec3_origin, endpos, MASK_DRIP, CEF_CLIP_TO_WORLD, &extratrace); + if(extratrace.fraction<1.0 && extratrace.fraction > 0.0625)//bewteen 16 and 256 + { + if(extratrace.plane.normal[2] >= 0.7) + { + bloodmark->radius = extratrace.fraction * 256; + VectorSubtract(extratrace.endpos, origin, bloodmark->startpos2); + VectorCopy(extratrace.plane.normal, bloodmark->endpos2); + ThrowBlood(extratrace.endpos, extratrace.plane.normal, dark, yellow, false); + } + } + + VectorClear(bloodmark->startpos); + bloodmark->LifeTime = 0; + if(yellow) + bloodmark->flags |= CEF_FLAG8; + bloodmark->Update = BloodSplatDripUpdate; + } + else + { + bloodmark->Update = AttemptRemoveSelf; + } + + AddEffect(NULL, bloodmark); + InsertInCircularList(bloodmark); + } +} + +void FXBloodTrail(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t normal; + + fxi.GetEffect(owner, flags, "d", &normal); + + VectorMA(origin, 0.25, normal, origin); + ThrowBlood(origin, normal, flags&CEF_FLAG7, flags&CEF_FLAG6, true); +} + +// ClientEffect FX_BLOOD +void FXBlood(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *spawner; + byte amount; + vec3_t velocity; + qboolean yellow_blood = false; + + fxi.GetEffect(owner, flags, "ub", &velocity, &amount); + + if(flags&CEF_FLAG8) + yellow_blood = true; + + // lets add level of detail here to the amount we pump out + switch((int)r_detail->value) + { + // half as much + case DETAIL_LOW: + amount = ((float)amount * 0.5); + break; + + // 3 quarters + case DETAIL_NORMAL: + amount = ((float)amount * 0.75); + break; + + default: + break; + } + if (!amount) + amount = 1; + + spawner = DoBloodSplash(origin, amount, yellow_blood); + VectorCopy(velocity, spawner->velocity); +} + +// ------------------------------------------------------------------------------ + +#define NUM_BLOOD_PARTS 3 + +static qboolean LinkedBloodThink(client_entity_t *spawner, centity_t *owner) +{ + client_particle_t *p; + client_entity_t *ce; + vec3_t org, vel; + int i; + int bpart; + qboolean yellow_blood; + + spawner->updateTime = irand(40, 60); + + spawner->LifeTime -= 50; + if(spawner->LifeTime < 0) // Effect finished + return(false); + + if(spawner->LifeTime < 800) // Effect needs to stay alive until particles die + return(true); + + if(spawner->flags&CEF_FLAG8)//yellow + yellow_blood = true; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return false; // Just end the effect. + + VectorGetOffsetOrigin(owner->referenceInfo->references[spawner->SpawnInfo].placement.origin, owner->current.origin, owner->current.angles[YAW], org); + ce = ClientEntity_new(-1, 0, org, NULL, 800); + ce->flags |= CEF_NO_DRAW | CEF_NOMOVE; + ce->radius = 32.0; + AddEffect(NULL, ce); + + VectorSubtract(org, spawner->origin, vel); + Vec3ScaleAssign(5.0, vel); + + for(i = 0; i < NUM_BLOOD_PARTS; i++) + { + if(yellow_blood) + bpart = InsectBloodParticle[irand(0, NUM_INSECT_BLOOD_PARTICLES - 1)]; + else + bpart = irand(PART_4x4_BLOOD1, PART_4x4_BLOOD2); + p = ClientParticle_new(bpart, spawner->color, 800); + Vec3AddAssign(vel, p->velocity); + p->acceleration[2] = GetGravity(); + p->d_alpha = 0.0; + p->d_scale = -1.0; + AddParticleToList(ce, p); + } + + // Remember current origin for calc of velocity + VectorCopy(org, spawner->origin); + return(true); +} + +void FXLinkedBlood(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *spawner; + byte refpointidx, life; + int count, i; + int lifetime = 0; + + fxi.GetEffect(owner, flags, "bb", &life, &refpointidx); + lifetime = life * 50; + count = 1; + if(life > 1600) + { + count = (life - 1600) / 100; + life = 1600; + if(count > 10) // Max out saftey check + count = 10; + } + + for(i = 0; i < count; i++) + { + spawner = ClientEntity_new(type, flags, origin, NULL, Q_ftol(fxi.cls->frametime * 2000.0)); + + spawner->LifeTime = life; + spawner->flags |= CEF_NO_DRAW; + spawner->color.c = 0xFFFFFFFF; + spawner->Update = LinkedBloodThink; + spawner->SpawnInfo = refpointidx; + spawner->AddToView = OffsetLinkedEntityUpdatePlacement; + + AddEffect(owner, spawner); + } +} + +/* +void FXTrailBlood(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *spawner; + byte amount; + vec3_t velocity; + qboolean yellow_blood = false; + + if(flags&CEF_FLAG8) + yellow_blood = true; + + spawner = DoBloodSplash(origin, amount, yellow_blood); + VectorCopy(velocity, spawner->velocity); +} +*/ +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_bubbler.c b/Toolkit/Programming/GameCode/client effects/fx_bubbler.c new file mode 100644 index 0000000..48bb5f2 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_bubbler.c @@ -0,0 +1,201 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// Created by JJS + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "Utilities.h" +#include "Ambient effects.h" +#include "motion.h" + +#define BUBBLE_MAX_DURATION 2.0F +#define BUBBLE_RADIUS 2.0F +#define BUBBLE_NUM_SPLASHES 8 +#define BUBBLE_ACCELERATION 100 + +#define NUM_BUBBLE_MODELS 1 + +static struct model_s *bubbler_models[NUM_BUBBLE_MODELS]; + +void PreCacheBubbler() +{ + bubbler_models[0] = fxi.RegisterModel("sprites/fx/bubble.sp2"); +} + +// ----------------------------------------------------------------------------------------- + +qboolean FXBubbleThink(client_entity_t *bubble, centity_t *owner) +{ + paletteRGBA_t color; + + // Delay the death of this entity by 500 ms. + bubble->updateTime = 500; + bubble->Update = RemoveSelfAI; + bubble->nextThinkTime = fxi.cl->time + 500; + + bubble->d_scale = -2.0; + bubble->d_alpha = -8.0F; + bubble->velocity[2] = bubble->acceleration[2] = 0; + bubble->r.origin[2] += 1.0; + + color.c = 0xffffffff; + DoWaterSplash(bubble, color, BUBBLE_NUM_SPLASHES); + + FXWaterRipples(NULL, FX_WATER_RIPPLES, 0, bubble->r.origin); + + fxi.S_StartSound(bubble->r.origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("ambient/waterdrop%c.wav", irand('1', '3'))), 1, ATTN_STATIC, 0); + return(true); +} + + +static qboolean FXBubblerParticleSpawner(client_entity_t *spawner, centity_t *owner) +{ + client_entity_t *bubble; + vec3_t origin; + + VectorCopy(spawner->r.origin, origin); + + origin[0] += flrand(0.0, 5.0); + origin[1] += flrand(0.0, 5.0); + origin[2] += flrand(0.0, 5.0); + + spawner->updateTime = irand(spawner->SpawnDelay / 2, spawner->SpawnDelay * 2); + + bubble = ClientEntity_new(-1, 0, origin, NULL, spawner->SpawnData); + + bubble->r.model = bubbler_models; + bubble->r.scale = flrand(0.10, 0.20); + bubble->r.flags = RF_TRANSLUCENT; + + bubble->radius = flrand(0.5, 1.5); + VectorCopy(spawner->acceleration, bubble->acceleration); + + bubble->Update = FXBubbleThink; + + AddEffect(NULL, bubble); + return(true); +} + +void FXBubbler(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *self; + char bubblespermin; + + vec3_t dest; + float time; + float dist, dust; + + GetSolidDist(Origin, 1.0, 1000, &dist); + + VectorCopy(Origin, dest); + dest[2] += dist; + + GetSolidDist(dest, 1.0, -1000, &dust); + + dist += dust; + + time = GetTimeToReachDistance(0, 100, abs(dist)); + + fxi.GetEffect(Owner, Flags, "b", &bubblespermin ); + + Flags |= CEF_NO_DRAW | CEF_NOMOVE | CEF_CULLED | CEF_VIEWSTATUSCHANGED |CEF_CHECK_OWNER; + self = ClientEntity_new(Type, Flags, Origin, NULL, 1000); + + self->SpawnDelay = (60 * 1000) / bubblespermin; + self->Update = FXBubblerParticleSpawner; + + self->acceleration[2] = BUBBLE_ACCELERATION; + self->radius = BUBBLE_RADIUS; + self->SpawnData = time; + AddEffect(Owner, self); +} + +void FXBubble(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + int time; + client_entity_t *bubble; + float up, down; + vec3_t dest; + + GetSolidDist(Origin, 1.0, 1000, &up); + + VectorCopy(Origin, dest); + dest[2] += up; + + GetSolidDist(dest, 1.0, -1000, &down); + up += down; + + time = GetTimeToReachDistance(0, BUBBLE_ACCELERATION, abs(up)); + bubble = ClientEntity_new(FX_BUBBLE, Flags, Origin, NULL, time); + + bubble->r.model = bubbler_models; + bubble->r.scale = flrand(0.025, 0.10); + bubble->r.flags = RF_TRANSLUCENT; + bubble->radius = BUBBLE_RADIUS*2; + bubble->acceleration[2] = BUBBLE_ACCELERATION; + + bubble->Update = FXBubbleThink; + + AddEffect(NULL, bubble); +} + + +void MakeBubble(vec3_t loc, client_entity_t *spawner) +{ + client_particle_t *bubble; + paletteRGBA_t color; + + color.c = 0xffffffff; + bubble = ClientParticle_new(PART_32x32_BUBBLE, color, 1000); + + VectorCopy(loc, bubble->origin); + bubble->d_alpha = 0; + bubble->scale = flrand(0.5, 1.0); + bubble->d_scale = -bubble->scale; + bubble->velocity[0] = flrand(-10.0F, 10.0F); + bubble->velocity[1] = flrand(-10.0F, 10.0F); + bubble->acceleration[2] = 100; + + AddParticleToList(spawner, bubble); +} + +qboolean Create_Bubble(client_entity_t *self, centity_t *owner) +{ + vec3_t loc; + + // give us a random location + VectorSet(loc, flrand(-15,15), flrand(-15,15), flrand(-15,15)); + VectorAdd(loc,self->r.origin,loc); + // create a bubble + MakeBubble(loc, self); + // random time till next bubble + self->updateTime = irand(50,500); + // Never kill this + return(true); +} + +// create a constant client effect attached to something in water that releases bubbles +void FXRandWaterBubble(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + client_entity_t *self; + + self = ClientEntity_new(Type, Flags | CEF_NO_DRAW | CEF_ABSOLUTE_PARTS | CEF_CHECK_OWNER , Origin, NULL, irand(50,500)); + self->Update = Create_Bubble; + self->AddToView = LinkedEntityUpdatePlacement; + self->radius = 20; + AddEffect(Owner, self); +} + +// end + + + diff --git a/Toolkit/Programming/GameCode/client effects/fx_crosshair.c b/Toolkit/Programming/GameCode/client effects/fx_crosshair.c new file mode 100644 index 0000000..ff73629 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_crosshair.c @@ -0,0 +1,74 @@ +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "Utilities.h" +#include "timing.h" + +#define CROSSHAIR_THINKTIME 20 + +#define NUM_MODELS 1 + +static struct model_s *crosshair_models[NUM_MODELS]; + +void PreCacheCrosshair() +{ + crosshair_models[0] = fxi.RegisterModel("sprites/fx/crosshair.sp2"); +} + +static qboolean FXDrawCrosshair(struct client_entity_s *cross_hair, centity_t *owner) +{ + float alpha; + byte type; + + cross_hair->flags |= CEF_CULLED | CEF_DISAPPEARED; + + // Get new destination + if (fxi.Get_Crosshair(cross_hair->r.origin, &type)) + { + if (type > 2) + cross_hair->r.frame = 0; + else + cross_hair->r.frame = type; + + cross_hair->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_NODEPTHTEST; + + alpha = 0.5 + (Q_fabs(sin(fxi.cl->time / 800.0)) * 0.5); + + if (alpha > 1.0f) + alpha = 1.0f; + + if (alpha < 0.0f) + alpha = 0.0f; + + cross_hair->alpha = 0.25 + alpha * 0.5; + cross_hair->r.scale = alpha * 0.5; + + cross_hair->flags &= ~(CEF_CULLED | CEF_DISAPPEARED | CEF_NO_DRAW); + } + return(true); +} + +/* +============== +UpdateCrosshair + +============== +*/ +void FXCrosshair(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *xh; + + xh = ClientEntity_new(type, flags | CEF_NO_DRAW, origin, NULL, CROSSHAIR_THINKTIME); + + xh->r.model = crosshair_models; + xh->Update = FXDrawCrosshair; + + AddEffect(owner, xh); +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_cwatcher.c b/Toolkit/Programming/GameCode/client effects/fx_cwatcher.c new file mode 100644 index 0000000..594df82 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_cwatcher.c @@ -0,0 +1,315 @@ +// +// fx_cwatcher.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "ce_DefaultMessageHandler.h" +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "Angles.h" +#include "q_sprite.h" +#include "ce_DLight.h" +#include "g_playstats.h" + +enum +{ + CWM_BEAM, + CWM_BEAM_HALO, + CWM_BEAM_LINE, + CWM_BEAM_SPARK, + CWM_STAR_HALO, + CWM_STAR_TRAIL, + CWM_STAR_SPARK, + NUM_CW_MODELS +} cwatcher_model_index_t; + +enum +{ + CW_STAR, + CW_STAR_HIT, + CW_BEAM, + CW_BEAM_START, + CW_METEOR, +} cwatcher_effect_id_t; + +static struct model_s *cwmodels[NUM_CW_MODELS]; + +void PreCacheCWModels() +{ + cwmodels[CWM_BEAM] = fxi.RegisterModel("sprites/fx/segment_trail_wt.sp2"); + cwmodels[CWM_BEAM_HALO] = fxi.RegisterModel("sprites/fx/halo.sp2"); + cwmodels[CWM_BEAM_LINE] = fxi.RegisterModel("sprites/fx/bluestreak.sp2"); + cwmodels[CWM_BEAM_SPARK] = fxi.RegisterModel("sprites/fx/spark.sp2"); + cwmodels[CWM_STAR_HALO] = fxi.RegisterModel("sprites/spells/halo_ind.sp2"); + cwmodels[CWM_STAR_TRAIL] = fxi.RegisterModel("Sprites/spells/indigostreak.sp2"); + cwmodels[CWM_STAR_SPARK] = fxi.RegisterModel("Sprites/spells/spark_ind.sp2"); +} + +static qboolean FXCWBeamUpdate(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *spawner; + vec3_t vel = {0, 0, 1}; + int i; + + LinkedEntityUpdatePlacement(self, owner); + VectorCopy(self->r.origin, self->r.endpos); + + //Spawn a bunch of lines and sparks + i = GetScaledCount(2, 0.85); + + while (i--) + { + spawner = ClientEntity_new(FX_CWATCHER, CEF_DONT_LINK, self->r.origin, NULL, 1000); + spawner->r.model = cwmodels + CWM_BEAM_LINE; + spawner->radius = 400; + + spawner->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + spawner->flags |= CEF_USE_VELOCITY2; + + spawner->r.spriteType = SPRITE_LINE; + + spawner->r.scale=flrand(1.5, 2.5); + spawner->alpha=0.75; + spawner->d_alpha=-2.5; + spawner->d_scale=-2.5; + + spawner->r.origin[0] += irand(-2, 2); + spawner->r.origin[1] += irand(-2, 2); + + VectorRandomCopy(vel, spawner->velocity2, 1.0); + VectorCopy(spawner->origin, spawner->r.startpos); + VectorMA(spawner->r.startpos, flrand(16,32), spawner->velocity2, spawner->r.endpos); + + VectorScale(spawner->velocity2, flrand(50,100), spawner->velocity2); + VectorClear(spawner->velocity); + + AddEffect(NULL, spawner); + } + + if(++self->LifeTime == 8) + { + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, fxi.S_RegisterSound("monsters/elflord/weld.wav"), 0.5, ATTN_IDLE, 0); + self->LifeTime = 0; + } + + return true; +} + +static qboolean FXCWBeamThink(struct client_entity_s *self, centity_t *owner) +{ + if (self->LifeTime < fxi.cl->time) + return false; + + self->r.scale = flrand(14.0, 16.0); + + return true; +} + +static qboolean FXCWBeamThink2(struct client_entity_s *self, centity_t *owner) +{ + if (self->LifeTime < fxi.cl->time) + return false; + + self->r.scale = flrand(1.5, 2.0); + + return true; +} + +static qboolean FXCWStarThink(struct client_entity_s *self, centity_t *owner) +{ + self->r.scale = flrand(0.3, 0.5); + + return true; +} + +void FXCWatcherEffects(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *spawner; + paletteRGBA_t light = { 160, 70, 240, 255 }, + white_light = { 255, 255, 255, 255 }; + + vec3_t vel; + byte fxID; + int i; + + fxi.GetEffect(owner, flags, "bv", &fxID, &vel); + + switch (fxID) + { + case CW_STAR: + + //Halo around the spark + spawner = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 17); + spawner->r.model = cwmodels + CWM_STAR_HALO; + spawner->radius = 400; + + spawner->r.frame = 0; + spawner->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + spawner->r.scale=0.8; + spawner->alpha=0.5; + spawner->d_alpha=0.0; + + spawner->Update = KeepSelfAI; + spawner->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner, spawner); + + //A bright star halo + spawner = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 17); + spawner->r.model = cwmodels + CWM_STAR_HALO; + spawner->radius = 400; + + spawner->r.frame = 1; + spawner->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD; + spawner->r.scale=0.5; + spawner->alpha=0.75; + spawner->d_alpha=0.0; + + spawner->dlight=CE_DLight_new(light,100.0f,0.0f); + + spawner->Update = FXCWStarThink; + spawner->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner, spawner); + + break; + + case CW_STAR_HIT: + + //A bright explosion + + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("monsters/elflord/impact.wav"), 0.5, ATTN_IDLE, 0); + + i = GetScaledCount(4, 0.8); + + while (i--) + { + spawner = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 500); + spawner->r.model = cwmodels + CWM_STAR_HALO; + spawner->radius = 400; + + spawner->r.frame = 1; + spawner->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + spawner->r.scale=flrand(0.5, 0.25); + spawner->alpha=0.75; + spawner->d_alpha=-2.0; + spawner->d_scale=-0.5; + + VectorRandomCopy(vel, spawner->velocity, 1.25); + VectorScale(spawner->velocity, flrand(100,200), spawner->velocity); + spawner->acceleration[2] = -128; + + AddEffect(NULL, spawner); + } + + i = GetScaledCount(2, 0.8); + + while (i--) + { + spawner = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 1000); + spawner->r.model = cwmodels + CWM_STAR_TRAIL; + spawner->radius = 400; + + spawner->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + spawner->flags |= CEF_USE_VELOCITY2; + + spawner->r.spriteType = SPRITE_LINE; + + spawner->r.scale=flrand(2.0, 1.5); + spawner->alpha=0.75; + spawner->d_alpha=-2.5; + spawner->d_scale=-4.0; + + VectorRandomCopy(vel, spawner->velocity2, 1.0); + VectorCopy(spawner->origin, spawner->r.startpos); + VectorMA(spawner->r.startpos, flrand(16,32), spawner->velocity2, spawner->r.endpos); + + VectorScale(spawner->velocity2, flrand(50,100), spawner->velocity2); + VectorClear(spawner->velocity); + + if (!i) + spawner->dlight=CE_DLight_new(light,200.0f,-400.0f); + + AddEffect(NULL, spawner); + } + + break; + + case CW_BEAM: + spawner = ClientEntity_new(type, flags, origin, NULL, 17); + spawner->r.model = cwmodels + CWM_BEAM; + spawner->radius = 400; + + spawner->r.flags = RF_TRANS_ADD | RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + spawner->r.scale = 16; + spawner->r.color.c = 0xA0FFFFFF; + spawner->r.spriteType = SPRITE_LINE; + VectorCopy(vel, spawner->r.startpos); + VectorCopy(origin, spawner->r.endpos); + + spawner->LifeTime = fxi.cl->time + 3100; + + spawner->Update = FXCWBeamThink; + spawner->AddToView = FXCWBeamUpdate; + + AddEffect(owner, spawner); + + //Spawn a halo to cover the flat end + spawner = ClientEntity_new(type, flags, origin, NULL, 17); + spawner->r.model = cwmodels + CWM_BEAM_HALO; + spawner->radius = 400; + + spawner->r.flags = RF_TRANS_ADD | RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA | RF_NODEPTHTEST; + spawner->r.scale = 2.5; + spawner->r.color.c = 0xFFFFFFFF; + + spawner->LifeTime = fxi.cl->time + 3100; + + spawner->dlight=CE_DLight_new(white_light,200.0f,0.0f); + + spawner->Update = FXCWBeamThink2; + spawner->AddToView = LinkedEntityUpdatePlacement; + + fxi.Activate_Screen_Shake(8, 4000, fxi.cl->time, SHAKE_ALL_DIR); + + AddEffect(owner, spawner); + + break; + + case CW_BEAM_START: + + //Spawn a halo to cover the flat end + spawner = ClientEntity_new(type, flags, origin, NULL, 4000); + spawner->r.model = cwmodels + CWM_BEAM_HALO; + spawner->radius = 400; + + spawner->r.flags = RF_TRANS_ADD | RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA | RF_NODEPTHTEST; + spawner->r.scale = 2.5; + spawner->r.color.c = 0xFFFFFFFF; + + spawner->dlight=CE_DLight_new(white_light,200.0f,0.0f); + + spawner->AddToView = LinkedEntityUpdatePlacement; + + spawner->LifeTime = fxi.cl->time + 3100; + + fxi.Activate_Screen_Shake(8, 3000, fxi.cl->time, SHAKE_ALL_DIR); + + AddEffect(owner, spawner); + + break; + + default: + assert(0); + break; + } +} + diff --git a/Toolkit/Programming/GameCode/client effects/fx_debris.c b/Toolkit/Programming/GameCode/client effects/fx_debris.c new file mode 100644 index 0000000..058bae2 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_debris.c @@ -0,0 +1,971 @@ +// +// fx_debris.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "ce_DefaultMessageHandler.h" +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "FX_DustPuff.h" +#include "Vector.h" +#include "Utilities.h" +#include "Angles.h" +#include "random.h" +#include "q_Physics.h" +#include "fx_debris.h" +#include "ce_DLight.h" +#include "g_playstats.h" +#include "Vector.h" + +client_entity_t *FXDebris_Throw(vec3_t origin, int material, vec3_t dir, float ke,float scale, int flags, qboolean altskin); +client_entity_t *DoBloodSplash(vec3_t loc, int amount, qboolean yellow_blood); +void ThrowBlood(vec3_t origin, vec3_t tnormal, qboolean dark, qboolean yellow, qboolean trueplane); + +void DoBloodTrail(client_entity_t *spawner, int amount); +void GenericSparks(centity_t *owner, int type, int flags, vec3_t origin, vec3_t dir); + +static void FXDebris_Collision(client_entity_t *self, CE_Message_t *msg); +static void FXBodyPart_Throw(centity_t *owner, int BodyPart, vec3_t origin, float ke, int frame, int type, byte modelindex, int flags, centity_t *harpy); + +qboolean FXDebris_Vanish(struct client_entity_s *self,centity_t *owner); +qboolean FXBodyPartAttachedUpdate(struct client_entity_s *self, centity_t *owner); + +extern int ref_soft; +//------------------------------------------------------------------ +// FX Debris base info +//------------------------------------------------------------------ + +typedef struct DebrisChunk +{ + char *modelName; + int skinNum; + struct model_s *model; + float mass; +} DebrisChunk_t; + +int debrisChunkOffsets[NUM_MAT+1]= +{ + 0, // Stone. + 4, // Grey stone. + 8, // Cloth. + 12, // Metal. + 16, // Flesh. + 22, // Pottery. + 26, // Glass. + 31, // Leaf. + 34, // Wood + 38, // Brown Stone + 42, // Nothing - just smoke + 43, // Insect chunks + 51, // one beyond +}; + +DebrisChunk_t debrisChunks[]= +{ + // Grey stone. + + {"models/debris/stone/schunk1/tris.fm", 0, NULL, 3.0},//0 + {"models/debris/stone/schunk2/tris.fm", 0, NULL, 3.0}, + {"models/debris/stone/schunk3/tris.fm", 0, NULL, 3.0}, + {"models/debris/stone/schunk4/tris.fm", 0, NULL, 3.0}, + + // Grey stone. + + {"models/debris/stone/schunk1/tris.fm", 0, NULL, 3.0},//4 + {"models/debris/stone/schunk2/tris.fm", 0, NULL, 3.0}, + {"models/debris/stone/schunk3/tris.fm", 0, NULL, 3.0}, + {"models/debris/stone/schunk4/tris.fm", 0, NULL, 3.0}, + + // Cloth. + {"models/debris/pottery/pot1/tris.fm", 0, NULL, 0.2},//8 + {"models/debris/pottery/pot1/tris.fm", 0, NULL, 0.2}, + {"models/debris/pottery/pot1/tris.fm", 0, NULL, 0.3}, + {"models/debris/pottery/pot1/tris.fm", 0, NULL, 0.4}, + + // Metal. + + {"models/debris/metal/mchunk1/tris.fm", 0, NULL, 2.0},//12 + {"models/debris/metal/mchunk2/tris.fm", 0, NULL, 3.0}, + {"models/debris/metal/mchunk3/tris.fm", 0, NULL, 4.0}, + {"models/debris/metal/mchunk4/tris.fm", 0, NULL, 5.0}, + + // Flesh. + + {"models/debris/meat/chunk1/tris.fm", 0, NULL, 3.0},//16 + {"models/debris/meat/chunk2/tris.fm", 0, NULL, 3.0}, + {"models/debris/meat/chunk3/tris.fm", 0, NULL, 3.0}, + {"models/debris/meat/chunk4/tris.fm", 0, NULL, 3.0}, + {"models/debris/meat/chunk5/tris.fm", 0, NULL, 3.0}, + {"models/debris/meat/chunk6/tris.fm", 0, NULL, 3.0}, + + // Pottery. + + {"models/debris/pottery/pot1/tris.fm", 0, NULL, 2.0},//22 + {"models/debris/pottery/pot2/tris.fm", 0, NULL, 3.0}, + {"models/debris/pottery/pot3/tris.fm", 0, NULL, 2.5}, + {"models/debris/pottery/pot4/tris.fm", 0, NULL, 1.4}, + + // Glass - models need different skins + {"models/debris/wood/splinter1/tris.fm", 0, NULL, 1.8},//26 + {"models/debris/wood/splinter2/tris.fm", 0, NULL, 2.0}, + {"models/debris/wood/splinter3/tris.fm", 0, NULL, 1.9}, + {"models/debris/wood/splinter4/tris.fm", 0, NULL, 1.6}, + {"models/debris/wood/splinter1/tris.fm", 0, NULL, 1.8}, + + + // Leaf - invalid debris type. + {"models/debris/pottery/pot1/tris.fm", 0, NULL, 2.0},//31 + {"models/debris/pottery/pot1/tris.fm", 0, NULL, 2.0}, + {"models/debris/pottery/pot1/tris.fm", 0, NULL, 2.0}, + + // Wood chunks. + {"models/debris/wood/splinter1/tris.fm", 0, NULL, 1.8},//34 + {"models/debris/wood/splinter2/tris.fm", 0, NULL, 2.0}, + {"models/debris/wood/splinter3/tris.fm", 0, NULL, 1.9}, + {"models/debris/wood/splinter4/tris.fm", 0, NULL, 1.6}, + + // Brown stone. + {"models/debris/stone/schunk1/tris.fm", 1, NULL, 3.0},//38 + {"models/debris/stone/schunk2/tris.fm", 1, NULL, 3.0}, + {"models/debris/stone/schunk3/tris.fm", 1, NULL, 3.0}, + {"models/debris/stone/schunk4/tris.fm", 1, NULL, 3.0}, + + // Nothing - just smoke + {"models/debris/meat/chunk6/tris.fm", 0, NULL, 3.0},//42 + + //Insect Chunks - fixme, use diff skins for diff bugs... + {"models/debris/pottery/pot1/tris.fm", 2, NULL, 2.0},//43 + {"models/debris/pottery/pot2/tris.fm", 2, NULL, 3.0}, + {"models/debris/pottery/pot3/tris.fm", 2, NULL, 2.5}, + {"models/debris/pottery/pot4/tris.fm", 2, NULL, 1.4}, + {"models/debris/insect/chunk1/tris.fm", 0, NULL, 2.0}, + {"models/debris/insect/chunk2/tris.fm", 0, NULL, 3.0}, + {"models/debris/insect/chunk3/tris.fm", 0, NULL, 2.5}, + {"models/debris/insect/chunk4/tris.fm", 0, NULL, 1.4}, +}; + +float debrisElasticity[NUM_MAT] = +{ + 1.3, // Stone + 1.3, // Grey Stone + 1.1, // Cloth + 1.4, // Metal + 1.2, // Flesh + 1.3, // Pottery + 1.3, // Glass + 1.1, // Leaf + 1.5, // Wood + 1.3, // Brown Stone + 1., // Nothing - just smoke + 1.3, // Insect chunks +}; + +void InitDebrisStatics() +{ + classStatics[CID_DEBRIS].msgReceivers[MSG_COLLISION] = FXDebris_Collision; +} + +void PreCacheDebris() +{ + int i, j, offset; + + for(j = 0; j < NUM_MAT; ++j) + { + offset = debrisChunkOffsets[j+1]; + for(i = debrisChunkOffsets[j]; i < offset; ++i) + { + debrisChunks[i].model = fxi.RegisterModel(debrisChunks[i].modelName); + } + } +} + +qboolean flame_out (struct client_particle_s *self, int crap) +{ + if((fxi.cl->time - self->startTime) < (self->duration/2)) + { + if(!irand(0, 9)) + { + self->type = irand(PART_16x16_FIRE1, PART_16x16_FIRE3); + self->type |= PFL_ADDITIVE;//whoo-hoo! Additive particle! + } + return true; + } + + self->scale += flrand(0.6, 0.8); + self->type = PART_16x16_MIST;//automatically removes additive drawing + self->color.r = 10; + self->color.g = 10; + self->color.b = 10; + self->color.a = 255; +// self->extraUpdate = NULL; + return true; +} + +void DoFireTrail (client_entity_t *spawner) +{ + client_particle_t *flame; + int i, material, count; + float radius, master_scale; + paletteRGBA_t color; + float flame_duration; + + if(spawner->flags&CEF_FLAG7 && spawner->dlight) + { + if(spawner->dlight->intensity<=0) + {//flame out + spawner->flags &= ~CEF_FLAG6; + return; + } + } + + color.c = 0xe5007fff; + + material = spawner->SpawnInfo & SIF_FLAG_MASK; + if(material == MAT_FLESH || material == MAT_INSECT || spawner->effectID == FX_BODYPART) + master_scale = spawner->r.scale * 3.33; + else + master_scale = spawner->r.scale; + + if (r_detail->value < DETAIL_NORMAL) + flame_duration = 700.0; + else + flame_duration = 1000.0; + + count = GetScaledCount(irand(2, 5), 0.3); + for(i = 0; i < count; i++) + { + flame = ClientParticle_new(irand(PART_16x16_FIRE1, PART_16x16_FIRE3), color, flame_duration); + + radius = spawner->r.scale * 2.0; + VectorSet(flame->origin, flrand(-radius, radius), flrand(-radius, radius), flrand(-4.0F, -2.0F) * spawner->r.scale); + VectorAdd(flame->origin, spawner->r.origin, flame->origin); + + flame->scale = master_scale; + VectorSet(flame->velocity, flrand(-1.0, 1.0), flrand(-1, 1.0), flrand(17.0, 20.0)); + flame->acceleration[2] = 32.0 * spawner->r.scale; + flame->d_scale = flrand(-5.0, -2.5); + flame->d_alpha = flrand(-200.0, -160.0); + +// flame->extraUpdate = flame_out; + + flame->duration = (255.0 * flame_duration) / -flame->d_alpha; // time taken to reach zero alpha + + flame->startTime = fxi.cl->time; + + flame->type |= PFL_ADDITIVE;//whoo-hoo! Additive particle! + AddParticleToList(spawner, flame); + } +} + +//------------------------------------------------------------------ +// FX Body Part spawn functions +//------------------------------------------------------------------ + +void FXBodyPart(centity_t *owner,int type, int flags, vec3_t origin) +{ + short frame; + short BodyPart; + byte damage; + byte modelindex, OwnerEntnum; + centity_t *realowner; + float ke; + + //increase count on owner so that can have multiple effects? + fxi.GetEffect(owner, flags, "ssbbb", &frame, &BodyPart, &damage, &modelindex, &OwnerEntnum); + + realowner = &fxi.server_entities[OwnerEntnum]; + + ke = damage * 10000.0f; + if(ke < 10000.0f) + { + ke = 10000.0f; + } + + FXBodyPart_Spawn(realowner, BodyPart, origin, ke, frame, type, modelindex, flags, owner); +} + +void FXBodyPart_Spawn(centity_t *owner, int BodyPart, vec3_t origin, float ke, int frame, int type, byte modelindex, int flags, centity_t *harpy) +{ + vec3_t spray_org; + + FXBodyPart_Throw(owner, BodyPart, origin, ke, frame, type, modelindex, flags, harpy); + + VectorAdd(origin, owner->origin, spray_org); + + if(ke && type!=FX_THROWWEAPON) + { + DoBloodSplash(origin, 5, flags&CEF_FLAG8); + } +} + +static void FXBodyPart_Throw(centity_t *owner, int BodyPart, vec3_t origin, float ke, int frame, int type, byte modelindex, int flags, centity_t *harpy) +{//FIXME: make sure parts have correct skins, even node 0! + int index, whichnode, material, node_num; + client_entity_t *debris; + vec3_t start; + trace_t trace; + vec3_t dir = {0, 0, 1}; + + debris = ClientEntity_new(type, 0, origin, NULL, 17);//flags sent as 0 + + if(type == FX_THROWWEAPON) + material = MAT_METAL;//not elastic enough for effect? + else + { + if(flags&CEF_FLAG8)//insect material type + material = MAT_INSECT; + else + material = MAT_FLESH; + } + + debris->SpawnInfo = material; + //FIXME: when do I run out of these?- ie, when is debris invalid? + + debris->classID = CID_DEBRIS; + debris->msgHandler = CE_DefaultMsgHandler; + if(modelindex == 255)//FIXME: these will tilt up and down with the player's torso!!! + debris->r.model = fxi.cl->baseclientinfo.model; + else + debris->r.model = &fxi.cl->model_draw[modelindex]; + debris->r.fmnodeinfo = FMNodeInfo_new(); + debris->r.frame = frame;//first frame should be parts frame of a flexmodel +//need to copy base skin also + debris->r.skinnum = owner->current.skinnum; + + for(whichnode = 1, node_num = 0; whichnode<=16384; whichnode*=2)//bitwise + { + node_num++; + if(!((int)(BodyPart)&(int)(whichnode))) + { + debris->r.fmnodeinfo[node_num].flags |= FMNI_NO_DRAW; + } + else + { + debris->r.fmnodeinfo[node_num] = owner->current.fmnodeinfo[node_num];//copy skins and flags and colors + debris->r.fmnodeinfo[node_num].flags &= ~FMNI_NO_DRAW; + } + } + //turn off first node always? + if(modelindex != 255 || (modelindex == 255 && !(BodyPart & 1))) + debris->r.fmnodeinfo[0].flags |= FMNI_NO_DRAW; + else + { + debris->r.fmnodeinfo[0] = owner->current.fmnodeinfo[0];//copy skins and flags and colors + debris->r.fmnodeinfo[0].flags &= ~FMNI_NO_DRAW; + } + + debris->flags |= (CEF_CLIP_TO_WORLD | CEF_ABSOLUTE_PARTS); + index = irand(debrisChunkOffsets[material], debrisChunkOffsets[material + 1] - 1); + if(owner->entity) + debris->r.skinnum = owner->entity->skinnum; + else + debris->r.skinnum = 0; + + debris->radius = 2.0; + + if(harpy)//HACK: harpy took it! + { + debris->flags |= CEF_OWNERS_ORIGIN; + debris->Update = FXBodyPartAttachedUpdate; + debris->updateTime = 50; + AddEffect(harpy, debris); + return; + } + + VectorRandomCopy(dir, debris->velocity, 0.5F); + + if(ke) + { + Vec3ScaleAssign(sqrt(ke/debrisChunks[index].mass), debris->velocity); + debris->color.c = 0xFFFFFFFF; + } + else + { + ke = irand(10, 100) * 10000.0f; + Vec3ScaleAssign(sqrt(ke/debrisChunks[index].mass), debris->velocity); + debris->color.c = 0x00000000; + } + + debris->acceleration[2] = GetGravity(); + + debris->r.angles[0] = flrand(-ANGLE_180, ANGLE_180); + debris->r.angles[1] = flrand(-ANGLE_90, ANGLE_90); + + debris->elasticity = debrisElasticity[MAT_FLESH]; + + debris->Update = FXBodyPart_Update; + debris->updateTime = 50; + + if(r_detail->value == DETAIL_UBERHIGH) + debris->LifeTime = fxi.cl->time + 10000; + else if(!r_detail->value) + debris->LifeTime = fxi.cl->time + 1000; + else + debris->LifeTime = fxi.cl->time + 3000; + + if(flags&CEF_FLAG6)//on fire- dynamic light + { + // Not-very-perfect way of doing a pointcontents from the FX dll + VectorCopy(origin, start); + start[2] += 1; + fxi.Trace(start, vec3_origin, vec3_origin, origin, 0, 0, &trace); + if(trace.contents&MASK_WATER) + {//in water- no flames, pal! + flags &= ~CEF_FLAG6; + } + else + { + if(!ref_soft && r_detail->value == DETAIL_HIGH) + {//uberhigh? + paletteRGBA_t color; + + debris->flags |= CEF_FLAG7;//don't spawn blood too, just flames + color.c = 0xe5007fff; + debris->dlight = CE_DLight_new(color, 50.0F, -5.0F); + } + + debris->flags |= CEF_FLAG6; + } + } + + AddEffect(NULL,debris); +} + + +qboolean FXBodyPartAttachedUpdate(struct client_entity_s *self, centity_t *owner) +{ + VectorCopy(owner->lerp_origin, self->r.origin); + VectorSet(self->r.angles, + owner->lerp_angles[PITCH] * -1 * ANGLE_TO_RAD, + owner->lerp_angles[YAW] * ANGLE_TO_RAD, + owner->lerp_angles[ROLL] * ANGLE_TO_RAD); + + if((self->SpawnInfo&SIF_FLAG_MASK)==MAT_FLESH||(self->SpawnInfo&SIF_FLAG_MASK) == MAT_INSECT) + DoBloodTrail(self, -1); + + if(self->flags&CEF_FLAG6)//on fire- do a fire trail + DoFireTrail(self); + + return true; +} + +qboolean FXBodyPart_Update(struct client_entity_s *self, centity_t *owner) +{ + int curTime = fxi.cl->time; + float d_time = (curTime - self->lastThinkTime) / 1000.0f; + + if ( curTime > self->LifeTime ) + { + self->d_alpha = flrand(-0.05, -0.2); + self->Update = FXDebris_Vanish; + return true; + } + + self->r.angles[0] += ANGLE_360*d_time; + self->r.angles[1] += ANGLE_360*d_time; + self->r.angles[2] += ANGLE_360*d_time; + + self->lastThinkTime = fxi.cl->time; + + if((self->SpawnInfo&SIF_FLAG_MASK)==MAT_FLESH||(self->SpawnInfo&SIF_FLAG_MASK) == MAT_INSECT) + DoBloodTrail(self, 6); + + if(self->flags&CEF_FLAG6)//on fire- do a fire trail + DoFireTrail(self); + + return true; +} +//------------------------------------------------------------------ +// FX Debris spawn functions +// CEF_FLAG6 = on fire +// CEF_FLAG7 = male insect skin on mat_insect (CEF_FLAG7 cleared out and set if has dynamic light for fire) +// CEF_FLAG8 = use reflection skin +//------------------------------------------------------------------ + +client_entity_t *FXDebris_Throw(vec3_t origin, int material, vec3_t dir, float ke, float scale, int flags, qboolean altskin) +{ + int index; + client_entity_t *debris; + + debris = ClientEntity_new(-1, 0, origin, NULL, 50); + debris->SpawnInfo = material; + + index = irand(debrisChunkOffsets[material], debrisChunkOffsets[material + 1] - 1); + + debris->classID = CID_DEBRIS; + debris->msgHandler = CE_DefaultMsgHandler; + + debris->r.model = &debrisChunks[index].model; + + debris->r.scale = scale; + debris->r.angles[0] = flrand(-ANGLE_180, ANGLE_180); + debris->r.angles[1] = flrand(-ANGLE_90, ANGLE_90); + + debris->flags |= CEF_CLIP_TO_WORLD | CEF_ABSOLUTE_PARTS; + debris->radius = 5.0; + + VectorRandomCopy(dir, debris->velocity, 0.5F); + Vec3ScaleAssign(sqrt(ke / debrisChunks[index].mass), debris->velocity); + + debris->acceleration[2] = GetGravity(); + + debris->elasticity = debrisElasticity[material]; + debris->r.skinnum = debrisChunks[index].skinNum; + + if(material == MAT_FLESH||material == MAT_INSECT) // Flesh need a different update for blood + { + debris->Update = FXFleshDebris_Update; + if(altskin) + { + if(index < 47)//using multiskinned pottery chunks + debris->r.skinnum = 1;//male + } + } + else + { + if(material == MAT_GLASS) + { + debris->r.skinnum = 1; + debris->r.flags |= RF_TRANSLUCENT; + } + + debris->Update = FXDebris_Update; + } + + //Debris lasts 10 seconds before it slowly goes away + debris->LifeTime = fxi.cl->time + 1000; + + if(flags&CEF_FLAG6)//on fire- dynamic light + { + if(flags&CEF_FLAG7)//high detail, non-ref_soft? + {//uberhigh? + paletteRGBA_t color; + + debris->flags |= CEF_FLAG7;//spawn blood too, not just flames + color.c = 0xe5007fff; + debris->dlight = CE_DLight_new(color, 50.0F, -5.0F); + } + + debris->flags |= CEF_FLAG6; + } + + if(flags&CEF_FLAG8)//reflective + { + debris->r.flags |= RF_REFLECTION; + } + + AddEffect(NULL, debris); + + return(debris); +} + +// Flesh debris throws should be a separate effect +// This would save quite a bit of code + +void FXDebris_SpawnChunks(int type, int flags, vec3_t origin, int num, int material, vec3_t dir, float ke, vec3_t mins, float scale, qboolean altskin) +{ + int i; + vec3_t holdorigin, start; + trace_t trace; + + if(flags&CEF_FLAG6)//onfire, check for highdetail, non-ref_soft + { + //Not-very-perfect way of doing a pointcontents from the FX dll + VectorCopy(origin, start); + start[2] += 1; + fxi.Trace(start, vec3_origin, vec3_origin, origin, 0, 0, &trace); + if(trace.contents&MASK_WATER) + {//in water- no flames, pal! + flags &= ~CEF_FLAG6; + } + else + { + if(!ref_soft && r_detail->value == DETAIL_HIGH) + flags|=CEF_FLAG7;//do dynamic light and blood trail + } + } + + for(i = 0; i < num; ++i) + { + VectorCopy(origin, holdorigin); + holdorigin[0] += flrand(-mins[0], mins[0]); + holdorigin[1] += flrand(-mins[1], mins[1]); + holdorigin[2] += flrand(-mins[2], mins[2]); + + if (material != MAT_NONE) + { + FXDebris_Throw(holdorigin, material, dir, ke, scale, flags, altskin); + + if(flags&CEF_FLAG6 && !irand(0, 3))//onfire + {//do a big flaming sparky thingy + } + if (material == MAT_FLESH) // Flesh need a different update for blood + { + DoBloodSplash(holdorigin, 5, false); + } + else if (material == MAT_INSECT) + { + DoBloodSplash(holdorigin, 5, true); + } + else if(irand(0, 1)) + { + CreateSinglePuff(holdorigin, 20.0); + } + } + else // Nothing but smoke + CreateSinglePuff(holdorigin, 20.0); + } +} + +void FXDebris_SpawnFleshChunks(int type, int flags, vec3_t origin, int num, int material, vec3_t dir, float ke, vec3_t mins, float scale, qboolean altskin) +{ + int i; + vec3_t holdorigin, start; + trace_t trace; + + if(flags&CEF_FLAG6)//onfire, check for highdetail, non-ref_soft + { + //Not-very-perfect way of doing a pointcontents from the FX dll + VectorCopy(origin, start); + start[2] += 1; + fxi.Trace(start, vec3_origin, vec3_origin, origin, 0, 0, &trace); + if(trace.contents&MASK_WATER) + {//in water- no flames, pal! + flags &= ~CEF_FLAG6; + } + else + { + if(!ref_soft && r_detail->value == DETAIL_HIGH) + flags|=CEF_FLAG7;//do dynamic light and blood trail + } + } + + for(i = 0; i < num; ++i) + { + VectorCopy(origin, holdorigin); + holdorigin[0] += flrand(-mins[0], mins[0]); + holdorigin[1] += flrand(-mins[1], mins[1]); + holdorigin[2] += flrand(-mins[2], mins[2]); + FXDebris_Throw(holdorigin, material, dir, ke, scale, flags, altskin); + DoBloodSplash(holdorigin, 5, material == MAT_INSECT); + } +} + + +// num = number of chunks to spawn (dependent on size and mass) +// material = type of chunk to explode +// dir = direction of debris (currently always 0.0 0.0 1.0) +// ke = kinetic energy (dependent of damage and number of chunks) +// mins = mins field of edict (so debris is spawned at base) +// scale = size of the spawned chunks (dependent on size) + +void FXDebris(centity_t *owner, int type, int flags, vec3_t origin) +{ + byte num, material, size, mag; + vec3_t dir, mins; + float ke, scale; + + fxi.GetEffect(owner, flags, "bbdb", &size, &material, mins, &mag); + + scale = size * 10; + VectorSet(dir, 0.0, 0.0, 1.0); + Vec3ScaleAssign(mag, mins); + scale = sqrt(scale) * 0.08; + if(r_detail->value < DETAIL_NORMAL) + num = ClampI(size, 1, 5); + else if(r_detail->value == DETAIL_NORMAL) + num = ClampI(size, 1, 12); + else if(r_detail->value == DETAIL_HIGH) + num = ClampI(size, 1, 16); + else + num = ClampI(size, 1, 24); + + ke = 40000.0 + (size * 400.0); + + FXDebris_SpawnChunks(type, flags, origin, num, material, dir, ke, mins, scale, false); +} + +void FXFleshDebris(centity_t *owner, int type, int flags, vec3_t origin) +{ + byte num, material, size, mag; + vec3_t dir, mins; + qboolean altskin = false; + float scale; + + if(flags&CEF_FLAG7) + {//male insect + material = MAT_INSECT; + flags &= ~CEF_FLAG7; + flags &= ~CEF_FLAG8; + altskin = true; + } + else if(flags&CEF_FLAG8) + {//normal insect + material = MAT_INSECT; + flags &= ~CEF_FLAG8; + } + else + material = MAT_FLESH; + + fxi.GetEffect(owner, flags, "bdb", &size, mins, &mag); + + VectorSet(dir, 0.0, 0.0, 1.0); + Vec3ScaleAssign(mag, mins); + if(r_detail->value < DETAIL_NORMAL) + num = ClampI(size, 1, 5); + else if(r_detail->value == DETAIL_NORMAL) + num = ClampI(size, 1, 12); + else if(r_detail->value == DETAIL_HIGH) + num = ClampI(size, 1, 16); + else + num = ClampI(size, 1, 24); + + scale = mag/24; + FXDebris_SpawnFleshChunks(type, flags, origin, num, material, dir, 80000.0, mins, scale, altskin); +} + +//------------------------------------------------------------------ +// FX Debris message receivers +//------------------------------------------------------------------ + +static void FXDebris_Collision(client_entity_t *self, CE_Message_t *msg) +{ + trace_t *trace; + float d_time; + int material; + qboolean dark = false; + qboolean yellow = false; + + if(self->flags & CEF_CLIP_TO_WORLD) + { + ParseMsgParms(msg, "g", &trace); + + if(trace->startsolid || trace->allsolid || Vec3IsZeroEpsilon(trace->plane.normal)) + return; + + // hit the world + if(trace->ent == (struct edict_s *)-1) + { + if(trace->contents&CONTENTS_SOLID) + {//hit a solid surface, make noise and leave any decals + material = self->SpawnInfo & SIF_FLAG_MASK;//again, the SpawnInfo lower 2 bits are material types, >=16 are flags- here we mask out those flags to get the actual materialtype + switch(material) + {//fixme: find out what surface this is hitting? + case MAT_METAL: + if(self->effectID == FX_THROWWEAPON && (!(irand(0,2)))) + { + vec3_t dir; + + VectorSet(dir, 0.0, 0.0, 1.0); + GenericSparks(NULL, FX_SPARKS, 0, self->r.origin, dir); + + if(!irand(0,1)) + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, fxi.S_RegisterSound("misc/dropmetal.wav"), 1, ATTN_NORM, 0); + else + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, fxi.S_RegisterSound("misc/dropmetal1.wav"), 1, ATTN_NORM, 0); + } + else + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("misc/drophvmtl%c.wav", irand('1', '3'))), 1, ATTN_STATIC, 0); + + //need more hollow sounds for big metal + break; + + case MAT_WOOD: + if(!irand(0,6)) + { + if(!irand(0,1)) + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, fxi.S_RegisterSound("misc/dropwood.wav"), 1, ATTN_STATIC, 0); + else + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, fxi.S_RegisterSound("misc/dropwood1.wav"), 1, ATTN_STATIC, 0); + } + break; + + case MAT_STONE: + case MAT_GREYSTONE: + case MAT_BROWNSTONE: + if(!irand(0,6)) + { + if(!irand(0,2)) + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, fxi.S_RegisterSound("misc/dropthing.wav"), 1, ATTN_STATIC, 0); + else + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("misc/boulder%c.wav", irand('1', '2'))), 1, ATTN_STATIC, 0); + } + break; + + case MAT_FLESH://maybe slide? Wet sound? + case MAT_INSECT: + if(self->flags&CEF_FLAG6) + dark = true; + + if(material==MAT_INSECT) + yellow = true; + + if(self->effectID == FX_BODYPART) + { + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("misc/fleshdrop%c.wav", irand('1', '3'))), 1, ATTN_STATIC, 0); + DoBloodSplash(self->r.origin, irand(1, 3), yellow); + if(!(self->SpawnInfo&SIF_INWATER)) + ThrowBlood(self->r.origin, trace->plane.normal, dark, yellow, false); + } + else if (!irand(0,1))//50% to splat + { + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("misc/fleshdrop%c.wav", irand('1', '3'))), 1, ATTN_STATIC, 0); + if(!(self->SpawnInfo&SIF_INWATER)) + ThrowBlood(self->r.origin, trace->plane.normal, dark, yellow, false); + } + break; + + case MAT_GLASS: + if(!irand(0,2)) + { + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("misc/dropglass%c.wav", irand('1', '2'))), 1, ATTN_STATIC, 0); + } + break; + + default: + break; + } + } + + if (trace->plane.normal[2] > GROUND_NORMAL) + { + // don't bounce if velocity is small + if(Q_fabs(self->velocity[2]) < 100.0f || VectorLength(self->velocity) < 100.0f || trace->fraction < 0.075) + { + // Set pitch so that chunks lie flat on ground + self->r.angles[PITCH] = ANGLE_90; + + BecomeStatic(self); + + self->d_alpha = flrand(-0.1, -0.25); + self->Update = FXDebris_Vanish; + return; + } + } + + BounceVelocity(self->velocity, trace->plane.normal, self->velocity, self->elasticity); + + d_time = fxi.cls->frametime * trace->fraction; + // The game might crash with a zero movement. --Pat + if (d_time) + { + Physics_MoveEnt(self, d_time, d_time * d_time * 0.5, trace); + } + } + } +} + +//------------------------------------------------------------------ +// FX Debris update +//------------------------------------------------------------------ + +void FXDarkSmoke(vec3_t origin, float scale, float range); +qboolean FXDebris_Remove(struct client_entity_s *self,centity_t *owner) +{ + return false; +} + +qboolean FXDebris_Vanish(struct client_entity_s *self,centity_t *owner) +{ + if(self->SpawnInfo&SIF_INLAVA) + FXDarkSmoke(self->r.origin, flrand(0.2, 0.5), flrand(30, 50)); + + if ((self->alpha < 0.1f)||(self->r.scale < 0.1f)) + { + if(self->flags&CEF_FLAG6) + {//let the smoke die out + self->alpha = 0.0f; + self->r.scale = 0.0f; + self->Update = FXDebris_Remove; + self->updateTime = 1000; + return true; + } + else + return false; + } + + if(self->flags&CEF_FLAG6 && !irand(0, 2))//on fire- do a fire trail + { + if(irand(0, 0.3)>self->alpha) + { + self->dlight = NULL; + self->flags &= ~CEF_FLAG6; + self->d_alpha = -0.01; + } + else if(irand(0, 0.3)>self->r.scale) + { + self->dlight = NULL; + self->flags &= ~CEF_FLAG6; + self->d_scale = -0.01; + } + else + DoFireTrail(self);//FIXME: make them just smoke when still? + } + + return true; +} + +qboolean FXDebris_Update(struct client_entity_s *self,centity_t *owner) +{ + int curTime = fxi.cl->time; + float d_time = (curTime - self->lastThinkTime) / 1000.0f; + + if ( curTime > self->LifeTime ) + { + self->d_alpha = flrand(-0.05, -0.2); + self->Update = FXDebris_Vanish; + return true; + } + + self->r.angles[0] += ANGLE_360*d_time; + self->r.angles[1] += ANGLE_360*d_time; + + self->lastThinkTime = fxi.cl->time; + + if(self->flags&CEF_FLAG6)//on fire- do a fire trail + DoFireTrail(self); + + return true; +} + +qboolean FXFleshDebris_Update(struct client_entity_s *self,centity_t *owner) +{ + int curTime = fxi.cl->time; + float d_time = (curTime - self->lastThinkTime) / 1000.0f; + + + if(self->flags&CEF_FLAG6)//on fire- do a fire trail + { + DoFireTrail(self); + if(self->flags&CEF_FLAG7) + DoBloodTrail(self, 2); + } + else + DoBloodTrail(self, 2); + + + if(curTime > self->LifeTime) + { + self->d_alpha = flrand(-0.05, -0.2); + self->Update = FXDebris_Vanish; + return true; + } + + self->r.angles[0] += ANGLE_360*d_time; + self->r.angles[1] += ANGLE_360*d_time; + + self->lastThinkTime = fxi.cl->time; + + return true; +} + diff --git a/Toolkit/Programming/GameCode/client effects/fx_debris.h b/Toolkit/Programming/GameCode/client effects/fx_debris.h new file mode 100644 index 0000000..fba3f07 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_debris.h @@ -0,0 +1,13 @@ +#ifndef FX_DEBRIS_H +#define FX_DEBRIS_H + +#include "q_Typedef.h" + +void FXDebris_SpawnChunks(int type, int flags, vec3_t origin, int num, int material, + vec3_t dir, float ke,vec3_t mins,float scale, qboolean altskin); +void FXBodyPart_Spawn(centity_t *owner, int BodyPart, vec3_t origin, float ke, int frame, int type, byte modelindex, int flags, centity_t *harpy); +qboolean FXDebris_Update(struct client_entity_s *self, centity_t *owner); +qboolean FXFleshDebris_Update(struct client_entity_s *self, centity_t *owner); +qboolean FXBodyPart_Update(struct client_entity_s *self,centity_t *owner); + +#endif // FX_DEBRIS_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_defensepickup.c b/Toolkit/Programming/GameCode/client effects/fx_defensepickup.c new file mode 100644 index 0000000..484c428 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_defensepickup.c @@ -0,0 +1,170 @@ +// +// fx_DefensePickup.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "ce_DefaultMessageHandler.h" +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "Angles.h" +#include "ce_Dlight.h" +#include "g_items.h" + +#define BOB_HEIGHT 6.0 +#define BOB_SPEED ANGLE_10 +#define HEALTH_RADIUS 6.0 +#define NUM_DEF_PICKUP_SPARKS 4 +#define EGG_TRAIL_DELAY 100 +#define EGG_RADIUS 10.0 +#define NUM_ITEMDEFENSE 10 +#define SPARK_OFFSET 5 +#define EGG_INTENSITY 255 + +static struct model_s *defense_models[NUM_ITEMDEFENSE]; +void PreCacheItemDefense() +{ + defense_models[0] = fxi.RegisterModel("models/items/defense/repulsion/tris.fm"); // ITEM_DEFENSE_REPULSION + defense_models[1] = fxi.RegisterModel("models/items/defense/meteorbarrier/tris.fm"); // ITEM_DEFENSE_METEORBARRIER + defense_models[2] = fxi.RegisterModel("models/items/defense/polymorph/tris.fm"); // ITEM_DEFENSE_POLYMORPH + defense_models[3] = fxi.RegisterModel("models/items/defense/teleport/tris.fm"); // ITEM_DEFENSE_TELEPORT + defense_models[4] = fxi.RegisterModel("models/items/defense/lightshield/tris.fm"); // ITEM_DEFENSE_SHIELD + defense_models[5] = fxi.RegisterModel("sprites/spells/spark_cyan.sp2"); // cyan spark + defense_models[6] = fxi.RegisterModel("sprites/spells/meteorbarrier.sp2"); // Meteor cloud + defense_models[7] = fxi.RegisterModel("sprites/spells/spark_green.sp2"); // green spark + defense_models[8] = fxi.RegisterModel("sprites/spells/spark_red.sp2"); // red spark + defense_models[9] = fxi.RegisterModel("sprites/spells/spark_blue.sp2"); // blue spark +} + + +static qboolean FXEggSparkThink(struct client_entity_s *shield,centity_t *owner) +{ + vec3_t angvect; +// client_particle_t *spark; +// int part; +// paletteRGBA_t color; + vec3_t origin = {0,0,0}; + + VectorCopy(shield->origin, origin); + origin[2] = shield->origin[2] + (cos(shield->d_scale2) * BOB_HEIGHT); + shield->d_scale2 += BOB_SPEED; + + // Update the angle of the spark. + VectorMA(shield->direction, (float)(fxi.cl->time-shield->lastThinkTime)/1000.0, shield->velocity2, shield->direction); + + // Update the position of the spark. + AngleVectors(shield->direction, angvect, NULL, NULL); + VectorMA(origin, shield->radius, angvect, shield->r.origin); + + shield->lastThinkTime = fxi.cl->time; + return true; +} + +// -------------------------------------------------------------- + +static qboolean FXDefensePickupThink(struct client_entity_s *self, centity_t *owner) +{ + + // Rotate and bob + self->r.angles[YAW] += ANGLE_5; + VectorCopy(owner->current.origin, self->r.origin); + self->r.origin[2] += (cos(self->SpawnData) * BOB_HEIGHT); + self->SpawnData += BOB_SPEED; + + return(true); +} + +// Create effect FX_PICKUP_DEFENSE +void FXDefensePickup(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *ce; + byte tag; + + fxi.GetEffect(owner, flags, "b", &tag); + + flags &= ~CEF_OWNERS_ORIGIN; + ce = ClientEntity_new(type, flags | CEF_DONT_LINK | CEF_CHECK_OWNER | CEF_VIEWSTATUSCHANGED, origin, NULL, 50); + + VectorCopy(ce->r.origin, ce->origin); + ce->r.flags = RF_TRANSLUCENT | RF_GLOW; + ce->r.model = defense_models + tag; + ce->r.scale = 1.0; + + if (tag == ITEM_DEFENSE_TELEPORT) + ce->r.scale = 1.25; + + ce->radius = 10.0; + ce->alpha = 0.8; + ce->Update = FXDefensePickupThink; + + AddEffect(owner, ce); + + // if we are looking at the polymorph egg, put a special effect around it + // stolen wholesale from Pats Shield Effect. Cheers Pat. + if (tag < 5) + { + client_entity_t *shield; + int i; + vec3_t angvect; + + // Add spinning electrical sparks + for(i=0; iflags |= CEF_ADDITIVE_PARTS | CEF_ABSOLUTE_PARTS | CEF_VIEWSTATUSCHANGED; + shield->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + shield->r.model = defense_models + SPARK_OFFSET + tag; + shield->radius = EGG_RADIUS; + shield->color.c = 0xffffffff; + shield->alpha = 0.1; + shield->d_alpha = 0.5; + if (tag == 1) + { + shield->r.scale = 0.2; + } + else + { + shield->r.scale = 0.8; + } + + shield->SpawnData = tag; + + shield->Update = FXEggSparkThink; + VectorCopy(shield->r.origin, shield->origin); + + VectorClear(shield->direction); + shield->direction[YAW] = flrand(0, 360.0); // This angle is kept at a constant distance from org. + shield->direction[PITCH] = flrand(0, 360.0); + + shield->velocity2[YAW] = flrand(-180.0, 180.0); + if (shield->velocity2[YAW] < 0) // Assure that the sparks are moving around at a pretty good clip. + shield->velocity2[YAW] -= 180.0; + else + shield->velocity2[YAW] += 180.0; + + shield->velocity2[PITCH] = flrand(-180.0, 180.0); // This is a velocity around the sphere. + if (shield->velocity2[PITCH] < 0) // Assure that the sparks are moving around at a pretty good clip. + shield->velocity2[PITCH] -= 180.0; + else + shield->velocity2[PITCH] += 180.0; + + shield->SpawnDelay = fxi.cl->time + EGG_TRAIL_DELAY; + shield->lastThinkTime = fxi.cl->time; + + AngleVectors(shield->direction, angvect, NULL, NULL); +// VectorMA(shield->origin, shield->radius, angvect, shield->r.origin); + + AddEffect(owner, shield); + } + } + +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_dust.c b/Toolkit/Programming/GameCode/client effects/fx_dust.c new file mode 100644 index 0000000..1cdce61 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_dust.c @@ -0,0 +1,114 @@ +// +// fx_dust.c +// +// Heretic II +// Copyright 1998 Raven Software +// +#include "Angles.h" +#include "Client Entities.h" +#include "Client Effects.h" +#include "q_shared.h" +#include "ce_DefaultMessageHandler.h" +#include "EffectFlags.h" +#include "q_Physics.h" +#include "fx_debris.h" +#include "random.h" +#include "Vector.h" +#include "Particle.h" +#include "Utilities.h" +#include "fx.h" + +typedef struct RockChunk +{ + char *modelName; + struct model_s *model; + float mass; +} RockChunk_t; + +static void FXDust_RockThrow(int type, int flags, vec3_t origin); +static void FXDust_DustThrow(int type, int flags, vec3_t origin); +void FXSmoke(vec3_t origin, float scale, float range); +client_entity_t *FXDebris_Throw(vec3_t origin, int material, vec3_t dir, float ke,float scale, int flags); + +#define NUM_ROCK_MODELS 4 +static struct model_s *rock_models[NUM_ROCK_MODELS]; +RockChunk_t RockChunks[]= +{ + {"models/debris/stone/schunk1/tris.fm", 0, 3.0}, + {"models/debris/stone/schunk2/tris.fm", 0, 3.0}, + {"models/debris/stone/schunk3/tris.fm", 0, 3.0}, + {"models/debris/stone/schunk4/tris.fm", 0, 3.0}, +}; + +void PreCacheRockchunks() +{ + int i; + + for(i = 0; i < NUM_ROCK_MODELS; i++) + { + rock_models[i] = fxi.RegisterModel(RockChunks[i].modelName); + } +} + +//------------------------------------------------------------------ +// FX Dust spawn functions +//------------------------------------------------------------------ + +static qboolean FXDustLandThink(client_entity_t *dust, centity_t *owner) +{ + FXSmoke(dust->r.origin, 1.0, 40.0); + return(false); +} + +static qboolean FXDustThink(client_entity_t *dust, centity_t *owner) +{ + vec3_t holdorigin, dir; + trace_t trace; + client_entity_t *ce; + int duration; + + dust->LifeTime++; + if(dust->LifeTime > dust->SpawnDelay) + { + return(false); + } + dust->updateTime = irand(dust->LifeTime * 17, dust->LifeTime * 50); + + VectorCopy(dust->r.origin, holdorigin); + holdorigin[0] += flrand(0.0, dust->startpos[0]); + holdorigin[1] += flrand(0.0, dust->startpos[1]); + + // Spawn a bit of smoke + FXSmoke(holdorigin, 3.0, 25.0); + + // Spawn a rock chunk + VectorSet(dir, 0.0, 0.0, -1.0); + ce = FXDebris_Throw(holdorigin, MAT_STONE, dir, 20000.0, flrand(0.75, 2.4), 0); + + // Create a cloud of dust when rock hits ground + duration = GetFallTime(ce->origin, ce->velocity[2], ce->acceleration[2], ce->radius, 3.0F, &trace); + ce = ClientEntity_new(-1, CEF_NO_DRAW | CEF_NOMOVE, trace.endpos, NULL, duration); + ce->Update = FXDustLandThink; + AddEffect(NULL, ce); + + return(true); +} + +void FXDust(centity_t *owner, int type, int flags, vec3_t origin) +{ + byte num, mag; + vec3_t size; + client_entity_t *ce; + + fxi.GetEffect(owner, flags, "bdb", &num, size, &mag); + + ce = ClientEntity_new(-1, CEF_NOMOVE | CEF_NO_DRAW, origin, NULL, 100); + VectorScale(size, mag, ce->startpos); + ce->SpawnDelay = num; + ce->LifeTime = 0; + ce->Update = FXDustThink; + AddEffect(NULL, ce); +} + +// end + diff --git a/Toolkit/Programming/GameCode/client effects/fx_dustpuff.c b/Toolkit/Programming/GameCode/client effects/fx_dustpuff.c new file mode 100644 index 0000000..d6abf58 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_dustpuff.c @@ -0,0 +1,73 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// Created by JDW + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "Utilities.h" + +void FXDustPuff(client_entity_t *owner, float scale) +{ + client_particle_t *puff; + paletteRGBA_t color; + + color.c = 0x80c0c0c0; + puff = ClientParticle_new(PART_32x32_STEAM, color, 500); + + VectorSet(puff->velocity, flrand(-50.0F, 50.0F), flrand(-50.0F, 50.0F), flrand(0.0F, 25.0F)); + VectorScale(puff->velocity, -1.23F, puff->acceleration); + puff->scale = scale; + puff->d_scale = 10.0; + puff->d_alpha *= 0.5; + + AddParticleToList(owner, puff); +} + +void CreateSinglePuff(vec3_t origin, float scale) +{ + client_entity_t *ce; + + ce = ClientEntity_new(-1, CEF_NOMOVE | CEF_NO_DRAW, origin, NULL, 500); + FXDustPuff(ce, scale); + AddEffect(NULL, ce); +} +void FXDustPuffOnGround(centity_t *owner, int type, int flags, vec3_t origin) +{ + int numPuffs, i; + vec3_t endpos; + trace_t trace; + client_entity_t *ce; + + VectorCopy(origin, endpos); + endpos[2] -= 128.0; + + //Find out where the ground is + fxi.Trace( origin, + vec3_origin, + vec3_origin, + endpos, + CONTENTS_SOLID, + CEF_CLIP_TO_WORLD, + &trace); + + if (trace.fraction == 1.0) + return; + + ce = ClientEntity_new(-1, CEF_NOMOVE | CEF_NO_DRAW, trace.endpos, NULL, 500); + numPuffs = irand(3,4); + for (i = 0; i < numPuffs; i++) + { + FXDustPuff(ce, 5.0F); + } + AddEffect(NULL, ce); +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_dustpuff.h b/Toolkit/Programming/GameCode/client effects/fx_dustpuff.h new file mode 100644 index 0000000..df42549 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_dustpuff.h @@ -0,0 +1,8 @@ +#ifndef FX_DUSTPUFF_H +#define FX_DUSTPUFFS_H + +#include "q_Typedef.h" + +void CreateSinglePuff(vec3_t origin, float scale); + +#endif // FX_DUSTPUFF_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_fire.c b/Toolkit/Programming/GameCode/client effects/fx_fire.c new file mode 100644 index 0000000..7d41d0b --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_fire.c @@ -0,0 +1,337 @@ +// +// fx_fire.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Reference.h" +#include "Utilities.h" +#include "ce_dlight.h" +#include "g_playstats.h" + +#define FLARE_COUNT 16 +#define FLARE_SPEED 64.0 +#define FLARE_SPAWN_RADIUS 2.0 +#define FLARE_ACCEL 128.0 +#define FLARE_SCALE 32.0 + +#define FLAME_COUNT 4 +#define FIRE_SPAWN_RADIUS 8.0 +#define FIRE_SCALE 12.0 +#define FIRE_ENT_SCALE 8.0 +#define FIRE_ACCEL 32.0 + + +#define NUM_FLAREUP_MODELS 1 + +static struct model_s *flareup_models[NUM_FLAREUP_MODELS]; +void PreCacheFlareup() +{ + flareup_models[0] = fxi.RegisterModel("sprites/fx/halo.sp2"); +} + +void FXFlareup(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *spawner; + client_particle_t *flame; + float radius; + int i, count; + + // Add a big ol' flash. + spawner = ClientEntity_new(type, flags | CEF_ADDITIVE_PARTS, origin, NULL, 500); + spawner->r.model = flareup_models ; // The starry halo. + spawner->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + spawner->radius = 128.0; + + spawner->r.scale = 1.0; + spawner->d_scale = -2.0; + spawner->alpha = 0.95; + spawner->d_alpha = -2.0; + spawner->color.c = 0xffffffff; + + AddEffect(NULL, spawner); + + count = GetScaledCount(FLARE_COUNT, 0.9); + for(i = 0; i < count; i++) + { + flame = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2) | PFL_NEARCULL, spawner->color, 1000); + + radius = spawner->r.scale * FLARE_SPAWN_RADIUS; + VectorSet(flame->origin, flrand(-radius, radius), flrand(-radius, radius), flrand(-radius, -radius)); + + flame->scale = FLARE_SCALE * spawner->r.scale; + VectorSet(flame->velocity, + flrand(-FLARE_SPEED, FLARE_SPEED), + flrand(-FLARE_SPEED, FLARE_SPEED), + flrand(-FLARE_SPEED, FLARE_SPEED)); + flame->acceleration[2] = FLARE_ACCEL * spawner->r.scale; + flame->d_scale = flrand(-20.0, -10.0); + flame->d_alpha = flrand(-320.0, -256.0); + + flame->type |= PFL_ADDITIVE; + + AddParticleToList(spawner, flame); + } +} + + + +qboolean FXFireThink(client_entity_t *spawner, centity_t *owner) +{ + client_particle_t *flame; + paletteRGBA_t color; + float radius; + int i, count, white; + + count = GetScaledCount(FLAME_COUNT, 0.9); + if (count>FLAME_COUNT) // Don't go over flame count + count=FLAME_COUNT; + for(i = 0; i < count; i++) + { + if (!irand(0,15) && (r_detail->value >= DETAIL_NORMAL)) // no steam in software, its around too long and doesn't do enough for us + { + white = irand(50, 100); + + color.r = color.g = color.b = white; + color.a = irand(100, 150); + + flame = ClientParticle_new(PART_32x32_STEAM | PFL_NEARCULL, color, 2000); + + radius = spawner->r.scale * FIRE_SPAWN_RADIUS; + VectorSet(flame->origin, flrand(-radius, radius), flrand(-radius, radius), 8 * spawner->r.scale); + + flame->scale = (FIRE_SCALE * spawner->r.scale) / 2; + VectorSet(flame->velocity, flrand(-5.0, 5.0), flrand(-5, 5.0), flrand(15.0, 22.0)); + flame->acceleration[2] = FIRE_ACCEL * spawner->r.scale; + flame->d_scale = flrand(15.0, 20.0); + flame->d_alpha = flrand(-100.0, -50.0); + flame->duration = (color.a * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + AddParticleToList(spawner, flame); + } + else + { + flame = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2) | PFL_NEARCULL, spawner->color, 2000); + + radius = spawner->r.scale * FIRE_SPAWN_RADIUS; + VectorSet(flame->origin, flrand(-radius, radius), flrand(-radius, radius), flrand(-16.0F, -8.0F) * spawner->r.scale); + + flame->scale = FIRE_SCALE * spawner->r.scale; + VectorSet(flame->velocity, flrand(-5.0, 5.0), flrand(-5, 5.0), flrand(15.0, 22.0)); + flame->acceleration[2] = FIRE_ACCEL * spawner->r.scale; + flame->d_scale = flrand(-10.0, -5.0); + flame->d_alpha = flrand(-200.0, -160.0); + flame->duration = (255.0 * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + flame->type |= PFL_ADDITIVE; + + AddParticleToList(spawner, flame); + } + } + if (spawner->dlight) + spawner->dlight->intensity = 150 + flrand(-8.0, 8.0); + + return(true); +} + +void FXFire(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *spawner; + byte scale; + + spawner = ClientEntity_new(type, flags, origin, NULL, 17); + + fxi.GetEffect(owner, flags, "b", &scale); + spawner->r.scale = scale / 32.0; + + spawner->r.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + spawner->flags |= CEF_NO_DRAW | CEF_NOMOVE | CEF_CULLED | CEF_CHECK_OWNER | CEF_VIEWSTATUSCHANGED; + spawner->color.c = 0xe5007fff; + spawner->radius = 96.0; + spawner->Update = FXFireThink; + + if(flags & CEF_FLAG6) + spawner->dlight = CE_DLight_new(spawner->color, 150.0F, 00.0F); + + AddEffect(owner, spawner); +} + +qboolean FXFireOnEntityThink(client_entity_t *spawner, centity_t *owner) +{ + client_particle_t *flame; + int i, count, white; + float radius; + paletteRGBA_t color; + + // For framerate-sensitive effect spawning + count = GetScaledCount(FLAME_COUNT, 0.9); + if (count>FLAME_COUNT) // Don't go over flame count + count=FLAME_COUNT; + VectorCopy(owner->origin, spawner->origin); + VectorCopy(owner->origin, spawner->r.origin); + + if ((owner->current.effects & EF_MARCUS_FLAG1) && (spawner->nextEventTime - fxi.cl->time >= 1000)) + { // Set up the fire to finish early. + spawner->nextEventTime = fxi.cl->time + 999; + spawner->dlight->d_intensity = -200; + } + + if (spawner->nextEventTime - fxi.cl->time > 1000) // Until 1 second before finish. + { + for(i = 0; i < count; i++) + { + if (!irand(0,15) && (r_detail->value >= DETAIL_NORMAL)) // no steam in software, its around too long and doesn't do enough for us + { + white = irand(8, 16); + + color.r = color.g = color.b = white; + color.a = 168; + + flame = ClientParticle_new(PART_32x32_STEAM | PFL_NEARCULL, color, 2000); + + radius = spawner->r.scale; + VectorSet(flame->origin, flrand(-radius, radius), flrand(-radius, radius), flrand(-0.25, 0.75) * spawner->r.scale); + VectorAdd(flame->origin, spawner->origin, flame->origin); + + flame->scale = spawner->r.scale*2.0; + VectorSet(flame->velocity, flrand(-5.0, 5.0), flrand(-5, 5.0), flrand(15.0, 22.0)); + flame->acceleration[2] = FIRE_ACCEL * spawner->r.scale; + flame->d_scale = flrand(15.0, 20.0); + flame->d_alpha = flrand(-100.0, -50.0); + flame->duration = (255.0 * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + AddParticleToList(spawner, flame); + } + else + { + flame = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2) | PFL_NEARCULL, spawner->color, 1000); + + radius = spawner->r.scale ; + VectorSet(flame->origin, flrand(-radius, radius), flrand(-radius, radius), flrand(-0.25, 0.75)*radius); + // If dead, then move the flame down a tad. + if(owner->current.effects&EF_DISABLE_EXTRA_FX) + { + spawner->origin[2] -= radius; + } + VectorAdd(flame->origin, spawner->origin, flame->origin); + + flame->scale = spawner->r.scale*2.0; + VectorSet(flame->velocity, flrand(-5.0, 5.0), flrand(-5, 5.0), flrand(32.0, 48.0)); + flame->acceleration[2] = 2.0 * spawner->r.scale; + flame->d_scale = flrand(-20.0, -10.0); + flame->d_alpha = flrand(-400.0, -320.0); + flame->duration = (255.0 * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + AddParticleToList(spawner, flame); + } + } + spawner->dlight->intensity = 150 + flrand(-8.0, 8.0); + + return(true); + } + else if (fxi.cl->time < spawner->nextEventTime) + { + spawner->dlight->intensity = (spawner->nextEventTime - fxi.cl->time)*0.3; + + return(true); + } + else + { + return(false); + } +} + + +qboolean FXFireOnEntity2Think(client_entity_t *spawner, centity_t *owner) +{ + client_particle_t *flame; + int i, count; + float radius; + + //fixme: can miss the message that tells you to remove the effect + if (fxi.cl->time > spawner->nextEventTime) + return (false);//just in case + else if (spawner->nextEventTime - fxi.cl->time < 1000) + return (true); // Let the flames finish. + + if (owner->current.effects & EF_MARCUS_FLAG1 && spawner->nextEventTime-fxi.cl->time >= 1000) + { + spawner->nextEventTime = fxi.cl->time + 999; + spawner->dlight->d_intensity = -200; + } + + // For framerate-sensitive effect spawning + count = GetScaledCount(FLAME_COUNT, 0.9); + if (count>FLAME_COUNT) // Don't go over flame count + count=FLAME_COUNT; + VectorCopy(owner->origin, spawner->origin); + VectorCopy(owner->origin, spawner->r.origin); + for(i = 0; i < count; i++) + { + flame = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2) | PFL_NEARCULL, spawner->color, 1000); + + radius = spawner->r.scale * FIRE_SPAWN_RADIUS; + VectorSet(flame->origin, flrand(-radius, radius), flrand(-radius, radius), flrand(-16.0F, -8.0F) * spawner->r.scale); + // If dead, then move the flame down a tad. + if(owner->current.effects&EF_DISABLE_EXTRA_FX) + { + spawner->origin[2] -= radius; + } + VectorAdd(flame->origin, spawner->origin, flame->origin); + + flame->scale = FIRE_ENT_SCALE * spawner->r.scale; + VectorSet(flame->velocity, flrand(-5.0, 5.0), flrand(-5, 5.0), flrand(15.0, 22.0)); + flame->acceleration[2] = FIRE_ACCEL * spawner->r.scale; + flame->d_scale = flrand(-10.0, -5.0); + flame->d_alpha = flrand(-200.0, -160.0); + flame->duration = (255.0 * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + AddParticleToList(spawner, flame); + } + spawner->dlight->intensity = 150 + flrand(-8.0, 8.0); + return(true); + +} + +//FIXME: have it constantly check a flag so it can go out if under water! +void FXFireOnEntity(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *spawner; + byte scale; + byte lifetime; + byte style; + + fxi.GetEffect(owner, flags, "bbb", &scale, &lifetime, &style); + + spawner = ClientEntity_new(type, flags, origin, NULL, 17); + + spawner->r.scale = sqrt((float)scale)*0.5; + spawner->nextEventTime = fxi.cl->time + (100*(int)lifetime); // How long to last. Lifetime was in 10th secs. + + spawner->r.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + spawner->flags |= CEF_NO_DRAW | CEF_NOMOVE | CEF_ADDITIVE_PARTS | CEF_ABSOLUTE_PARTS | CEF_CULLED | CEF_CHECK_OWNER; +// spawner->flags |= CEF_NO_DRAW | CEF_NOMOVE | CEF_ADDITIVE_PARTS | CEF_ABSOLUTE_PARTS | CEF_CULLED | CEF_VIEWSTATUSCHANGED; + spawner->color.c = 0xe5007fff; + spawner->radius = 128; + if (!style)//fire fades out- for things that catch fire + { + spawner->Update = FXFireOnEntityThink; + } + else//fire never goes away- for moving fire ents + { + spawner->Update = FXFireOnEntity2Think; + spawner->nextEventTime = fxi.cl->time + 60000;//60 seconds max, just in case + } + spawner->dlight = CE_DLight_new(spawner->color, 150.0F, 00.0F); + + AddEffect(owner, spawner); +} +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_firehands.c b/Toolkit/Programming/GameCode/client effects/fx_firehands.c new file mode 100644 index 0000000..8037d34 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_firehands.c @@ -0,0 +1,139 @@ +// +// fx_firehands.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Matrix.h" +#include "Random.h" +#include "Utilities.h" +#include "Reference.h" +#include "ce_DLight.h" +#include "g_playstats.h" + + +#define HANDFIRE_NUM 1 +#define HANDFIRE_RADIUS 2.0 +#define HANDFIRE_SCALE 8.0 +#define HANDFIRE_ACCEL 32.0 + + + +static qboolean FXFireHandsThink(struct client_entity_s *self,centity_t *owner) +{ + + client_particle_t *flame; + int i; + vec3_t firestart, origin; + matrix3_t rotation; + int hand_flame_dur; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return false; // Remove the effect in this case. + + // If we've timed out, stop the effect (allow for fading) + if ( (self->LifeTime > 0) && (self->LifeTime < fxi.cl->time) ) + { + self->Update=RemoveSelfAI; + self->updateTime = fxi.cl->time + 500; + return true; + } + + VectorCopy(owner->origin, self->r.origin); + + // Let's take the origin and transform it to the proper coordinate offset from the owner's origin. + VectorCopy(owner->referenceInfo->references[self->refPoint].placement.origin, firestart); + // Create a rotation matrix + Matrix3FromAngles(owner->lerp_angles, rotation); + Matrix3MultByVec3(rotation, firestart, origin); + + if (r_detail->value < DETAIL_NORMAL) + hand_flame_dur = 1500; + else + hand_flame_dur = 2000; + + for(i = 0; i < HANDFIRE_NUM; i++) + { + flame = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), self->color, hand_flame_dur); + VectorSet( flame->origin, + flrand(-HANDFIRE_RADIUS, HANDFIRE_RADIUS), + flrand(-HANDFIRE_RADIUS, HANDFIRE_RADIUS), + flrand(-HANDFIRE_RADIUS, HANDFIRE_RADIUS)); + VectorAdd(flame->origin, origin, flame->origin); + + flame->scale = HANDFIRE_SCALE; + VectorSet(flame->velocity, flrand(-5.0, 5.0), flrand(-5, 5.0), flrand(15.0, 22.0)); + flame->acceleration[2] = HANDFIRE_ACCEL; + flame->d_scale = flrand(-10.0, -5.0); + flame->d_alpha = flrand(-200.0, -160.0); + flame->duration = (255.0 * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + AddParticleToList(self, flame); + } + + return(true); +} + +// ************************************************************************************************ +// FXFireHands +// ------------ +// ************************************************************************************************ + +void FXFireHands(centity_t *owner,int type,int flags,vec3_t origin) +{ + short refpoints; + client_entity_t *trail; + int i; + int flame_dur; + char lifetime; + + refpoints=0; + + fxi.GetEffect(owner, flags, "b", &lifetime); + + if (flags & CEF_FLAG6) + refpoints=(1 << CORVUS_LEFTHAND) | (1 << CORVUS_RIGHTHAND); + else + refpoints=(1 << CORVUS_LEFTHAND); + + VectorClear(origin); + + + if (r_detail->value > DETAIL_NORMAL) + flame_dur = 50; + else + flame_dur = 75; + + // Add a fiery trail effect to the player's hands / feet etc. + + for(i=0;i<16;i++) + { + if(!(refpoints & (1 << i))) + continue; + + trail=ClientEntity_new(type,flags,origin,0,flame_dur); + + trail->Update=FXFireHandsThink; + trail->flags|=CEF_NO_DRAW | CEF_OWNERS_ORIGIN | CEF_ADDITIVE_PARTS; + trail->radius = 128; + trail->AddToView = LinkedEntityUpdatePlacement; + trail->refPoint = i; + trail->color.c = 0xe5007fff; + + if (lifetime > 0) + trail->LifeTime = fxi.cl->time + (lifetime * 100); + else + trail->LifeTime = -1; + + + AddEffect(owner,trail); + } +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_flamethrow.c b/Toolkit/Programming/GameCode/client effects/fx_flamethrow.c new file mode 100644 index 0000000..5b1cc0f --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_flamethrow.c @@ -0,0 +1,183 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// jweier + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Utilities.h" +#include "random.h" +#include "motion.h" +#include "g_playstats.h" +#include "ce_DLight.h" + +#define FLAME_COUNT 4 +#define FIRE_SPAWN_RADIUS 8.0 +#define FIRE_SCALE 14.0 +#define FIRE_ACCEL 32.0 + +qboolean FXFlamethrower_trail(client_entity_t *self, centity_t *owner) +{ + client_particle_t *flame; + client_entity_t *light; + paletteRGBA_t color; + float radius; + int count, white; + + if (self->LifeTime < fxi.cl->time) + { + self->Update = RemoveSelfAI; + self->updateTime = fxi.cl->time + 2000; + + return true; + } + + count = GetScaledCount(FLAME_COUNT, 0.9); + + while (count--) + { + color.c = 0xFFFFFFFF; + + flame = ClientParticle_new(irand(PART_16x16_FIRE1, PART_16x16_FIRE3), color, 2000); + flame->d_scale = flrand(-10.0, -5.0); + flame->d_alpha = flrand(-600.0, -560.0); + flame->duration = (255.0 * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + radius = self->r.scale * FIRE_SPAWN_RADIUS; + VectorCopy(self->direction, flame->velocity); + VectorSet(flame->origin, irand(-2,2), irand(-2,2), irand(-2,2)); + VectorScale(flame->velocity, flrand(0.75, 1), flame->velocity); + + flame->scale = flrand(14.0, 20.0); + + flame->velocity[2] += flrand(0, 48); + flame->acceleration[2] = 64; + + AddParticleToList(self, flame); + } + + if(r_detail->value >= DETAIL_NORMAL) + { + //Spawn a dynamic light + light = ClientEntity_new(FX_FLAMETHROWER, CEF_NO_DRAW, self->origin, 0, 500); + VectorCopy(self->direction, light->velocity); + + white = irand(8, 16); + + color.r = 128 + irand(108, 127); + color.g = 64 + white; + color.b = 16 + white; + color.a = 64 + irand(16, 128); + + light->dlight = CE_DLight_new(color, 150.0F, -100.0F); + + AddEffect(NULL, light); + } + + + return true; +} + +static qboolean FXFlamethrower_steam_trail(client_entity_t *self, centity_t *owner) +{ + client_particle_t *flame; + paletteRGBA_t color; + float radius; + int count; + + if (self->LifeTime < fxi.cl->time) + { + self->Update = RemoveSelfAI; + self->updateTime = fxi.cl->time + 2000; + + return true; + } + + count = GetScaledCount(FLAME_COUNT, 0.9); + + while (count--) + { + if (self->flags & CEF_FLAG7) + color.c = 0x33777777; + else + color.c = 0x50FFFFFF; + + flame = ClientParticle_new(PART_32x32_STEAM, color, 2000); + + flame->d_alpha = flrand(-200.0, -150.0); + flame->duration = (255.0 * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + radius = self->r.scale * FIRE_SPAWN_RADIUS; + VectorCopy(self->direction, flame->velocity); + VectorSet(flame->origin, irand(-2,2), irand(-2,2), irand(-2,2)); + VectorScale(flame->velocity, flrand(0.75, 1), flame->velocity); + + if (self->flags & CEF_FLAG7) + { + flame->d_scale = flrand(20.0, 30.0); + flame->scale = flrand(2.0, 3.0); + VectorScale(flame->velocity, -0.1, flame->acceleration); + } + else + { + flame->d_scale = flrand(-10.0, -5.0); + flame->scale = flrand(14.0, 20.0); + } + + flame->velocity[2] += flrand(0, 32); + flame->acceleration[2] = 128; + + AddParticleToList(self, flame); + } + + return true; +} + +// create the initial fire entity that we can attach all the particles to +void FXFlamethrower(centity_t *owner, int type, int flags, vec3_t origin) +{ + float distance; + vec3_t dir; + client_entity_t *glow; + + fxi.GetEffect(owner, flags, "df", &dir, &distance); + + // create the dummy entity, so particles can be attached + glow = ClientEntity_new(type, (flags | CEF_NO_DRAW | CEF_ADDITIVE_PARTS) , origin, 0, 17); + + VectorScale(dir, distance, glow->direction); + glow->radius = 100; + glow->LifeTime = fxi.cl->time + 1000; + + //Steam? + if (flags & CEF_FLAG6) + { + if(!(flags & CEF_FLAG7)) + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("objects/steamjet.wav"), 1, ATTN_NORM, 0); + else + glow->LifeTime = fxi.cl->time + 200; + + glow->Update = FXFlamethrower_steam_trail; + } + else + { + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("misc/flamethrow.wav"), 1, ATTN_NORM, 0); + glow->Update = FXFlamethrower_trail; + } + + AddEffect(NULL, glow); +} + + + + +// put out there just so we can make the real effect match this +void FXflametest(centity_t *owner, int type, int flags, vec3_t origin) +{ +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_flyingfist.c b/Toolkit/Programming/GameCode/client effects/fx_flyingfist.c new file mode 100644 index 0000000..3bac47f --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_flyingfist.c @@ -0,0 +1,299 @@ +// +// fx_flyingfist.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "Utilities.h" +#include "fx_debris.h" +#include "g_playstats.h" + +#define FIST_DELTA_FORWARD 8.0 +#define FIST_DELTA_THETA 0.12 +#define FIST_SPIRAL_RAD 0.75 +#define FIST_SCALE 0.25 +#define FIST_WIMPY_SCALE 0.15 +#define FIST_BLAST_VEL 64.0 +#define FIST_POWER_BLAST_VEL 200.0 + +#define NUM_FIST_MODELS 3 + +static struct model_s *fist_models[NUM_FIST_MODELS]; + +void PreCacheFist() +{ + fist_models[0] = fxi.RegisterModel("Sprites/Spells/flyingfist.sp2"); + fist_models[1] = fxi.RegisterModel("Sprites/Spells/spellhands_red.sp2"); + fist_models[2] = fxi.RegisterModel("models/spells/meteorbarrier/tris.fm"); +} + +// ************************************************************************************************ +// FXFlyingFistTrailThink +// ************************************************************************************************ + +static qboolean FXFlyingFistTrailThink(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *TrailEnt; + vec3_t accel_dir; + int i; + qboolean wimpy=false; + float trailscale=FIST_SCALE; + + self->updateTime = 20; + + if(self->SpawnInfo > 9) + self->SpawnInfo--; + + i = GetScaledCount( irand(self->SpawnInfo >> 3, self->SpawnInfo >> 2), 0.8 ); + if (self->flags & CEF_FLAG8) + { + wimpy=true; + i /= 2.0; + trailscale = FIST_WIMPY_SCALE; + } + + while(i--) + { + TrailEnt = ClientEntity_new(FX_WEAPON_FLYINGFIST, 0, self->r.origin, NULL, 1000); + TrailEnt->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + VectorCopy(self->velocity, accel_dir); + VectorNormalize(accel_dir); + + if (self->flags & CEF_FLAG7) + { + TrailEnt->r.model = fist_models + 1; + TrailEnt->r.scale = 3.0 * (trailscale + flrand(0.0, 0.05)); + VectorRandomCopy(self->r.origin, TrailEnt->r.origin, flrand(-8.0, 8.0)); + VectorScale(accel_dir, flrand(-100.0, -400.0), TrailEnt->velocity); + } + else + { + TrailEnt->r.model = fist_models; + TrailEnt->r.scale = trailscale + flrand(0.0, 0.05); + VectorRandomCopy(self->r.origin, TrailEnt->r.origin, flrand(-5.0, 5.0)); + VectorScale(accel_dir, flrand(-50.0, -400.0), TrailEnt->velocity); + } + + if (wimpy) + { // Wimpy shot, because no mana. + VectorScale(TrailEnt->velocity, 0.5, TrailEnt->velocity); + } + + TrailEnt->d_alpha = flrand(-1.5, -2.0); + TrailEnt->d_scale = flrand(-1.0, -1.25); + TrailEnt->updateTime = (TrailEnt->alpha * 1000.0) / -TrailEnt->d_scale; + TrailEnt->radius = 20.0; + + AddEffect(NULL,TrailEnt); + } + + return(true); +} + +// ************************************************************************************************ +// FXFlyingFist +// ************************************************************************************************ + +//////////////////////////////////// +// From CreateEffect FX_WEAPON_FLYINGFIST +//////////////////////////////////// +void FXFlyingFist(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t vel, dir; + client_entity_t *missile; + paletteRGBA_t LightColor; + float lightsize; + + fxi.GetEffect(owner, flags, "t", vel); + if (flags & CEF_FLAG6) + Vec3ScaleAssign(FLYING_FIST_SPEED/2,vel); + else + Vec3ScaleAssign(FLYING_FIST_SPEED,vel); + + missile = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 100); + + if (flags & CEF_FLAG7) + { // Powered up fireball. Use a meteor model. + missile->r.model = fist_models + 2; + missile->r.skinnum = 1; + if (flags & CEF_FLAG8) // Wimpy shot, because didn't have mana. + missile->r.scale = 1.0; + else + missile->r.scale = 1.5; + + LightColor.c = 0xff0000ff; // Red light + lightsize = 160.0; + } + else + { // Just a normal fireball. + missile->flags |= CEF_NO_DRAW; + LightColor.c = 0xff2040ff; // Orange light + lightsize = 120.0; + } + + VectorCopy(vel, missile->velocity); + VectorNormalize2(vel, dir); + AnglesFromDir(dir, missile->r.angles); + + missile->radius = 128; + missile->dlight = CE_DLight_new(LightColor, lightsize, 0.0f); + missile->Update = FXFlyingFistTrailThink; + + missile->SpawnInfo = 32; + + AddEffect(owner, missile); +} + + + +// ************************************************************************************************ +// FXFlyingFistExplode +// ************************************************************************************************ + +/////////////////////////////////////// +// From CreateEffect FX_WEAPON_FLYINGFISTEXPLODE +/////////////////////////////////////// +void FXFlyingFistExplode(centity_t *owner,int type,int flags,vec3_t origin) +{ + vec3_t dir, mins; + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor; + byte powerup = 0, wimpy=0; + float lightrad; + float blastvel; + float volume=1.0; + + fxi.GetEffect(owner, flags, "d", dir); + + if(flags & CEF_FLAG6) + { + FXClientScorchmark(origin, dir); + } + + if (flags&CEF_FLAG7) + { + powerup=1; + } + + if (flags&CEF_FLAG8) + { + wimpy=1; + volume=0.75; + } + +// fxi.GetEffect(owner, flags, "xb", dir, &powerup); + Vec3ScaleAssign(32.0, dir); + + if(powerup) + { + i = GetScaledCount(irand(12, 16), 0.8); + LightColor.c = 0xff0000ff; + if (wimpy) + lightrad = 160; + else + lightrad = 200; + } + else + { + i = GetScaledCount(irand(8, 12), 0.8); + LightColor.c = 0xff2040ff; + if (wimpy) + lightrad = 120; + else + lightrad = 150; + } + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(type,flags,origin,NULL,500); + else + SmokePuff=ClientEntity_new(type,flags,origin,NULL,1000); + + SmokePuff->r.model = fist_models + 1; + if (powerup) + { // Meteor impact! + SmokePuff->d_scale=-2.0; + blastvel = FIST_POWER_BLAST_VEL; + if (wimpy) + { + blastvel*=0.3; + SmokePuff->r.scale=flrand(0.8,1.4); + } + else + { + SmokePuff->r.scale=flrand(1.2,2.0); + } + + VectorRandomCopy(dir, SmokePuff->velocity, blastvel); + SmokePuff->velocity[2] += 100.0; + SmokePuff->acceleration[2] = -400.0; + } + else + { // Non-powered up. + SmokePuff->d_scale=-2.0; + blastvel = FIST_BLAST_VEL; + if (wimpy) + { + blastvel*=0.5; + SmokePuff->r.scale=flrand(0.5,1.0); + } + else + { + SmokePuff->r.scale=flrand(0.8,1.6); + } + + VectorRandomCopy(dir, SmokePuff->velocity, blastvel); + SmokePuff->acceleration[0] = flrand(-200, 200); + SmokePuff->acceleration[1] = flrand(-200, 200); + SmokePuff->acceleration[2] = flrand(-40, -60); + } + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + SmokePuff->r.frame=0; + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + if(!i) + { + if (powerup) + { + fxi.S_StartSound(SmokePuff->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/FireballPowerImpact.wav"), + volume, ATTN_NORM, 0); + } + else + { + fxi.S_StartSound(SmokePuff->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/FlyingFistImpact.wav"), + volume, ATTN_NORM, 0); + } + SmokePuff->dlight=CE_DLight_new(LightColor,lightrad, -50.0f); + VectorClear(SmokePuff->velocity); + } + + AddEffect(NULL,SmokePuff); + } + + if (powerup) + { // Meteor throws out chunks. + VectorSet(dir, 0.0, 0.0, 1.0); + VectorSet(mins, 2.0, 2.0, 2.0); // because SpawnChunks needs a value for bounding box + + if (wimpy) // No mana meteors are wimpy! - clear out cef_flag# stuff, means different stuff to debris + FXDebris_SpawnChunks(type, flags & ~(CEF_FLAG6|CEF_FLAG7|CEF_FLAG8), origin, 5, MAT_GREYSTONE, dir, 80000.0f, mins, 0.5, false); + else + FXDebris_SpawnChunks(type, flags & ~(CEF_FLAG6|CEF_FLAG7|CEF_FLAG8), origin, 5, MAT_GREYSTONE, dir, 80000.0f, mins, 1.0, false); + } +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_halo.c b/Toolkit/Programming/GameCode/client effects/fx_halo.c new file mode 100644 index 0000000..4d341c0 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_halo.c @@ -0,0 +1,199 @@ +// +// fx_halo.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "Utilities.h" +#include "g_playstats.h" + +#define NUM_HALO_MODELS 3 +static struct model_s *halo_models[NUM_HALO_MODELS]; + +void PreCacheHalos() +{ + halo_models[0] = fxi.RegisterModel("sprites/lens/halo1.sp2"); + halo_models[1] = fxi.RegisterModel("sprites/lens/halo2.sp2"); + halo_models[2] = fxi.RegisterModel("sprites/lens/halo3.sp2"); +} + +// ************************************************************************************************ +// FXHaloThink +// ************************************************************************************************ + +static qboolean FXHaloThink(struct client_entity_s *self,centity_t *Owner) +{ + float dot, dist, camdist; + + vec3_t mins = { 0, 0, 0}, + maxs = { 0, 0, 0}, + pos1, pos2, + ent_vec, light_vec, res_vec, org; + + trace_t trace; + entity_state_t *es; + + // Effect will be deleted if CEF_DISAPPEARED flag set + self->flags &= ~CEF_DISAPPEARED; + // Default to nodraw + self->flags |= CEF_NO_DRAW; + + AngleVectors (fxi.cl->refdef.viewangles, pos1, NULL, NULL); + VectorSubtract (self->r.origin, fxi.cl->refdef.vieworg, pos2); + VectorNormalize (pos2); + + dot = DotProduct (pos1, pos2); + + if (dot < 0.75) + { + return true; + } + + VectorSubtract(self->r.origin, fxi.cl->refdef.vieworg, pos1); + dist = VectorNormalize(pos1); + + if (dist > 1024) + { + return true; + } + + //Determine Visibility + fxi.Trace( self->r.origin, + mins, + maxs, + fxi.cl->refdef.vieworg, + (CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_DEADMONSTER), + CEF_CLIP_TO_ALL, + &trace); + + if (trace.fraction < 1.0) //Hit something + { + if ((trace.ent != ((struct edict_s *)-1))) //Model + { + es = (entity_state_t *) trace.ent; + + if ((fxi.cl->playernum + 1) == es->number) + { + VectorCopy(es->origin, org); + org[2] += 8; + + VectorSubtract(fxi.cl->refdef.vieworg, self->r.origin, light_vec); + VectorSubtract(self->r.origin, org, ent_vec); + VectorSubtract(fxi.cl->refdef.vieworg, org, pos1); + + camdist = VectorNormalize(pos1); + + dist = VectorNormalize(ent_vec); + + VectorNormalize(light_vec); + VectorMA(self->r.origin, dist, light_vec, res_vec); + VectorSubtract(org, res_vec, pos1); + + dist = VectorNormalize(pos1); + + if (dist < (10 + (camdist/100))) + { + if (self->alpha > 0.25) + { + self->alpha -= 0.25; + return true; + } + else + { + return true; + } + } + else + { + self->flags &= ~CEF_NO_DRAW; + + if (self->alpha < 0.5) + self->alpha += 0.25; + return true; + } + } + else + { + return true; + } + } + else //Hit a brush + { + return true; + } + } + + self->flags &= ~CEF_NO_DRAW; + + if (self->alpha < 0.5) + self->alpha += 0.25; + + return (true); +} + +// ************************************************************************************************ +// FXHalo +// ************************************************************************************************ + +void FXHalo(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *halo; + + + // no halo's for normal or low details.. they are really expensive in traces. + if (r_detail->value <= DETAIL_NORMAL) + return; + + halo = ClientEntity_new(FX_HALO, Flags | CEF_NO_DRAW | CEF_VIEWSTATUSCHANGED, Origin, NULL, 100); + + // decide which halo image to use + if (Flags & CEF_FLAG6) + halo->r.model = halo_models + 1; + else + halo->r.model = halo_models; + + halo->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_NODEPTHTEST; + + // to figure out tint, we only want the top two bits of flags + Flags &= CEF_FLAG7 | CEF_FLAG8; + + switch (Flags) + { + case CEF_FLAG7: + halo->r.color.r = 90; + halo->r.color.g = 90; + halo->r.color.b = 175; + break; + case CEF_FLAG8: + halo->r.color.r = 190; + halo->r.color.g = 180; + halo->r.color.b = 16; + break; + case CEF_FLAG7|CEF_FLAG8: + halo->r.color.r = 255; + halo->r.color.g = 255; + halo->r.color.b = 255; + break; + case 0: + default: + halo->r.color.r = 148; + halo->r.color.g = 132; + halo->r.color.b = 82; + break; + } + halo->alpha = 0.6; + halo->Update = FXHaloThink; + + AddEffect(Owner, halo); +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_healthpickup.c b/Toolkit/Programming/GameCode/client effects/fx_healthpickup.c new file mode 100644 index 0000000..07367b0 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_healthpickup.c @@ -0,0 +1,95 @@ +// +// fx_healthpickup.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "ce_DefaultMessageHandler.h" +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "Angles.h" + +#define BOB_HEIGHT 6.0 +#define BOB_SPEED ANGLE_10 +#define HEALTH_RADIUS 6.0 + + +#define NUM_HEALTH_MODELS 2 +#define HEALTH_SMALL 0 +#define HEALTH_BIG 1 + +static struct model_s *health_models[NUM_HEALTH_MODELS]; +void PreCacheHealth() +{ + health_models[0] = fxi.RegisterModel("models/items/health/healthsmall/tris.fm"); + health_models[1] = fxi.RegisterModel("models/items/health/healthbig/tris.fm"); +} + +// -------------------------------------------------------------- + +static qboolean FXHealthPickupThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *p; + paletteRGBA_t color; + + // Rotate and bob + self->r.angles[YAW] += ANGLE_15; + VectorCopy(owner->current.origin, self->r.origin); + self->r.origin[2] += (cos(self->SpawnData) * BOB_HEIGHT); + self->SpawnData += BOB_SPEED; + + // spawn particles + if (self->flags & CEF_FLAG6) + { + color.g = irand(80, 120); + color.r = irand(210, 255); + color.b = color.r; + } + else + { + color.r = irand(80, 120); + color.b = irand(210, 255); + color.g = color.r; + } + + color.a = 255; + p = ClientParticle_new(PART_4x4_WHITE | PFL_SOFT_MASK, color, 600); + + VectorSet(p->origin, flrand(-HEALTH_RADIUS, HEALTH_RADIUS), flrand(-HEALTH_RADIUS, HEALTH_RADIUS), 0.0); + VectorSet(p->velocity, 0.0, 0.0, flrand(20.0, 40.0)); + p->acceleration[2] = 20.0; + AddParticleToList(self, p); + + return(true); +} + +void FXHealthPickup(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *ce; + + flags &= ~CEF_OWNERS_ORIGIN; + ce = ClientEntity_new(type, flags | CEF_DONT_LINK | CEF_CHECK_OWNER | CEF_VIEWSTATUSCHANGED, origin, NULL, 50); + + VectorCopy(ce->r.origin, ce->origin); + ce->r.model = health_models + ((flags & CEF_FLAG6) >> 5); + ce->r.flags = RF_GLOW | RF_TRANSLUCENT | RF_TRANS_ADD; + + if ((flags & CEF_FLAG6) >> 5) // Full health + ce->r.scale = 1; + else + ce->r.scale = 1.5; + ce->radius = 10.0; + ce->alpha = 0.8; + ce->Update = FXHealthPickupThink; + + AddEffect(owner, ce); +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_hitpuff.c b/Toolkit/Programming/GameCode/client effects/fx_hitpuff.c new file mode 100644 index 0000000..fccb11d --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_hitpuff.c @@ -0,0 +1,89 @@ +// +// fx_hitpuff.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "Angles.h" +#include "Random.h" +#include "Utilities.h" +#include "q_sprite.h" +#include "g_playstats.h" + +#define NUM_HIT_MODELS 3 +static struct model_s *hit_models[NUM_HIT_MODELS]; +void PreCacheHitPuff() +{ + hit_models[0] = fxi.RegisterModel("sprites/fx/halo.sp2"); + hit_models[1] = fxi.RegisterModel("sprites/fx/bluestreak.sp2"); + hit_models[2] = fxi.RegisterModel("sprites/fx/firestreak.sp2"); +} + +// -------------------------------------------------------------- + + +#define LIGHTNING_VEL 256.0 + +#define NUM_LIGHTNING_BITS 25 +void FXLightningHit(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t dir; + paletteRGBA_t color; + int part; + client_entity_t *blast; + client_particle_t *spark; + int i; + + fxi.GetEffect(owner, flags, "t", dir); + + Vec3ScaleAssign(LIGHTNING_VEL*0.25, dir); + + if (flags&CEF_FLAG7) + { // RED hit puff + color.c = 0xff4040ff; + part=PART_16x16_SPARK_R; + } + else if (flags&CEF_FLAG8) + { // FIRE hit puff + color.c = 0xffff80ff; + part=PART_32x32_FIRE1; + } + else + { // BLUE hit puff + color.c = 0xffff8080; + part=PART_16x16_SPARK_B; + } + + blast = ClientEntity_new(-1, CEF_ADDITIVE_PARTS, origin, NULL, 500); + blast->r.model = hit_models; + blast->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT; // | + blast->r.frame = 1; + blast->radius = 64.0; + blast->r.scale=1.5; + blast->d_alpha=-4.0; + blast->d_scale=-4.0; + fxi.S_StartSound(blast->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/HellHit.wav"), 1, ATTN_NORM, 0); + blast->dlight = CE_DLight_new(color, 75.0f, 0.0f); + VectorClear(blast->velocity); + AddEffect(NULL, blast); + + color.c = 0xffffffff; + for(i = 0; i < NUM_LIGHTNING_BITS; i++) + { + spark = ClientParticle_new(part, color, 500); + VectorRandomCopy(dir, spark->velocity, LIGHTNING_VEL); +// VectorSet(dir, 0.0, 0.0, GetGravity() * 0.3); + spark->scale = flrand(20.0, 32.0); + spark->d_scale = -32.0; + spark->d_alpha = flrand(-640.0, -512.0); + AddParticleToList(blast, spark); + } +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_hpproj.c b/Toolkit/Programming/GameCode/client effects/fx_hpproj.c new file mode 100644 index 0000000..e137931 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_hpproj.c @@ -0,0 +1,1188 @@ +// +// fx_hpproj.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "q_Sprite.h" +#include "Utilities.h" +#include "reference.h" +#include "Matrix.h" +#include "g_playstats.h" + +#define NUM_MISSILE_MODELS 11 +#define NUM_STAFF_MODELS 1 + +static struct model_s *hpproj_models[NUM_MISSILE_MODELS]; +static struct model_s *hpstaff_models[NUM_STAFF_MODELS]; + +enum { + HPMISSILE1, + HPMISSILE2, + HPMISSILE3, + HPMISSILE4, + HPMISSILE5, + HPMISSILE1_EXPLODE, + HPMISSILE2_EXPLODE, + HPMISSILE3_EXPLODE, + HPMISSILE4_EXPLODE, + HPMISSILE5_EXPLODE, + HPMISSILE1_LIGHT, + HPMISSILE2_LIGHT, + HPMISSILE3_LIGHT, + HPMISSILE4_LIGHT, + HPMISSILE5_LIGHT, + HPTELEPORT_START, + HPTELEPORT_END, + HPLIGHTNING_BOLT, +}; + +/* + Precaching Functions + +*/ + +void PreCacheHPStaff() +{ + //Staff Trail + hpstaff_models[0] = fxi.RegisterModel("sprites/fx/hpproj1_2.sp2"); +} + +void PreCacheHPMissile() +{ + //Projectile head sprites + hpproj_models[0] = fxi.RegisterModel("sprites/fx/hpproj1_1.sp2"); + hpproj_models[1] = fxi.RegisterModel("sprites/fx/hpproj1_2.sp2"); + + //Trail segments + hpproj_models[2] = fxi.RegisterModel("sprites/fx/segment_trail.sp2"); + hpproj_models[6] = fxi.RegisterModel("sprites/fx/segment_trail_y.sp2"); + hpproj_models[7] = fxi.RegisterModel("sprites/fx/segment_trail_wt.sp2"); + + //Halos + hpproj_models[3] = fxi.RegisterModel("sprites/fx/hp_halo.sp2"); + hpproj_models[4] = fxi.RegisterModel("sprites/lens/halo1.sp2"); + + //Light Bug model + hpproj_models[5] = fxi.RegisterModel("models/objects/lights/bug/tris.fm"); + + //Rocks + hpproj_models[8] = fxi.RegisterModel("models/debris/stone/schunk1/tris.fm"); + hpproj_models[9] = fxi.RegisterModel("models/debris/stone/schunk2/tris.fm"); + + //Lightning bolts + hpproj_models[10] = fxi.RegisterModel("sprites/fx/hp_lightning.sp2"); +} + +/* + High Priestess Projectile Functions + +*/ + +#define PRIESTESS_TELEPORT_LINEHEIGHT 764 + +static qboolean FXHPTeleportLineThink(struct client_entity_s *self,centity_t *Owner) +{ + client_entity_t *effect; + client_particle_t *p; + int i, color_ofs; + paletteRGBA_t color = {255,255,255,255}; + + if (self->alpha <= 0.0) + return false; + + self->r.endpos[2] += 32; + + if ((self->r.endpos[2] - self->r.startpos[2]) > PRIESTESS_TELEPORT_LINEHEIGHT) + { + if (self->SpawnInfo == 0.0) + fxi.Activate_Screen_Flash(0xffffffff); + + self->SpawnInfo = 1; + self->d_alpha = -1.0; + self->r.scale += 16; + } + else + { + self->r.scale += 1.5; + + //Spawn some particles and some rock chunks + + i = GetScaledCount(8, 0.7);//irand(8,12); + + while(i--) + { + p = ClientParticle_new(PART_4x4_WHITE, color, 2500); + + //Chance to make them brown + if (irand(0,1)) + { + color_ofs = irand(0, 64); + p->color.r = color_ofs; + p->color.g = color_ofs; + p->color.b = 0; + p->color.a = 255; + } + else + { + color_ofs = irand(32, 128); + p->color.r = p->color.g = p->color.b = color_ofs; + p->color.a = 255; + } + + p->origin[0] += irand(-24,24); + p->origin[1] += irand(-24,24); + p->origin[2] -= 36; + + p->scale = flrand(0.25, 1.0); + + p->acceleration[0] = irand(-75,75); + p->acceleration[1] = irand(-75,75); + p->acceleration[2] = irand(400,500); + + p->d_alpha = -2.0; + AddParticleToList(self, p); + } + + i = GetScaledCount(5, 0.7);//irand(4,6); + + while(i--) + { + effect=ClientEntity_new( FX_HP_MISSILE, + CEF_DONT_LINK, + self->origin, + NULL, + 1000); + + effect->r.model = hpproj_models + irand(8,9); + + effect->r.scale = flrand(0.1, 0.5); + + VectorCopy(self->r.origin, effect->r.origin); + effect->r.origin[0] += irand(-32,32); + effect->r.origin[1] += irand(-32,32); + effect->r.origin[2] -= 36; + + effect->velocity[2] = 1; + + effect->acceleration[0] = irand(-150, 150); + effect->acceleration[1] = irand(-150, 150); + effect->acceleration[2] = irand( 300, 600 - ( self->r.scale * 100) ); + + effect->d_alpha = -0.25; + + effect->radius = 500; + + AddEffect(NULL, effect); + } + } + + return true; +} + +static qboolean FXHPTeleportLineThink2(struct client_entity_s *self,centity_t *Owner) +{ + if (self->alpha <= 0.0f) + return false; + + if (self->r.scale <= 0.0f) + return false; + + self->r.scale -= 4; + + return true; +} + +/*----------------------------------------------- + FXHPMissileSpawnerThink +-----------------------------------------------*/ + +static qboolean FXHPMissileSpawnerThink(struct client_entity_s *self,centity_t *Owner) +{ + client_entity_t *TrailEnt; + + if (self->LifeTime < fxi.cl->time) + return false; + + TrailEnt=ClientEntity_new(FX_HP_MISSILE, + CEF_DONT_LINK, + self->origin, + NULL, + 1000); + + TrailEnt->radius = 500; + + TrailEnt->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = hpproj_models + 3; + + TrailEnt->r.color.c = 0xFFFFFFFF; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 0.1; + + TrailEnt->d_alpha = -2.5; + TrailEnt->d_scale = 4.0; + + VectorCopy(self->origin, TrailEnt->origin); + + TrailEnt->velocity[0] = irand(-16, 16); + TrailEnt->velocity[1] = irand(-16, 16); + TrailEnt->velocity[2] = irand(-16, 16); + + AddEffect(NULL,TrailEnt); + + return true; +} + +/*----------------------------------------------- + FXHPMissileSpawnerThink2 +-----------------------------------------------*/ + +static qboolean FXHPMissileSpawnerThink2(struct client_entity_s *self,centity_t *Owner) +{ + client_entity_t *TrailEnt; + + if (self->LifeTime < fxi.cl->time) + return false; + + TrailEnt=ClientEntity_new(FX_HP_MISSILE, + CEF_DONT_LINK, + self->origin, + NULL, + 1000); + + TrailEnt->radius = 500; + + TrailEnt->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = hpproj_models + 4; + + TrailEnt->r.color.r = 229; + TrailEnt->r.color.g = 250; + TrailEnt->r.color.b = 88; + TrailEnt->r.color.a = 255; + + TrailEnt->alpha = 0.5; + TrailEnt->r.scale = 0.25; + + TrailEnt->d_alpha = -2.5; + TrailEnt->d_scale = 2.0; + + VectorCopy(self->origin, TrailEnt->origin); + + TrailEnt->velocity[0] = irand(-16, 16); + TrailEnt->velocity[1] = irand(-16, 16); + TrailEnt->velocity[2] = irand(-16, 16); + + AddEffect(NULL,TrailEnt); + + return true; +} + +/*----------------------------------------------- + FXHPHaloDie +-----------------------------------------------*/ + +static qboolean FXHPHaloDie(struct client_entity_s *self,centity_t *Owner) +{ + if (self->r.scale <= 0.0f) + return false; + + if (self->alpha <= 0.0f) + return false; + + return true; +} +/*----------------------------------------------- + FXHPMissileSpawnerThink3 +-----------------------------------------------*/ + +static qboolean FXHPMissileSpawnerThink3(struct client_entity_s *self,centity_t *Owner) +{ + if (self->LifeTime < fxi.cl->time) + { + self->Update = FXHPHaloDie; + self->d_scale = -2.0; + self->d_alpha = -1.0; + return true; + } + + if (self->d_scale == 0.0) + { + self->r.scale = flrand(1.75, 2.25); + return true; + } + + if (self->r.scale >= 2) + self->d_scale = 0.0; + + if (self->alpha > 0.5) + { + self->d_alpha = 0.0; + self->alpha = 0.5; + } + + return true; +} + +/*----------------------------------------------- + FXHPTrailThink +-----------------------------------------------*/ + +static qboolean FXHPTrailThink(struct client_entity_s *self,centity_t *Owner) +{ + if (self->alpha <= 0.1 || self->r.scale <= 0.0) + return false; + + self->r.scale -= 0.1; + + return true; +} + +/*----------------------------------------------- + FXHPTrailThink2 +-----------------------------------------------*/ + +static qboolean FXHPTrailThink2(struct client_entity_s *self,centity_t *Owner) +{ + if (self->alpha <= 0.1 || self->r.scale <= 0.0) + return false; + + self->r.scale -= 0.15; + + return true; +} + +/*----------------------------------------------- + FXHPTrailThink3 +-----------------------------------------------*/ + +static qboolean FXHPTrailThink3(struct client_entity_s *self,centity_t *Owner) +{ + if (self->alpha <= 0.1 || self->r.scale <= 0.0) + return false; + + self->r.scale -= 0.25; + + return true; +} + +/*----------------------------------------------- + FXHPBugThink +-----------------------------------------------*/ + +static qboolean FXHPBugThink(struct client_entity_s *self,centity_t *Owner) +{ + self->r.scale = flrand(0.2, 0.4); + self->alpha = flrand(0.3, 0.5); + + return true; +} + +/*----------------------------------------------- + FXHPMissileTrailThink +-----------------------------------------------*/ + +static qboolean FXHPMissileTrailThink(struct client_entity_s *self,centity_t *Owner) +{ + client_entity_t *TrailEnt; + + self->r.scale = flrand(0.35, 0.65); + + TrailEnt=ClientEntity_new(FX_HP_MISSILE, + CEF_DONT_LINK, + Owner->origin, + NULL, + 17); + + TrailEnt->radius = 500; + + VectorCopy( Owner->origin, TrailEnt->origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = hpproj_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = 2.5; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 1.0; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( Owner->origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -2.5; + TrailEnt->d_scale = 0.0; + TrailEnt->Update = FXHPTrailThink; + + AddEffect(NULL,TrailEnt); + + VectorCopy(Owner->origin, self->startpos); + + return true; +} + +/*----------------------------------------------- + FXHPMissileTrailThink2 +-----------------------------------------------*/ + +static qboolean FXHPMissileTrailThink2(struct client_entity_s *self,centity_t *Owner) +{ + client_entity_t *TrailEnt; + + self->r.scale = flrand(0.35, 0.55); + + TrailEnt=ClientEntity_new(FX_HP_MISSILE, + CEF_DONT_LINK, + Owner->origin, + NULL, + 17); + + TrailEnt->radius = 500; + + VectorCopy( Owner->origin, TrailEnt->origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = hpproj_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = 2; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 1.0; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( Owner->origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -4.0; + TrailEnt->d_scale = 0.0; + TrailEnt->Update = FXHPTrailThink2; + + AddEffect(NULL,TrailEnt); + + VectorCopy(Owner->origin, self->startpos); + + return true; +} + +/*----------------------------------------------- + FXHPMissileTrailThink3 +-----------------------------------------------*/ + +static qboolean FXHPMissileTrailThink3(struct client_entity_s *self,centity_t *Owner) +{ + client_entity_t *TrailEnt; + + TrailEnt=ClientEntity_new(FX_HP_MISSILE, + CEF_DONT_LINK, + Owner->origin, + NULL, + 17); + + TrailEnt->radius = 500; + + VectorCopy( Owner->origin, TrailEnt->origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = hpproj_models + 6; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = 2.0; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 1.0; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( Owner->origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -2.0; + TrailEnt->d_scale = 0.0; + TrailEnt->Update = FXHPTrailThink3; + + AddEffect(NULL,TrailEnt); + + VectorCopy(Owner->origin, self->startpos); + + return true; +} + +/*----------------------------------------------- + FXHPMissileExplode +-----------------------------------------------*/ + +void FXHPMissileExplode(struct client_entity_s *self,centity_t *Owner) +{ + vec3_t dir; + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor={255,64,32,255}; + byte powerup = 0; + + VectorSet(dir, 1, 1, 1); + //Vec3ScaleAssign(32.0, dir); + + i = GetScaledCount(irand(6,8), 0.8); + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(FX_HP_MISSILE,0,Owner->origin,NULL,500); + else + SmokePuff=ClientEntity_new(FX_HP_MISSILE,0,Owner->origin,NULL,1500); + + SmokePuff->r.model = hpproj_models + 3; + SmokePuff->r.scale=flrand(0.5,1.0); + SmokePuff->d_scale = flrand(-1.0, -1.5); + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + SmokePuff->r.frame = 0; + + VectorRandomCopy(dir, SmokePuff->velocity, flrand(64.0, 128.0)); + + SmokePuff->acceleration[0] = flrand(-100, -50); + SmokePuff->acceleration[1] = flrand(-100, -50); + SmokePuff->acceleration[2] = flrand(-100, -250); + + SmokePuff->d_alpha= -0.2; + + SmokePuff->radius=20.0; + + AddEffect(NULL,SmokePuff); + } +} + +/*----------------------------------------------- + FXHPBugExplode +-----------------------------------------------*/ + +void FXHPBugExplode(struct client_entity_s *self,centity_t *Owner) +{ + vec3_t dir; + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor={255,64,32,255}; + byte powerup = 0; + + //Vec3ScaleAssign(32.0, dir); + VectorSet(dir, 1, 1, 1); + + i = GetScaledCount(irand(12,16), 0.8); + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(FX_HP_MISSILE,0,Owner->origin,NULL,500); + else + SmokePuff=ClientEntity_new(FX_HP_MISSILE,0,Owner->origin,NULL,1500); + + SmokePuff->r.model = hpproj_models; + SmokePuff->r.scale=flrand(0.5,1.0); + SmokePuff->d_scale=-2.0; + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + SmokePuff->r.frame = 0; + + VectorRandomCopy(dir, SmokePuff->velocity, flrand(16.0, 64.0)); + + SmokePuff->acceleration[0] = flrand(-200, 200); + SmokePuff->acceleration[1] = flrand(-200, 200); + SmokePuff->acceleration[2] = flrand(-60, -100); + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + AddEffect(NULL,SmokePuff); + } +} + +/*----------------------------------------------- + FXHPMissileCreateWarp +-----------------------------------------------*/ + +void FXHPMissileCreateWarp(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *Trail; + + Trail = ClientEntity_new( Type, CEF_DONT_LINK, Origin, NULL, 2000); + + Trail->radius = 500; + Trail->r.model = hpproj_models + 3; + Trail->r.color.c = 0xffff5555; + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->r.scale = 0.1; + Trail->d_scale = 2.0; + Trail->d_alpha = -2.0; + + AddEffect(NULL,Trail); +} + +static qboolean PriestessLinkedEntityUpdatePlacement(struct client_entity_s *self, centity_t *owner) +{ + LinkedEntityUpdatePlacement(self, owner); + VectorCopy(self->r.origin, self->r.startpos); + + return true; +} + +/*----------------------------------------------- + FXHPMissile +-----------------------------------------------*/ + +void FXHPMissile(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *Trail; + paletteRGBA_t LightColor={0,0,255,255}; + paletteRGBA_t BugColor={229,250,88,255}; + paletteRGBA_t BrightColor={255,255,255,255}; + vec3_t vel, boltDir, boltAng, boltDest, oldPos, ang, huntdir; + float boltDist, boltStep, width, alpha; + byte effectType; + int bends, i, bolts, j; + + + fxi.GetEffect(Owner, Flags, "vb", &vel, &effectType); + + switch ( effectType ) + { + + //Blue swirling, homing missiles + case HPMISSILE1: + + FXHPMissileCreateWarp(Owner, Type, Flags, Origin); + + Trail = ClientEntity_new( Type, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, Origin, NULL, 20); + + VectorCopy(vel, Trail->up); + Trail->Update=FXHPMissileTrailThink; + Trail->dlight=CE_DLight_new(LightColor,150.0f,0.0f); + Trail->radius = 500; + Trail->r.model = hpproj_models + 3; + Trail->r.color.c = 0x00999999; + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->r.scale = 0.5; + Trail->AddToView = PriestessLinkedEntityUpdatePlacement; + + VectorCopy(Origin, Trail->startpos); + + AddEffect(Owner,Trail); + + FXHPMissileTrailThink(Trail,Owner); + + break; + + //Normal trails off projectiles + case HPMISSILE2: + + FXHPMissileCreateWarp(Owner, Type, Flags, Origin); + + Trail = ClientEntity_new( Type, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, Origin, NULL, 20); + + VectorCopy(vel, Trail->up); + Trail->Update=FXHPMissileTrailThink2; + Trail->dlight=CE_DLight_new(LightColor,150.0f,0.0f); + Trail->radius = 500; + Trail->r.model = hpproj_models + 3; + Trail->r.color.c = 0x00999999; + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->r.scale = 0.45; + Trail->AddToView = PriestessLinkedEntityUpdatePlacement; + + VectorCopy(Owner->origin, Trail->startpos); + + AddEffect(Owner,Trail); + + FXHPMissileTrailThink2(Trail,Owner); + + break; + + //Light bugs/mines + case HPMISSILE3: + + Trail = ClientEntity_new( Type, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, Origin, NULL, 20); + + Trail->Update=FXHPMissileTrailThink3; + + Trail->dlight=CE_DLight_new(BugColor, 50.0f, 0.0f); + Trail->radius = 500; + Trail->r.model = hpproj_models + 5; + + VectorNormalize(vel); + + AnglesFromDir(vel, Trail->r.angles); + Trail->r.angles[PITCH] -= ANGLE_90; + + Trail->r.color.c = 0xFF999999; + Trail->r.scale = flrand(0.3, 0.4); + Trail->AddToView = LinkedEntityUpdatePlacement; + + VectorCopy(Owner->origin, Trail->startpos); + + AddEffect(Owner,Trail); + + FXHPMissileTrailThink3(Trail,Owner); + + //Create the halo to follow the bug + Trail = ClientEntity_new( Type, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, Origin, NULL, 20); + + Trail->Update=FXHPBugThink; + + Trail->radius = 500; + Trail->r.model = hpproj_models + 4; + + Trail->r.color.r = 229; + Trail->r.color.g = 250; + Trail->r.color.b = 88; + Trail->r.color.a = 255; + + Trail->alpha = 0.5; + + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + Trail->r.scale = flrand(0.3, 0.4); + + Trail->AddToView = LinkedEntityUpdatePlacement; + + VectorCopy(Origin, Trail->startpos); + + AddEffect(Owner,Trail); + + FXHPBugThink(Trail,Owner); + + break; + + //Light shafts coming from the priestess' staff + case HPMISSILE4: + + i = irand(5,8); + + while (i--) + { + Trail = ClientEntity_new( Type, CEF_DONT_LINK, Origin, NULL, 2000); + + Trail->radius = 500; + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->r.model = hpproj_models + 7; + + Trail->r.spriteType = SPRITE_LINE; + Trail->r.tile = 1; + Trail->r.scale = irand(1.0, 2.0); + Trail->alpha = 1.0; + Trail->r.scale = 1.0; + + ang[PITCH] = irand( 0, 720 ); + ang[YAW] = irand( 0, 720 ); + ang[ROLL] = irand( 0, 720 ); + + AngleVectors( ang, vel, NULL, NULL ); + VectorMA( Origin, 512, vel, Trail->r.endpos ); + + VectorCopy( Origin, Trail->r.startpos ); + VectorCopy( Origin, Trail->r.origin ); + + Trail->d_alpha = -2.0; + Trail->d_scale = 0.0; + + AddEffect(NULL,Trail); + } + + break; + + //The power bolts she shoots from her staff + case HPMISSILE5: + + bolts = irand(2,3); + + for (j=0;jr.startpos); + VectorCopy(Origin, Trail->r.endpos); + } + + Trail->radius = 500; + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->r.model = hpproj_models + 10; + + Trail->r.spriteType = SPRITE_LINE; + Trail->r.scale = width; + Trail->alpha = 1.0; + Trail->r.scale = 1.0; + + VectorCopy(vel, Trail->r.origin); + + if (i == bends) + { + VectorCopy(oldPos, Trail->r.startpos); + VectorCopy(vel, Trail->r.endpos); + + Trail->r.endpos[2] += irand(-4, 4); + } + else + { + VectorSubtract(vel, oldPos, huntdir); + boltStep = VectorNormalize(huntdir); + boltStep /= ((bends+1) - i); + + VectorScale(boltDir, (2.5/bends), boltDir); + VectorAdd(boltDir, huntdir, boltDir); + + VectorNormalize(boltDir); + + VectorCopy(oldPos, Trail->r.startpos); + + Trail->r.tile = ceil(boltStep / 128); + + VectorMA(Trail->r.startpos, boltStep, boltDir, Trail->r.endpos); + VectorCopy(Trail->r.endpos, oldPos); + } + + Trail->d_alpha = alpha; + Trail->d_scale = 0.0; + + AddEffect(NULL,Trail); + } + } + + break; + + //Normal explosions + case HPMISSILE1_EXPLODE: + case HPMISSILE2_EXPLODE: + Trail = ClientEntity_new( Type, CEF_NO_DRAW | CEF_DONT_LINK, Origin, NULL, 2000); + AddEffect(NULL, Trail); + FXHPMissileExplode(Trail,Owner); + break; + + //Light bug explosion + case HPMISSILE3_EXPLODE: + Trail = ClientEntity_new( Type, CEF_NO_DRAW | CEF_DONT_LINK, Origin, NULL, 2000); + AddEffect(NULL, Trail); + FXHPBugExplode(Trail,Owner); + break; + + //Light the eminates from her staff when casting effects + case HPMISSILE1_LIGHT: + case HPMISSILE2_LIGHT: + + Trail = ClientEntity_new( Type, CEF_NO_DRAW | CEF_DONT_LINK, Origin, NULL, 20); + + VectorCopy( Origin, Trail->origin ); + Trail->Update=FXHPMissileSpawnerThink; + Trail->radius = 500; + Trail->r.model = hpproj_models + 3; + Trail->r.color.c = 0xFFFFFFFF; + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->dlight=CE_DLight_new(LightColor,200.0f,0.0f); + Trail->LifeTime = fxi.cl->time + 4000; + + AddEffect(NULL,Trail); + + break; + + //Light the eminates from her staff when casting bugs + case HPMISSILE3_LIGHT: + + Trail = ClientEntity_new( Type, CEF_NO_DRAW | CEF_DONT_LINK, Origin, NULL, 20); + + VectorCopy( Origin, Trail->origin ); + Trail->Update=FXHPMissileSpawnerThink2; + + Trail->radius = 500; + Trail->dlight=CE_DLight_new(BugColor,10.0f,0.0f); + Trail->LifeTime = fxi.cl->time + 2000; + + AddEffect(NULL,Trail); + + break; + + //Light for the massive light attack + case HPMISSILE4_LIGHT: + + fxi.Activate_Screen_Flash(0xffffffff); + + //Create the large halo that scales up and fades out + Trail = ClientEntity_new( Type, CEF_DONT_LINK, Origin, NULL, 4000); + + VectorCopy( Origin, Trail->origin ); + + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + Trail->r.model = hpproj_models + 4; + Trail->r.scale = 0.1; + Trail->alpha = 1.0; + Trail->d_alpha = -1.0; + Trail->d_scale = 4.0; + Trail->radius = 500; + Trail->LifeTime = fxi.cl->time + 4000; + + AddEffect(NULL,Trail); + + //Create the sparkling center + Trail = ClientEntity_new( Type, CEF_DONT_LINK, Origin, NULL, 20); + + VectorCopy( Origin, Trail->origin ); + + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->Update=FXHPMissileSpawnerThink3; + + Trail->r.model = hpproj_models + 4; + Trail->r.scale = 0.1; + Trail->alpha = 0.1; + Trail->d_alpha = 0.5; + Trail->d_scale = 2.0; + Trail->radius = 500; + Trail->dlight=CE_DLight_new(BrightColor,250.0f,0.0f); + Trail->LifeTime = fxi.cl->time + 4000; + + AddEffect(NULL,Trail); + + //Shake the screen + fxi.Activate_Screen_Shake(4, 5500, fxi.cl->time, SHAKE_ALL_DIR); + + break; + + //Empty + case HPMISSILE5_LIGHT: + + break; + + //Starting effect for her teleport + case HPTELEPORT_START: + + Trail = ClientEntity_new( Type, CEF_DONT_LINK, Origin, NULL, 20); + + VectorCopy( Origin, Trail->origin ); + + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->Update=FXHPTeleportLineThink; + + Trail->r.model = hpproj_models + 7; + Trail->r.spriteType = SPRITE_LINE; + Trail->r.tile = 1.0; + Trail->r.scale = 2; + Trail->alpha = 1.0; + Trail->r.scale = 1.0; + + VectorCopy( Origin, Trail->r.startpos ); + Trail->r.startpos[2] -= 128; + + VectorCopy( Origin, Trail->r.endpos ); + Trail->r.endpos[2] += 32; + + Trail->dlight=CE_DLight_new(BrightColor,250.0f,0.0f); + Trail->d_alpha = 0.0; + Trail->d_scale = 0.0; + + AddEffect(NULL,Trail); + + break; + + //Ending effect for her teleport + case HPTELEPORT_END: + + Trail = ClientEntity_new( Type, CEF_DONT_LINK, Origin, NULL, 20); + + VectorCopy( Origin, Trail->origin ); + + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->Update=FXHPTeleportLineThink2; + + Trail->r.model = hpproj_models + 7; + Trail->r.spriteType = SPRITE_LINE; + Trail->r.tile = 1.0; + Trail->r.scale = 64; + Trail->alpha = 1.0; + Trail->r.scale = 1.0; + + VectorCopy( Origin, Trail->r.startpos ); + Trail->r.startpos[2] -= 128; + + VectorCopy( Origin, Trail->r.endpos ); + Trail->r.endpos[2] += 512; + + Trail->dlight=CE_DLight_new(BrightColor,250.0f,0.0f); + Trail->d_alpha = -1.0; + Trail->d_scale = 0.0; + + AddEffect(NULL,Trail); + + break; + + default: + + Com_DPrintf("ERROR FXHPMissile: No available effect processor! (EFFECT ID %d)\n", effectType); + break; + } +} + + + + + + + + + + + + + + + + + + + + + +/* + + High Priestess Staff Effects + +*/ + +enum +{ + HP_STAFF_INIT, + HP_STAFF_TRAIL, +} HighPriestessStaff_e; + +/*----------------------------------------------- + FXHPStaff +-----------------------------------------------*/ + +qboolean HPStaffTrailThink(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *Trail; + matrix3_t RotationMatrix; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid((centity_t *)(self->extra))) + return true; + + Trail = ClientEntity_new( FX_HP_STAFF, CEF_DONT_LINK, self->r.origin, NULL, 2000); + + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + Trail->r.model = hpstaff_models; + Trail->r.scale = 0.75; + Trail->alpha = 0.5; + Trail->d_alpha = -2.0; + Trail->d_scale = -2.0; + Trail->radius = 500; + + Matrix3FromAngles(((centity_t *)(self->extra))->lerp_angles,RotationMatrix); + + Matrix3MultByVec3( RotationMatrix, + ((centity_t *)(self->extra))->referenceInfo->references[PRIESTESS_STAFF].placement.origin, + Trail->r.origin); + + VectorAdd(((centity_t *)(self->extra))->origin, Trail->r.origin, Trail->r.origin); + Trail->r.origin[2] -= 36; + + AddEffect(NULL,Trail); + + return true; +} + +/*----------------------------------------------- + PriestessEffectStayAlive +-----------------------------------------------*/ + +qboolean PriestessEffectStayAlive(struct client_entity_s *self, centity_t *owner) +{ + return true; +} + +/*----------------------------------------------- + PriestessFirstSeenInit +-----------------------------------------------*/ + +qboolean PriestessFirstSeenInit(struct client_entity_s *self, centity_t *owner) +{ + self->refMask |= PRIESTESS_MASK; + + EnableRefPoints(owner->referenceInfo, self->refMask); + + self->AddToView = NULL; + self->Update = HPStaffTrailThink; + + HPStaffTrailThink(self, owner); + + return true; +} + +/*----------------------------------------------- + FXHPStaff +-----------------------------------------------*/ + +void FXHPStaff(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *self; + short entID; + byte type; + + fxi.GetEffect(Owner, Flags, "bs", &type, &entID); + + switch (type) + { + case HP_STAFF_INIT: + + self = ClientEntity_new(Type, Flags | CEF_NO_DRAW | CEF_ABSOLUTE_PARTS, Origin, NULL, 17); + + self->Update = NULL; + self->AddToView = PriestessFirstSeenInit; + self->Update = PriestessEffectStayAlive; + self->extra=(void *)(&fxi.server_entities[entID]); + + AddEffect(Owner, self); + + PriestessEffectStayAlive(self, Owner); + break; + + case HP_STAFF_TRAIL: + + //Add trailing code here + break; + + default: + + //Effect was passed with invalid effect modifier type + assert(0); + break; + } +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_insectstaff.c b/Toolkit/Programming/GameCode/client effects/fx_insectstaff.c new file mode 100644 index 0000000..1dc5d21 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_insectstaff.c @@ -0,0 +1,1001 @@ +// +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "Utilities.h" +#include "Reference.h" +#include "Matrix.h" +#include "g_playstats.h" + +#define FIST_DELTA_FORWARD 8.0 +#define FIST_DELTA_THETA 0.12 +#define FIST_SPIRAL_RAD 0.75 +#define FIST_SCALE 0.20 + +#define NUM_FF_MODELS 1 +#define NUM_GL_MODELS 5 +#define NUM_SW_MODELS 1 +#define NUM_SP_MODELS 4 + +static struct model_s *globe_models[NUM_GL_MODELS]; +static struct model_s *ins_models[NUM_FF_MODELS]; +static struct model_s *sword_models[NUM_SW_MODELS]; +static struct model_s *spear_models[NUM_SP_MODELS]; + +void PreCacheIEffects() +{ + ins_models[0] = fxi.RegisterModel("sprites/spells/spark_blue.sp2");//sprites/spells/bluball.sp2"); + + sword_models[0] = fxi.RegisterModel("sprites/spells/patball.sp2"); + + spear_models[0] = fxi.RegisterModel("sprites/Spells/spark_red.sp2"); + spear_models[1] = fxi.RegisterModel("sprites/Spells/flyingfist.sp2"); + spear_models[2] = fxi.RegisterModel("sprites/Spells/spark_yellow.sp2"); + spear_models[3] = fxi.RegisterModel("sprites/fx/halo.sp2"); + + globe_models[0] = fxi.RegisterModel("sprites/spells/shboom.sp2"); + globe_models[1] = fxi.RegisterModel("sprites/fx/halo.sp2"); + globe_models[2] = fxi.RegisterModel("Sprites/Spells/spark_blue.sp2");//"sprites/spells/glowball.sp2"); + globe_models[3] = fxi.RegisterModel("models/spells/sphere/tris.fm"); + globe_models[4] = fxi.RegisterModel("sprites/fx/neon.sp2");//bluball.sp2");//bluball.sp2"); +} + +// -------------------------------------------------------------- + +#define FX_GLOBE_FLY_SPEED 600.0 +#define FX_SOFT_GLOBE_AURA_SCALE 0.6 +#define FX_GLOBE_AURA_SCALE 0.8 +#define FX_GLOBE_EXPLOSION_BASE_RADIUS 89.0 +#define NUM_SPEAR_EXPLODES 8 + +enum +{ + FX_I_SWORD, + FX_I_SPEAR, + FX_I_SP_MSL_HIT, + FX_I_GLOBE, + FX_I_GLOW, + FX_I_STAFF, + FX_I_ST_MSL_HIT, + FX_I_RREFS, + FX_I_SPEAR2, + FX_I_SP_MSL_HIT2 +}; + +static qboolean FXHellboltTrailElementThink(struct client_entity_s *self,centity_t *owner); +static qboolean FXHellboltTrailThink(struct client_entity_s *self,centity_t *owner); +static qboolean FXHellboltModelThink(struct client_entity_s *self,centity_t *owner); +static qboolean FXHellboltSmokePuffThink(struct client_entity_s *self,centity_t *owner); + +// -------------------------------------------------------------- + + +static qboolean FXGlobeOfOuchinessSphereThink(struct client_entity_s *self,centity_t *owner); +static qboolean FXGlobeOfOuchinessAuraElementThink(struct client_entity_s *self,centity_t *owner); +static qboolean FXGlobeOfOuchinessAuraThink(struct client_entity_s *self,centity_t *owner); +static qboolean FXGlobeOfOuchinessGlowballSparkThink(struct client_entity_s *self,centity_t *owner); +static qboolean FXGlobeOfOuchinessGlowballThink(struct client_entity_s *self,centity_t *owner); +static qboolean FXGlobeOfOuchinessGlowballSpawnerThink(struct client_entity_s *self,centity_t *owner); +static qboolean FXGlobeOfOuchinessSmokePuffThink(struct client_entity_s *self,centity_t *owner); + +// ************************************************************************************************ +// FXInsectStaffTrailThink +// ************************************************************************************************ + +static qboolean FXInsectStaffTrailThink(struct client_entity_s *self,centity_t *owner) +{ + vec3_t TrailStart,Trail; + float TrailLength,DeltaTrailLength; + vec3_t Right,Up; + int NoOfIntervals; + float Theta,DeltaTheta; + client_entity_t *TrailEnt; + + VectorCopy(owner->origin,TrailStart); + VectorSubtract(owner->origin, self->origin, Trail); + + self->r.scale = flrand(0.8, 1.3); + if((TrailLength=VectorNormalize(Trail))>0.05) + { + PerpendicularVector(Right,Trail); + CrossProduct(Trail,Right,Up); + + DeltaTrailLength = FIST_DELTA_FORWARD; + VectorScale(Trail, FIST_DELTA_FORWARD, Trail); + + NoOfIntervals=(int)(TrailLength/DeltaTrailLength); + + if(NoOfIntervals > 40) + return(false); + + Theta=fxi.cl->time*FIST_DELTA_THETA; + DeltaTheta=(fxi.cls->frametime*FIST_DELTA_THETA)/NoOfIntervals; + + while(TrailLength>0.0) + { + + TrailEnt=ClientEntity_new(FX_I_EFFECTS, + self->flags&~(CEF_OWNERS_ORIGIN|CEF_NO_DRAW), + TrailStart, + NULL, + 1000); + + TrailEnt->r.model = ins_models; + VectorMA(TrailStart,FIST_SPIRAL_RAD*cos(Theta),Right,TrailEnt->r.origin); + VectorMA(TrailStart,FIST_SPIRAL_RAD*sin(Theta),Up,TrailEnt->r.origin); + + TrailEnt->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD; + + VectorRandomCopy(self->velocity, TrailEnt->velocity, flrand(0, 4)); + + TrailEnt->r.scale = FIST_SCALE+flrand(0.0, 0.05); + TrailEnt->d_alpha = flrand(-1.75, -2); + TrailEnt->d_scale = flrand(-0.75, -1.0); + TrailEnt->radius=20.0; + + AddEffect(NULL,TrailEnt); + + TrailLength-=DeltaTrailLength; + + Theta+=DeltaTheta; + + VectorAdd(TrailStart,Trail,TrailStart); + } + } + + VectorCopy(owner->origin, self->origin); + VectorCopy(TrailStart, self->r.origin); + return true; +} + +// ************************************************************************************************ +// FXInsectStaff +// ************************************************************************************************ + +void FXInsectStaff(centity_t *owner,int type,int flags,vec3_t origin) +{ + client_entity_t *Trail; + paletteRGBA_t LightColor={255,64,32,255}; + + Trail=ClientEntity_new(type,flags,origin,NULL,17); + + Trail->r.model = ins_models; + Trail->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD; + Trail->r.scale = flrand(0.8, 1.3); + Trail->d_alpha = 0.0f; + Trail->d_scale = 0.0f; + Trail->r.color.c = 0xffffffff; + Trail->radius = 20.0; + + Trail->Update=FXInsectStaffTrailThink; + + if(r_detail->value > DETAIL_NORMAL) + Trail->dlight=CE_DLight_new(LightColor,150.0f,0.0f); + + AddEffect(owner,Trail); +} + +// ************************************************************************************************ +// FXInsectStaffExplode +// ************************************************************************************************ + +void FXInsectStaffExplode(centity_t *owner,int type,int flags,vec3_t origin, vec3_t Dir) +{ + client_entity_t *SmokePuff; + int I; + paletteRGBA_t LightColor={255,64,32,255}; + + if(flags & CEF_FLAG6) + FXClientScorchmark(origin, Dir); + + VectorScale(Dir,32.0,Dir); + + I = GetScaledCount(irand(8,12), 0.8); + + while(I--) + { + if (!I) + SmokePuff=ClientEntity_new(type,flags,origin,NULL,500); + else + SmokePuff=ClientEntity_new(type,flags,origin,NULL,1000); + + SmokePuff->r.model = ins_models; + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + SmokePuff->r.frame=0; + + VectorRandomCopy(Dir, SmokePuff->velocity, flrand(16.0, 128.0)); + + SmokePuff->acceleration[2] = flrand(-40, -60); + + SmokePuff->d_scale=flrand(-1.75,-2); + SmokePuff->d_alpha=-0.2; + + SmokePuff->radius=20.0; + + if(!I) + { + SmokePuff->dlight=CE_DLight_new(LightColor,150.0f,0.0f); + VectorClear(SmokePuff->velocity); + } + + SmokePuff->Scale=flrand(0.25, 0.35); + + AddEffect(NULL,SmokePuff); + } +} + + +// **************************************************************************** +// FXGlobeOfOuchinessGlobeThink - +// **************************************************************************** + +static qboolean FXGlobeOfOuchinessGlobeThink(struct client_entity_s *self,centity_t *owner) +{ + self->r.scale = flrand(0.35, 0.50); + + return(true); +} + +// **************************************************************************** +// FXGlobeOfOuchinessAuraThink - +// **************************************************************************** + +static qboolean FXGlobeOfOuchinessAuraThink(struct client_entity_s *self,centity_t *owner) +{ + vec3_t TrailStart,Trail; + float TrailLength,DeltaTrailLength; + vec3_t Right,Up; + client_entity_t *TrailEnt; + int i; + + // + + VectorCopy(owner->origin,TrailStart); + VectorSubtract(owner->lerp_origin,owner->origin,Trail); + + if((TrailLength=VectorNormalize(Trail))<0.001) + { + TrailLength+=2.0; + } + + // + + PerpendicularVector(Right,Trail); + CrossProduct(Trail,Right,Up); + + DeltaTrailLength=FX_GLOBE_FLY_SPEED; + VectorScale(Trail,FX_GLOBE_FLY_SPEED,Trail); + + i=0; + while(TrailLength>0.0) + { + // + i++; + if (i>40) + return true; + TrailEnt=ClientEntity_new(FX_I_EFFECTS, + self->flags&~(CEF_OWNERS_ORIGIN|CEF_NO_DRAW), + TrailStart, + NULL, + 500); + + TrailEnt->r.model = globe_models; + TrailEnt->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + if (r_detail->value < DETAIL_NORMAL) + TrailEnt->Scale=FX_SOFT_GLOBE_AURA_SCALE+flrand(0.0, 0.1); + else + TrailEnt->Scale=FX_GLOBE_AURA_SCALE+flrand(0.0, 0.1); + TrailEnt->color.r=irand(128, 180); + TrailEnt->color.g=irand(128, 180); + TrailEnt->color.b=irand(64, 80); + TrailEnt->alpha = 0.7; + TrailEnt->d_alpha = -1.0; + if (r_detail->value < DETAIL_NORMAL) + TrailEnt->d_scale = -1.0; + else + TrailEnt->d_scale = -0.5; + + TrailEnt->radius=70.0; + + AddEffect(NULL,TrailEnt); + + TrailLength-=DeltaTrailLength; + + VectorAdd(TrailStart,Trail,TrailStart); + } + + return(true); +} + +// **************************************************************************** +// FXGlobeOfOuchiness - +// **************************************************************************** + +void FXInsectGlobe(centity_t *owner,int type,int flags,vec3_t origin, short CasterEntnum) +{ + client_entity_t *GlobeThinker, + *AuraThinker; + paletteRGBA_t LightColor={0,0,255,255}; + int caster_update; + + // Create a fiery blue aura around the globe. + + if (r_detail->value < DETAIL_NORMAL) + caster_update = 125; + else + caster_update = 100; + + AuraThinker=ClientEntity_new(type,flags,origin,NULL,caster_update); + + AuraThinker->flags|=CEF_NO_DRAW; + AuraThinker->dlight=CE_DLight_new(LightColor,150.0,0.0); + AuraThinker->Update=FXGlobeOfOuchinessAuraThink; + AuraThinker->extra=owner;//(void *)(&fxi.server_entities[CasterEntnum]);// The caster's centity_t. + + AddEffect(owner,AuraThinker); + + FXGlobeOfOuchinessAuraThink(AuraThinker,owner); + + // Create the globe of ouchiness itself. + + GlobeThinker = ClientEntity_new(type, flags, origin, NULL, 100); + + GlobeThinker->r.model = globe_models + 1; + GlobeThinker->r.flags |= RF_TRANSLUCENT|RF_TRANS_ADD; + GlobeThinker->r.scale = flrand(0.15, 0.20); + + GlobeThinker->r.color.r=irand(128, 180); + GlobeThinker->r.color.g=irand(128, 180); + GlobeThinker->r.color.b=irand(180, 255); + + GlobeThinker->radius = 70.0; + GlobeThinker->Update = FXGlobeOfOuchinessGlobeThink; + GlobeThinker->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner, GlobeThinker); +} + +// **************************************************************************** +// FXGlobeOfOuchinessGlowballThink - +// **************************************************************************** + +static qboolean FXGlobeOfOuchinessGlowballThink(struct client_entity_s *self,centity_t *owner) +{ + client_entity_t *Spark; + + if((owner->current.effects&EF_MARCUS_FLAG1)) + self->color.r++; + + if(self->color.r>3) + { + // Create a trailing spark. + + Spark=ClientEntity_new(FX_I_EFFECTS, + self->flags&~(CEF_OWNERS_ORIGIN), + self->r.origin, + NULL, + 500); + + Spark->r.model = globe_models + 2; + Spark->r.flags|=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Spark->r.scale = FIST_SCALE+flrand(0.0, 0.05); + Spark->d_alpha = flrand(-1.75, -2); + Spark->d_scale = flrand(-0.75, -1.0); + Spark->radius=20.0; + + AddEffect(NULL,Spark); + } + + // 'self->extra' refers to the globe's centity_t. + + if(self->color.r<16) + { + self->velocity[0]*=3.0; + self->velocity[0]+=6.0*(owner->origin[0]-self->r.origin[0]); + self->velocity[0]*=0.265; + + self->velocity[1]*=3.0; + self->velocity[1]+=6.0*(owner->origin[1]-self->r.origin[1]); + self->velocity[1]*=0.265; + + self->velocity[2]*=3.0; + self->velocity[2]+=6.0*(owner->origin[2]-self->r.origin[2]); + self->velocity[2]*=0.265; + + return(true); + } + else + { + return(false); + } +} + +// **************************************************************************** +// FXGlobeOfOuchinessGlowballSpawnerThink - +// **************************************************************************** + +static qboolean FXGlobeOfOuchinessGlowballSpawnerThink(struct client_entity_s *self,centity_t *owner) +{ + client_entity_t *Glowball; + vec3_t Forward,Right, + Forward2,Right2, + Temp; + matrix3_t RotationMatrix; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid((centity_t *)(self->extra))) + return true; + + // If the spell is still building, create some swirling blue Glowballs. + + if(owner->current.effects&EF_MARCUS_FLAG1) + { + // 'self->extra' refers to the caster's centity_t. + + Glowball=ClientEntity_new(FX_I_EFFECTS, + self->flags&~(CEF_NO_DRAW|CEF_OWNERS_ORIGIN), + ((centity_t *)(self->extra))->origin, + NULL, + 50); + + self->flags|=CEF_DONT_LINK; + + VectorCopy(((centity_t *)(self->extra))->current.angles,Temp); + VectorScale(Temp,180.0/M_PI,Temp); + AngleVectors(Temp,Forward,Right,NULL); + + VectorCopy(owner->current.angles,Temp); + VectorScale(Temp,180.0/M_PI,Temp); + AngleVectors(Temp,Forward2,Right2,NULL); + + // Make me spawn from my caster's left / right hands (alternating). + + Matrix3FromAngles(((centity_t *)(self->extra))->lerp_angles,RotationMatrix); + + if(!(self->color.g&1)) + { + Matrix3MultByVec3(RotationMatrix, + ((centity_t *)(self->extra))->referenceInfo->references[INSECT_STAFF].placement.origin, + Glowball->r.origin); + } + else + { + Matrix3MultByVec3(RotationMatrix, + ((centity_t *)(self->extra))->referenceInfo->references[INSECT_SWORD].placement.origin, + Glowball->r.origin); + } + + VectorAdd(((centity_t *)(self->extra))->origin,Glowball->r.origin,Glowball->r.origin); + + // Set my velocity and accelaration. + + Glowball->velocity[0]=Forward2[0]*175.0+flrand(-25.0, 25.0); + + if(self->color.g&1) + Glowball->velocity[0]=-Glowball->velocity[0]; + + Glowball->velocity[1]=Forward2[1]*175.0+flrand(-25.0, 25.0); + + if(!(self->color.g&1)) + Glowball->velocity[1]=-Glowball->velocity[1]; + + Glowball->velocity[2]=flrand(-200.0, 100.0); + + VectorClear(Glowball->acceleration); + + // Fill in the rest of my info. + Glowball->r.model = globe_models + 2; + + Glowball->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD; + Glowball->r.color.r= irand(128, 180); + Glowball->r.color.g= irand(128, 180); + Glowball->r.color.b= irand(180, 255); + Glowball->color.r=1; + Glowball->radius=20.0; + + Glowball->extra=(void *)owner; + Glowball->Update=FXGlobeOfOuchinessGlowballThink; + + AddEffect(owner,Glowball); + + FXGlobeOfOuchinessGlowballThink(Glowball,owner); + + self->color.g++; + } + + return(true); +} + +// **************************************************************************** +// FXGlobeOfOuchinessGlowballs - +// **************************************************************************** + +void FXInsectGlow(centity_t *owner,int type,int flags,vec3_t origin, short CasterEntnum) +{ + client_entity_t *GlowballSpawner; + int caster_update; + + // Create a spawner that will create the glowballs. + + if (r_detail->value < DETAIL_NORMAL) + caster_update = 250; + else + caster_update = 100; + + GlowballSpawner=ClientEntity_new(type,flags,origin,NULL,caster_update); + + GlowballSpawner->flags|=CEF_NO_DRAW; + GlowballSpawner->color.g=0; + GlowballSpawner->Update=FXGlobeOfOuchinessGlowballSpawnerThink; + GlowballSpawner->extra=(void *)(&fxi.server_entities[CasterEntnum]); +// GlowballSpawner->extra=(void *)owner; + + AddEffect(owner,GlowballSpawner); +} + +qboolean InsectFirstSeenInit(struct client_entity_s *self, centity_t *owner) +{ + self->refMask |= INSECT_MASK; + + EnableRefPoints(owner->referenceInfo, self->refMask); + + self->AddToView = NULL; + self->Update = KeepSelfAI; + return true; +} + +void FXInsectReadyRefs (centity_t *owner,int type,int flags,vec3_t origin) +{ + client_entity_t *self; + + flags |= CEF_NO_DRAW; + self = ClientEntity_new(type, flags, origin, NULL, 17); + + self->Update = NULL; + self->AddToView = InsectFirstSeenInit; + + AddEffect(owner, self); +} + +//HELLSTAFF + +// ************************************************************************************************ +// FXHellbolt +// ************************************************************************************************ + +static qboolean FXISpMslThink (struct client_entity_s *self, centity_t *owner) +{ + if(self->LifeTime < fxi.cl->time) + return (false); + + self->r.frame++; + if(self->r.frame>2) + self->r.frame = 0; + + return (true); +} + +void FXISpear(centity_t *owner, int type, int flags, vec3_t origin, vec3_t vel) +{ + client_entity_t *hellbolt; + paletteRGBA_t LightColor = {255, 128, 64, 255}; + + hellbolt = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 10000); + + hellbolt->r.model = spear_models; + hellbolt->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + hellbolt->r.scale = 1.0; + hellbolt->r.color = LightColor; + hellbolt->d_alpha = 0.0; + hellbolt->radius = 10.0F; + VectorCopy(vel, hellbolt->velocity); + hellbolt->AddToView = LinkedEntityUpdatePlacement; + + if(r_detail->value > DETAIL_NORMAL) + hellbolt->dlight = CE_DLight_new(LightColor, 150.0f, -300.0f); + + AddEffect(owner, hellbolt); +} + +qboolean FXISpear2Update(struct client_entity_s *self, centity_t *owner) +{ + paletteRGBA_t LightColor = {255, 128, 255, 255}; + client_particle_t *spark; + int i; + float dist; + vec3_t dir; + + self->r.color.a = irand(128, 136); + self->r.scale = flrand(0.1, 0.5); + + if(!VectorCompare(owner->lerp_origin, self->startpos2)) + VectorCopy(owner->lerp_origin, self->startpos2); + + VectorSubtract(owner->lerp_origin, self->startpos2, dir); + dist = VectorNormalize(dir); + + for(i = 0; i < 10; i++) + { + spark = ClientParticle_new(PART_16x16_SPARK_Y, self->r.color, 200); + spark->type |= PFL_ADDITIVE; + + spark->acceleration[2] = 0.5; + + spark->scale = flrand(5, 6); + spark->d_scale = flrand(-13, -20); + + spark->color.r = irand(240, 255); + spark->color.g = irand(240, 255); + spark->color.b = irand(240, 255); + + spark->color.a = irand(64, 196); + spark->d_alpha = -128; + + VectorAdd(self->startpos2, spark->origin, spark->origin); + VectorMA(spark->origin, dist/i, dir, spark->origin); + spark->origin[0] += flrand(-2, 2); + spark->origin[1] += flrand(-2, 2); + spark->origin[2] += flrand(-2, 2); + + AddParticleToList(self, spark); + } + + return (true); +} + +void FXISpear2(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *hellbolt; + paletteRGBA_t LightColor = {255, 128, 255, 255}; + + hellbolt = ClientEntity_new(type, CEF_OWNERS_ORIGIN | CEF_ABSOLUTE_PARTS, origin, NULL, 20); + + hellbolt->r.model = spear_models + 3; + hellbolt->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + hellbolt->r.color.c = 0xffffffff; + hellbolt->r.scale = flrand(0.2, 0.4); + hellbolt->d_alpha = 0.0; + hellbolt->radius = 10.0F; + hellbolt->AddToView = LinkedEntityUpdatePlacement; + VectorCopy(owner->current.origin, hellbolt->startpos2); + + if(r_detail->value > DETAIL_NORMAL) + hellbolt->dlight = CE_DLight_new(LightColor, 150.0f, -300.0f); + + hellbolt->Update = FXISpear2Update; + + AddEffect(owner, hellbolt); + +// + hellbolt = ClientEntity_new(type, CEF_OWNERS_ORIGIN, origin, NULL, 10000); + + hellbolt->r.model = spear_models + 2; + hellbolt->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + hellbolt->r.color.c = 0x33ffffff; + hellbolt->r.scale = flrand(1, 2); + hellbolt->d_alpha = 0.0; + hellbolt->radius = 10.0F; + hellbolt->AddToView = LinkedEntityUpdatePlacement; + + + AddEffect(owner, hellbolt); +} +// ************************************************************************************************ +// FXISpMslHit +// --------------------- +// ************************************************************************************************ + +void FXISpMslHit(centity_t *owner, int type, int flags, vec3_t origin, vec3_t Dir) +{ + client_entity_t *smokepuff; + int i; + paletteRGBA_t lightcolor = {255, 96, 48, 255}; + + if(flags & CEF_FLAG6) + { + FXClientScorchmark(origin, Dir); + } + Vec3ScaleAssign(32.0, Dir); + + for(i = 0; i < NUM_SPEAR_EXPLODES; i++) + { + smokepuff = ClientEntity_new(type, flags, origin, NULL, 500); + + smokepuff->r.model = spear_models + 1; + smokepuff->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + smokepuff->r.scale = flrand(0.2, 0.3); + smokepuff->r.color = lightcolor; + + VectorRandomCopy(Dir, smokepuff->velocity, 64); + VectorSet(smokepuff->acceleration, 0.0, 0.0, GetGravity() * 0.3); + + smokepuff->radius = 200.0; + smokepuff->d_scale = -0.5; + smokepuff->d_alpha = -2.0; + + if(!i) + { + fxi.S_StartSound(smokepuff->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/HellHit.wav"), 1, ATTN_NORM, 0); + smokepuff->dlight = CE_DLight_new(lightcolor, 150.0f, 0.0f); + VectorClear(smokepuff->velocity); + } + AddEffect(NULL,smokepuff); + } +} + +void FXISpMslHit2(centity_t *owner, int type, int flags, vec3_t origin, vec3_t Dir) +{ + client_entity_t *smokepuff; + int i; + + Vec3ScaleAssign(32.0, Dir); + + for(i = 0; i < NUM_SPEAR_EXPLODES; i++) + { + smokepuff = ClientEntity_new(type, flags, origin, NULL, 500); + + smokepuff->r.model = spear_models + 2; + smokepuff->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + smokepuff->r.scale = flrand(0.7, 1); + + VectorRandomCopy(Dir, smokepuff->velocity, 64); + VectorSet(smokepuff->acceleration, 0.0, 0.0, GetGravity() * 0.3); + + smokepuff->radius = 200.0; + smokepuff->d_scale = -0.7; + smokepuff->d_alpha = -2.0; + + if(!i) + { + fxi.S_StartSound(smokepuff->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/HellHit.wav"), 1, ATTN_NORM, 0); + VectorClear(smokepuff->velocity); + } + AddEffect(NULL,smokepuff); + } + + smokepuff = ClientEntity_new(type, CEF_OWNERS_ORIGIN, origin, NULL, 500); + + smokepuff->r.model = spear_models + 3; + smokepuff->r.frame = 1; + smokepuff->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + smokepuff->r.color.c = 0x77ffffff; + smokepuff->r.scale = flrand(0.3, 0.5); + smokepuff->d_scale = 2; + smokepuff->d_alpha = -2; + smokepuff->radius = 10.0F; + + AddEffect(NULL, smokepuff); +} +//Insect reference points +// INSECT_STAFF, +// INSECT_SWORD, +// INSECT_SPEAR, +// INSECT_RIGHTFOOT, +// INSECT_LEFTFOOT, +static qboolean FXStaffElementThink(struct client_entity_s *self,centity_t *owner) +{ + float Frac, + Multiplier; + int FrameNo; + + Frac=(fxi.cl->time-self->startTime)/100.0; + + if(self->AnimSpeed>0.0) + { + Frac*=self->AnimSpeed; + } + + if((FrameNo=floor(Frac))>=(self->NoOfAnimFrames-1)) + { + return(false); + } + else + { + Multiplier=1.0-Frac/(self->NoOfAnimFrames-1); + + self->r.color.r=self->color.r*Multiplier; + self->r.color.b=self->color.g*Multiplier; + self->r.color.g=self->color.b*Multiplier; + + self->r.frame=FrameNo+1; + + return(true); + } +} + +// ************************************************************************************************ +// FXStaffThink +// ----------------- +// ************************************************************************************************ + +static qboolean FXISwordTrailThink(struct client_entity_s *self,centity_t *owner) +{ + int I; + int NoOfIntervals; + client_entity_t *TrailEnt; + vec3_t diff, newpoint, last_org, current_org; + matrix3_t RotationMatrix; + float incr; + + if(self->LifeTime < fxi.cl->time) + return (false); + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return false; // Remove the effect in this case. + + self->updateTime = 17; // FIXME : With a next think time this effect does not look right + + I=self->NoOfAnimFrames; + + //extrapolate down length of sword from hand! + + Matrix3MultByVec3(RotationMatrix, + ((centity_t *)(self->extra))->referenceInfo->references[INSECT_SWORD].placement.origin, + current_org); + + Matrix3MultByVec3(RotationMatrix, + ((centity_t *)(self->extra))->referenceInfo->oldReferences[INSECT_SWORD].placement.origin, + last_org); + + // If this reference point hasn't changed since the last frame, return. + VectorSubtract( current_org, last_org, diff); + + if (Q_fabs(diff[0] + diff[1] + diff[2]) < .1) + return(true); + + NoOfIntervals=(int)(VectorLength(diff)*.5); + if(NoOfIntervals > 40) + return(false); + + incr = VectorNormalize(diff)/NoOfIntervals; + + Matrix3FromAngles(((centity_t *)(self->extra))->lerp_angles, RotationMatrix); + + while (NoOfIntervals >= 0) + { + VectorMA(last_org, incr, diff, newpoint); + TrailEnt=ClientEntity_new(FX_SPELLHANDS, self->flags & ~CEF_NO_DRAW, newpoint, 0, 100); + VectorCopy(newpoint, TrailEnt->origin); + TrailEnt->r.model = sword_models; + TrailEnt->alpha=.3; + TrailEnt->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + TrailEnt->r.frame=1; + TrailEnt->d_scale=-0.25; + TrailEnt->d_alpha=-0.1; + TrailEnt->color.c=0x50000018; + TrailEnt->r.scale=self->xscale*2.0; + TrailEnt->startTime=fxi.cl->frame.servertime-100; + TrailEnt->AnimSpeed=0.20; + TrailEnt->NoOfAnimFrames=2; + TrailEnt->Update=FXStaffElementThink; + TrailEnt->AddToView=OffsetLinkedEntityUpdatePlacement; + AddEffect(owner,TrailEnt); + + FXStaffElementThink(TrailEnt,owner); + + VectorCopy(newpoint, last_org); + NoOfIntervals--; + } + + return(true); +} + +// ************************************************************************************************ +// FXStaff +// ------------ +// ************************************************************************************************ + +// This effect spawns 70+ client fx which will cause problems + +void FXISwordTrail(centity_t *owner,int type,int flags,vec3_t origin) +{ + short Refpoints; + client_entity_t *trail; + int I; + + Refpoints=0; + + Refpoints = (1<Update = FXISwordTrailThink; + trail->flags |= CEF_NO_DRAW; + trail->NoOfAnimFrames = I; + + trail->color.c = 0x50285020; + trail->xscale = .175; + + trail->LifeTime = fxi.cl->time + 180; + trail->extra = (void *)owner; + + AddEffect(owner,trail); + } +} + +/*============================== + + Insect Effects Handler + + ==============================*/ + +void FXIEffects(centity_t *owner,int type,int flags, vec3_t origin) +{ + paletteRGBA_t LightColor={0,0,255,255}; + vec3_t vel; + byte fx_index; + + fxi.GetEffect(owner, flags, "bv", &fx_index, &vel);//fixme- make this 1 dir and 1 float + + switch (fx_index) + { + case FX_I_SWORD: + FXISwordTrail(owner, type, flags, origin); + break; + + case FX_I_SPEAR: + FXISpear(owner, type, flags, origin, vel); + break; + + case FX_I_SP_MSL_HIT: + FXISpMslHit(owner, type, flags, origin, vel); + break; + + case FX_I_GLOBE: + FXInsectGlobe(owner, type, flags, origin, (short)(vel[0])); + break; + + case FX_I_GLOW: + FXInsectGlow(owner, type, flags, origin, (short)(vel[0])); + break; + + case FX_I_STAFF: + FXInsectStaff(owner, type, flags, origin); + break; + + case FX_I_ST_MSL_HIT: + FXInsectStaffExplode(owner, type, flags, origin, vel); + break; + + case FX_I_RREFS: + FXInsectReadyRefs (owner, type, flags, origin); + break; + + case FX_I_SPEAR2: + FXISpear2(owner, type, flags, origin); + break; + + case FX_I_SP_MSL_HIT2: + FXISpMslHit2(owner, type, flags, origin, vel); + break; + + default: + break; + } +} + diff --git a/Toolkit/Programming/GameCode/client effects/fx_lensflare.c b/Toolkit/Programming/GameCode/client effects/fx_lensflare.c new file mode 100644 index 0000000..8d3bc10 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_lensflare.c @@ -0,0 +1,547 @@ +// +// fx_lensflare.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "Utilities.h" +#include "g_playstats.h" + +#define NUM_LENS_MODELS 7 + +static struct model_s *flare_models[NUM_LENS_MODELS]; + +void PreCacheFlare() +{ + int i; + char model[128]; + + flare_models[0] = fxi.RegisterModel("sprites/lens/blind1.sp2"); + for(i = 1; i < NUM_LENS_MODELS; i++) + { + sprintf(model, "sprites/lens/flare%d.sp2", i); + flare_models[i] = fxi.RegisterModel(model); + } +} + +// FIXME: These need to interpolate their movement so as to not do snap position changes + +// ************************************************************************************************ +// FXFlareThink +// ************************************************************************************************ + +static qboolean FXFlareThink(struct client_entity_s *self,centity_t *owner) +{ + float dot, near_clip, dist; + + vec3_t from, at, center, view_dir, light_dir, light, axis, dx, dy, tmp, t_axis, pos1, pos2; + + vec3_t mins = { 0, 0, 0}, + maxs = { 0, 0, 0}; + + trace_t trace; + + if ( ( self->LifeTime > 0 ) && ( self->LifeTime < fxi.cl->time ) ) + return false; + + //Determine Visibility + fxi.Trace( fxi.cl->refdef.vieworg, + mins, + maxs, + self->direction, + (CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER), + CEF_CLIP_TO_WORLD, + &trace); + + if (trace.fraction < 1 && !(trace.surface->flags & SURF_SKY)) + { + self->flags |= CEF_NO_DRAW; + return true; + } + + if (self->up[1]) + { + if (self->flags & CEF_NO_DRAW) + self->flags &= ~CEF_NO_DRAW; + + AngleVectors (fxi.cl->refdef.viewangles, pos1, NULL, NULL); + VectorSubtract (self->direction, fxi.cl->refdef.vieworg, pos2); + VectorNormalize (pos2); + + dot = DotProduct (pos1, pos2); + + if (dot < 0.75) + { + self->flags |= CEF_NO_DRAW; + return true; + } + + self->alpha = self->up[2] - ((1 - dot) * 2); + + if (self->alpha > 1) + self->alpha = 1; + + if (self->alpha < 0.1) + self->alpha = 0.1; + + VectorMA(fxi.cl->refdef.vieworg, 16, pos2, pos1); + VectorCopy(pos1, self->r.origin); + return true; + } + + AngleVectors (fxi.cl->refdef.viewangles, pos1, NULL, NULL); + VectorSubtract (self->direction, fxi.cl->refdef.vieworg, pos2); + VectorNormalize (pos2); + + dot = DotProduct (pos1, pos2); + + if (dot < 0.75) + { + self->flags |= CEF_NO_DRAW; + return true; + } + + if (self->flags & CEF_NO_DRAW) + self->flags &= ~CEF_NO_DRAW; + + VectorCopy(self->direction, from); + VectorCopy(fxi.cl->refdef.vieworg, at); + + VectorSubtract(from, at, view_dir); + dist = VectorNormalize(view_dir); + + VectorMA(at, 250, view_dir, from); + + VectorSubtract(from, at, view_dir); + dist = VectorNormalize(view_dir); + + AngleVectors(fxi.cl->refdef.viewangles, light, NULL, NULL); + + VectorScale(light, dist, light); + VectorAdd(from, light, light); + + near_clip = 1.01f; + + VectorScale(view_dir, near_clip, view_dir); + VectorAdd(from, view_dir, center); + + VectorSubtract(light, from, light_dir); + VectorNormalize(light_dir); + + dot = (DotProduct(view_dir, light_dir)); + VectorScale(light_dir, near_clip, tmp); + VectorScale(tmp, 1.0f / dot, tmp); + VectorAdd(tmp, from, light); + + VectorSubtract(light, center, axis); + + VectorCopy(axis, dx); + VectorNormalize(dx); + CrossProduct(dx, view_dir, dy); + + VectorScale(axis, self->up[0]*1000, t_axis); + VectorAdd(center, t_axis, self->r.origin); + return (true); +} + +// ************************************************************************************************ +// FXFlareThinkAttached +// ************************************************************************************************ + +static qboolean FXFlareThinkAttached(struct client_entity_s *self,centity_t *owner) +{ + float dot, near_clip, dist; + float lerp, oldtime, newtime; + + vec3_t from, at, center, view_dir, light_dir, light, axis, dx, dy, tmp, t_axis, pos1, pos2, vec_diff; + + vec3_t mins = { 0, 0, 0}, + maxs = { 0, 0, 0}; + + trace_t trace; + centity_t *fake_owner = (centity_t *) self->extra; + + + if ( ( self->LifeTime > 0 ) && ( self->LifeTime < fxi.cl->time ) ) + return (false); + + if(fake_owner->current.effects & EF_DISABLE_EXTRA_FX) + return (false); + +//Interpolate- why am I only getting 2 frames of interpolation? + oldtime = self->lastThinkTime/100.0; + newtime = fxi.cl->time/100.0; + + if ((int)oldtime < (int)newtime) + { + VectorCopy(self->endpos2, self->startpos2); + VectorCopy(fake_owner->current.origin, self->endpos2);//where I need to be + self->lastThinkTime = fxi.cl->time; + } + + lerp = newtime - (int)newtime; + + VectorSubtract(self->endpos2, self->startpos2, vec_diff);//diff between last updated spot and where to be + VectorMA(self->startpos2, lerp, vec_diff, self->direction); + + //Determine Visibility + fxi.Trace( fxi.cl->refdef.vieworg, + mins, + maxs, + self->direction, + (CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER), + CEF_CLIP_TO_WORLD, + &trace); + + if (trace.fraction < 1 && !(trace.surface->flags & SURF_SKY)) + { + self->flags |= CEF_NO_DRAW; + return true; + } + + if (self->up[1]) + { + if (self->flags & CEF_NO_DRAW) + self->flags &= ~CEF_NO_DRAW; + + AngleVectors (fxi.cl->refdef.viewangles, pos1, NULL, NULL); + VectorSubtract (self->direction, fxi.cl->refdef.vieworg, pos2); + VectorNormalize (pos2); + + dot = DotProduct (pos1, pos2); + + if (dot < 0.75) + { + self->flags |= CEF_NO_DRAW; + return true; + } + + self->alpha = self->up[2] - ((1 - dot) * 2); + + if (self->alpha > 1) + self->alpha = 1; + + if (self->alpha < 0.1) + self->alpha = 0.1; + + VectorMA(fxi.cl->refdef.vieworg, 16, pos2, pos1); + VectorCopy(pos1, self->r.origin); + return true; + } + + AngleVectors (fxi.cl->refdef.viewangles, pos1, NULL, NULL); + VectorSubtract (self->direction, fxi.cl->refdef.vieworg, pos2); + VectorNormalize (pos2); + + dot = DotProduct (pos1, pos2); + + if (dot < 0.75) + { + self->flags |= CEF_NO_DRAW; + return true; + } + + if (self->flags & CEF_NO_DRAW) + self->flags &= ~CEF_NO_DRAW; + + VectorCopy(self->direction, from); + VectorCopy(fxi.cl->refdef.vieworg, at); + + VectorSubtract(from, at, view_dir); + dist = VectorNormalize(view_dir); + + VectorMA(at, 250, view_dir, from); + + VectorSubtract(from, at, view_dir); + dist = VectorNormalize(view_dir); + + AngleVectors(fxi.cl->refdef.viewangles, light, NULL, NULL); + + VectorScale(light, dist, light); + VectorAdd(from, light, light); + + near_clip = 1.01f; + + VectorScale(view_dir, near_clip, view_dir); + VectorAdd(from, view_dir, center); + + VectorSubtract(light, from, light_dir); + VectorNormalize(light_dir); + + dot = (DotProduct(view_dir, light_dir)); + VectorScale(light_dir, near_clip, tmp); + VectorScale(tmp, 1.0f / dot, tmp); + VectorAdd(tmp, from, light); + + VectorSubtract(light, center, axis); + + VectorCopy(axis, dx); + VectorNormalize(dx); + CrossProduct(dx, view_dir, dy); + + VectorScale(axis, self->up[0]*1000, t_axis); + VectorAdd(center, t_axis, self->r.origin); + + return true; +} + +// ************************************************************************************************ +// FXLensFlare +// ************************************************************************************************ + +float flare_loc[] = { 1.0, 0.7, 0.3, 0.1, 0.0, -0.2, + 1.0, 0.8, 0.6, 0.2, 0.0, -0.4 }; + +float flare_scale[] = {2, 1.75, 1.5, 1.25, 1.5, 1.75, 2, 2 }; + +void FXLensFlare(centity_t *owner,int Type,int Flags,vec3_t Origin) +{ + int Count,I; + client_entity_t *Explosion; + int useOther, lifeTime; + float alpha; + paletteRGBA_t tint; + + Count = 7; + + fxi.GetEffect(owner, Flags, "ibbbf", &lifeTime, &tint.r, &tint.g, &tint.b, &alpha); + + // no lens flares in low detail + if(r_detail->value <= DETAIL_NORMAL) + return; + + if (Flags & CEF_FLAG6) + useOther = 6; + else + useOther = 0; + + for(I=0;Iup, 0.0f, 0.0f, 0.0f); + + Explosion->r.color.r = tint.r; + Explosion->r.color.g = tint.g; + Explosion->r.color.b = tint.b; + Explosion->alpha=alpha; + + switch (I) + { + case 0: + Explosion->r.model = flare_models + 1; + break; + case 1: + Explosion->r.model = flare_models + 2; + break; + case 2: + Explosion->r.model = flare_models + 4; + break; + case 3: + Explosion->r.model = flare_models + 3; + break; + case 4: + Explosion->r.model = flare_models + 6; + break; + case 5: + Explosion->r.model = flare_models + 3; + break; + case 6: + Explosion->r.model = flare_models; + Explosion->up[1] = 1; + Explosion->up[2] = alpha; + if (Flags & CEF_FLAG8) + { + Explosion->r.color.r=255; + Explosion->r.color.g=255; + Explosion->r.color.b=255; + } + break; + } + + if (lifeTime > 0) + Explosion->LifeTime = (lifeTime*1000)+fxi.cl->time; + + Explosion->r.flags|=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA|RF_NODEPTHTEST; + Explosion->Scale=flare_scale[I]; + Explosion->r.frame=0; + Explosion->d_scale=0.0; + Explosion->d_alpha=0.0; + Explosion->NoOfAnimFrames=1; + Explosion->Update=FXFlareThink; + VectorCopy(Origin, Explosion->direction); + + if (Flags & CEF_FLAG7) + { + Explosion->direction[0] *= 4; + Explosion->direction[1] *= 4; + Explosion->direction[2] *= 4; + } + + VectorCopy(Origin, Explosion->origin); + Explosion->up[0] = flare_loc[I + useOther]; + + if (owner) + { +/* client_entity_t *nullfx; + nullfx=ClientEntity_new(FX_LENSFLARE, + CEF_NO_DRAW|CEF_OWNERS_ORIGIN, + Origin, + NULL, + 1000000); + nullfx->flags |= CEF_NO_DRAW; + + AddEffect(owner, nullfx);*/ + + AddEffect(owner,Explosion); +// Explosion->AddToView = LinkedEntityUpdatePlacement; + + Explosion->extra = (centity_t *) owner; + Explosion->Update=FXFlareThinkAttached; + Explosion->updateTime = 17; + FXFlareThinkAttached(Explosion,owner); + + VectorCopy(Explosion->direction, Explosion->startpos2); + VectorCopy(Explosion->direction, Explosion->endpos2); + Explosion->lastThinkTime = fxi.cl->time; + } + else + { + AddEffect(NULL,Explosion); + FXFlareThink(Explosion,NULL); + } + } +} + + +void FXClientLensFlare(centity_t *owner,int Type,int Flags,vec3_t Origin, int lifeTime, paletteRGBA_t *tint) +{ + int Count,I; + client_entity_t *Explosion; + int useOther; + + Count = 7; + + // no lens flares in low detail + if(r_detail->value <= DETAIL_NORMAL) + return; + + if (Flags & CEF_FLAG6) + useOther = 6; + else + useOther = 0; + + for(I=0;Iup, 0.0f, 0.0f, 0.0f); + + Explosion->r.color.r = tint->r; + Explosion->r.color.g = tint->g; + Explosion->r.color.b = tint->b; + Explosion->alpha = (float)(tint->a)/255.0; + + switch (I) + { + case 0: + Explosion->r.model = flare_models + 1; + break; + case 1: + Explosion->r.model = flare_models + 2; + break; + case 2: + Explosion->r.model = flare_models + 4; + break; + case 3: + Explosion->r.model = flare_models + 3; + break; + case 4: + Explosion->r.model = flare_models + 6; + break; + case 5: + Explosion->r.model = flare_models + 3; + break; + case 6: + Explosion->r.model = flare_models; + Explosion->up[1] = 1; + Explosion->up[2] = Explosion->alpha; + if (Flags & CEF_FLAG8) + { + Explosion->r.color.r=255; + Explosion->r.color.g=255; + Explosion->r.color.b=255; + } + break; + } + + if (lifeTime > 0) + Explosion->LifeTime = (lifeTime*1000)+fxi.cl->time; + + Explosion->r.flags|=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA|RF_NODEPTHTEST; + Explosion->Scale=flare_scale[I]; + Explosion->r.frame=0; + Explosion->d_scale=0.0; + Explosion->d_alpha=0.0; + Explosion->NoOfAnimFrames=1; + Explosion->Update=FXFlareThink; + VectorCopy(Origin, Explosion->direction); + + if (Flags & CEF_FLAG7) + { + Explosion->direction[0] *= 4; + Explosion->direction[1] *= 4; + Explosion->direction[2] *= 4; + } + + VectorCopy(Origin, Explosion->origin); + Explosion->up[0] = flare_loc[I + useOther]; + + if (owner) + { +/* client_entity_t *nullfx; + nullfx=ClientEntity_new(FX_LENSFLARE, + CEF_NO_DRAW|CEF_OWNERS_ORIGIN, + Origin, + NULL, + 1000000); + nullfx->flags |= CEF_NO_DRAW; + + AddEffect(owner, nullfx);*/ + + AddEffect(owner,Explosion); +// Explosion->AddToView = LinkedEntityUpdatePlacement; + + Explosion->extra = (centity_t *) owner; + Explosion->Update=FXFlareThinkAttached; + Explosion->updateTime = 17; + FXFlareThinkAttached(Explosion,owner); + + VectorCopy(Explosion->direction, Explosion->startpos2); + VectorCopy(Explosion->direction, Explosion->endpos2); + Explosion->lastThinkTime = fxi.cl->time; + } + else + { + AddEffect(NULL,Explosion); + FXFlareThink(Explosion,NULL); + } + } +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_lightning.c b/Toolkit/Programming/GameCode/client effects/fx_lightning.c new file mode 100644 index 0000000..5a9ace8 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_lightning.c @@ -0,0 +1,417 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "angles.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "motion.h" +#include "Reference.h" +#include "ce_Dlight.h" +#include "q_Sprite.h" +#include "g_playstats.h" + +#define LIGHTNING_WIDTH 6.0 +#define LIGHTNING_WIDTH_MULT 1.4 +#define LIGHTNING_POWER_WIDTH_MULT 2.0 +#define LIGHTNING_JOINT_SCALE (1.0/12.0) + +#define LIGHTNING_TYPE_BLUE 0 +#define LIGHTNING_TYPE_RED 1 +#define LIGHTNING_TYPE_GREEN 2 +#define LIGHTNING_JOINT_OFFSET 3 + +#define MIN_LIGHTNING_PARTS 5 +#define MAX_LIGHTNING_SEGMENT 64.0 + +#define LIGHTNING_INTERVAL 100 +#define NUM_LIGHTNING_RINGBITS 12 +#define LIGHTNING_RING_VEL 320 +#define LIGHTNING_RING_UPVEL 32 + +#define NUM_LIGHTNING_MODELS 7 +static struct model_s *lightning_models[NUM_LIGHTNING_MODELS]; + +void PreCacheLightning() +{ + lightning_models[LIGHTNING_TYPE_BLUE] = fxi.RegisterModel("sprites/fx/lightning.sp2"); + lightning_models[LIGHTNING_TYPE_RED] = fxi.RegisterModel("sprites/fx/rlightning.sp2"); + lightning_models[LIGHTNING_TYPE_GREEN] = fxi.RegisterModel("sprites/fx/plightning.sp2"); + lightning_models[LIGHTNING_TYPE_BLUE + LIGHTNING_JOINT_OFFSET] = fxi.RegisterModel("sprites/spells/spark_blue.sp2"); + lightning_models[LIGHTNING_TYPE_RED + LIGHTNING_JOINT_OFFSET] = fxi.RegisterModel("sprites/spells/spark_red.sp2"); + lightning_models[LIGHTNING_TYPE_GREEN + LIGHTNING_JOINT_OFFSET] = fxi.RegisterModel("sprites/spells/spark_green.sp2"); + lightning_models[6] = fxi.RegisterModel("sprites/fx/halo.sp2"); +} + +// -------------------------------------------------------------- + +client_entity_t *MakeLightningPiece(int type, float width, vec3_t start, vec3_t end, float radius) +{ + client_entity_t *lightning; + + lightning = ClientEntity_new(FX_LIGHTNING, CEF_DONT_LINK, start, NULL, 250); + lightning->r.model = lightning_models + type; + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->r.scale = width; + lightning->radius = radius; + lightning->alpha = 0.95; + lightning->d_alpha = -4.0; + VectorCopy(start, lightning->r.startpos); + VectorCopy(end, lightning->r.endpos); + lightning->r.spriteType = SPRITE_LINE; + AddEffect(NULL, lightning); + + lightning = ClientEntity_new(FX_LIGHTNING, CEF_DONT_LINK, start, NULL, 400); + lightning->r.model = lightning_models + type; + lightning->r.frame = 1; + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->r.scale = width * LIGHTNING_WIDTH_MULT; + lightning->radius = radius; + lightning->alpha = 0.5; + lightning->d_alpha = -1.250; + VectorCopy(start, lightning->r.startpos); + VectorCopy(end, lightning->r.endpos); + lightning->r.spriteType = SPRITE_LINE; + AddEffect(NULL, lightning); + + // Add a little ball at the joint (end) + + lightning = ClientEntity_new(FX_LIGHTNING, CEF_DONT_LINK, start, NULL, 250); + lightning->r.model = lightning_models + type + LIGHTNING_JOINT_OFFSET; + lightning->r.frame = 0; + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->r.scale = width * LIGHTNING_JOINT_SCALE; + lightning->radius = radius; + lightning->alpha = 0.95; + lightning->d_alpha = -2.0; + lightning->d_scale = -2.0; + VectorCopy(start, lightning->r.startpos); + VectorCopy(end, lightning->r.endpos); + AddEffect(NULL, lightning); + + return(lightning); +} + +// Occasional lightning bolt strikes inside +void DoLightning(vec3_t groundpos, vec3_t airpos) +{ + vec3_t curpos, lastpos, top, bottom, refpoint, diffpos, rand; + float scale; + int i; + + VectorSet(top, flrand(-RED_RAIN_RADIUS, RED_RAIN_RADIUS), flrand(-RED_RAIN_RADIUS, RED_RAIN_RADIUS), 0); + VectorAdd(airpos, top, top); + VectorSet(bottom, flrand(-RED_RAIN_RADIUS, RED_RAIN_RADIUS), flrand(-RED_RAIN_RADIUS, RED_RAIN_RADIUS), 0); + VectorAdd(groundpos, bottom, bottom); + + VectorSubtract(top, bottom, diffpos); + VectorScale(diffpos, 0.2, diffpos); + scale = (airpos[2] - groundpos[2]) / 10.0; + + VectorCopy(bottom, lastpos); + VectorCopy(bottom, refpoint); + for (i=0; i<5; i++) + { + VectorAdd(refpoint, diffpos, refpoint); + VectorSet(rand, flrand(-scale, scale), flrand(-scale, scale), flrand(-scale, scale)); + VectorAdd(refpoint, rand, curpos); + MakeLightningPiece(LIGHTNING_TYPE_RED, LIGHTNING_WIDTH, curpos, lastpos, scale); + VectorCopy(curpos, lastpos); + } +} + + +// Directed lightning bolt +void LightningBolt(int model, float width, vec3_t startpos, vec3_t endpos) +{ + vec3_t curpos, lastpos, refpoint, diffpos, rand; + vec3_t fwd, right, up; + float segmult, length, variance; + int i, segments; + + VectorSubtract(endpos, startpos, diffpos); + length = VectorLength(diffpos); + if (length < MIN_LIGHTNING_PARTS*MAX_LIGHTNING_SEGMENT) + { + segments = MIN_LIGHTNING_PARTS; + segmult = 1.0/(float)MIN_LIGHTNING_PARTS; + } + else + { + segments = (int)(length / (float)MAX_LIGHTNING_SEGMENT); + segmult = 1.0/(float)segments; + } + VectorNormalize2(diffpos, fwd); + PerpendicularVector(up, fwd); + CrossProduct(up, fwd, right); + + VectorScale(diffpos, segmult, diffpos); + variance = 0.4 * length*segmult; + + VectorCopy(startpos, lastpos); + VectorCopy(startpos, refpoint); + for (i=0; itime - thinker->lastThinkTime < thinker->LifeTime) + { + LightningBolt(thinker->SpawnInfo, thinker->xscale, thinker->r.startpos, thinker->r.endpos); + return true; + } + else + { + return false; + } +} + + +// This is from creating the effect FX_LIGHTNING +void FXLightning(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + vec3_t target, diffpos; + byte width, duration; + client_entity_t *lightning; + + fxi.GetEffect(Owner, Flags, "vbb", target, &width, &duration); + + if (duration > 1) // duration is in 1/10 of a second + { // Create a client effect to zap over time. + lightning = ClientEntity_new(FX_LIGHTNING, Flags | CEF_NO_DRAW, Origin, NULL, LIGHTNING_INTERVAL); + VectorSubtract(target, Origin, diffpos); + lightning->radius = VectorLength(diffpos)*0.5; + VectorCopy(Origin, lightning->r.startpos); + VectorCopy(target, lightning->r.endpos); + lightning->lastThinkTime = fxi.cl->time; + lightning->LifeTime = ((int)duration)*100+250; + lightning->Update = FXLightningThink; + lightning->xscale = (float)width; + if (Flags & CEF_FLAG6) + lightning->SpawnInfo = LIGHTNING_TYPE_RED; + else + lightning->SpawnInfo = LIGHTNING_TYPE_BLUE; + AddEffect(NULL, lightning); + } + + // If flagged, do red lightning. + if (Flags & CEF_FLAG6) + LightningBolt(LIGHTNING_TYPE_RED, (float)width, Origin, target); + else if (Flags & CEF_FLAG7) + LightningBolt(LIGHTNING_TYPE_GREEN, (float)width, Origin, target); // powered up rain lightning + else + LightningBolt(LIGHTNING_TYPE_BLUE, (float)width, Origin, target); // Normal, blue lightning + +} + + +// This is from creating the effect FX_POWER_LIGHTNING +void FXPowerLightning(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + vec3_t target, diffpos; + byte width; + client_entity_t *lightning; + client_particle_t *spark; + int i; + float length; + float curang, degreeinc; + vec3_t lastvel, upvel; + + fxi.GetEffect(Owner, Flags, "vb", target, &width); + + VectorSubtract(target, Origin, diffpos); + length = VectorLength(diffpos); + + // Big ol' monster zapper + lightning = ClientEntity_new(FX_POWER_LIGHTNING, CEF_AUTO_ORIGIN, Origin, NULL, 750); + lightning->r.model = lightning_models + LIGHTNING_TYPE_GREEN; + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->r.scale = width; + lightning->d_scale = -0.5*width; + lightning->radius = length; + lightning->alpha = 0.95; + lightning->d_alpha = -1.5; + VectorCopy(Origin, lightning->r.startpos); + VectorCopy(target, lightning->r.endpos); + lightning->r.spriteType = SPRITE_LINE; + AddEffect(NULL, lightning); + + // Halo around the lightning + lightning = ClientEntity_new(FX_POWER_LIGHTNING, CEF_AUTO_ORIGIN, Origin, NULL, 1000); + lightning->r.model = lightning_models + LIGHTNING_TYPE_GREEN; + lightning->r.frame = 1; + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->r.scale = width * LIGHTNING_POWER_WIDTH_MULT; + lightning->d_scale = -0.5*width; + lightning->radius = length; + lightning->alpha = 0.5; + lightning->d_alpha = -0.5; + VectorCopy(Origin, lightning->r.startpos); + VectorCopy(target, lightning->r.endpos); + lightning->r.spriteType = SPRITE_LINE; + AddEffect(NULL, lightning); + + // Big ol' flash at source to cover up the flatness of the line's end. + lightning = ClientEntity_new(FX_POWER_LIGHTNING, CEF_ADDITIVE_PARTS, Origin, NULL, 750); + lightning->r.model = lightning_models + 6; // The bright halo model + lightning->r.frame = 1; + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->r.scale = 0.75; + lightning->d_scale = 2.0; + lightning->radius = 128.0; + lightning->alpha = 0.95; + lightning->d_alpha = -1.333; + lightning->color.c = 0xffffffff; + AddEffect(NULL, lightning); + + // Now add a bunch of sparks to the source too to add interest. + for(i=0; i<8; i++) + { // Half green, half yellow particles + if (i&0x01) + spark = ClientParticle_new(PART_16x16_SPARK_Y, lightning->color, 1000); + else + spark = ClientParticle_new(PART_16x16_SPARK_G, lightning->color, 1000); + VectorSet(spark->velocity, flrand(-80,80), flrand(-80,80), flrand(-80,80)); + VectorScale(spark->velocity, -1.0, spark->acceleration); + spark->scale = flrand(20.0, 32.0); + spark->d_scale = -spark->scale; + spark->d_alpha = flrand(-384.0, -256); + AddParticleToList(lightning, spark); + } + + lightning = ClientEntity_new(FX_POWER_LIGHTNING, CEF_ADDITIVE_PARTS, target, NULL, 1000); + lightning->r.model = lightning_models + 6; // The bright halo model + lightning->r.origin[2] += 8.0; + lightning->r.frame = 1; + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->r.scale = 2.0; + lightning->d_scale = -2.0; + lightning->radius = 128.0; + lightning->alpha = 0.95; + lightning->d_alpha = -1.333; + lightning->color.c = 0xffffffff; + AddEffect(NULL, lightning); + + // And yet more sparks to the hit point too to add interest. + for(i=0; i<12; i++) + { // Half green, half yellow particles + if (i&0x01) + spark = ClientParticle_new(PART_16x16_SPARK_Y, lightning->color, 1000); + else + spark = ClientParticle_new(PART_16x16_SPARK_G, lightning->color, 1000); + VectorSet(spark->velocity, + flrand(-LIGHTNING_RING_VEL,LIGHTNING_RING_VEL), + flrand(-LIGHTNING_RING_VEL,LIGHTNING_RING_VEL), + flrand(0,32)); + VectorScale(spark->velocity, -1.0, spark->acceleration); + spark->scale = flrand(20.0, 32.0); + spark->d_scale = -spark->scale; + spark->d_alpha = flrand(-384.0, -256); + AddParticleToList(lightning, spark); + } + + // Draw a circle of expanding lines. + curang = 0; + degreeinc = (360.0*ANGLE_TO_RAD)/(float)NUM_LIGHTNING_RINGBITS; + VectorSet(lastvel, LIGHTNING_RING_VEL, 0.0, 0.0); + VectorSet(upvel, 0, 0, 32.0); + for(i = 0; i < NUM_LIGHTNING_RINGBITS; i++) + { + curang+=degreeinc; + + lightning = ClientEntity_new(FX_LIGHTNING, + CEF_PULSE_ALPHA | CEF_USE_VELOCITY2 | CEF_AUTO_ORIGIN | CEF_ABSOLUTE_PARTS | CEF_ADDITIVE_PARTS, + target, NULL, 750); + lightning->r.model = lightning_models + LIGHTNING_TYPE_GREEN; + lightning->r.frame = 1; // Just use the halo + lightning->r.spriteType = SPRITE_LINE; + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->radius = 64.0; + + // The startpos and startvel comes from the last velocity. + VectorCopy(lastvel, lightning->velocity); + VectorScale(lightning->velocity, -1.0, lightning->acceleration); + VectorMA(target, .01, lightning->velocity, lightning->r.startpos); // Move the line out a bit to avoid a zero-length line. + + // The endpos is calculated from the current angle. + VectorSet(lightning->velocity2, LIGHTNING_RING_VEL*cos(curang), LIGHTNING_RING_VEL*sin(curang), 0.0); + VectorScale(lightning->velocity2, -1.0, lightning->acceleration2); + VectorMA(target, .01, lightning->velocity2, lightning->r.endpos); // Move the line out a bit to avoid a zero-length line. + + // Finally, copy the last velocity we used. + VectorCopy(lightning->velocity2, lastvel); + + // Now, add the additional velocity upwards + VectorAdd(lightning->velocity, upvel, lightning->velocity); + VectorAdd(lightning->velocity2, upvel, lightning->velocity2); + + lightning->r.scale = .5; + lightning->d_scale = 32.0; + lightning->alpha = 0.1; + lightning->d_alpha = 3.0; + lightning->color.c = 0xffffffff; + + AddEffect(NULL, lightning); + + // Now spawn a particle quick to save against the nasty joints (ugh). + // Half green, half yellow particles + if (i&0x01) + { + lightning->r.tile = 0.5; // Alternate tiles + lightning->r.tileoffset = 0.5; + spark = ClientParticle_new(PART_16x16_SPARK_Y, lightning->color, 750); + } + else + { + lightning->r.tile = 0.5; // Alternate tiles + lightning->r.tileoffset = 0.0; + spark = ClientParticle_new(PART_16x16_SPARK_G, lightning->color, 750); + } + VectorCopy(lightning->r.startpos, spark->origin); + VectorCopy(lightning->velocity, spark->velocity); + VectorCopy(lightning->acceleration, spark->acceleration); + spark->scale = 0.5; + spark->d_scale = 32.0; + spark->color.a = 1; + spark->d_alpha = 768.0; + + AddParticleToList(lightning, spark); + } + + // Now finally flash the screen + fxi.Activate_Screen_Flash(0x8080ffc0); + // make our screen shake a bit + // values are : a, b, c, d + // a = amount of maximum screen shake, in pixels + // b = duration of screen shake in milli seconds + // c = current time - in milli seconds - if this routine is called from the server, remember this + // d = dir of shake - see game_stats.h for definitions + fxi.Activate_Screen_Shake(4, 500, fxi.cl->time, SHAKE_ALL_DIR); + + if (Flags & CEF_FLAG8) // Play sound flag + fxi.S_StartSound(target, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/LightningPower.wav"), 1, ATTN_NORM, 0); +} + + + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_maceball.c b/Toolkit/Programming/GameCode/client effects/fx_maceball.c new file mode 100644 index 0000000..3e2a9cf --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_maceball.c @@ -0,0 +1,473 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "angles.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "motion.h" +#include "Reference.h" +#include "ce_Dlight.h" +#include "q_Sprite.h" +#include "g_playstats.h" +#include "fx_debris.h" + +#define BALL_RADIUS 0.15 +#define NUM_RIPPER_PUFFS 12 +#define RIPPER_PUFF_ANGLE ((360.0*ANGLE_TO_RAD)/(float)NUM_RIPPER_PUFFS) +#define RIPPER_RING_VEL 96.0 +#define MACEBALL_RING_VEL 64.0 +#define MACEBALL_SPARK_VEL 128.0 + +#define NUM_MACE_MODELS 7 +static struct model_s *mace_models[NUM_MACE_MODELS]; +void PreCacheMaceball() +{ + mace_models[0] = fxi.RegisterModel("sprites/spells/maceball.sp2"); + mace_models[1] = fxi.RegisterModel("sprites/fx/halo.sp2"); + mace_models[2] = fxi.RegisterModel("sprites/fx/neon.sp2"); + mace_models[3] = fxi.RegisterModel("models/spells/maceball/tris.fm"); + mace_models[4] = fxi.RegisterModel("sprites/fx/ballstreak.sp2"); + mace_models[5] = fxi.RegisterModel("sprites/spells/patball.sp2"); + mace_models[6] = fxi.RegisterModel("sprites/spells/spark_green.sp2"); +} + +// -------------------------------------------------------------- +// Need to create some pretty effect here + +#define BALL_GROWTH 0.05 +#define BALL_MAX (6.0 * BALL_RADIUS) + +static qboolean FXMaceballThink(struct client_entity_s *self, centity_t *owner) +{ + self->dlight->intensity = 150.0 + (cos(fxi.cl->time * 0.01) * 20.0); + self->r.angles[2] += ANGLE_30; + if(self->r.scale >= BALL_MAX) + { + self->d_scale = 0.0; + } + return(true); +} + +void FXMaceball(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + glow = ClientEntity_new(type, flags, origin, 0, 100); + + glow->r.model = mace_models; + glow->r.scale = BALL_RADIUS; + glow->d_scale = BALL_GROWTH; + glow->color.c = 0xff00ffff; + glow->dlight = CE_DLight_new(glow->color, 150.0F, 0.0F); + glow->Update = FXMaceballThink; + + AddEffect(owner, glow); +} + +// ----------------------------------------------------------------------------------------- + +#define NUM_BOUNCE_PARTS 8 +#define BOUNCE_LIFETIME 500 +#define BOUNCE_PART_SPEED 40.0 + +void FXMaceballBounce(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *ring, *hitfx; + client_particle_t *spark; + paletteRGBA_t color; + int i; + vec3_t norm, up, right, lastvel; + float curyaw; + + fxi.GetEffect(owner, flags, "d", norm); + + color.c = 0xffffffff; + + // Take the normal and find two "axis" vectors that are in the plane the normal defines + PerpendicularVector(up, norm); + CrossProduct(up, norm, right); + + hitfx = ClientEntity_new(type, flags, origin, NULL, BOUNCE_LIFETIME); + hitfx->r.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + hitfx->flags |= CEF_NO_DRAW | CEF_ADDITIVE_PARTS; + hitfx->radius = BALL_RADIUS; + VectorScale(norm, MACEBALL_SPARK_VEL, hitfx->velocity); // This velocity is used by the sparks. + AddEffect(NULL, hitfx); + + VectorScale(norm, 8.0, norm); + color.c = 0xffffffff; + + // Draw a circle of expanding lines. + curyaw = 0; + VectorScale(right, MACEBALL_RING_VEL, lastvel); + for(i = 0; i < NUM_RIPPER_PUFFS; i++) + { + curyaw+=RIPPER_PUFF_ANGLE; + + ring = ClientEntity_new(type, CEF_PULSE_ALPHA | CEF_USE_VELOCITY2 | CEF_AUTO_ORIGIN | CEF_ABSOLUTE_PARTS | CEF_ADDITIVE_PARTS, + origin, NULL, 500); + ring->r.model = mace_models + 2; + ring->r.frame = 1; + ring->r.spriteType = SPRITE_LINE; + ring->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + ring->radius = 64.0; + + // The startpos and startvel comes from the last velocity. + VectorCopy(lastvel, ring->velocity); + VectorScale(ring->velocity, -1.0, ring->acceleration); + VectorMA(origin, .01, ring->velocity, ring->r.startpos); // Move the line out a bit to avoid a zero-length line. + + VectorScale(up, RIPPER_RING_VEL*sin(curyaw), ring->velocity2); + VectorMA(ring->velocity2, MACEBALL_RING_VEL*cos(curyaw), right, ring->velocity2); + + VectorScale(ring->velocity2, -1.0, ring->acceleration2); + VectorMA(origin, .01, ring->velocity2, ring->r.endpos); // Move the line out a bit to avoid a zero-length line. + + // Finally, copy the last velocity we used. + VectorCopy(ring->velocity2, lastvel); + + // NOW apply the extra directional velocity to force it slightly away from the surface. + VectorAdd(ring->velocity, norm, ring->velocity); + VectorAdd(ring->velocity2, norm, ring->velocity2); + + ring->r.scale = .5; + ring->d_scale = 16.0; + ring->alpha = 0.1; + ring->d_alpha = 4.0; + + AddEffect(NULL, ring); + + // Now spawn a particle quick to save against the nasty joints (ugh). + spark = ClientParticle_new(PART_16x16_SPARK_G, color, 500); + VectorCopy(ring->r.startpos, spark->origin); + VectorCopy(ring->velocity, spark->velocity); + VectorCopy(ring->acceleration, spark->acceleration); + spark->scale = 0.5; + spark->d_scale = 16.0; + spark->color.a = 1; + spark->d_alpha = 1024.0; + + AddParticleToList(ring, spark); + } + + // Add a few sparks to the imapct + for (i=0; i<8; i++) + { + spark = ClientParticle_new(PART_16x16_SPARK_G, color, 500); + VectorSet(spark->velocity, + flrand(-MACEBALL_SPARK_VEL, MACEBALL_SPARK_VEL), + flrand(-MACEBALL_SPARK_VEL, MACEBALL_SPARK_VEL), + flrand(-MACEBALL_SPARK_VEL, MACEBALL_SPARK_VEL)); + spark->d_alpha = flrand(-768.0, -512.0); + spark->scale = 4.0; + spark->d_scale = flrand(-10.0, -8.0); + spark->acceleration[2] = -2.0*MACEBALL_SPARK_VEL; + + AddParticleToList(hitfx, spark); + } +} + +// **************************************************************************** +// FXMaceballExplode - +// **************************************************************************** + +#define MACEBALL_EXP_VEL 128.0 +void FXMaceballExplode(centity_t *owner,int type,int flags,vec3_t origin) +{ + vec3_t dir; + client_entity_t *explosion; + client_particle_t *spark; + int i; + vec3_t mins={BALL_RADIUS, BALL_RADIUS, BALL_RADIUS}; + + fxi.GetEffect(owner,flags,"d",dir); + + // Create an expanding ball of gre. + + explosion=ClientEntity_new(type,CEF_DONT_LINK|CEF_ADDITIVE_PARTS,origin,dir,750); + explosion->r.model = mace_models+3; + explosion->r.flags |= RF_TRANSLUCENT; + explosion->r.scale = 0.17; + explosion->d_scale = -0.17; + explosion->d_alpha = -1.4; + explosion->radius = 64.0; + VectorScale(dir, 8.0, explosion->velocity); + explosion->color.c=0xffffffff; + AddEffect(NULL,explosion); + + for (i=0; i<32; i++) + { + spark = ClientParticle_new(PART_16x16_SPARK_G, explosion->color, 1000); + VectorSet(spark->velocity, + flrand(-MACEBALL_EXP_VEL, MACEBALL_EXP_VEL), + flrand(-MACEBALL_EXP_VEL, MACEBALL_EXP_VEL), + flrand(0, MACEBALL_EXP_VEL)); + spark->d_alpha = flrand(-320.0, -256.0); + spark->scale = 8.0; + spark->d_scale = flrand(-10.0, -8.0); + spark->acceleration[2] = -2.0*MACEBALL_SPARK_VEL; + + AddParticleToList(explosion, spark); + } + + // Spawn some chunks too + FXDebris_SpawnChunks(type, flags & ~(CEF_FLAG6|CEF_FLAG7|CEF_FLAG8), origin, 5, MAT_METAL, dir, 80000.0f, mins, 1.5, false); +} + + + +// end + + + + + + +// ************************************************************************************************ +// FXRipperBall +// ************************************************************************************************ + + +// ************************************************************************************************ +// FXRipperExplode +// --------------------- +// ************************************************************************************************ + +static qboolean FXRipperExplodeLightThink(struct client_entity_s *self, centity_t *owner) +{ + if (fxi.cl->time > self->lastThinkTime) + return(false); + + if(self->dlight->intensity > 0.0F) + self->dlight->intensity -= 10.0F; + + return(true); +} + + + +static qboolean FXRipperExplodeBallThink(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *trail; + vec3_t diff, curpos; + float scale; + int i; + + VectorScale(self->direction, -6, diff); + VectorCopy(self->r.origin, curpos); + scale = 0.8; + for (i=0; i<4; i++) + { + trail = ClientEntity_new(FX_WEAPON_RIPPEREXPLODE, 0, curpos, NULL, 500); + trail->r.model = mace_models + 6; + trail->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + VectorCopy(self->velocity, trail->velocity); + VectorScale(trail->velocity, -1.0, trail->acceleration); + trail->r.scale = scale; + trail->d_scale = -scale; + trail->alpha = 0.3; + trail->d_alpha = -0.6; + trail->radius = 10.0; + + AddEffect(NULL, trail); + + VectorAdd(curpos, diff, curpos); + scale -= 0.12; + } + + return(true); +} + + +// Create Effect FX_WEAPON_RIPPEREXPLODE +void FXRipperExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *ripper; + paletteRGBA_t color = {255, 255, 255, 255}; + short ballarray[8]; + byte byaw; + float curyaw; + vec3_t casterpos; + int i, num; + float length; + vec3_t lastvel, diff, curpos; + client_entity_t *flash, *ring; + client_particle_t *spark; + + + fxi.GetEffect(owner, flags, "vbssssssss", + casterpos, + &byaw, + &ballarray[0], + &ballarray[1], + &ballarray[2], + &ballarray[3], + &ballarray[4], + &ballarray[5], + &ballarray[6], + &ballarray[7]); + + // Convert from a byte back to radians + curyaw = ((float)byaw)*((2*M_PI)/256.0); + + // + // Throw out a bunch o' balls + // + for (i=0; ir.model = mace_models; + ripper->r.flags = RF_TRANSLUCENT; // Use the alpha channel + + // Set up the velocities + VectorSet(ripper->velocity, cos(curyaw), sin(curyaw), 0.0); + VectorCopy(ripper->velocity, ripper->direction); + vectoangles(ripper->velocity, ripper->r.angles); + Vec3ScaleAssign(RIPPER_EXPLODE_SPEED, ripper->velocity); + + // Set up the basic attributes + ripper->r.scale = 0.25; + ripper->r.color = color; + ripper->radius = 10.0F; + ripper->Update = FXRipperExplodeBallThink; + + // Add to the entity passed in, not the "owner". + assert(ballarray[i]); + AddEffect((centity_t *)(&fxi.server_entities[ballarray[i]]), ripper); + + curyaw += RIPPER_BALL_ANGLE; + } + + // + // Draw the impact graphic + // + flash = ClientEntity_new(type, 0, origin, NULL, 50); + flash->r.model = mace_models + 1; + flash->r.frame = 1; + flash->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + flash->radius = 20.0; + + flash->r.scale = 0.75; + flash->d_scale = -1.0; + flash->d_alpha = -1.4; + fxi.S_StartSound(flash->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/RipperImpact.wav"), 1, ATTN_NORM, 0); + flash->dlight = CE_DLight_new(color, 150.0f, -100.0f); + flash->lastThinkTime = fxi.cl->time + 750; +// flash->Update = FXRipperExplodeLightThink; + + AddEffect(NULL, flash); + + // Draw a circle of expanding lines. + curyaw = 0; + VectorSet(lastvel, RIPPER_RING_VEL, 0.0, 0.0); + for(i = 0; i < NUM_RIPPER_PUFFS; i++) + { + curyaw+=RIPPER_PUFF_ANGLE; + + ring = ClientEntity_new(type, CEF_PULSE_ALPHA | CEF_USE_VELOCITY2 | CEF_AUTO_ORIGIN | CEF_ABSOLUTE_PARTS | CEF_ADDITIVE_PARTS, + origin, NULL, 750); + ring->r.model = mace_models + 2; + ring->r.frame = 1; + ring->r.spriteType = SPRITE_LINE; + ring->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + ring->radius = 64.0; + + // The startpos and startvel comes from the last velocity. + VectorCopy(lastvel, ring->velocity); + VectorScale(ring->velocity, -1.0, ring->acceleration); + VectorMA(origin, .01, ring->velocity, ring->r.startpos); // Move the line out a bit to avoid a zero-length line. + + // The endpos is calculated from the current angle. + VectorSet(ring->velocity2, RIPPER_RING_VEL*cos(curyaw), RIPPER_RING_VEL*sin(curyaw), 0.0); + VectorScale(ring->velocity2, -1.0, ring->acceleration2); + VectorMA(origin, .01, ring->velocity2, ring->r.endpos); // Move the line out a bit to avoid a zero-length line. + + // Finally, copy the last velocity we used. + VectorCopy(ring->velocity2, lastvel); + + // NOW apply the extra directional velocity. + VectorAdd(ring->velocity, flash->velocity, ring->velocity); + VectorAdd(ring->velocity2, flash->velocity, ring->velocity2); + + ring->r.scale = .5; + ring->d_scale = 32.0; + ring->alpha = 0.1; + ring->d_alpha = 3.0; + + AddEffect(NULL, ring); + + // Now spawn a particle quick to save against the nasty joints (ugh). + spark = ClientParticle_new(PART_16x16_SPARK_G, color, 750); + VectorCopy(ring->r.startpos, spark->origin); + VectorCopy(ring->velocity, spark->velocity); + VectorCopy(ring->acceleration, spark->acceleration); + spark->scale = 0.5; + spark->d_scale = 32.0; + spark->color.a = 1; + spark->d_alpha = 768.0; + + AddParticleToList(ring, spark); + } + + // Get the length for the firing streak. + VectorSubtract(origin, casterpos, diff); + length = VectorLength(diff); + + if (length > 8.0) + { + // Draw the streak from the caster to the impact point. + flash = ClientEntity_new(FX_WEAPON_RIPPEREXPLODE, CEF_AUTO_ORIGIN, casterpos, NULL, 500); + flash->r.model = mace_models + 4; + flash->r.spriteType = SPRITE_LINE; + flash->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + VectorCopy(casterpos, flash->r.endpos); + VectorCopy(origin, flash->r.startpos); + flash->radius = length*0.5; + + flash->r.scale = 8.0; + flash->d_scale = -8.0; + flash->alpha = 0.5; + flash->d_alpha = -1.0; + + AddEffect(NULL, flash); + + // Draw some flashy bits along the line for thickness + num = (int)(length/32.0); + VectorCopy(casterpos, curpos); + VectorScale(diff, 1/(float)num, diff); + if (num>40) + num=40; + for (i=0; ir.model = mace_models + 5; + flash->r.frame = 1; + flash->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + flash->r.scale = .16; + flash->d_scale = -.16; + flash->alpha = 0.5; + flash->d_alpha = -1.0; + + AddEffect(NULL, flash); + + VectorAdd(curpos, diff, curpos); + } + } + +} + + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_magicmissile.c b/Toolkit/Programming/GameCode/client effects/fx_magicmissile.c new file mode 100644 index 0000000..b054c6f --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_magicmissile.c @@ -0,0 +1,341 @@ +// +// fx_magicmissile.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "Angles.h" +#include "Random.h" +#include "q_Sprite.h" +#include "Utilities.h" +#include "g_playstats.h" + +static qboolean FXMagicMissileTrailElementThink(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXMagicMissileTrailThink(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXMagicMissileModelThink1(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXMagicMissileModelThink2(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXMagicMissileSmokePuffThink(struct client_entity_s *Self,centity_t *Owner); + +#define NUM_MISSILE_MODELS 3 + +static struct model_s *array_models[NUM_MISSILE_MODELS]; + +void PreCacheArray() +{ + array_models[0] = fxi.RegisterModel("sprites/spells/halo_ind.sp2"); + array_models[1] = fxi.RegisterModel("Sprites/spells/spark_ind.sp2"); + array_models[2] = fxi.RegisterModel("Sprites/spells/indigostreak.sp2"); +} + + +// ************************************************************************************************ +// FXMagicMissileTrailThink +// ------------------------ +// ************************************************************************************************ + +// These need to be converted to particles + +#define ARRAY_TRAIL_SCALE 0.3 +#define ARRAY_TRAIL_COUNT 3 +#define TRAIL_SPEED 32.0 + +static qboolean FXMagicMissileTrailThink(struct client_entity_s *Self,centity_t *Owner) +{ + int i; + client_entity_t *trail; + vec3_t NormVelocity; + + VectorCopy(Self->velocity,NormVelocity); + VectorNormalize(NormVelocity); + +// count = GetScaledCount(ARRAY_TRAIL_COUNT, 0.8); +// for(i = 0; i < count; i++) + for (i=0; i<2; i++) // Each cardinal direction + { + trail = ClientEntity_new(FX_WEAPON_MAGICMISSILE, + 0, + Self->r.origin, + NULL, + 500); + + // Self->up holds the direction to move in. + + VectorMA(trail->r.origin, -i * 3.0 - flrand(0.0F, 3.0F), NormVelocity, trail->r.origin); + switch(i) + { + case 0: // Up/right + VectorCopy(Self->up, trail->velocity); + break; + case 1: // Down/left + VectorScale(Self->up, -1.0, trail->velocity); + break; + } + + trail->r.model = array_models; + trail->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + trail->r.scale = flrand(ARRAY_TRAIL_SCALE, ARRAY_TRAIL_SCALE + 0.1); + trail->d_scale = -1.0; + trail->d_alpha = -2.0; + trail->radius = 20.0; + + AddEffect(NULL,trail); + } + + trail = ClientEntity_new(FX_WEAPON_MAGICMISSILE, + CEF_AUTO_ORIGIN | CEF_USE_VELOCITY2, + Self->r.origin, + NULL, + 500); + + trail->r.model = array_models + 2; + trail->r.spriteType = SPRITE_LINE; + trail->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + VectorCopy(trail->r.origin, trail->r.startpos); + VectorMA(trail->r.origin, -0.1, Self->velocity, trail->r.endpos); + VectorScale(Self->velocity, 0.9, trail->velocity); + VectorScale(Self->velocity, 0.5, trail->velocity2); + trail->r.scale = 12.0; + trail->d_scale = -24.0; + trail->d_alpha = -2.0; + + AddEffect(NULL, trail); + + return(true); +} + +// ************************************************************************************************ +// FXMagicMissileModelThink1 +// ------------------------- +// ************************************************************************************************ + +static qboolean FXMagicMissileModelThink1(struct client_entity_s *Self,centity_t *Owner) +{ + Self->d_scale=0.0; + Self->r.scale = 0.8; + + Self->Update=FXMagicMissileModelThink2; + + FXMagicMissileTrailThink(Self,Owner); + return(true); +} + +// ************************************************************************************************ +// FXMagicMissileModelThink2 +// ------------------------- +// ************************************************************************************************ + +static qboolean FXMagicMissileModelThink2(struct client_entity_s *Self,centity_t *Owner) +{ + FXMagicMissileTrailThink(Self,Owner); + return(true); +} + +// ************************************************************************************************ +// FXMagicMissile +// -------------- +// ************************************************************************************************ + +void FXMagicMissile(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + vec3_t ang; + client_entity_t *Missile; + paletteRGBA_t LightColor={128,64,96,255}; + vec3_t fwd, up, right; + short shortyaw, shortpitch; + + fxi.GetEffect(Owner,Flags,"ss", &shortyaw, &shortpitch); + + ang[YAW]=(float)shortyaw * (360.0/65536.0); + ang[PITCH]=(float)shortpitch * (360.0/65536.0); + ang[ROLL]=0.0; + + AngleVectors(ang, fwd, right, up); + + // Add the magic-missile model. + Missile=ClientEntity_new(Type, Flags | CEF_DONT_LINK, Origin, NULL, 100); + + Missile->r.model = array_models; + Missile->r.frame = 1; + if (Flags & CEF_FLAG6) + VectorScale(fwd, MAGICMISSILE_SPEED/2, Missile->velocity); + else + VectorScale(fwd, MAGICMISSILE_SPEED, Missile->velocity); + VectorCopy(ang, Missile->r.angles); + + // Set up the direction we want the trail to fly from the missile. + VectorMA(up, 2.0, right, Missile->up); + VectorScale(Missile->up, TRAIL_SPEED, Missile->up); + + Missile->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD; + Missile->r.scale=0.4; + Missile->alpha=1.0; + Missile->d_alpha=0.0; + Missile->d_scale=4.0; + Missile->dlight=CE_DLight_new(LightColor,150.0f,0.0f); + Missile->Update=FXMagicMissileModelThink1; + +// FXMagicMissileTrailThink(Self, Owner); + + AddEffect(Owner, Missile); +} + +// ************************************************************************************************ +// FXMagicMissileExplode +// ************************************************************************************************ + +#define NUM_ARRAY_EXPLODE_PARTS 12 +#define ARRAY_SCALE 1.0 +#define ARRAY_EXPLODE_SPEED 200 +void FXMagicMissileExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t dir; + client_entity_t *smokepuff; + int i; + paletteRGBA_t lightcolor = {0, 128, 128, 255}; + + fxi.GetEffect(owner, flags, "d", dir); + if(flags & CEF_FLAG6) + { + FXClientScorchmark(origin, dir); + } + Vec3ScaleAssign(32.0, dir); + + for(i = 0; i < NUM_ARRAY_EXPLODE_PARTS; i++) + { + smokepuff = ClientEntity_new(type, flags, origin, 0, 500); + + smokepuff->r.model = array_models + 1; + smokepuff->r.scale = flrand(ARRAY_SCALE * 0.75, ARRAY_SCALE * 1.5); + smokepuff->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + VectorRandomCopy(dir, smokepuff->velocity, ARRAY_EXPLODE_SPEED); + smokepuff->acceleration[2] = GetGravity()*0.3; + + smokepuff->d_scale = -1.0; + smokepuff->d_alpha = -2.0; + smokepuff->radius = 20.0; + + AddEffect(NULL, smokepuff); + } + + // Big flash + smokepuff = ClientEntity_new(type, flags, origin, 0, 500); + + smokepuff->r.model = array_models; + smokepuff->r.frame = 0; + + smokepuff->r.scale = 2.0; + smokepuff->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + VectorScale(dir, 8.0, smokepuff->velocity); + + smokepuff->d_scale = -6.0; + smokepuff->d_alpha = -2.0; + smokepuff->radius = 20.0; + + smokepuff->dlight = CE_DLight_new(lightcolor, 150.0, -50.0); + + AddEffect(NULL, smokepuff); +} + +#define BLAST_DIFF 40.0 +#define BLAST_SCALE 0.3 +#define BLAST_BACKSPEED -1.5 +#define BLAST_GRAVITY -32.0 + +// Create Effect FX_WEAPON_BLAST +void FXBlast(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t endpos, curpos; + vec3_t unit, back; + int i, numpuffs; + client_entity_t *puff; + client_particle_t *spark; + paletteRGBA_t pal; + float length, scale; + short slength[BLAST_NUM_SHOTS], syaw, spitch; + int shot; + vec3_t angles; + + assert(BLAST_NUM_SHOTS==5); + + // Sends over the network 7 shorts and an origin. + // Note that this is a vast improvement over five seperate effects with a vector each (60 bytes+origins) + fxi.GetEffect(owner, flags, "sssssss", &syaw, &spitch, &slength[0], &slength[1], &slength[2], &slength[3], &slength[4]); + + // Compress the angles into two shorts. + angles[YAW] = (float)syaw*(360.0/65536.0); + angles[PITCH] = (float)spitch*(360.0/65536.0); + angles[ROLL] = 0.0; + + // Set up for array. + angles[YAW] -= BLAST_ANGLE_INC * (BLAST_NUM_SHOTS-1) * 0.5; + for (shot=0; shot40) + numpuffs=40; + for(i=0; i<=numpuffs; i++) + { + puff = ClientEntity_new(type, flags | CEF_ADDITIVE_PARTS, curpos, NULL, 750); + puff->r.model = array_models + 1; + puff->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + puff->r.scale = scale; + puff->radius = 14.0; + puff->alpha = 0.95; +// puff->d_alpha = -1.0; + puff->d_scale = -1.4*scale; + VectorSet(puff->velocity, flrand(-8.0,8.0), flrand(-8.0,8.0), flrand(-8.0,8.0)); + VectorAdd(puff->velocity, back, puff->velocity); + puff->acceleration[2] = BLAST_GRAVITY; + AddEffect(NULL, puff); + VectorAdd(curpos, unit, curpos); + scale+=0.1; + } + + // We added the line, now throw out the impact + // Big flash first... + puff = ClientEntity_new(type, CEF_ADDITIVE_PARTS, endpos, NULL, 1000); + puff->r.model = array_models; + puff->r.frame = 0; + puff->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + puff->r.scale = 1.0 + length * 0.001; // Bigger when further out. + puff->alpha = 0.95; + puff->d_scale = -5.0; + puff->d_alpha = -1.0; + puff->radius = 16.0; + VectorCopy(back, puff->velocity); + + AddEffect(NULL, puff); + + pal.c = 0xffffffff; + for (i=0; i<9; i++) + { + spark = ClientParticle_new(PART_16x16_SPARK_I, pal, 750); + VectorSet(spark->velocity, flrand(-64.0, 64.0), flrand(-64.0, 64.0), flrand(64.0, 128.0)); + spark->acceleration[2] = -PARTICLE_GRAVITY*3.0; + spark->scale = 16.0; + spark->d_scale = -16.0*1.4; + AddParticleToList(puff, spark); + } + + angles[YAW] += BLAST_ANGLE_INC; + } +} + \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_meteorbarrier.c b/Toolkit/Programming/GameCode/client effects/fx_meteorbarrier.c new file mode 100644 index 0000000..1d411d0 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_meteorbarrier.c @@ -0,0 +1,198 @@ +// +// fx_meteorbarrier.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "fx_debris.h" +#include "Utilities.h" +#include "g_playstats.h" + +#define NUM_METEOR_MODELS 1 + +static struct model_s *meteor_models[NUM_METEOR_MODELS]; + +void PreCacheMeteor() +{ + meteor_models[0] = fxi.RegisterModel("models/spells/meteorbarrier/tris.fm"); +} + +// ------------------------------------------------- + +#define NUM_METEOR_CHUNKS 12 +#define METEOR_DELTA_FORWARD 6.0 +#define METEOR_TRAIL_ALPHA 0.8 +#define METEOR_ROLL_SPEED 13.0 +#define METEOR_YAW_SPEED 10.0 + +static qboolean FXMeteorBarriertrailThink(struct client_entity_s *self, centity_t *owner) +{ + + vec3_t org, delta; + float length, alpha; + int numtrails; + client_particle_t *ce; + + // we theoretically shouldn't need to do this.. Just in case. + if (!(owner->flags & CF_INUSE)) + return(false); + + // no trails in low detail mode + if (r_detail->value == DETAIL_LOW) + return(true); + + // Length of trail + VectorSubtract(self->origin, self->r.origin, delta); + // Number of trails to render + if (r_detail->value >= DETAIL_HIGH) + length = VectorLength(delta) / (METEOR_DELTA_FORWARD); + else + length = VectorLength(delta) / (METEOR_DELTA_FORWARD * 1.5); + // Set start + VectorCopy(self->r.origin, org); + // Work out increment between trails + Vec3ScaleAssign(1.0 / length, delta); + // Work out number of bits + numtrails = Q_ftol(length); + alpha = METEOR_TRAIL_ALPHA; + + VectorCopy(self->r.origin, self->origin); + + if (numtrails>10) + return true; + if (numtrails <= 0) + numtrails = 1; + while(numtrails-->0) + { + ce = ClientParticle_new(PART_16x16_SPARK_G, self->r.color, 400); + ce->scale = 13; + ce->d_scale = -10.0; + ce->color.a = 255*alpha; + VectorCopy(org, ce->origin); + AddParticleToList(self, ce); + + Vec3AddAssign(delta, org); + alpha *= 0.9; + } + return(true); + +} + +// Putting the angular velocity in here saves 3 bytes of net traffic +// per meteor per server frame + +qboolean MeteorAddToView(client_entity_t *current, centity_t *owner) +{ + float roll, yaw; + int d_time; + float Angle; + + d_time = fxi.cl->time - current->startTime; + roll = d_time * 0.001 * METEOR_ROLL_SPEED; + yaw = d_time * 0.001 * METEOR_YAW_SPEED; + current->r.angles[ROLL] = roll; + current->r.angles[YAW] = yaw; + + Angle = ((fxi.cl->time * .1500) + (90.0 * current->SpawnData)) * ANGLE_TO_RAD; + current->r.origin[0] = cos(Angle) * 30.0; + current->r.origin[1] = sin(Angle) * 30.0; + current->r.origin[2] = cos(Angle / (M_PI / 5)) * 10.0; + + VectorAdd(owner->origin, current->r.origin, current->r.origin); + return(true); +} + +void FXMeteorBarrier(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *trail; + paletteRGBA_t lightcolor = {63, 255, 77, 255}; + + // Add a fiery trail effect. + trail = ClientEntity_new(type, flags|CEF_ABSOLUTE_PARTS|CEF_ADDITIVE_PARTS|CEF_VIEWSTATUSCHANGED, origin, 0, 50); + + trail->Update = FXMeteorBarriertrailThink; + trail->r.model = meteor_models; + trail->AddToView = MeteorAddToView; + trail->SpawnData = (flags & (CEF_FLAG6|CEF_FLAG7)) >> 5; + trail->radius = 10.0; + trail->r.color.c = -1; + if (r_detail->value >= DETAIL_NORMAL) + trail->dlight = CE_DLight_new(lightcolor, 150.0, 0.0); + + AddEffect(owner, trail); +} + +void FXMeteorBarrierTravel(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *trail; + paletteRGBA_t lightcolor = {63, 255, 77, 255}; + + // Add a fiery trail effect. + trail = ClientEntity_new(type, flags|CEF_ABSOLUTE_PARTS|CEF_ADDITIVE_PARTS|CEF_VIEWSTATUSCHANGED, origin, 0, 50); + + trail->Update = FXMeteorBarriertrailThink; + trail->r.model = meteor_models; + trail->AddToView = LinkedEntityUpdatePlacement; + trail->radius = 10.0; + trail->r.color.c = -1; + if (r_detail->value >= DETAIL_NORMAL) + trail->dlight = CE_DLight_new(lightcolor, 150.0, 0.0); + + AddEffect(owner, trail); +} + + + +// ------------------------------------------------------- + +void FXMeteorBarrierExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t dir, mins; + int i; + client_entity_t *smokepuff; + paletteRGBA_t LightColor = {64, 255, 76, 255}; + int count; + client_particle_t *ce; + + fxi.GetEffect(owner, flags, "d", dir); + Vec3ScaleAssign(32.0, dir); + + if(flags&CEF_FLAG6) + { + // Impact explosion: throw off chunks of glowing meteor-rock and puffs of green smoke. + vec3_t DebrisDir; + + VectorSet(DebrisDir, 0.0, 0.0, 1.0); + VectorSet(mins, 2.0, 2.0, 2.0); // because SpawnChunks needs a value for bounding box + //clear out cef_flag# stuff, means different stuff to debris + FXDebris_SpawnChunks(type, flags & ~(CEF_FLAG6|CEF_FLAG7|CEF_FLAG8), origin, 5, MAT_GREYSTONE, DebrisDir, 80000.0f, mins, 1.0, false); + } + + smokepuff = ClientEntity_new(type, flags|CEF_NO_DRAW | CEF_ADDITIVE_PARTS, origin, 0, 500); + smokepuff->radius = 10.0; + if(r_detail->value != DETAIL_LOW) + smokepuff->dlight = CE_DLight_new(LightColor, 150.0, 0.0); + + AddEffect(NULL, smokepuff); + + count = GetScaledCount(NUM_METEOR_CHUNKS, 0.4); + for(i = 0; i < count; i++) + { + ce = ClientParticle_new(PART_16x16_SPARK_G, smokepuff->r.color, 500); + ce->scale = flrand(11,15); + ce->d_scale = -10.0; + VectorRandomCopy(dir, ce->velocity, 64.0); + ce->acceleration[2] = GetGravity() * 0.3; + AddParticleToList(smokepuff, ce); + } +} +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_mist.c b/Toolkit/Programming/GameCode/client effects/fx_mist.c new file mode 100644 index 0000000..b05b5d6 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_mist.c @@ -0,0 +1,76 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// Created by JJS + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "Utilities.h" + +#define MIST_ALPHA 0.6F +#define MIST_FAR 512.0F +#define MIST_NEAR 96.0F + +#define NUM_MIST_MODELS 1 +static struct model_s *mist_models[NUM_MIST_MODELS]; +void PreCacheMist() +{ + mist_models[0] = fxi.RegisterModel("sprites/fx/mist.sp2"); +} + +// ----------------------------------------------------------------------------------------- + +static qboolean FXMistThink(client_entity_t *mist, centity_t *owner) +{ + float mod; + + mist->flags &= ~CEF_DISAPPEARED; + + mist->Scale += flrand(-0.05, 0.05) * mist->SpawnData; + mist->Scale = Clamp(mist->Scale, 0.6 * mist->SpawnData, 1.4 * mist->SpawnData); + mist->r.scale = Approach(mist->r.scale, mist->Scale, 0.003 * mist->SpawnData); + + mod = (mist->r.scale / mist->SpawnData) * MIST_ALPHA; + if(mist->r.depth > MIST_FAR) + { + mist->alpha = mod; + return(true); + } + if(mist->r.depth > MIST_NEAR) + { + mist->alpha = mod * (mist->r.depth - MIST_NEAR) * (1.0F / (MIST_FAR - MIST_NEAR)); + return(true); + } + mist->alpha = 0.0F; + return(true); +} + +void FXMist(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *mist; + byte scale; + + fxi.GetEffect(owner, flags, "b", &scale); + mist = ClientEntity_new(type, flags, origin, NULL, 100); + + mist->SpawnData = scale * 0.1; + + mist->r.model = mist_models; + mist->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + mist->r.scale = mist->SpawnData; + + mist->flags |= CEF_NOMOVE; + mist->Update = FXMistThink; + mist->radius = 1.0F; + mist->alpha = 0.5F; + + AddEffect(NULL, mist); +} +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_mork.c b/Toolkit/Programming/GameCode/client effects/fx_mork.c new file mode 100644 index 0000000..c5a8e4a --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_mork.c @@ -0,0 +1,3826 @@ +// +// fx_Mork.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "q_Sprite.h" +#include "Utilities.h" +#include "Reference.h" +#include "Matrix.h" +#include "g_playstats.h" + +client_entity_t *MorkMakeLightningPiece(vec3_t start, vec3_t end, float radius, int lifetime, qboolean plasma); + +#define NUM_M_MISSILE_MODELS 4 +#define NUM_M_SHIELD_MODELS 3 +#define NUM_M_LIGHTNING_MODELS 3 +#define NUM_M_PP_MODELS 6 +#define NUM_IMP_MODELS 3 +#define NUM_CW_MODELS 2 +#define NUM_BUOY_MODELS 1 + +static struct model_s *Morkproj_models[NUM_M_MISSILE_MODELS]; +static struct model_s *Morkshield_models[NUM_M_SHIELD_MODELS]; +static struct model_s *Morklightning_models[NUM_M_LIGHTNING_MODELS]; +static struct model_s *Morkpp_models[NUM_M_PP_MODELS]; +static struct model_s *Imp_models[NUM_IMP_MODELS]; +static struct model_s *CW_models[NUM_CW_MODELS]; +static struct model_s *buoy_models[NUM_BUOY_MODELS]; +static struct model_s *mork_model[1]; +static struct model_s *ass_dagger_model[1]; + +static struct model_s *morc_models[6]; +static struct model_s *mssithra_models[6]; + +void FireSparks(centity_t *owner, int type, int flags, vec3_t origin, vec3_t dir); +void FXDarkSmoke(vec3_t origin, float scale, float range); + +void PreCacheMEffects() +{ + Morkproj_models[0] = fxi.RegisterModel("sprites/fx/hpproj1_1.sp2"); + Morkproj_models[1] = fxi.RegisterModel("sprites/fx/hpproj1_2.sp2"); + Morkproj_models[2] = fxi.RegisterModel("sprites/fx/segment_trail_wt.sp2"); + Morkproj_models[3] = fxi.RegisterModel("sprites/lens/halo2.sp2"); + + Morklightning_models[0] = fxi.RegisterModel("sprites/fx/lightning.sp2"); + Morklightning_models[1] = fxi.RegisterModel("sprites/fx/rlightning.sp2"); + Morklightning_models[2] = fxi.RegisterModel("sprites/fx/neon.sp2"); + + Morkpp_models[0] = fxi.RegisterModel("sprites/fx/steam.sp2"); + Morkpp_models[1] = fxi.RegisterModel("models/spells/phoenixarrow/tris.fm"); + Morkpp_models[2] = fxi.RegisterModel("sprites/fx/halo.sp2"); + Morkpp_models[3] = fxi.RegisterModel("sprites/fx/core_b.sp2");//spells/phoenix.sp2"); + Morkpp_models[4] = fxi.RegisterModel("models/fx/explosion/inner/tris.fm"); + Morkpp_models[5] = fxi.RegisterModel("models/fx/explosion/outer/tris.fm"); + + Imp_models[0] = fxi.RegisterModel("sprites/fx/halo.sp2"); + Imp_models[1] = fxi.RegisterModel("sprites/fx/fire.sp2"); + Imp_models[2] = fxi.RegisterModel("sprites/fx/halo.sp2"); + + CW_models[0] = fxi.RegisterModel("sprites/spells/patball.sp2"); + CW_models[1] = fxi.RegisterModel("sprites/fx/waterentryripple.sp2"); + + buoy_models[0] = fxi.RegisterModel("sprites/fx/segment_trail_buoy.sp2"); + + mork_model[0] = fxi.RegisterModel("models/monsters/morcalavin/tris.fm"); + ass_dagger_model[0] = fxi.RegisterModel("models/monsters/assassin/dagger/tris.fm"); + + morc_models[0] = fxi.RegisterModel("sprites/fx/neon.sp2"); + morc_models[1] = fxi.RegisterModel("sprites/fx/lightning.sp2"); + morc_models[2] = fxi.RegisterModel("sprites/fx/hpproj1_2.sp2"); + morc_models[3] = fxi.RegisterModel("sprites/fx/hp_halo.sp2"); + morc_models[4] = fxi.RegisterModel("sprites/fx/morc_halo.sp2"); + morc_models[5] = fxi.RegisterModel("sprites/fx/segment_trail.sp2"); + + mssithra_models[0] = fxi.RegisterModel("models/fx/explosion/inner/tris.fm"); + mssithra_models[1] = fxi.RegisterModel("models/fx/explosion/outer/tris.fm"); + mssithra_models[2] = fxi.RegisterModel("sprites/fx/firestreak.sp2"); + mssithra_models[3] = fxi.RegisterModel("models/debris/stone/schunk1/tris.fm"); + mssithra_models[4] = fxi.RegisterModel("models/debris/stone/schunk2/tris.fm"); + mssithra_models[5] = fxi.RegisterModel("sprites/lens/halo2.sp2"); +} + +enum { +//offensive + FX_M_BEAM, +//impacts + FX_M_MISC_EXPLODE, +//other + FX_IMP_FIRE, + FX_IMP_FBEXPL, + FX_CW_STARS, + FX_BUOY, + FX_BUOY_PATH, + FX_M_MOBLUR, + FX_ASS_DAGGER, + FX_UNDER_WATER_WAKE, + +//jweier + FX_QUAKE_RING, + FX_GROUND_ATTACK, + FX_MORK_BEAM, + FX_MORK_MISSILE, + FX_MORK_MISSILE_HIT, + FX_MORK_TRACKING_MISSILE, + + FX_MSSITHRA_EXPLODE, + FX_MSSITHRA_ARROW, + FX_MSSITHRA_ARROW_CHARGE, +}; + +extern int ref_soft; +// ************************************************************************************************ +// FXMorkprojTrailElementThink +// ************************************************************************************************ + +static qboolean FXMorkprojTrailElementThink(struct client_entity_s *self,centity_t *owner) +{ + if ( (self->alpha <= 0) || (self->r.scale <= 0) ) + return false; + + self->color.g -= 32; + self->color.b -= 32; + + return true; +} + +// ************************************************************************************************ +//FX_M_STRAFE +// ************************************************************************************************ + +static qboolean FXMorkTrailThink_old(struct client_entity_s *self,centity_t *owner) +{ + if (self->alpha <= 0.1 || self->r.scale <= 0.0) + return false; + + self->r.scale -= 0.1; + + return true; +} + + +void FXMorkMissileExplode_old(struct client_entity_s *self,centity_t *owner, vec3_t dir) +{ + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor={255,64,32,255}; + byte powerup = 0; + + Vec3ScaleAssign(32.0, dir); + + i = GetScaledCount(irand(12,16), 0.8); + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(FX_M_EFFECTS,0,owner->origin,NULL,500); + else + SmokePuff=ClientEntity_new(FX_M_EFFECTS,0,owner->origin,NULL,1500); + + SmokePuff->r.model = Morkproj_models + 1; + SmokePuff->r.scale=flrand(0.5,1.0); + SmokePuff->d_scale=-4.0; + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + SmokePuff->r.frame=0; + + VectorRandomCopy(dir, SmokePuff->velocity, flrand(16.0, 128.0)); + + SmokePuff->acceleration[0] = flrand(-400, 400); + SmokePuff->acceleration[1] = flrand(-400, 400); + SmokePuff->acceleration[2] = flrand(-40, -60); + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + AddEffect(NULL,SmokePuff); + } +} + +static qboolean FXhpprojTrailElementThink(struct client_entity_s *self,centity_t *owner) +{ + if ( (self->alpha <= 0) || (self->r.scale <= 0) ) + return false; + + self->color.g -= 32; + self->color.b -= 32; + + return true; +} + +static qboolean FXMorkMissileSpawnerThink(struct client_entity_s *self,centity_t *owner) +{ + client_entity_t *TrailEnt; + + if (self->LifeTime < fxi.cl->time) + return false; + + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + self->origin, + NULL, + 1000); + + TrailEnt->radius = 500; + + TrailEnt->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = Morkproj_models + 3; + + TrailEnt->r.color.c = 0xFFFFFFFF; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 0.1; + + TrailEnt->d_alpha = -2.5; + TrailEnt->d_scale = 2.0; + + VectorCopy(self->origin, TrailEnt->origin); + + TrailEnt->velocity[0] = irand(-16, 16); + TrailEnt->velocity[1] = irand(-16, 16); + TrailEnt->velocity[2] = irand(-16, 16); + + AddEffect(NULL,TrailEnt); + + return true; +} + +// ************************************************************************************************ +// FXhpprojTrailThink +// ************************************************************************************************ + +static qboolean FXMorkTrailThink(struct client_entity_s *self,centity_t *owner) +{ + if (self->alpha <= 0.1 || self->r.scale <= 0.0) + return false; + + self->r.scale -= 0.1; + + return true; +} + +static qboolean FXCWTrailThink(struct client_entity_s *self,centity_t *owner) +{ + vec3_t forward; + if (self->alpha <= 0.1 || self->r.scale <= 0.0) + return false; + + self->r.scale -= 0.15; + + VectorCopy(owner->lerp_origin, self->r.origin); + + VectorCopy(self->r.origin, self->r.startpos); + + Vec3AddAssign(self->up, self->direction); + + AngleVectors(self->direction, forward, NULL, NULL); + + VectorMA(self->r.startpos, self->SpawnInfo, forward, self->r.endpos); + return true; +} + + +static qboolean FXMorkTrailThink2(struct client_entity_s *self,centity_t *owner) +{ + if (self->alpha <= 0.1 || self->r.scale <= 0.0) + return false; + + self->r.scale -= 0.15; + + return true; +} + +static qboolean FXMorkMissileTrailThink(struct client_entity_s *self,centity_t *owner) +{ +// client_entity_t *TrailEnt; + + self->r.scale = flrand(0.35, 0.65); + + MorkMakeLightningPiece(self->startpos, owner->origin, 2000, 400, false); + VectorCopy(owner->origin, self->startpos); + + return true; +} + +/*================== + + FX_M_QUAKE + + ==================*/ + +static qboolean FXQuakeThink (struct client_entity_s *self,centity_t *owner) +{ + if(self->LifeTime <= 0) + return (false); + + self->LifeTime -= 5; + Cvar_SetValue("quake_amount", self->LifeTime); + return (true); +} + +/*================== + + FX_M_POWERPUFF + + ==================*/ + +static qboolean FXMorkMissileTrailThink2(struct client_entity_s *self,centity_t *owner) +{ + client_entity_t *TrailEnt; + + self->r.scale = flrand(0.15, 0.35); + + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + owner->origin, + NULL, + 17); + + TrailEnt->radius = 2000; + + VectorCopy( owner->origin, TrailEnt->origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = Morkproj_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = 1.5; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 1.0; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( owner->origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -4.0; + TrailEnt->d_scale = 0.0; + TrailEnt->Update = FXMorkTrailThink2; + + AddEffect(NULL,TrailEnt); + + VectorCopy(owner->origin, self->startpos); + + return true; +} + +static qboolean FXMorkPPTrailThink(struct client_entity_s *self,centity_t *owner) +{ + client_entity_t *TrailEnt; + client_particle_t *spark; + int i, numparts; + vec3_t offset; + int parttype; + + if(self->r.color.r<250) + self->r.color.r += 8; + + if(self->r.color.g<150) + self->r.color.g += 4; + + if(self->r.color.b>100)//was r? + self->r.color.b -= 4; + + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + owner->origin, + NULL, + 17); + + TrailEnt->radius = 2000; + + VectorCopy( owner->origin, TrailEnt->origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = Morkproj_models + 2; + + TrailEnt->r.color = self->r.color; + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = 1.5 * self->r.scale/0.35; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = self->r.scale/0.35; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( owner->origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -4.0; + TrailEnt->d_scale = 0.0; + TrailEnt->Update = FXMorkTrailThink2; + + AddEffect(NULL,TrailEnt); + + VectorCopy(owner->origin, self->startpos); + + numparts = floor(irand(6, 9)*self->r.scale); + if (numparts>500) + numparts=500; + for(i = 0; i < numparts; i++) + { + parttype = irand(0, 6); + switch(parttype) + { + case 0: + parttype = PART_4x4_WHITE; + break; + case 1: + parttype = PART_4x4_BLUE2; + break; + case 2: + parttype = PART_4x4_BLUE3; + break; + case 3: + parttype = PART_8x8_BLUE_CIRCLE; + break; + case 4: + parttype = PART_8x8_BLUE_X; + break; + case 5: + parttype = PART_16x16_STAR; + break; + case 6: + parttype = PART_16x16_SPARK_B; + break; + default: + parttype = PART_4x4_WHITE; + break; + } + + spark = ClientParticle_new(parttype, self->r.color, 2000); + spark->acceleration[2] = -10; + spark->scale = flrand(3, 5); + spark->d_scale = flrand(-10.0, -15.0); + spark->color.a = irand(100, 200.0); + spark->d_alpha = flrand(-40.0, -32.0); + spark->duration = (255.0 * 2000.0) / -spark->d_alpha; // time taken to reach zero alpha + + VectorCopy(owner->origin, spark->origin); + offset[0] = flrand(-10, 10); + offset[1] = flrand(-10, 10); + offset[2] = flrand(0, 10); + VectorAdd(spark->origin, offset, spark->origin); + VectorSet(spark->velocity, offset[0] * (-1.3, -0.9), + offset[1] * (-1.3, -0.9), + flrand(50, 75)); + + AddParticleToList(self, spark); + } + + return true; +} + +#define EXPLODE_SPEED 160.0 +#define EXPLODE_GRAVITY (-320.0) +#define EXPLODE_SCALE 14.0 +#define EXPLODE_NUM_BITS 32 +#define EXPLODE_BALL_RANGE 20.0 +#define EXPLODE_BALL_DELAY 5 +#define EXPLODE_NUM_SMALLBALLS 3 +#define PP_EXPLODE_LIFETIME 50 + +#define NUM_Morkpp_models 6 + +static qboolean FXMPPExplosionBallThink(client_entity_t *explosion, centity_t *owner) +{ + explosion->LifeTime--; + if (explosion->LifeTime<=0) + return(false); + + if(explosion->dlight->intensity > 0.0F) + explosion->dlight->intensity -= 5.0F; + + // Spin the ball of fire while it expands and fades. + if((explosion->r.angles[0]+=(M_PI/64.0))>(M_PI*2.0)) + explosion->r.angles[0]=0.0; + + if((explosion->r.angles[1]+=(M_PI/64.0))>(M_PI*2.0)) + explosion->r.angles[1]=0.0; + + return(true); +} + +static qboolean FXMPPExplosionSmallBallThink(client_entity_t *explosion, centity_t *owner) +{ + client_entity_t *flash; + + explosion->LifeTime--; + if (explosion->LifeTime>PP_EXPLODE_LIFETIME) + { + return(true); + } + else if (explosion->LifeTime==PP_EXPLODE_LIFETIME) + { // The explosion ball becomes visible and flashes + fxi.Activate_Screen_Flash(0xff0077ff); + explosion->alpha = 1.0; + explosion->r.scale= 0.1; + explosion->d_alpha=-5.0; + explosion->d_scale=8.0; + + flash = ClientEntity_new(-1, explosion->r.flags, explosion->origin, NULL, 250); + flash->r.model = Morkpp_models + 2; + flash->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + flash->r.frame = 1; + flash->radius=128; + flash->r.scale=1.0; + flash->d_alpha=-4.0; + flash->d_scale=-4.0; + AddEffect(NULL, flash); + + return (true); + } + else if (explosion->LifeTime<=0) + { + return(false); + } + + // Spin the ball of fire while it expands and fades. + if((explosion->r.angles[0]-=(M_PI/64.0))>(M_PI*2.0)) + explosion->r.angles[0]=0.0; + + if((explosion->r.angles[1]+=(M_PI/64.0))>(M_PI*2.0)) + explosion->r.angles[1]=0.0; + + return(true); +} + +qboolean FXMPPExplosionCoreUpdate (client_entity_t *self, centity_t *owner) +{ + if(self->r.color.r<=50) + return(false); + + if(self->r.frame < 11) + self->r.frame++; + else if(self->r.frame == 11) + { + self->alpha = 0.0; + self->d_alpha = 0.0; + self->d_scale = -1; + self->dlight->d_intensity = -30; + } + + if(self->r.color.r>50) + self->r.color.r -= 1; + + if(self->r.color.g>10) + self->r.color.g -= 10; + + self->dlight->color = self->r.color; + return true; +} + +static qboolean FXMPPExplosionCoreThink(client_entity_t *core, centity_t *owner) +{ + client_entity_t *newcore; + vec3_t pos; + + core->LifeTime--; + if (core->LifeTime <= 0) + { + return(false); + } + + if(core->r.color.g>10) + core->r.color.g -= 10; + + // Spawn another trail core + VectorSet(pos, flrand(-8, 8), flrand(-8, 8), flrand(-8, 8)); + VectorAdd(pos, core->r.origin, pos); + newcore = ClientEntity_new(-1, core->r.flags, pos, NULL, 250); +// newcore = ClientEntity_new(-1, core->r.flags, pos, NULL, 100); +// newcore->Update = FXMPPExplosionCoreUpdate; + newcore->r.model = Morkpp_models + 3; + newcore->r.color.c = 0xFF0077ff; + newcore->r.frame = 0;//1 + newcore->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + newcore->radius = 128; + newcore->r.scale= core->r.scale; + newcore->alpha = core->alpha; + newcore->d_alpha= -(newcore->alpha*4.0); + newcore->d_scale= 2.0; + VectorCopy(core->velocity, newcore->velocity); + AddEffect(NULL, newcore); + + return (true); +} + +void FXMPPExplode(client_entity_t *explosion, centity_t *owner, int type, int flags, vec3_t origin, vec3_t dir) +{ + client_entity_t *subexplosion; + paletteRGBA_t color; + vec3_t ballorigin; + client_particle_t *spark; + int i; + + flags |= CEF_OWNERS_ORIGIN; + + // Create three smaller explosion spheres. + for (i=0; i < EXPLODE_NUM_SMALLBALLS; i++) + { + ballorigin[0] = origin[0] + flrand(-EXPLODE_BALL_RANGE, EXPLODE_BALL_RANGE) + (dir[0]*EXPLODE_BALL_RANGE); + ballorigin[1] = origin[1] + flrand(-EXPLODE_BALL_RANGE, EXPLODE_BALL_RANGE) + (dir[1]*EXPLODE_BALL_RANGE); + ballorigin[2] = origin[2] + flrand(-EXPLODE_BALL_RANGE, EXPLODE_BALL_RANGE) + (dir[2]*EXPLODE_BALL_RANGE); + subexplosion = ClientEntity_new(type, flags, ballorigin, NULL, 17); + subexplosion->r.model = Morkpp_models + 4; + subexplosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + subexplosion->alpha = 0.1; + subexplosion->r.scale=0.01; + subexplosion->radius=128; + + subexplosion->r.color.r = irand(150, 250); + subexplosion->r.color.g = irand(100, 200); + subexplosion->r.color.b = irand(50, 100); + + subexplosion->r.angles[PITCH] = flrand(-180, 180); + subexplosion->r.angles[YAW] = flrand(-180, 180); + subexplosion->r.angles[ROLL] = flrand(-180, 180); + + subexplosion->LifeTime=PP_EXPLODE_LIFETIME + 1 + (EXPLODE_BALL_DELAY*i); // Each successive ball has an additional delay. + subexplosion->Update = FXMPPExplosionSmallBallThink; + + AddEffect(NULL, subexplosion); + } + + // Create the main big explosion sphere. +// explosion = ClientEntity_new(type, flags, origin, NULL, 17); + + explosion->r.model = Morkpp_models + 1; + explosion->r.frame = 0; + + // explosion->r.model = Morkpp_models + 5; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->flags |= CEF_ADDITIVE_PARTS; + explosion->alpha = 1.0; + explosion->r.scale= 2;//0.1; + explosion->d_alpha=-0.3;//-2.0; + explosion->d_scale= 0.0;//4.0; + explosion->radius=128; + explosion->LifeTime=PP_EXPLODE_LIFETIME; + + explosion->r.color.c = 0xff00ffff; + color.c = 0xff0000ff; + + explosion->dlight = CE_DLight_new(color, 150.0F, -0.3F); + explosion->Update = FXMPPExplosionCoreUpdate; +// explosion->Update = FXMPPExplosionBallThink; + AddEffect(NULL, explosion); + + // Add some glowing blast particles. + VectorScale(dir,EXPLODE_SPEED,dir); + for(i = 0; i < EXPLODE_NUM_BITS; i++) + { + spark = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), color, 2000); + VectorSet(spark->velocity, flrand(-EXPLODE_SPEED, EXPLODE_SPEED), + flrand(-EXPLODE_SPEED, EXPLODE_SPEED), + flrand(-EXPLODE_SPEED, EXPLODE_SPEED)); + VectorAdd(spark->velocity, dir, spark->velocity); + spark->acceleration[2] = EXPLODE_GRAVITY; + spark->scale = EXPLODE_SCALE; + spark->d_scale = flrand(-20.0, -10.0); + spark->d_alpha = flrand(-400.0, -320.0); + spark->duration = (255.0 * 2000.0) / -spark->d_alpha; // time taken to reach zero alpha + + AddParticleToList(explosion, spark); + } + + // ...and a big-ass flash + explosion = ClientEntity_new(-1, flags, origin, NULL, 250); + explosion->r.model = Morkpp_models + 2; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->r.frame = 1; + explosion->radius=128; + explosion->r.scale=1.5; + explosion->d_alpha=-4.0; + explosion->d_scale=-4.0; + AddEffect(NULL, explosion); + + // ...and draw the MPP rising from the explosion + explosion = ClientEntity_new(type, flags, origin, NULL, 100); + explosion->r.model = Morkpp_models + 3; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->r.color.c = 0xFF00aaFF; + explosion->r.frame = 0; + explosion->radius=128; + explosion->r.scale=1.0; + VectorScale(dir, 0.25, explosion->velocity); +// explosion->velocity[2] += 64; + explosion->acceleration[2] = 64; + explosion->alpha = 1.0; + explosion->d_alpha=-1.5; + explosion->d_scale=2.0; + explosion->LifeTime = 6; + explosion->Update = FXMPPExplosionCoreThink; + AddEffect(NULL, explosion); + + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("weapons/ramphit1.wav"), 1, ATTN_NORM, 0); +} + +//================================================== + +void FXMorkMissileExplode(struct client_entity_s *self,centity_t *owner, vec3_t dir) +{ + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor={255,64,32,255}; + byte powerup = 0; + + Vec3ScaleAssign(32.0, dir); + + i = GetScaledCount(irand(12,16), 0.8); + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(FX_M_EFFECTS,0,owner->origin,NULL,500); + else + SmokePuff=ClientEntity_new(FX_M_EFFECTS,0,owner->origin,NULL,1500); + + SmokePuff->r.model = Morkproj_models + 1; + SmokePuff->r.scale=flrand(0.5,1.0); + SmokePuff->d_scale=-2.0; + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + SmokePuff->r.frame = 0; + + VectorRandomCopy(dir, SmokePuff->velocity, flrand(16.0, 64.0)); + + SmokePuff->acceleration[0] = flrand(-400, 400); + SmokePuff->acceleration[1] = flrand(-400, 400); + SmokePuff->acceleration[2] = flrand(-40, -60); + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + AddEffect(NULL,SmokePuff); + } +} + +/*=============================== + + FX_M_READYPP + + ===============================*/ +static qboolean FXMorkPPReadyThink(struct client_entity_s *self, centity_t *owner) +{ + int add_rate = 5; + client_particle_t *spark; + int i, numparts; + vec3_t offset; + int parttype; + paletteRGBA_t color={255,255,255,255}; + + if(self->LifeTimetime) + return (false); + + if(self->r.color.g<100) + self->r.color.g+=add_rate; + + if(self->r.color.b<250) + self->r.color.b+=add_rate; + + if(self->r.color.r<100) + self->r.color.r+=add_rate; + + if(self->r.color.a<251) + self->r.color.a+=add_rate; + + self->dlight->color = self->r.color; + if(self->dlight->intensity<246) + self->dlight->intensity += 10; + + + numparts = floor(irand(6, 9)*self->r.scale); + if (numparts>500) + numparts=500; + for(i = 0; i < numparts; i++) + { + parttype = irand(0, 6); + switch(parttype) + { + case 0: + parttype = PART_4x4_WHITE; + break; + case 1: + parttype = PART_4x4_BLUE2; + break; + case 2: + parttype = PART_4x4_BLUE3; + break; + case 3: + parttype = PART_8x8_BLUE_CIRCLE; + break; + case 4: + parttype = PART_8x8_BLUE_X; + break; + case 5: + parttype = PART_16x16_STAR; + break; + case 6: + parttype = PART_16x16_SPARK_B; + break; + default: + parttype = PART_4x4_WHITE; + break; + } + + spark = ClientParticle_new(parttype, color, 2000); + spark->acceleration[2] = 10; + spark->scale = flrand(3, 5); + spark->d_scale = flrand(-10.0, -15.0); + spark->color.a = irand(100, 200.0); + spark->d_alpha = flrand(-40.0, -32.0); + spark->duration = (255.0 * 2000.0) / -spark->d_alpha; // time taken to reach zero alpha + + offset[0] = flrand(-10, 10); + offset[1] = flrand(-10, 10); + offset[2] = flrand(0, 10); + VectorAdd(spark->origin, offset, spark->origin); + VectorSet(spark->velocity, offset[0] * (-1.3, -0.9), + offset[1] * (-1.3, -0.9), + flrand(50, 75)); + + AddParticleToList(self, spark); + } + + return (true); +} +/*===================== + + FX_M_SHIELD + + =====================*/ + +static qboolean FXMorkShieldThink(struct client_entity_s *self, centity_t *owner) +{ + return true; +} + +static qboolean FXMorkShieldForm(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *Trail; + + if (self->r.scale <= 2.5) + { + return false; + self->d_alpha = 0.0; + self->d_scale = 0.0; + self->Update = FXMorkShieldThink; + return true; + } + + if (self->r.scale <= 3.0 && !self->SpawnInfo) + { + self->SpawnInfo = 1; + Trail=ClientEntity_new(FX_M_EFFECTS, 0, self->origin, NULL, 100); + + Trail->r.model = Morkshield_models; + + Trail->r.flags |= RF_TRANSLUCENT | RF_FULLBRIGHT | RF_REFLECTION; + Trail->alpha = self->alpha; + Trail->r.scale = self->r.scale; + + Trail->d_scale = 4.0; + Trail->d_alpha = -0.15; + Trail->radius = 1000; + + AddEffect(NULL,Trail); + } + + self->flags &= ~CEF_DISAPPEARED; + + return true; +} + + +/*===================== + + FX_M_LIGHTNING + + =====================*/ + +#define M_LIGHTNING_RADIUS 40.0F +#define M_LIGHTNING_WIDTH 6.0 +#define M_LIGHTNING_WIDTH2 8.0 +client_entity_t *MorkMakeLightningPiece(vec3_t start, vec3_t end, float radius, int lifetime, qboolean plasma) +{ + client_entity_t *lightning; + vec3_t vec; + float dist, tile_num; + + VectorSubtract(end, start, vec); + dist = VectorNormalize(vec); + tile_num = dist/32; + + lightning = ClientEntity_new(-1, CEF_DONT_LINK, start, NULL, lifetime); + if(plasma) + { + lightning->r.model = Morklightning_models + 2; + lightning->r.frame = 2; + lightning->alpha = 2.55; + } + else + { + lightning->r.model = Morklightning_models; + lightning->alpha = 0.95; + } + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->r.scale = M_LIGHTNING_WIDTH; + lightning->r.tile = tile_num; + lightning->radius = radius; + lightning->d_alpha = -4.0; + VectorCopy(start, lightning->r.startpos); + VectorCopy(end, lightning->r.endpos); + lightning->r.spriteType = SPRITE_LINE; + AddEffect(NULL, lightning); + if(plasma) + return(lightning); + + lightning = ClientEntity_new(-1, CEF_DONT_LINK, start, NULL, lifetime * 2); + lightning->r.model = Morklightning_models + 1; + lightning->r.frame = irand(0, 1); + lightning->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + lightning->r.scale = M_LIGHTNING_WIDTH2; + lightning->radius = radius; + lightning->r.tile = 1; + lightning->alpha = 0.5; + lightning->d_alpha = -1.250; + VectorCopy(start, lightning->r.startpos); + VectorCopy(end, lightning->r.endpos); + lightning->r.spriteType = SPRITE_LINE; + AddEffect(NULL, lightning); + + return(lightning); +} + +// Occasional lightning bolt strikes inside +void MorkDoLightning(vec3_t groundpos, vec3_t airpos, qboolean random, qboolean plasma) +{ + vec3_t curpos, lastpos, top, bottom, refpoint, diffpos, rand; + float scale; + int i; + + if(!random) + { + VectorCopy(groundpos, bottom); + VectorCopy(airpos, top); + } + else + { + VectorSet(top, flrand(-M_LIGHTNING_RADIUS, M_LIGHTNING_RADIUS), flrand(-M_LIGHTNING_RADIUS, M_LIGHTNING_RADIUS), 0); + VectorAdd(airpos, top, top); + VectorSet(bottom, flrand(-M_LIGHTNING_RADIUS, M_LIGHTNING_RADIUS), flrand(-M_LIGHTNING_RADIUS, M_LIGHTNING_RADIUS), 0); + VectorAdd(groundpos, bottom, bottom); + } + + VectorSubtract(top, bottom, diffpos); + VectorScale(diffpos, 0.2, diffpos); + scale = (airpos[2] - groundpos[2]) / 10.0; + + VectorCopy(bottom, lastpos); + VectorCopy(bottom, refpoint); + for (i=0; i<5; i++) + { + VectorAdd(refpoint, diffpos, refpoint); + VectorSet(rand, flrand(-scale, scale), flrand(-scale, scale), flrand(-scale, scale)); + VectorAdd(refpoint, rand, curpos); + if(!random) + MorkMakeLightningPiece(airpos, lastpos, scale, 250, false); + else + MorkMakeLightningPiece(curpos, lastpos, scale, 250, false); + VectorCopy(curpos, lastpos); + } +} + +void MorkDoEyesLightning(centity_t *owner, vec3_t groundpos) +{ + vec3_t curpos, lastpos, top, bottom, refpoint, diffpos, rand; + float scale; + int i, e; + matrix3_t RotationMatrix; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return; + + VectorCopy(groundpos, bottom); + + for(e = 0; e<2; e++) + { + Matrix3FromAngles(owner->lerp_angles,RotationMatrix); + + Matrix3MultByVec3(RotationMatrix, + owner->referenceInfo->references[MORK_LEYEREF + e].placement.origin, + top); + + VectorAdd(owner->current.origin, top, top); + + VectorSubtract(bottom, top, diffpos); + VectorScale(diffpos, 0.2, diffpos); + scale = (top[2] - groundpos[2]) / 10.0; + + VectorCopy(top, lastpos); + VectorCopy(top, refpoint); + for (i=0; i<5; i++) + { + VectorAdd(refpoint, diffpos, refpoint); + VectorSet(rand, flrand(-scale, scale), flrand(-scale, scale), flrand(-scale, scale)); + VectorAdd(refpoint, rand, curpos); + MorkMakeLightningPiece(curpos, lastpos, scale, 250, false); + VectorCopy(curpos, lastpos); + } + } +} + +/*static vec3_t plas_start; +static vec3_t plas_end; + +qboolean FXCWRingUpdate (struct client_entity_s *self, centity_t *owner) +{ + vec3_t plas_dir; + float plas_length; + + self->SpawnInfo++; + + if(self->SpawnInfo >= 100) + return (false); + + VectorSubtract(plas_start, plas_end, plas_dir); + plas_length = VectorNormalize(plas_dir); + assert(plas_length); + + VectorMA(plas_end, (float)(self->SpawnInfo)/100 * plas_length, plas_dir, self->r.origin); + + vectoangles(plas_dir, self->r.angles); + + return (true); +} +*/ +void FizzleEffect (client_entity_t *self, vec3_t surface_top, vec3_t normal); +void CWPlasma(vec3_t top, vec3_t groundpos, int flags) +{ + vec3_t curpos, lastpos, bottom, refpoint, diffpos, rand, normal; + float scale; + int i; +// client_entity_t *ring; + + //store in local globals +// VectorCopy(top, plas_start); +// VectorCopy(groundpos, plas_end); + + VectorCopy(groundpos, bottom); + + VectorSubtract(bottom, top, diffpos); + scale = VectorLength(diffpos) / 100.0; + VectorScale(diffpos, -1, normal); + VectorScale(diffpos, 0.2, diffpos); + + VectorCopy(top, lastpos); + VectorCopy(top, refpoint); + for (i=0; i<5; i++) + { + VectorAdd(refpoint, diffpos, refpoint); + VectorSet(rand, flrand(-scale, scale), flrand(-scale, scale), flrand(-scale, scale)); + VectorAdd(refpoint, rand, curpos); + MorkMakeLightningPiece(curpos, lastpos, scale, 250, true); + VectorCopy(curpos, lastpos); + + if(flags & CEF_FLAG7 && !irand(0,9))//make it smoke? + { + FXClientScorchmark(curpos, diffpos); + FizzleEffect (NULL, curpos, normal); + } + } + + //rings +/* + if(flags & CEF_FLAG6) + { + ring = ClientEntity_new(FX_M_EFFECTS, 0, bottom, NULL, 20); + ring->r.model = CW_models + 1; + ring->r.flags |= RF_FIXED | RF_GLOW | RF_TRANSLUCENT; + ring->r.scale = 1.0f; + ring->alpha = 0.5; + ring->SpawnInfo = 0; + ring->Update = FXCWRingUpdate; + AddEffect(NULL, ring); + }*/ +} +/*=============================== + + FX_M_EYES + + ===============================*/ +#define FIREEYES_PARTS 4 +#define FIREEYES_RADIUS 6.0 +#define FIREEYES_SPEED 16.0 +#define FIREEYES_SCALE 12.0 +#define FIREEYES_ACCEL 32.0 + +#define SMOKEEYES_RADIUS 2.0 +#define SMOKEEYES_SCALE 0.25 +#define SMOKEEYES_ALPHA 0.5 + +qboolean MorkEyesParticleUpdate(client_particle_t *self, qboolean ignore) +{ + int fade_down = 0, darken = 0; + float dec_rate = 5; + + if(self->color.g>=10) + self->color.g-=dec_rate; + else + { + fade_down++; + if(self->color.g) + self->color.g--; + else + darken++; + } + + if(self->color.b>=5) + self->color.b-=dec_rate; + else + { + fade_down++; + if(self->color.b) + self->color.b--; + else + darken++; + } + + if(fade_down) + { + if(self->color.r>=15) + { + self->color.r-=dec_rate; + } + else if(self->color.r) + self->color.r--; + else + darken++; + + + if(self->color.r>150 && self->color.r<156) + { + float d_time, d_time2; + int d_msec; + + d_msec = (fxi.cl->time - self->startTime); + d_time = d_msec * 0.001f; + d_time2 = d_time * d_time * 0.5; + self->origin[0] = self->origin[0] + (self->velocity[0] * d_time) + (self->acceleration[0] * d_time2); + self->origin[1] = self->origin[1] + (self->velocity[1] * d_time) + (self->acceleration[1] * d_time2); + self->origin[2] = self->origin[2] + (self->velocity[2] * d_time) + (self->acceleration[2] * d_time2); + + self->velocity[0] = flrand(-0.2, 0.2); + self->velocity[1] = flrand(-0.2, 0.2); + self->acceleration[0] = self->acceleration[1] = 0; + self->startTime = fxi.cl->time; + self->d_alpha = -0.01; + self->d_scale = 0.01; + } + else if(self->color.r<30 && self->d_alpha != -0.1) + { + self->d_alpha = -0.1; + self->d_scale = 0.1; + } + } + return true; +} + +static qboolean FXMorkEyes (struct client_entity_s *self, centity_t *owner) +{ + vec3_t angles, forward, right, pos, pos2, side; + int num_parts, e, n; + client_particle_t *flame; + +// if(self->LifeTimetime) +// return false; + + VectorScale(owner->current.angles, 180.0/M_PI, angles); + AngleVectors(angles, forward, right, NULL); + + //left or right eye + e = self->LifeTime; + + VectorCopy(owner->current.origin, pos); + pos[2] += 36; + if(!e) + {//right side + VectorCopy(right, side); + VectorMA(pos, 2, right, pos); + } + else + { + VectorScale(right, -1, side); + VectorMA(pos, -2, right, pos); + } + VectorMA(pos, 8, forward, pos); + + num_parts = irand(3, 7); + + for(n = 0; nr.color, 50);// + + VectorCopy(pos, flame->origin);//pos2 + flame->scale = 0.75; + + // Make the fire shoot out the front and to the side + VectorScale(side, 3, flame->velocity); + VectorScale(side, -1, flame->acceleration); + flame->acceleration[2] = 7; + + flame->d_scale = flrand(-0.1, -0.15); + flame->d_alpha = flrand(-200.0, -160.0); + flame->duration = ((255.0 * 1000.0) / -flame->d_alpha)*2; // time taken to reach zero alpha +// flame->extraUpdate = MorkEyesParticleUpdate; + + AddParticleToList(self, flame); + } + return (true); +} + +static qboolean FXMorkEyes2 (struct client_entity_s *self, centity_t *owner) +{ + vec3_t angles, forward, right, pos, pos2, side; + int num_parts, e, n; + client_particle_t *flame; + matrix3_t RotationMatrix; + client_entity_t *fx; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return true; + +// if(self->LifeTimetime) +// return false; + +// VectorScale(owner->current.angles, 180.0/M_PI, angles); + VectorScale(owner->lerp_angles, 180.0/M_PI, angles); + AngleVectors(angles, forward, right, NULL); + + //left or right eye + e = self->LifeTime; + + Matrix3FromAngles(((centity_t *)(self->extra))->lerp_angles,RotationMatrix); + + Matrix3MultByVec3(RotationMatrix, + ((centity_t *)(self->extra))->referenceInfo->references[MORK_LEYEREF + e].placement.origin, + pos); + + /*Matrix3MultByVec3(RotationMatrix, +VectorCopy ((centity_t *)(self->extra))->referenceInfo->references[MORK_LEYEREF + e].placement.direction, + dir);*/ + + +// VectorCopy(((centity_t *)(self->extra))->referenceInfo->references[MORK_RHANDREF].placement.direction, +// dir); + +// VectorNormalize(dir); + + if(e) + { + VectorCopy(right, side); + VectorMA(pos, 2, right, pos); + } + else + { + VectorScale(right, -1, side); + VectorMA(pos, -2, right, pos); + } + + VectorMA(pos, 8, forward, pos); + +// Com_Printf("%4.2f z diff\n", pos[2]); + + VectorAdd(((centity_t *)(self->extra))->current.origin, pos, pos); + + num_parts = irand(3, 7); + + //update the controlling Effect + VectorCopy(pos, self->origin); + + for(n = 0; nr.color, 50);// + + VectorCopy(pos, flame->origin);//pos2 + flame->scale = 0.75; + + // Make the fire shoot out the front and to the side + VectorScale(side, 3, flame->velocity); + VectorScale(side, -1, flame->acceleration); + flame->acceleration[2] = 7; + + flame->d_scale = flrand(-0.1, -0.15); + flame->d_alpha = flrand(-200.0, -160.0); + flame->duration = ((255.0 * 1000.0) / -flame->d_alpha)*2; // time taken to reach zero alpha +// flame->extraUpdate = MorkEyesParticleUpdate; + + AddParticleToList(self, flame); + } + + fx=ClientEntity_new(FX_M_EFFECTS, 0, pos, NULL, 20); + fx->r.color.c = 0xe5007fff; + fx->r.model = Morkproj_models + 3; + fx->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + fx->r.scale = flrand(0.15, 0.25); + fx->alpha = flrand(0.85, 0.95); + fx->radius = 100.0f; + AddEffect(NULL,fx); + + return (true); +} + + +/*=============================== + + FX_M_SHOVE + + ===============================*/ + +static qboolean ShoveThink (struct client_entity_s *self,centity_t *owner) +{ + int dec_rate = 5; + if (self->alpha <= 0.1)// || self->r.scale > 0.0) + return false; + + self->r.scale += 0.1; + + if(self->r.color.g>10) + self->r.color.g-=dec_rate; + + if(self->r.color.b>25) + self->r.color.b-=dec_rate; + + if(self->r.color.r>10) + self->r.color.r-=dec_rate; + + if(self->r.color.a>50) + self->r.color.a-=dec_rate; + + return (true); +} + +static qboolean ShoveInnerThink (struct client_entity_s *self,centity_t *owner) +{ + int dec_rate = 5; + if (self->alpha <= 0.1 || self->alpha > 2.0 || self->r.scale <= 0.1) + return false; + + self->r.scale -= 0.1; + + return (true); +} + +static qboolean ShoveOuterThink (struct client_entity_s *self,centity_t *owner) +{ + int dec_rate = 0.05; + if (self->alpha <= 0.1 || self->alpha > 1.0) + return false; + + self->r.scale += 0.1; + + return (true); +} + +static qboolean FXMorkShove(struct client_entity_s *self,centity_t *owner) +{ + client_entity_t *TrailEnt; + vec3_t forward, right, pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8, crap, angles; + vec3_t lllf, llf, lf, rrrf, rrf, rf, temp_r, temp_f; + float dist; + int i, j; + + if(self->LifeTimetime) + return false; + + VectorScale(self->endpos2, 180.0/M_PI, angles); + AngleVectors(angles, forward, right, NULL); + VectorSubtract(self->r.origin, self->startpos2, crap); + dist = VectorNormalize(crap); + + VectorScale(right, -0.75, temp_r); + VectorScale(forward, 0.25, temp_f); + VectorAdd(temp_r, temp_f, lllf); + VectorNormalize(lllf); + + VectorScale(right, -0.5, temp_r); + VectorScale(forward, 0.5, temp_f); + VectorAdd(temp_r, temp_f, llf); + VectorNormalize(llf); + + VectorScale(right, -0.25, temp_r); + VectorScale(forward, 0.75, temp_f); + VectorAdd(temp_r, temp_f, lf); + VectorNormalize(lf); + + VectorScale(right, 0.25, temp_r); + VectorScale(forward, 0.75, temp_f); + VectorAdd(temp_r, temp_f, rf); + VectorNormalize(rf); + + VectorScale(right, 0.5, temp_r); + VectorScale(forward, 0.5, temp_f); + VectorAdd(temp_r, temp_f, rrf); + VectorNormalize(rrf); + + VectorScale(right, 0.75, temp_r); + VectorScale(forward, 0.25, temp_f); + VectorAdd(temp_r, temp_f, rrrf); + VectorNormalize(rrrf); + + VectorMA(self->startpos2, -dist, right, pos1); + VectorMA(self->startpos2, dist, lllf, pos2); + VectorMA(self->startpos2, dist, llf, pos3); + VectorMA(self->startpos2, dist, lf, pos4); + VectorMA(self->startpos2, dist, rf, pos5); + VectorMA(self->startpos2, dist, rrf, pos6); + VectorMA(self->startpos2, dist, rrrf, pos7); + VectorMA(self->startpos2, dist, right, pos8); + + for(j=0;j<2;j++) + { + if(j) + {//extra 10 to avoid depth clip confusion + VectorMA(pos1, -10, right, pos1); + VectorMA(pos2, 10, lllf, pos2); + VectorMA(pos3, 10, llf, pos3); + VectorMA(pos4, 10, lf, pos4); + VectorMA(pos5, 10, rf, pos5); + VectorMA(pos6, 10, rrf, pos6); + VectorMA(pos7, 10, rrrf, pos7); + VectorMA(pos8, 10, right, pos8); + } + for(i = 0; i<7; i++) + { + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + self->r.origin, + NULL, + 17); + + TrailEnt->radius = 2000; + + VectorCopy( self->r.origin, TrailEnt->origin ); + + switch(i) + { + case 0: + VectorCopy(pos1 , TrailEnt->r.startpos); + VectorCopy(pos2 , TrailEnt->r.endpos); + break; + case 1: + VectorCopy(pos2 , TrailEnt->r.startpos); + VectorCopy(pos3 , TrailEnt->r.endpos); + break; + case 2: + VectorCopy(pos3 , TrailEnt->r.startpos); + VectorCopy(pos4 , TrailEnt->r.endpos); + break; + case 3: + VectorCopy(pos4 , TrailEnt->r.startpos); + VectorCopy(pos5 , TrailEnt->r.endpos); + break; + case 4: + VectorCopy(pos5 , TrailEnt->r.startpos); + VectorCopy(pos6 , TrailEnt->r.endpos); + break; + case 5: + VectorCopy(pos6 , TrailEnt->r.startpos); + VectorCopy(pos7 , TrailEnt->r.endpos); + break; + case 6: + VectorCopy(pos7 , TrailEnt->r.startpos); + VectorCopy(pos8 , TrailEnt->r.endpos); + break; + } + + /* TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = Morkproj_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = (dist/32)*4; + if(TrailEnt->r.scale<1) + TrailEnt->r.scale = 1; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 1.0; + TrailEnt->d_alpha = -1.5; + TrailEnt->d_scale = 0.5;*/ + TrailEnt->Update = ShoveThink; + + if(j) + {//white inner + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = Morkproj_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = (dist/32); + if(TrailEnt->r.scale<1) + TrailEnt->r.scale = 1; + TrailEnt->alpha = 2.0; + TrailEnt->r.scale = 1.0; + + TrailEnt->d_alpha = -1.0; + TrailEnt->d_scale = -0.1; + TrailEnt->Update = ShoveInnerThink; + // TrailEnt->Update = FXMorkTrailThink_old; + } + else + {//blue outer + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = Morkproj_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = (dist/32)*4; + if(TrailEnt->r.scale<4) + TrailEnt->r.scale = 4; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 4.0; + TrailEnt->r.color.r = 100; + TrailEnt->r.color.g = 75; + TrailEnt->r.color.b = 250; + TrailEnt->d_alpha = -0.5; + TrailEnt->Update = ShoveOuterThink; + TrailEnt->d_scale = 0.1; + // TrailEnt->Update = FXMorkTrailThink_old; + } + AddEffect(NULL,TrailEnt); + } + } + + return true; +} + + +/*=============================== + + FX_M_BEAM + + ===============================*/ +qboolean ParticleFadeToBlue(client_particle_t *self, qboolean ignore) +{ + float dec_rate = 5; + + if(self->color.g>=10) + self->color.g-=dec_rate; + + if(self->color.b>=50) + self->color.b-=dec_rate; + + if(self->color.r>=15) + self->color.r-=dec_rate; + + return true; +} + +static qboolean FXMorkMissileTrailThink_old(struct client_entity_s *self,centity_t *owner) +{ + client_entity_t *TrailEnt; + + //VectorCopy(owner->origin, self->origin); + + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + owner->origin, + NULL, + 17); + + TrailEnt->radius = 2000; + + VectorCopy( owner->origin, TrailEnt->origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = Morkproj_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = 4; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 1.0; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( owner->origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -1.5; + TrailEnt->d_scale = 0.0; + TrailEnt->Update = FXMorkTrailThink_old; + + AddEffect(NULL,TrailEnt); + + VectorCopy(owner->origin, self->startpos); + + return true; +} + +static qboolean FXMorkBeamCircle (struct client_entity_s *self,centity_t *owner) +{ + vec3_t angles, up; + + self->LifeTime+=54; + + VectorSet(angles, self->r.angles[PITCH], self->r.angles[YAW], anglemod(self->LifeTime)); + AngleVectors(angles, NULL, NULL, up); + VectorMA(owner->current.origin, 12, up, self->r.origin); + + MorkMakeLightningPiece(self->startpos, self->r.origin, 2000, 1000, false); + + VectorCopy(self->r.origin, self->startpos); + + return true; +} + +static qboolean FXMorkBeam (struct client_entity_s *self,centity_t *owner) +{ + client_entity_t *TrailEnt; + int numparts, parttype; + client_particle_t *spark; + int i; + //VectorCopy(owner->origin, self->origin); +//Make inner beam + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + owner->origin, + NULL, + 17); + + TrailEnt->radius = 2000; + + VectorCopy( owner->origin, TrailEnt->origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = Morkproj_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->alpha = 2.0; + TrailEnt->r.scale = 1.0; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( owner->origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -1.0; + TrailEnt->d_scale = -0.1; + TrailEnt->Update = FXMorkTrailThink_old; + + AddEffect(NULL,TrailEnt); + +//make outer beam + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + owner->origin, + NULL, + 17); + + TrailEnt->radius = 2000; + + VectorCopy( owner->origin, TrailEnt->origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = Morkproj_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = 16; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 4.0; + TrailEnt->r.color.r = 100; + TrailEnt->r.color.g = 75; + TrailEnt->r.color.b = 250; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( owner->origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -0.6; + TrailEnt->d_scale = -0.5; + + TrailEnt->Update = FXMorkTrailThink_old; + + AddEffect(NULL,TrailEnt); + + VectorCopy(owner->origin, self->startpos); + + numparts = floor(irand(6, 9)*self->r.scale); + if (numparts>500) + numparts=500; + for(i = 0; i < numparts; i++) + { + parttype = irand(0, 4); + switch(parttype) + { + case 0: + parttype = PART_4x4_WHITE; + break; + case 1: + parttype = PART_16x16_STAR; + break; + case 2: + parttype = PART_32x32_BUBBLE; + break; + case 3: + parttype = PART_16x16_SPARK_B; + break; + case 4: + parttype = PART_8x8_BLUE_CIRCLE; + break; + default: + parttype = PART_4x4_WHITE; + break; + } + + spark = ClientParticle_new(parttype, self->r.color, 20); + spark->scale = flrand(1, 2); + spark->d_scale = flrand(-1, -1.5); + spark->color.r = 255; + spark->color.g = 255; + spark->color.b = 255; + spark->color.a = irand(100, 200.0); + spark->d_alpha = flrand(-60.0, -42.0); + spark->duration = flrand(1500, 3000); + spark->acceleration[2] = flrand(10, 20); +// spark->extraUpdate = ParticleFadeToBlue; + + VectorSet(spark->origin, flrand(-10,10), + flrand(-10,10), + flrand(-10, 10)); + + AddParticleToList(TrailEnt, spark); + } + + return true; +} + +/*=============================== + + FX_M_RREFS + + ===============================*/ + +qboolean MorkFirstSeenInit(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *fx; + + self->refMask |= MORK_MASK; + + EnableRefPoints(owner->referenceInfo, self->refMask); + + self->AddToView = NULL; + self->Update = KeepSelfAI; + +//Make the eyes + fx=ClientEntity_new(FX_M_EFFECTS, CEF_NO_DRAW|CEF_OWNERS_ORIGIN | CEF_ABSOLUTE_PARTS, owner->current.origin, NULL, 20); + fx->flags |= CEF_NO_DRAW | CEF_ABSOLUTE_PARTS; + fx->Update = FXMorkEyes2; + fx->LifeTime = 0; + fx->r.color.c = 0xe5007fff; + fx->dlight=CE_DLight_new(fx->r.color,60.0f,0.0f); + fx->AddToView = LinkedEntityUpdatePlacement; + fx->extra = (void *)owner; + + AddEffect(owner,fx); + //-------------------------------------- + fx=ClientEntity_new(FX_M_EFFECTS, CEF_NO_DRAW|CEF_OWNERS_ORIGIN | CEF_ABSOLUTE_PARTS, owner->current.origin, NULL, 20); + fx->flags |= CEF_NO_DRAW|CEF_ABSOLUTE_PARTS; + fx->Update = FXMorkEyes2; + fx->LifeTime = 1; + fx->r.color.c = 0xe5007fff; + fx->dlight=CE_DLight_new(fx->r.color,60.0f,0.0f); + fx->AddToView = LinkedEntityUpdatePlacement; + fx->extra = (void *)owner; + + AddEffect(owner,fx); + return true; +} + +void FXMorkReadyRefs (centity_t *owner,int type,int flags,vec3_t origin) +{ + client_entity_t *self; + + flags |= CEF_NO_DRAW; + self = ClientEntity_new(type, flags, origin, NULL, 17); + + self->Update = NULL; + self->AddToView = MorkFirstSeenInit; + + AddEffect(owner, self); +} + + +static qboolean DreamyHyperMechaAtomicGalaxyPhaseIIPlusEXAlphaSolidProRad_ParticleUpdate_opt (struct client_particle_s *self, int crap) +{ + float add_rate = 5; + float d_time, d_time2; + int d_msec, yaw; + vec3_t dir, angles, right;//, center_dist, part_dist; + float dist, counter;//, view_dist; + float sum; + +/*======================= + + Further optimization: have one think and 50 others trail behind it + with a 0.1 - 10 ms offset? Or using it's velocity as the + oldorigin and it's own velocity as an offset off that velocity... + need to use the ->next field? + + =======================*/ + + + d_msec = (fxi.cl->time - self->startTime); + d_time = d_msec * 0.001f; + d_time2 = d_time * d_time * 0.5; + + VectorSubtract(self->acceleration, self->origin, dir); + dist = VectorLengthSquared(dir);//no quare root! + //normalization trick + sum = Q_fabs(dir[0]) + Q_fabs(dir[1]) + Q_fabs(dir[2]); + dir[0] /= sum; + dir[1] /= sum; + dir[2] /= sum; + + if (!fx_FreezeWorld) + { + if(dist< 22500) + { + if(self->color.g<250) + self->color.g+=2; + + if(self->color.b<254) + self->color.b+=2; + + if(self->color.r<250) + self->color.r+=2; + } + else if(dist<32400) + { + if(self->color.b<255) + self->color.b++; + } + + if(dist < 100) + {//shoot out sooner? + if(!irand(0, 10)) + {//spray out + VectorCopy(self->acceleration, self->origin); + if(!irand(0, 1)) + VectorSet(self->acceleration, 0, 0, 10); + else + VectorSet(self->acceleration, 0, 0, -10); + VectorClear(self->velocity); + VectorSet(self->velocity, flrand(-2, 2), flrand(-2, 2), 0); + self->d_alpha = -40.0f; + self->scale = flrand(2.0, 3.0); + self->d_scale = 0.5f; +// self->extraUpdate = NULL; + self->duration = Q_fabs((self->color.a/(self->d_alpha/255)) * 1000); + self->startTime = fxi.cl->time; + return (true); + } + self->scale = 20;//dist == 200, scale = 0.1; dist = 0, scale = 5 + } + else if(dist<2500) + { + self->scale = (10000 - dist)/10000 * 14;//dist == 200, scale = 0.1; dist = 0, scale = 5 + self->d_scale = 0.0f; + } + else if(dist<22500) + { + self->scale = (44100 - dist)/44100 * 7;//dist == 200, scale = 0.1; dist = 0, scale = 5 + self->d_scale = 0.0f; + } + + if (dir[YAW] == 0 && dir[PITCH] == 0) + yaw = 0; + else + {//ignore pitch? shouldn't be any! + yaw = (int) (atan2(dir[YAW], dir[PITCH]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + } + + VectorSet(angles, 0, yaw, 0); + AngleVectors(angles, NULL, right, NULL); + + counter = self->duration - 1000000000; + self->duration = 1000000000 + counter + 1; + if(counter>1000) + counter = 1000; + + VectorScale(right, -1000/(1000 - counter), right); + VectorScale(dir, 1000/(1000 - counter), dir); + VectorAdd(dir, right, dir); + sum = Q_fabs(dir[0]) + Q_fabs(dir[1]) + Q_fabs(dir[2]); + dir[0] /= sum; + dir[1] /= sum; + dir[2] /= sum; +//Store oldorigin in velocity for particles that trail me +//use velocity as offset for trailing particles + VectorAdd(self->origin, dir, self->origin); + } + +//L-o-D +/*Only if one of below used + VectorSubtract(fxi.cl->refdef.vieworg, self->origin, part_dist); + view_dist = VectorLengthSquared(part_dist); +*/ +/*//Do only if not high detail + if(view_dist>65536) + self->type = PART_4x4_WHITE;//too far away, use smaller particle + else + self->type = PART_32x32_ALPHA_GLOBE;//closer, use nicer particles + self->type &= ~PFL_DRAWLAST;//done auto above +*/ + +//PLANETS! - Ultra high detail!!! +/* + if(view_dist<257) + {//closer than 16 to viewport draw planets + client_particle_t *planet; + int p; + vec3_t forward; + client_entity_t *owner; + + self->type = PART_16x16_STAR; + for(p = 1; pvelocity[0] + 1; p++) + {//number of planets + planet = ClientParticle_new(PART_4x4_WHITE, self->color, 10); + + VectorClear(angles); + angles[YAW] = p * 60;//counter/10 + (p * self->velocity[1]); + AngleVectors(angles, forward, NULL, NULL); + +// if(DotProduct(forward, part_dist)>0) + planet->type |= PFL_DRAWLAST; + +// VectorMA(self->origin, self->scale + p * 2, forward, planet->origin);//self->velocity[1] / 10 + VectorMA(self->origin, 10 + p * 2, forward, planet->origin); + planet->acceleration[2] = 0; + + planet->d_alpha = 0; + planet->scale = 1;//p * self->velocity[1] / 100 * self->scale; + planet->color.r = self->color.r;// - p * self->velocity[1]/100; + planet->color.g = self->color.g;//- p * self->velocity[1]/100; + planet->color.b = self->color.b;// - p * self->velocity[1]/100; + planet->color.a = 1; + planet->extraUpdate = KeepSelfAI; + + owner = ((client_entity_t *)((long)(self->velocity[2]))); + + owner->flags|=(CEF_ABSOLUTE_PARTS | CEF_STATIC_PARTICLES); + + AddParticleToList(owner, planet); + } + + } +*/ + +/*Again, High detail +//draw in front? + if(dist>10000) + {//at least 100 away from core + VectorSubtract(fxi.cl->refdef.vieworg, self->acceleration, center_dist); + if(view_disttype |= PFL_DRAWLAST; + } + } +*/ + return (true); +} + +static qboolean DreamyHyperMechaAtomicGalaxyPhaseIIPlusEXAlphaSolidProRad_SpawnerUpdate (struct client_entity_s *self, centity_t *owner) +{ + vec3_t angles, forward, o_pos, pos; + int num_parts, n; + client_particle_t *star; + + self->r.angles[YAW] += 0.1; + VectorSet(angles, 0, self->r.angles[YAW] + irand(-3, 3) * 60, 0); + AngleVectors(angles, forward, NULL, NULL); + + //FIXME: staff! + VectorCopy(owner->current.origin, o_pos); + + VectorMA(o_pos, flrand(195, 205), forward, pos); + + num_parts = irand(3, 7); + + self->r.color.r = 0; + self->r.color.g = 0; + self->r.color.b = 0; + for(n = 0; nr.color, 3000);// + //use 4x4? + VectorCopy(pos, star->origin);//pos2 + VectorSet(star->velocity, + irand(1, 12),//number of planets + irand(1, 100),//color offset of planets + ((long)(&owner)));//owning fx entity + VectorCopy(o_pos, star->acceleration);//used for homing + star->scale = flrand(0.3, 0.75); + star->d_scale = 0.3; + star->color.a = 200; + star->d_alpha = 0.1; + star->duration = 1000000000; + +// star->extraUpdate = DreamyHyperMechaAtomicGalaxyPhaseIIPlusEXAlphaSolidProRad_ParticleUpdate_opt; + + AddParticleToList(self, star); + } + + return (true); +} + +void DreamyHyperMechaAtomicGalaxyPhaseIIPlusEXAlphaSolidProRad (centity_t *owner,int type,int flags, vec3_t org) +{ + client_entity_t *fx; + + fx=ClientEntity_new(type, CEF_NO_DRAW|CEF_OWNERS_ORIGIN, owner->current.origin, NULL, 20); + + fx->flags |= (CEF_NO_DRAW|CEF_ABSOLUTE_PARTS); + fx->Update = DreamyHyperMechaAtomicGalaxyPhaseIIPlusEXAlphaSolidProRad_SpawnerUpdate ; + fx->radius = 1000.0f; + fx->r.color.c = 0xFFFF3377; + fx->dlight=CE_DLight_new(fx->r.color,200.0f,0.0f); + fx->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner,fx); + +//------------------------------------------------------------------------- + + fx=ClientEntity_new(FX_M_EFFECTS, 0, owner->current.origin, NULL, 10000000); + + fx->r.color.c = 0xFFFFFFFF; + fx->r.model = Morkproj_models + 3; + fx->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + fx->r.scale = 3; + fx->alpha = 1; + fx->Update = KeepSelfAI; + fx->radius = 1000.0f; + + AddEffect(owner, fx); +} + +void ImpFireBallExplode(struct client_entity_s *self,centity_t *owner, vec3_t dir) +{ + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor={255,64,32,255}; + byte powerup = 0; + + Vec3ScaleAssign(32.0, dir); + + i = GetScaledCount(irand(12,16), 0.8); + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(FX_M_EFFECTS,0,owner->origin,NULL,500); + else + SmokePuff=ClientEntity_new(FX_M_EFFECTS,0,owner->origin,NULL,1500); + + SmokePuff->r.model = Imp_models + 1; + SmokePuff->r.scale=flrand(0.5,1.0); + SmokePuff->d_scale=-2.0; + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + SmokePuff->r.frame = 0; + + VectorRandomCopy(dir, SmokePuff->velocity, flrand(16.0, 64.0)); + + SmokePuff->acceleration[0] = flrand(-400, 400); + SmokePuff->acceleration[1] = flrand(-400, 400); + SmokePuff->acceleration[2] = flrand(-40, -60); + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + AddEffect(NULL,SmokePuff); + } +} + +int ImpFireBallUpdate (struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *p; + client_entity_t *TrailEnt; + vec3_t angles, fwd, right; + int num_parts, i; + paletteRGBA_t LightColor; + + VectorScale(self->r.angles, 180.0/M_PI, angles); + AngleVectors(angles, fwd, right, NULL); + + LightColor.c = 0xe5007fff; + num_parts = irand(3, 7); + for(i = 0; i < num_parts; i++) + { + p = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), LightColor, 1000); + VectorSet(p->origin, flrand(-4, 4), flrand(-4, 4), flrand(-4, 4)); + VectorAdd(self->r.origin, p->origin, p->origin); + p->scale = flrand(0.1, 0.5); + p->type |= PFL_ADDITIVE; + + VectorSet(p->velocity, flrand(-10, 10), flrand(-10, 10), flrand(-1.0, 1.0)); + // Make the fire shoot out the back and to the side + VectorMA(p->velocity, flrand(-40, -10), fwd, p->velocity); + // Alternate left and right side of phoenix + if (i&0x01) + VectorMA(p->velocity, flrand(-10, -2), right, p->velocity); + else + VectorMA(p->velocity, flrand(10, 2), right, p->velocity); + p->acceleration[2] = flrand(2, 10); + p->d_scale = flrand(-15.0, -10.0); + p->d_alpha = flrand(-200.0, -160.0); + p->duration = (255.0 * 1000.0) / -p->d_alpha; // time taken to reach zero alpha + + + AddParticleToList(self, p); + } + +//trail + + self->r.scale = flrand(0.35, 0.65); + + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + owner->origin, + NULL, + 17); + + TrailEnt->radius = 2000; + + VectorCopy( owner->origin, TrailEnt->origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA | RF_TRANS_ADD; + TrailEnt->r.model = Morkproj_models + 2; + + TrailEnt->r.color.r = 180; + TrailEnt->r.color.g = 60; + TrailEnt->r.color.b = 0; + TrailEnt->r.color.a = 255; + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = 3.0; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( owner->origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -4.0; + TrailEnt->d_scale = 0.0; + TrailEnt->Update = FXMorkTrailThink2; + + AddEffect(NULL,TrailEnt); + + VectorCopy(owner->origin, self->startpos); + + return true; +} + +int star_particle [3] = +{ + PART_16x16_STAR, + PART_16x16_SPARK_C, + PART_16x16_SPARK_B, +}; + +int FXCWUpdate (struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *p; + client_entity_t *TrailEnt; + vec3_t angles, fwd, right, vec; + int num_parts, i; + paletteRGBA_t LightColor={255,255,255,255}; + + client_entity_t *placeholder; + placeholder = ClientEntity_new(FX_M_EFFECTS, CEF_NO_DRAW|CEF_ABSOLUTE_PARTS, self->r.origin, NULL, 500); + AddEffect(NULL, placeholder); + + VectorScale(self->r.angles, 180.0/M_PI, angles); + AngleVectors(angles, fwd, right, NULL); + + num_parts = irand(3, 7); + for(i = 0; i < num_parts; i++) + { + p = ClientParticle_new(star_particle[irand(0, 2)], LightColor, 2000); + VectorSet(p->origin, flrand(-4, 4), flrand(-4, 4), flrand(-4, 4)); + VectorAdd(self->r.origin, p->origin, p->origin); + p->scale = flrand(2.5, 3.0); + + VectorSet(p->velocity, flrand(-10, 10), flrand(-10, 10), flrand(-1.0, 1.0)); + VectorMA(p->velocity, flrand(-40, -10), fwd, p->velocity); + + if (i&0x01) + VectorMA(p->velocity, flrand(-10, -2), right, p->velocity); + else + VectorMA(p->velocity, flrand(10, 2), right, p->velocity); + + p->acceleration[2] = 0; + p->d_scale = flrand(-0.15, -0.10); + p->duration = (p->scale * 1000.0) / -p->d_scale; // time taken to reach zero scale + + AddParticleToList(placeholder, p); + } + +//trail + + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + owner->origin, + NULL, + 17); + + TrailEnt->radius = 2000; + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = CW_models; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 3.0; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( owner->current.origin , TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -2.0; + TrailEnt->d_scale = 0.0; + TrailEnt->Update = FXMorkTrailThink2; + + AddEffect(NULL,TrailEnt); + +//=============================================== + + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_OWNERS_ORIGIN|CEF_AUTO_ORIGIN|CEF_USE_VELOCITY2, + owner->current.origin, + NULL, + 17); + + TrailEnt->radius = 2000; + + if(ref_soft) + { + TrailEnt->r.model = CW_models; + TrailEnt->r.scale = flrand(1.0, 2.5); + } + else + { + TrailEnt->r.model = Morkproj_models + 2; + TrailEnt->flags |= CEF_USE_SCALE2; + TrailEnt->r.scale = 3.0; + TrailEnt->r.scale2 = 0.2; + } + + TrailEnt->r.spriteType = SPRITE_LINE; + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.color.c = 0xFFFFaacc; + TrailEnt->alpha = flrand(1.0, 0.75); + TrailEnt->d_alpha = -1.0; + TrailEnt->d_scale = -0.1;//outer part does not scale down + + //angle + VectorSet(vec, flrand(0, 359), flrand(0, 359), flrand(0, 359)); + VectorCopy(vec, TrailEnt->direction); + AngleVectors(vec, fwd, NULL, NULL); + + //length + TrailEnt->SpawnInfo = flrand(20, 70); + VectorCopy(owner->current.origin, TrailEnt->r.startpos); + VectorMA(owner->current.origin, TrailEnt->SpawnInfo, fwd, TrailEnt->r.endpos); + + //avelocity + VectorSet(TrailEnt->up, flrand(-10, 10), flrand(-10, 10), flrand(-10, 10)); + + //speed + VectorCopy(self->direction, TrailEnt->velocity); + VectorCopy(self->direction, TrailEnt->velocity2); + + TrailEnt->Update = FXCWTrailThink; + + AddEffect(owner, TrailEnt); + +//============================================== + + self->r.scale = flrand(0.65, 0.95); + + VectorCopy(owner->current.origin, self->startpos); + + return (true); +} + +void FXCWStars (centity_t *owner,int type,int flags, vec3_t vel) +{ + client_entity_t *fx; + + fx = ClientEntity_new( type, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, owner->origin, NULL, 20); + + fx->Update=FXCWUpdate; + fx->radius = 500; + fx->r.model = Morkpp_models + 3; + VectorCopy(vel, fx->direction); + fx->r.color.r = 10; + fx->r.color.g = 50; + fx->r.color.b = 255; + fx->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + fx->r.scale = 0.8; + fx->AddToView = LinkedEntityUpdatePlacement; + + VectorCopy(owner->origin, fx->startpos); + + AddEffect(owner,fx); +} + +#define BUOY_FX_END PART_4x4_RED +#define BUOY_FX_START PART_4x4_GREEN +#define BUOY_FX_JUMP_FROM PART_4x4_CYAN +#define BUOY_FX_JUMP_TO PART_4x4_BLUE +#define BUOY_FX_ACTIVATE PART_4x4_MAGENTA +#define BUOY_FX_ONEWAY PART_4x4_WHITE + +int FXBuoyUpdate (struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *p; + int num_parts, i; + paletteRGBA_t LightColor={255,255,255,255}; + vec3_t offset, forward, angles; + int type = (int)(self->acceleration2[2]); + + if(type == BUOY_FX_START || type == BUOY_FX_END) + {//these effects time out + if(self->LifeTime < fxi.cl->time) + return (false); + } + + if(owner) + { + if(!owner->current.frame) + return (false); + + if(owner->current.frame > 5) + num_parts = 5; + else + num_parts = owner->current.frame; + } + else + num_parts = irand(1, 3); + + for(i = 0; i < num_parts; i++) + { + p = ClientParticle_new(type, LightColor, 1000); + + switch(type) + { + case BUOY_FX_END://red + if(irand(0,1)) + offset[0] = flrand(4, 12); + else + offset[0] = flrand(-12, -4); + if(irand(0,1)) + offset[1] = flrand(4, 12); + else + offset[1] = flrand(-12, -4); + offset[2] = 0; + VectorSet(p->origin, offset[0], offset[1], 0); + VectorSet(p->velocity, offset[0], offset[1], 0); + p->acceleration[2] = 0; + break; + + case BUOY_FX_START://green + VectorSet(p->origin, flrand(-2, 2), flrand(-2, 2), flrand(8, 16)); + VectorSet(p->velocity, 0, 0, flrand(3.0, 7.0)); + p->acceleration[2] = flrand(0.05, 2); + break; + + case BUOY_FX_JUMP_FROM://cyan + if(irand(0,1)) + offset[0] = flrand(4, 12); + else + offset[0] = flrand(-12, -4); + if(irand(0,1)) + offset[1] = flrand(4, 12); + else + offset[1] = flrand(-12, -4); + offset[2] = 0; + VectorSet(p->origin, offset[0], offset[1], 0); + VectorSet(p->velocity, offset[0], offset[1], 1); + p->acceleration[2] = 2; + break; + + case BUOY_FX_JUMP_TO://blue + if(irand(0, 1)) + offset[0] = 8; + else + offset[0] = -8; + if(irand(0, 1)) + offset[1] = 8; + else + offset[1] = -8; + offset[2] = -2; + + VectorSet(p->origin, offset[0], offset[1], offset[2]); + VectorSet(p->velocity, offset[0], offset[1], offset[2]); + p->acceleration[2] = -2; + break; + + case BUOY_FX_ACTIVATE://magenta + VectorSet(angles, 0, self->yaw++, 0); + AngleVectors(angles, forward, NULL, NULL); + + VectorScale(forward, 8, p->origin); + p->origin[2] = 8; + VectorCopy(p->origin, p->velocity); + p->acceleration[2] = 0; + break; + + case BUOY_FX_ONEWAY://white + VectorSet(p->origin, 0, 0, flrand(8, 16)); + VectorSet(p->velocity, 0, 0, 7); + p->acceleration[2] = flrand(0.05, 2); + break; + + default: + assert(0); + break; + } + + p->scale = flrand(0.5, 1.0); + p->d_alpha = flrand(-200.0, -160.0); + p->duration = (255.0 * 1000.0) / -p->d_alpha; // time taken to reach zero alpha + + AddParticleToList(self, p); + } + + return true; +} + +void FXBuoy (centity_t *owner, int flags, vec3_t org, float white) +{ + client_entity_t *fx; + + if(owner) + fx = ClientEntity_new(FX_BUOY, CEF_OWNERS_ORIGIN, owner->current.origin, NULL, 50); + else + fx = ClientEntity_new(FX_BUOY, 0, org, NULL, 50); + + if(white) + fx->acceleration2[2] = BUOY_FX_ONEWAY;//white + else if(flags&CEF_FLAG6) + fx->acceleration2[2] = BUOY_FX_START;//green + else if(flags&CEF_FLAG7) + fx->acceleration2[2] = BUOY_FX_JUMP_FROM;//cyan + else if(flags&CEF_FLAG8) + fx->acceleration2[2] = BUOY_FX_JUMP_TO;//blue - maybe 3 - yellow? + else if(flags&CEF_DONT_LINK) + fx->acceleration2[2] = BUOY_FX_ACTIVATE;//magenta + else + fx->acceleration2[2] = BUOY_FX_END;//red +//otherwise red + fx->flags |= CEF_NO_DRAW; + fx->Update=FXBuoyUpdate; + fx->LifeTime = fxi.cl->time + 10000; + + if(owner) + { + AddEffect(owner, fx); + } + else + { + VectorCopy(org, fx->startpos); + AddEffect(NULL, fx); + } +} + +qboolean FXPermanentUpdate (struct client_entity_s *self, centity_t *owner) +{ + self->updateTime = 16384; + return true; +} + +qboolean FXRemoveUpdate(struct client_entity_s *self,centity_t *owner) +{ + return false; +} + +qboolean FXBuoyPathDelayedStart (struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *TrailEnt; + vec3_t v; + float dist; + + TrailEnt=ClientEntity_new(FX_BUOY, + CEF_DONT_LINK, + self->origin, + NULL, + 16384); + + TrailEnt->Update = FXPermanentUpdate; + TrailEnt->updateTime = 16384; + TrailEnt->radius = 500; + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = buoy_models; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->alpha = 1.0; + TrailEnt->r.scale = 7.0; + + VectorSubtract(self->startpos, self->endpos, v); + dist = VectorLength(v); + if(VectorLength(v)<64) + TrailEnt->r.tile = 1; + else + TrailEnt->r.tile = 3; + + VectorCopy(self->startpos, TrailEnt->r.startpos); + VectorCopy(self->endpos, TrailEnt->r.endpos); + + AddEffect(NULL, TrailEnt); + + self->Update = FXRemoveUpdate; + self->updateTime = 100; + + return true; +} + +void FXBuoyPath (vec3_t org, vec3_t vel) +{ + client_entity_t *fx; + vec3_t origin; + + VectorAdd(org, vel, origin); + Vec3ScaleAssign(0.5, origin); + + fx = ClientEntity_new(FX_BUOY, CEF_DONT_LINK | CEF_NO_DRAW, origin, NULL, 100); + + fx->flags |= CEF_NO_DRAW; + fx->Update=FXBuoyPathDelayedStart; + fx->radius = 100; + + VectorCopy(org, fx->startpos); + VectorCopy(vel, fx->endpos); + + AddEffect(NULL,fx); +} + + +qboolean FXMMoBlurUpdate(struct client_entity_s *self, centity_t *owner) +{ + if (self->alpha <= 0.05f) + return false; + + return true; +} + +void FXMMoBlur(centity_t *owner, vec3_t org, vec3_t angles, qboolean dagger) +{//r_detail 2 only? + client_entity_t *blur; + + if(dagger) + { + blur = ClientEntity_new(FX_M_EFFECTS, 0, org, NULL, 20);//CEF_DONT_LINK + VectorCopy(angles, blur->r.angles); + blur->r.model = ass_dagger_model; + blur->alpha = 0.75; + blur->r.scale = 0.9; + + blur->d_alpha = -3.0; + blur->d_scale = -0.3; + } + else + { + blur = ClientEntity_new(FX_M_EFFECTS, 0, owner->current.origin, NULL, 20);//CEF_DONT_LINK + VectorSet(blur->r.angles, + angles[PITCH] * -1 * ANGLE_TO_RAD, + angles[YAW] * ANGLE_TO_RAD, + angles[ROLL] * ANGLE_TO_RAD); + blur->r.model = mork_model; + blur->r.frame = owner->current.frame; + blur->d_alpha = -1.0; + blur->d_scale = -0.1; + blur->alpha = 1.0; + blur->r.scale = 1.0; + } + blur->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA | RF_GLOW; + blur->r.scale = 1.0; + blur->Update = FXMMoBlurUpdate; + blur->updateTime = 20; + AddEffect(NULL,blur); +} + +qboolean FXAssDaggerUpdate (struct client_entity_s *self, centity_t *owner) +{ + if(++self->LifeTime == 4) + { + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, fxi.S_RegisterSound(va("monsters/assassin/throw%c.wav", irand('1', '2'))), 0.5, ATTN_IDLE, 0); + self->LifeTime = 0; + } + + FXMMoBlur(NULL, self->r.origin, self->r.angles, true); + self->r.angles[PITCH] += self->velocity2[0]; + return true; +} + +void FXAssDagger(centity_t *owner, vec3_t vel, float avel) +{ + client_entity_t *dagger; + + dagger = ClientEntity_new(FX_M_EFFECTS, CEF_DONT_LINK, owner->current.origin, NULL, 20); + +// vectoangles(vel, dagger->r.angles); +// VectorScale(dagger->r.angles, ANGLE_TO_RAD, dagger->r.angles); + VectorScale(owner->current.angles, ANGLE_TO_RAD, dagger->r.angles); + dagger->r.model = ass_dagger_model; + dagger->r.flags |= RF_FULLBRIGHT; + dagger->Update = FXAssDaggerUpdate; + VectorCopy(vel, dagger->velocity); + dagger->velocity2[0] = (avel*ANGLE_TO_RAD); + + AddEffect(owner, dagger); +} + + +int water_particle [6] = +{ + PART_4x4_WHITE, + PART_8x8_BUBBLE, + PART_16x16_WATERDROP, + PART_32x32_WFALL, + PART_32x32_STEAM, + PART_32x32_BUBBLE +}; + +qboolean FXUnderWaterWakeUpdate (struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *p; + vec3_t right; + int num_parts, i; + paletteRGBA_t LightColor={200, 255, 255, 140};//RGBA + + VectorCopy(owner->lerp_origin, self->r.origin); + AngleVectors(owner->lerp_angles, NULL, right, NULL); + + num_parts = irand(3, 7); + for(i = 0; i < num_parts; i++) + { + if(r_detail->value > DETAIL_LOW) + p = ClientParticle_new(water_particle[irand(0, 5)], LightColor, 1000); + else + p = ClientParticle_new(water_particle[irand(0, 5)]|PFL_SOFT_MASK, LightColor, 1000); + + VectorSet(p->origin, flrand(-8, 8), flrand(-8, 8), flrand(-4, 4)); + VectorAdd(self->r.origin, p->origin, p->origin); + + p->scale = flrand(0.75, 1.5); + p->color.a = irand(60, 120); + + VectorSet(p->velocity, flrand(-2, 2), flrand(-2, 2), flrand(-2.0, 2.0)); + + if (irand(0, 1)) + VectorMA(p->velocity, flrand(-10, -2), right, p->velocity); + else + VectorMA(p->velocity, flrand(10, 2), right, p->velocity); + + p->acceleration[2] = 2; + p->d_alpha = flrand(-3, -1); + p->d_scale = flrand(-0.15, -0.10); + + AddParticleToList(self, p); + } + + self->LifeTime--; + if(self->LifeTime<=0) + return (false); + + return (true); +} + +void FXUnderWaterWake (centity_t *owner) +{ + client_entity_t *fx; + + fx = ClientEntity_new(FX_M_EFFECTS, CEF_OWNERS_ORIGIN|CEF_NO_DRAW|CEF_ABSOLUTE_PARTS, owner->current.origin, NULL, 20); + + fx->Update=FXUnderWaterWakeUpdate; + fx->radius = 30; + fx->LifeTime = 77; + + AddEffect(owner, fx); +} + + + + + + +/* + + JWEIER EFFECTS BLOCKS + +*/ + + + +/*----------------------------------------------- + FXQuakeRing +-----------------------------------------------*/ + + +#define BALL_RADIUS 0.15 +#define NUM_RIPPER_PUFFS 12 +#define RIPPER_PUFF_ANGLE ((360.0*ANGLE_TO_RAD)/(float)NUM_RIPPER_PUFFS) +#define RIPPER_RING_VEL 256.0 +#define MACEBALL_RING_VEL 256.0 +#define MACEBALL_SPARK_VEL 128.0 +#define NUM_RINGS 3 + +void FXQuakeRing ( vec3_t origin ) +{ + client_entity_t *ring; + paletteRGBA_t color; + int i, j; + vec3_t norm = {0,0,1}; + vec3_t up, right, lastvel; + float curyaw; + float ring_vel = MACEBALL_RING_VEL; + + color.c = 0xffffffff; + + // Take the normal and find two "axis" vectors that are in the plane the normal defines + PerpendicularVector(up, norm); + CrossProduct(up, norm, right); + + VectorScale(norm, 8.0, norm); + color.c = 0xffffffff; + + // Draw a circle of expanding lines. + for(j = 0; j < NUM_RINGS; j++) + { + curyaw = 0; + VectorScale(right, ring_vel, lastvel); + + for(i = 0; i < NUM_RIPPER_PUFFS; i++) + { + curyaw += RIPPER_PUFF_ANGLE; + + ring = ClientEntity_new(FX_M_EFFECTS, CEF_USE_VELOCITY2 | CEF_AUTO_ORIGIN | CEF_ABSOLUTE_PARTS | CEF_ADDITIVE_PARTS, + origin, NULL, 3000); + + ring->r.model = morc_models; + ring->r.frame = 0; + ring->r.spriteType = SPRITE_LINE; + ring->r.frame = 1; + ring->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + ring->radius = 256.0; + ring->r.tile = 1; + + // The startpos and startvel comes from the last velocity. + VectorCopy(lastvel, ring->velocity); + VectorScale(ring->velocity, 1.0, ring->acceleration); + VectorMA(origin, .01, ring->velocity, ring->r.startpos); // Move the line out a bit to avoid a zero-length line. + + VectorScale(up, ring_vel*sin(curyaw), ring->velocity2); + VectorMA(ring->velocity2, ring_vel*cos(curyaw), right, ring->velocity2); + + VectorScale(ring->velocity2, 1.0, ring->acceleration2); + VectorMA(origin, .01, ring->velocity2, ring->r.endpos); // Move the line out a bit to avoid a zero-length line. + + // Finally, copy the last velocity we used. + VectorCopy(ring->velocity2, lastvel); + + // NOW apply the extra directional velocity to force it slightly away from the surface. + VectorAdd(ring->velocity, norm, ring->velocity); + VectorAdd(ring->velocity2, norm, ring->velocity2); + + ring->r.scale = 8.0; + ring->d_scale = 32.0; + ring->alpha = 0.75; + ring->d_alpha = -1.0; + + AddEffect(NULL, ring); + } + + ring_vel /= 2; + } + + fxi.Activate_Screen_Shake(12, 1000, fxi.cl->time, SHAKE_ALL_DIR); + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("world/quakeshort.wav"), 1, ATTN_NONE, 0); +} + +/*----------------------------------------------- + FXGroundAttack +-----------------------------------------------*/ + +extern qboolean FXFlamethrower_trail(client_entity_t *self, centity_t *owner); + +void FXGroundAttack( vec3_t origin ) +{ + client_entity_t *glow; + vec3_t dir = {0,0,1}; + + origin[2] -= 16; + + // create the dummy entity, so particles can be attached + glow = ClientEntity_new(FX_M_EFFECTS, CEF_NO_DRAW | CEF_ADDITIVE_PARTS, origin, 0, 17); + + VectorScale(dir, 50, glow->direction); + + glow->radius = 100; + glow->LifeTime = fxi.cl->time + 1000; + + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("misc/flamethrow.wav"), 1, ATTN_NORM, 0); + glow->Update = FXFlamethrower_trail; + + AddEffect(NULL, glow); +} + +static qboolean beam_update(struct client_entity_s *self, centity_t *owner) +{ + //TODO: Cool ass effects here + + return true; +} + +static qboolean beam_add_to_view(struct client_entity_s *self, centity_t *owner) +{ + LinkedEntityUpdatePlacement(self, owner); + VectorCopy(self->r.origin, self->r.endpos); + + return true; +} + +void FXMorkBeam2 ( centity_t *owner, vec3_t startpos ) +{ + client_entity_t *fx; + paletteRGBA_t LightColor={128,128,255,255}; + //vec3_t vel; + + fx = ClientEntity_new( FX_M_EFFECTS, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, owner->origin, NULL, 17); + + fx->r.spriteType = SPRITE_LINE; + + fx->radius = 1024; + fx->r.model = Morkproj_models + 2; + fx->r.scale = 8; + fx->alpha = 1.0; + fx->r.color.c = 0xFFFFFFFF; + + VectorCopy(startpos, fx->r.startpos); + VectorCopy(owner->origin, fx->r.endpos); + + fx->Update = beam_update; + fx->AddToView = beam_add_to_view; + + AddEffect(owner, fx); +} + +static qboolean missile_add_to_view(struct client_entity_s *self, centity_t *owner) +{ + LinkedEntityUpdatePlacement(self, owner); + VectorCopy(self->r.origin, self->r.startpos); + + self->direction[0] += flrand(-1.0, 1.0); + self->direction[1] += flrand(-1.0, 1.0); + self->direction[2] += flrand(-1.0, 1.0); + + VectorNormalize(self->direction); + VectorMA(self->r.startpos, irand(self->LifeTime/4, self->LifeTime), self->direction, self->r.endpos); + + self->r.scale = flrand(1.0, 2.0); + + return true; +} + +static qboolean MorkMissileThink1(struct client_entity_s *self, centity_t *owner) +{ + if (self->LifeTime < 24) + { + self->LifeTime += 1; + } + + return true; +} + +static qboolean MorkMissileThink2(struct client_entity_s *self, centity_t *owner) +{ + if (self->alpha < 0.25) + { + self->alpha += 0.1; + } + + if (self->r.scale < 3.0) + { + self->r.scale += 0.1; + } + + if (self->dlight->intensity <= 200.0f) + { + self->dlight->intensity += 10.0f; + } + + return true; +} + +static qboolean MorkMissileThink3(struct client_entity_s *self, centity_t *owner) +{ + if (self->alpha < 0.5) + { + self->alpha += 0.1; + } + + if (self->r.scale < 1.0) + { + self->r.scale += 0.1; + } + + if (self->SpawnInfo > irand(15, 20)) + { + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, fxi.S_RegisterSound("monsters/elflord/weld.wav"), 0.5, ATTN_IDLE, 0); + self->SpawnInfo=0; + } + + self->SpawnInfo++; + return true; +} + +void FXMorkMissile ( centity_t *owner, vec3_t startpos ) +{ + client_entity_t *fx; + paletteRGBA_t LightColor={128,128,255,255}; + int i; + + i = GetScaledCount(8, 0.85); + + while (i--) + { + fx = ClientEntity_new( FX_M_EFFECTS, CEF_OWNERS_ORIGIN, startpos, NULL, 17); + + fx->r.spriteType = SPRITE_LINE; + fx->r.flags |= RF_TRANS_ADD | RF_TRANSLUCENT | RF_FULLBRIGHT; + + fx->radius = 1024; + fx->r.model = morc_models + 1; + fx->r.scale = irand(0.1, 1); + fx->r.scale2 = 0.1; + fx->alpha = 1.0; + fx->r.color.c = 0xFFFFFFFF; + + VectorCopy(startpos, fx->r.startpos); + + fx->direction[0] = flrand(-1.0, 1.0); + fx->direction[1] = flrand(-1.0, 1.0); + fx->direction[2] = flrand(-1.0, 1.0); + + VectorMA(startpos, irand(4, 16), fx->direction, fx->r.endpos); + + fx->Update = MorkMissileThink1; + fx->AddToView = missile_add_to_view; + + AddEffect(owner, fx); + } + + //Light blue halo + fx = ClientEntity_new( FX_M_EFFECTS, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, startpos, NULL, 100); + fx->dlight = CE_DLight_new(LightColor,10.0f,0.0f); + fx->r.model = morc_models + 2; + fx->r.flags |= RF_TRANS_ADD | RF_TRANSLUCENT | RF_FULLBRIGHT; + fx->alpha = 0.1; + fx->r.scale = 0.1; + + fx->Update = MorkMissileThink2; + fx->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner, fx); + + //The white core + fx = ClientEntity_new( FX_M_EFFECTS, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, startpos, NULL, 100); + fx->r.model = morc_models + 3; + fx->r.flags |= RF_TRANS_ADD | RF_TRANSLUCENT | RF_FULLBRIGHT; + fx->alpha = 0.1; + fx->r.scale = 0.1; + + fx->Update = MorkMissileThink3; + fx->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner, fx); + +} + +extern client_entity_t *MakeLightningPiece(int type, float width, vec3_t start, vec3_t end, float radius); +#define LIGHTNING_TYPE_BLUE 0 +#define LIGHTNING_WIDTH 1.0 + +void MorkLightning(vec3_t groundpos, vec3_t airpos) +{ + vec3_t curpos, lastpos, top, bottom, refpoint, diffpos, rand; + float scale; + int i; + + VectorSet(top, flrand(-RED_RAIN_RADIUS, RED_RAIN_RADIUS), flrand(-RED_RAIN_RADIUS, RED_RAIN_RADIUS), 0); + VectorAdd(airpos, top, top); + VectorSet(bottom, flrand(-RED_RAIN_RADIUS, RED_RAIN_RADIUS), flrand(-RED_RAIN_RADIUS, RED_RAIN_RADIUS), 0); + VectorAdd(groundpos, bottom, bottom); + + VectorSubtract(top, bottom, diffpos); + VectorScale(diffpos, 0.2, diffpos); + scale = (airpos[2] - groundpos[2]) / 10.0; + + VectorCopy(bottom, lastpos); + VectorCopy(bottom, refpoint); + for (i=0; i<5; i++) + { + VectorAdd(refpoint, diffpos, refpoint); + VectorSet(rand, flrand(-scale, scale), flrand(-scale, scale), flrand(-scale, scale)); + VectorAdd(refpoint, rand, curpos); + MakeLightningPiece(LIGHTNING_TYPE_BLUE, LIGHTNING_WIDTH, curpos, lastpos, scale); + VectorCopy(curpos, lastpos); + } +} + +void FXMorkMissileHit ( vec3_t origin, vec3_t dir ) +{ + client_entity_t *fx; + paletteRGBA_t LightColor={128,128,255,255}; + + //The white core + fx = ClientEntity_new( FX_M_EFFECTS, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, origin, NULL, 2000); + fx->r.model = morc_models + 3; + fx->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT | RF_FULLBRIGHT | RF_NODEPTHTEST; + fx->r.scale = 1; + fx->alpha = 0.5; + fx->d_alpha = -1.0; + fx->d_scale = 16.0; + + AddEffect(NULL, fx); + + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("monsters/mork/ppexplode.wav"), 1.0, ATTN_IDLE, 0); +} + +/*----------------------------------------------- + FXMTrailThink +-----------------------------------------------*/ + +static qboolean FXMTrailThink(struct client_entity_s *self,centity_t *Owner) +{ + if (self->alpha <= 0.1 || self->r.scale <= 0.0) + return false; + + self->r.scale -= 0.1; + self->r.scale2 -= 0.1; + + return true; +} + +/*----------------------------------------------- + FXMMissileTrailThink +-----------------------------------------------*/ + +static qboolean FXMMissileTrailThink(struct client_entity_s *self,centity_t *Owner) +{ + client_entity_t *TrailEnt; + + self->r.scale = flrand(0.35, 0.65); + + TrailEnt=ClientEntity_new(FX_M_EFFECTS, + CEF_DONT_LINK, + Owner->lerp_origin, + NULL, + 17); + + TrailEnt->radius = 500; + + VectorCopy( Owner->lerp_origin, TrailEnt->r.origin ); + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + TrailEnt->r.model = morc_models + 5; + + TrailEnt->r.spriteType = SPRITE_LINE; + TrailEnt->r.tile = 1; + TrailEnt->r.scale = 2.0; + TrailEnt->r.scale2 = 2.0; + TrailEnt->alpha = 0.5; + + VectorCopy( self->startpos, TrailEnt->r.startpos ); + VectorCopy( Owner->lerp_origin, TrailEnt->r.endpos ); + + TrailEnt->d_alpha = -2.5; + TrailEnt->d_scale = 0.0; + TrailEnt->Update = FXMTrailThink; + + AddEffect(NULL,TrailEnt); + + VectorCopy(Owner->lerp_origin, self->startpos); + + return true; +} + +extern void FXHPMissileCreateWarp(centity_t *Owner,int Type,int Flags,vec3_t Origin); + +void FXMorkTrackingMissile ( centity_t *owner, vec3_t origin, vec3_t velocity ) +{ + client_entity_t *Trail; + paletteRGBA_t LightColor={0,0,255,255}; + + FXHPMissileCreateWarp(owner, FX_M_EFFECTS, 0, origin); + + Trail = ClientEntity_new( FX_M_EFFECTS, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, origin, NULL, 20); + + Trail->Update=FXMMissileTrailThink; + Trail->dlight=CE_DLight_new(LightColor,150.0f,0.0f); + Trail->radius = 500; + Trail->r.model = morc_models + 4; + Trail->r.color.c = 0xFFFFFFFF; + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->r.scale = 1.0; + Trail->AddToView = LinkedEntityUpdatePlacement; + + VectorCopy(origin, Trail->startpos); + + AddEffect(owner,Trail); + + FXMMissileTrailThink(Trail,owner); +} + +void FXMorkRecharge( centity_t *owner, vec3_t velocity ) +{ + client_entity_t *Trail; + paletteRGBA_t LightColor={0,0,255,255}; + float duration = velocity[0]; + int i; + + i = GetScaledCount(8, 0.85); + + while (i--) + { + Trail = ClientEntity_new( FX_M_EFFECTS, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, owner->origin, NULL, 2000); + + Trail->radius = 500; + Trail->r.model = morc_models + irand(6,8); + Trail->r.color.c = 0xFFFFFFFF; + Trail->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Trail->r.scale = 0.1; + Trail->velocity[2] = 32; + Trail->acceleration[2] = 64; + Trail->d_scale = 2.0; + Trail->d_alpha = -0.1; + + Trail->r.origin[0] = irand(-32, 32); + Trail->r.origin[1] = irand(-32, 32); + + AddEffect(owner,Trail); + } +} + +qboolean rubble_spin (client_entity_t *self, centity_t *owner) +{ + if (self->LifeTime < fxi.cl->time) + return false; + + self->r.angles[YAW] += 0.1; + self->r.angles[PITCH] += 0.1; + self->r.angles[ROLL] += 0.1; + + return true; +} + +qboolean mssithra_explosion_think (client_entity_t *self, centity_t *owner) +{ + client_entity_t *explosion, *TrailEnt; + paletteRGBA_t color = {255,255,255,255}; + vec3_t dir; + int i; + int white; + + if (self->LifeTime < fxi.cl->time) + return false; + + //Spawn a white core + explosion = ClientEntity_new( FX_M_EFFECTS, 0, self->origin, NULL, 1000); + explosion->r.model = mssithra_models + 5; + + explosion->r.flags |= RF_FULLBRIGHT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + explosion->r.scale = 0.1; + explosion->radius = 500; + explosion->r.color.c = 0xFFFFFFFF; + explosion->alpha = 0.75; + explosion->d_scale = 4.0; + explosion->d_alpha = -2.5; + + explosion->r.origin[0] += irand(-8,8); + explosion->r.origin[1] += irand(-8,8); + explosion->r.origin[2] += irand(-8,8); + + AddEffect(NULL, explosion); + + i = GetScaledCount(3, 0.85); + + //Spawn a small explosion sphere + while (i--) + { + explosion = ClientEntity_new( FX_M_EFFECTS, 0, self->origin, NULL, 1000); + explosion->r.model = mssithra_models + irand(0, 1); + + explosion->r.flags |= RF_FULLBRIGHT; + explosion->r.scale = 0.1; + explosion->radius = 500; + explosion->r.color.c = 0xFFFFFFFF; + explosion->alpha = 0.75; + explosion->d_scale = 2.0; + explosion->d_alpha = -2.5; + + explosion->r.origin[0] += irand(-16,16); + explosion->r.origin[1] += irand(-16,16); + explosion->r.origin[2] += irand(-16,16); + + AddEffect(NULL, explosion); + } + + VectorCopy(self->direction, dir); + + if (irand(0,1)) + { + if (r_detail->value > 1) + { + //Spawn an explosion of lines + i = GetScaledCount(2, 0.85); + + while (i--) + { + TrailEnt=ClientEntity_new(FX_M_EFFECTS, 0, self->r.origin, 0, 17); + + TrailEnt->r.model = mssithra_models + irand(3,4); + + TrailEnt->r.flags |= RF_FULLBRIGHT; + TrailEnt->r.scale = flrand(0.5, 1.5); + TrailEnt->alpha = 1.0; + + VectorRandomCopy(dir, TrailEnt->velocity, 1.25); + + VectorScale(TrailEnt->velocity, irand(50,100), TrailEnt->velocity); + TrailEnt->acceleration[2] -= 256; + + TrailEnt->Update = rubble_spin; + TrailEnt->LifeTime = fxi.cl->time + 2000; + + AddEffect(NULL, TrailEnt); + } + } + } + else + { + //Spawn an explosion of lines + i = GetScaledCount(2, 0.85); + + while (i--) + { + TrailEnt=ClientEntity_new(FX_M_EFFECTS, 0, self->r.origin, 0, 500); + + TrailEnt->r.model = mssithra_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + + TrailEnt->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.color.c = 0xFFFFFFFF; + TrailEnt->r.scale = flrand(1.0, 2.5); + TrailEnt->alpha = 1.0; + TrailEnt->d_alpha = -1.0; + TrailEnt->d_scale = -1.0; + + white = irand(128, 255); + + TrailEnt->r.color.r = white; + TrailEnt->r.color.g = white; + TrailEnt->r.color.b = 128 + irand(108, 127); + TrailEnt->r.color.a = 64 + irand(16, 128); + + VectorRandomCopy(dir, TrailEnt->velocity, 1.25); + + VectorCopy(self->r.origin, TrailEnt->r.endpos); + VectorMA(TrailEnt->r.endpos, irand(16, 32), TrailEnt->velocity, TrailEnt->r.startpos); + + VectorScale(TrailEnt->velocity, irand(50,150), TrailEnt->velocity); + + AddEffect(NULL, TrailEnt); + } + } + + return true; +} + +void FXMSsithraExplode( vec3_t origin, vec3_t dir ) +{ + client_entity_t *spawner; + + //Create an explosion spawner + spawner = ClientEntity_new( FX_M_EFFECTS, CEF_NO_DRAW, origin, NULL, 20); + spawner->Update = mssithra_explosion_think; + spawner->color.c = 0xff00ffff; + spawner->dlight = CE_DLight_new(spawner->color, 100.0f,-50.0f); + spawner->LifeTime = fxi.cl->time + 250; + VectorCopy(dir, spawner->direction); + + AddEffect(NULL, spawner); + + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("monsters/mssithra/hit.wav"), 0.5, ATTN_NORM, 0); +} + +void FXMSsithraExplodeSmall( vec3_t origin, vec3_t dir ) +{ + //Play correct sound here + FireSparks(NULL, FX_SPARKS, 0, origin, vec3_up); + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("monsters/mssithra/hit.wav"), 0.5, ATTN_NORM, 0); +} + +qboolean ArrowCheckFuse (client_entity_t *self, centity_t *owner) +{ + if ( (owner->current.effects & EF_ALTCLIENTFX) || (owner->current.effects & EF_MARCUS_FLAG1) ) + {//We've stopped moving and have imbedded ourself in a wall + if(!(self->flags & CEF_NO_DRAW)) + { + FireSparks(NULL, FX_SPARKS, 0, self->r.origin, vec3_up); + self->flags |= CEF_NO_DRAW; + } + + if(irand(0, 1)) + FXDarkSmoke(self->r.origin, flrand(0.2, 0.5), flrand(30, 50)); + } + + return true; +} + +qboolean ArrowDrawTrail (client_entity_t *self, centity_t *owner) +{ + LinkedEntityUpdatePlacement(self, owner); + + VectorCopy(self->r.origin, self->r.startpos); + VectorMA(self->r.startpos, self->SpawnInfo, self->direction, self->r.endpos); + VectorMA(self->r.startpos, 8, self->direction, self->r.startpos); + + if (self->flags & CEF_FLAG6) + { + if (self->r.scale > 8.0) + self->r.scale = self->r.scale2 = flrand(8.0, 12.0); + + if (self->SpawnInfo > -64) + self->SpawnInfo-=4; + + if (self->LifeTime > 10) + { + self->LifeTime = 0; + fxi.S_StartSound(self->r.origin, -1, CHAN_AUTO, fxi.S_RegisterSound("monsters/pssithra/guntravel.wav"), 0.5, ATTN_NORM, 0); + } + else + self->LifeTime++; + } + else + { + if (self->r.scale > 4.0) + self->r.scale = self->r.scale2 = flrand(4.0, 6.0); + + //Let the trail slowly extend + if (self->SpawnInfo > -64) + self->SpawnInfo-=2; + } + + self->alpha = flrand(0.5, 1.0); + + return true; +} + +void FXMSsithraArrow( centity_t *owner, vec3_t velocity, qboolean super ) +{ + client_entity_t *spawner; + + //Create an explosion spawner + spawner = ClientEntity_new( FX_M_EFFECTS, CEF_OWNERS_ORIGIN, owner->current.origin, NULL, 20); + spawner->r.model = mssithra_models + 2; + spawner->r.spriteType = SPRITE_LINE; + spawner->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + spawner->r.color.c = 0xFFFFFFFF; + spawner->r.scale = 1.0; + spawner->alpha = 1.0; + spawner->LifeTime = 0; + + if (super) + { + spawner->flags |= CEF_FLAG6; + spawner->d_scale = spawner->d_scale2 = 16.0; + } + else + { + spawner->d_scale = spawner->d_scale2 = 8.0; + } + + VectorCopy(spawner->r.origin, spawner->r.startpos); + VectorNormalize2(velocity, spawner->direction); + VectorMA(spawner->r.startpos, -64, spawner->direction, spawner->r.endpos); + + spawner->Update = ArrowCheckFuse; + spawner->AddToView = ArrowDrawTrail; + spawner->SpawnInfo = 0; + + AddEffect(owner, spawner); +} + +void FXMSsithraArrowCharge( vec3_t startpos ) +{ + client_entity_t *TrailEnt; + paletteRGBA_t color = {255,128,255,255}; + vec3_t dir; + int length; + int i; + int white; + + i = GetScaledCount(6, 0.85); + + while (i--) + { + TrailEnt=ClientEntity_new(FX_M_EFFECTS, 0, startpos, 0, 500); + + TrailEnt->r.model = mssithra_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + + TrailEnt->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->flags |= CEF_USE_VELOCITY2; + TrailEnt->r.color.c = 0xFFFFFFFF; + TrailEnt->r.scale = flrand(4.0, 6.0); + TrailEnt->alpha = 0.1; + TrailEnt->d_alpha = 0.25; + TrailEnt->d_scale = 0.0; + + white = irand(128, 255); + + TrailEnt->r.color.r = white; + TrailEnt->r.color.g = white; + TrailEnt->r.color.b = 128 + irand(108, 127); + TrailEnt->r.color.a = 64 + irand(16, 128); + + VectorSet(dir, 0, 0, 1); + VectorRandomCopy(dir, TrailEnt->velocity2, 1.5); + + VectorCopy(startpos, TrailEnt->r.startpos); + length = irand(24, 32); + VectorMA(TrailEnt->r.startpos, length, TrailEnt->velocity2, TrailEnt->r.endpos); + + VectorScale(TrailEnt->velocity2, -(length*2), TrailEnt->velocity2); + VectorClear(TrailEnt->velocity); + + AddEffect(NULL, TrailEnt); + } + + TrailEnt=ClientEntity_new(FX_M_EFFECTS, 0, startpos, 0, 500); + + white = irand(128, 255); + + TrailEnt->r.color.r = white; + TrailEnt->r.color.g = white; + TrailEnt->r.color.b = 128 + irand(108, 127); + TrailEnt->r.color.a = 64 + irand(16, 128); + + TrailEnt->dlight = CE_DLight_new(TrailEnt->r.color, 200, -25); +} + +/*=============================== + + Morcalavin's FX handler + + ===============================*/ + + + + +void FXMEffects(centity_t *owner,int type,int flags, vec3_t org) +{ + client_entity_t *fx; + paletteRGBA_t LightColor={0,0,255,255}; + vec3_t vel; + byte fx_index; + int i; + + fxi.GetEffect(owner, flags, "bv", &fx_index, &vel);//fixme- make this 1 dir and 1 float + + switch (fx_index) + { + /* + case FX_M_POWERPUFF: + fx = ClientEntity_new( type, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, org, NULL, 20); + + VectorCopy(vel, fx->up); + fx->flags |= CEF_ABSOLUTE_PARTS; + fx->Update=FXMorkPPTrailThink; + fx->dlight=CE_DLight_new(LightColor,150.0f,0.0f); + fx->radius = 500; + fx->r.model = Morkproj_models + 3; + fx->r.color.r = 10; + fx->r.color.g = 50; + fx->r.color.b = 200; + fx->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + fx->r.scale = 0.35; + fx->d_scale = 1.5; + fx->AddToView = LinkedEntityUpdatePlacement; + + VectorCopy(owner->origin, fx->startpos); + + AddEffect(owner,fx); + + FXMorkPPTrailThink(fx,owner); + break;*/ + + case FX_M_MISC_EXPLODE: + FXMorkMissileExplode(NULL, owner, vel); + break; + + /* + case FX_M_PP_EXPLODE: + fx = ClientEntity_new(type, flags, org, NULL, 50); + FXMPPExplode(fx, owner, type, flags, org, vel); + break;*/ + + /* + case FX_M_QUAKE: + fxi.Activate_Screen_Shake(10, 4000, fxi.cl->time, SHAKE_ALL_DIR); + fx = ClientEntity_new(type, CEF_NO_DRAW, vec3_origin, NULL, 100); + fx->LifeTime = 200; + fx->flags |= CEF_NO_DRAW; + fx->Update = FXQuakeThink; + AddEffect(NULL,fx); + + break;*/ + + /* + case FX_M_STRAFE: + fx = ClientEntity_new( type, CEF_OWNERS_ORIGIN | CEF_DONT_LINK, org, NULL, 20); + + VectorCopy(vel, fx->up); + fx->Update=FXMorkMissileTrailThink; + fx->dlight=CE_DLight_new(LightColor,150.0f,0.0f); + fx->radius = 500; + fx->r.model = Morkproj_models + 3; + fx->r.color.r = 250; + fx->r.color.g = 200; + fx->r.color.b = 110; + fx->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + fx->r.scale = 0.5; + fx->AddToView = LinkedEntityUpdatePlacement; + + VectorCopy(owner->origin, fx->startpos); + + AddEffect(owner,fx); + + FXMorkMissileTrailThink(fx,owner); + break;*/ + + /* + case FX_M_LIGHTNING: + MorkDoEyesLightning(owner, vel); + break;*/ + + case FX_M_BEAM: + fx = ClientEntity_new( type, CEF_NO_DRAW | CEF_OWNERS_ORIGIN | CEF_DONT_LINK, org, NULL, 20); + + fx->flags |= CEF_NO_DRAW; + VectorCopy(owner->current.origin, fx->r.origin); + fx->Update=FXMorkBeam; + fx->dlight=CE_DLight_new(LightColor,150.0f,0.0f); + fx->radius = 500; + fx->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + fx->AddToView = LinkedEntityUpdatePlacement; + + VectorCopy(owner->origin, fx->startpos); + + AddEffect(owner,fx); + + FXMorkBeam(fx,owner); + + for(i = 0; i<3; i++) + { + fx = ClientEntity_new( type, 0, org, NULL, 20); + + VectorCopy(owner->current.origin, fx->r.origin); + fx->Update=FXMorkBeamCircle; + fx->radius = 500; + fx->r.model = Morkproj_models + 3; + fx->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + fx->r.scale = 0.5; + fx->LifeTime = i * 120; + + VectorCopy(owner->origin, fx->startpos); + VectorCopy(vel, fx->r.angles); + + AddEffect(owner,fx); + + FXMorkBeamCircle(fx,owner); + } + break; + + /* + case FX_M_SHOVE: + fx = ClientEntity_new( type, CEF_NO_DRAW | CEF_DONT_LINK | CEF_ABSOLUTE_PARTS, org, NULL, 20); + fx->flags|=CEF_NO_DRAW; + fx->radius = 500; + VectorCopy(owner->current.origin, fx->r.origin); + VectorCopy(owner->current.origin, fx->startpos2); + VectorCopy(vel, fx->velocity); + vectoangles(vel, fx->endpos2); + Vec3ScaleAssign(ANGLE_TO_RAD, fx->endpos2); + fx->Update = FXMorkShove; + fx->LifeTime = fxi.cl->time + 420; + AddEffect(NULL,fx); + break;*/ + + /* + case FX_M_SHIELD: + fx=ClientEntity_new(type, flags, org, NULL, 20); + + fx->r.model = Morkshield_models; + + fx->r.flags |= (RF_TRANSLUCENT | RF_FULLBRIGHT); + fx->alpha = 0.0; + fx->r.scale = 4.0; + + fx->d_scale = -1.5; + fx->d_alpha = 0.25; + + fx->Update=FXMorkShieldForm; + fx->SpawnInfo = 0; + fx->radius = 1000; + + AddEffect(owner,fx); + break;*/ + + /* + case FX_M_EYES: + fx=ClientEntity_new(type, CEF_NO_DRAW|CEF_OWNERS_ORIGIN, owner->current.origin, NULL, 20); + + fx->flags |= (CEF_NO_DRAW|CEF_ABSOLUTE_PARTS); + fx->Update = FXMorkEyes; + fx->LifeTime = 0; + fx->r.color.c = 0xe5007fff; + fx->dlight=CE_DLight_new(fx->r.color,30.0f,0.0f); + fx->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner,fx); + //-------------------------------------- + fx=ClientEntity_new(type, CEF_NO_DRAW|CEF_OWNERS_ORIGIN, owner->current.origin, NULL, 20); + + fx->flags |= (CEF_NO_DRAW|CEF_ABSOLUTE_PARTS); + fx->Update = FXMorkEyes; + fx->LifeTime = 1; + fx->r.color.c = 0xe5007fff; + fx->dlight=CE_DLight_new(fx->r.color,30.0f,0.0f); + fx->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner,fx); + break;*/ + + /* + case FX_M_READYPP: + fx = ClientEntity_new(type, flags, org, NULL, 50); + + fx->flags |= (CEF_DONT_LINK); + VectorCopy(vel, fx->velocity); + fx->acceleration[2] = fx->velocity[2] * -0.8; + fx->radius = 500; + fx->r.model = Morkproj_models + 3; + fx->r.color.r = 10; + fx->r.color.g = 0; + fx->r.color.b = 10; + fx->r.color.a = 10; + fx->dlight=CE_DLight_new(fx->r.color,150.0f,0.0f); + fx->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + fx->r.scale = 0.1; + fx->d_scale = 0.5; + + fx->Update = FXMorkPPReadyThink; + fx->LifeTime = fxi.cl->time + 1200; + + AddEffect(NULL, fx); + break;*/ + + /* + case FX_M_RREFS: + FXMorkReadyRefs(owner, type, flags, org); + break;*/ + + /* + case FX_M_GALAXY: + if(r_detail->valuer.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + fx->r.model = Imp_models + 2; + + vectoangles(vel, fx->r.angles); + + fx->r.frame = 2; + fx->radius = 64; + fx->r.scale = 0.5; + fx->d_alpha = 0.0f; + fx->d_scale = 0.0f; + fx->r.color.c = 0xe5007fff; + + fx->Update = ImpFireBallUpdate; + fx->AddToView = LinkedEntityUpdatePlacement; + + if(r_detail->value > DETAIL_NORMAL) + { + LightColor.c = 0xff3333ff; + fx->dlight = CE_DLight_new(LightColor,150.0f,0.0f); + } + + VectorCopy(owner->origin, fx->startpos); + + AddEffect(owner,fx); + break; + + case FX_IMP_FBEXPL: + ImpFireBallExplode(NULL, owner, vel); + break; + + case FX_CW_STARS: + FXCWStars(owner, type, flags, org); + break; + + /* + case FX_CW_PLASMA: + CWPlasma(org, vel, flags); + break;*/ + + case FX_BUOY: + FXBuoy(owner, flags, org, vel[0]); + break; + + case FX_BUOY_PATH: + FXBuoyPath(org, vel); + break; + + case FX_M_MOBLUR: + FXMMoBlur(owner, org, vel, false); + break; + + case FX_ASS_DAGGER: + FXAssDagger(owner, vel, org[0]); + break; + + case FX_UNDER_WATER_WAKE: + FXUnderWaterWake(owner); + break; + + case FX_QUAKE_RING: + FXQuakeRing(vel); + break; + + case FX_GROUND_ATTACK: + FXGroundAttack(vel); + break; + + case FX_MORK_BEAM: + FXMorkBeam2(owner, vel); + break; + + case FX_MORK_MISSILE: + FXMorkMissile(owner, vel); + break; + + case FX_MORK_MISSILE_HIT: + FXMorkMissileHit(org, vel); + break; + + case FX_MORK_TRACKING_MISSILE: + FXMorkTrackingMissile(owner, org, vel); + break; + + /* + case FX_MORK_RECHARGE: + FXMorkRecharge(owner, vel); + break;*/ + + case FX_MSSITHRA_EXPLODE: + if (flags & CEF_FLAG6) + FXMSsithraExplodeSmall(org, vel); + else + FXMSsithraExplode(org, vel); + + break; + + case FX_MSSITHRA_ARROW: + FXMSsithraArrow(owner, vel, (flags & CEF_FLAG6)); + break; + + case FX_MSSITHRA_ARROW_CHARGE: + FXMSsithraArrowCharge(vel); + break; + + default: + break; + } +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_morph.c b/Toolkit/Programming/GameCode/client effects/fx_morph.c new file mode 100644 index 0000000..718e129 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_morph.c @@ -0,0 +1,398 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "angles.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "motion.h" +#include "Reference.h" +#include "ce_Dlight.h" +#include "g_playstats.h" + +#define SMALL_RAD 8 +#define MORPH_GLOW_DUR 10 +#define MORPH_COL 0xff00ff00 +#define GLOW_INTENSITY 255 +#define FX_SPHERE_BASE_RADIUS 89.0 +#define FEATH_RAD 50 +#define FLOAT_TIME 15.0 +#define FLOAT_SLOW 3.14156/FLOAT_TIME +#define MORPH_ANGLE_INC 6.283185 / NUM_OF_OVUMS + +#define NUM_MORPH_MODELS 4 +static struct model_s *morph_models[NUM_MORPH_MODELS]; +void PreCacheMorph() +{ + morph_models[0] = fxi.RegisterModel("sprites/lens/halo1.sp2"); + morph_models[1] = fxi.RegisterModel("models/objects/eggs/chickenegg/tris.fm"); + morph_models[2] = fxi.RegisterModel("models/objects/feathers/feather1/tris.fm"); + morph_models[3] = fxi.RegisterModel("models/objects/feathers/feather2/tris.fm"); +} + +// ----------------------------------------------------------------------------------------- + +#define PART_OFF 5.0 +#define NUM_TRAIL_PARTS 6 + +static qboolean FXMorphMissileThink(client_entity_t *missile, centity_t *owner) +{ + int i; + client_particle_t *ce; + vec3_t scaled_vel; + client_entity_t *trail; + int count; + paletteRGBA_t color; + vec3_t diff, curpos; + int dur; + + // create a new entity for these particles to attach to + trail = ClientEntity_new(FX_SPELL_MORPHMISSILE, missile->flags | CEF_NO_DRAW | CEF_ADDITIVE_PARTS, missile->r.origin, NULL, 1000); + // and give it no onwer, so its not deleted if the missile is + AddEffect(NULL, trail); + + // ensure we can see this stuff + color.c = 0xffffffff; + + // create small particles + count = GetScaledCount(7, 0.5); + VectorSubtract(missile->r.origin, missile->origin, diff); + Vec3ScaleAssign((1.0 / count), diff); + VectorClear(curpos); + + if (r_detail->value >= DETAIL_HIGH) + { + dur = 700; + } + else + if (r_detail->value >= DETAIL_NORMAL) + { + dur= 600; + } + else + { + dur= 500; + } + + + for (i=0; iacceleration[2] = 0.0; + // figure out our random velocity + VectorSet(ce->origin, flrand(-SMALL_RAD,SMALL_RAD), flrand(-SMALL_RAD,SMALL_RAD), flrand(-SMALL_RAD,SMALL_RAD) ); + // scale it and make it the origin + VectorScale(ce->origin, -1.0, ce->velocity); + VectorAdd(curpos, ce->origin, ce->origin); + // add a fraction of the missile velocity to this particle velocity + VectorScale(missile->velocity, 0.1, scaled_vel); + VectorAdd(scaled_vel, ce->velocity, ce->velocity); + ce->scale = flrand(3, 6); + AddParticleToList(trail, ce); + Vec3SubtractAssign(diff, curpos); + } + + // Remember for even spread of particles + VectorCopy(missile->r.origin, missile->origin); + // rotate the missile + missile->r.angles[0] -= 0.7; + return(true); +} + +#define ARROW_SPEED 400.0F + +// we reflected, create a new missile +void FXMorphMissile(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *missile; + byte blah,pitch; + + // get the initial Yaw + fxi.GetEffect(owner, flags, "bb", &blah,&pitch); + + // create the client effect with the light on it + missile = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 100); + missile->r.angles[YAW] = (blah /255.0) * 6.283185; + missile->r.angles[PITCH] = (pitch /255.0) * 6.283185; + + // figure out where we are going + DirFromAngles(missile->r.angles, missile->velocity); + if (flags & CEF_FLAG6) + Vec3ScaleAssign(ARROW_SPEED/2, missile->velocity); + else + Vec3ScaleAssign(ARROW_SPEED, missile->velocity); + + missile->r.model = morph_models + 1; + missile->r.scale = 3.0; + missile->r.angles[0] = -1.57; + missile->Update = FXMorphMissileThink; + missile->radius = 32.0F; + missile->color.c = MORPH_COL; + missile->dlight = CE_DLight_new(missile->color, 150.0F, 00.0F); + AddEffect(owner, missile); + + fxi.S_StartSound(missile->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/OvumFire.wav"), 1, ATTN_NORM, 0); +} + +// initial entry from server - create first object - this has the light on it - but no trail yet +void FXMorphMissile_initial(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *missile; + client_entity_t *glow; + byte yaw; + float yawf; + short morpharray[NUM_OF_OVUMS]; + int i; + + // get the initial Yaw + fxi.GetEffect(owner, flags, "bssssss", + &yaw, + &morpharray[0], + &morpharray[1], + &morpharray[2], + &morpharray[3], + &morpharray[4], + &morpharray[5]); + + yawf = (yaw /255.0) * 6.283185; + for (i = 0; ir.angles[YAW] = yawf; + + // figure out where we are going + DirFromAngles(missile->r.angles, missile->velocity); + Vec3ScaleAssign(ARROW_SPEED, missile->velocity); + + missile->r.model = morph_models + 1; + missile->r.scale = 3.0; + missile->r.angles[0] = -1.57; + missile->Update = FXMorphMissileThink; + missile->radius = 32.0F; + missile->color.c = MORPH_COL; + missile->dlight = CE_DLight_new(missile->color, 110.0F, 00.0F); + AddEffect((centity_t *)(&fxi.server_entities[morpharray[i]]), missile); + yawf += MORPH_ANGLE_INC; + } + + fxi.S_StartSound(missile->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/OvumFire.wav"), 1, ATTN_NORM, 0); + + if (r_detail->value >= DETAIL_HIGH) + { + glow = ClientEntity_new(type, flags, origin, 0, 800); + glow->r.model = morph_models; + + glow->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + glow->color.c = MORPH_COL; + glow->r.color.c = MORPH_COL; + glow->dlight = CE_DLight_new(glow->color, GLOW_INTENSITY, -GLOW_INTENSITY); + glow->d_scale = 1.8; + glow->r.scale = 0.5; + glow->d_alpha = -1.0; + glow->SpawnInfo = MORPH_GLOW_DUR; + + AddEffect(NULL, glow); + } +} + + +// ----------------------------------------------------------------------------------------- + +// we hit a wall or an object +#define SMOKE_SPEED 160 +void FXMorphExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *dlight; + paletteRGBA_t color; + vec3_t Dir; + client_particle_t *ce; + int i, count, dur; + float max_rand; + + fxi.GetEffect(owner,flags,"d",Dir); + + // make a bunch of small particles explode out the wall / object + VectorScale(Dir,SMOKE_SPEED,Dir); + count = GetScaledCount(40, 0.3); + + if (r_detail->value >= DETAIL_HIGH) + { + max_rand = 10.0; + dur = 600; + } + else + if (r_detail->value >= DETAIL_NORMAL) + { + max_rand = 8.0; + dur= 500; + } + else + { + max_rand = 7.0; + dur= 400; + } + + // create a light at the point of explosion + dlight = ClientEntity_new(-1, CEF_NO_DRAW | CEF_NOMOVE | CEF_ADDITIVE_PARTS, origin, NULL, dur); + color.c = MORPH_COL; + dlight->dlight = CE_DLight_new(color, 110.0F, 100.0F); + AddEffect(NULL, dlight); + + for(i=0;ivelocity); + + ce->scale=flrand(3.0, max_rand); + + ce->velocity[0]+=flrand(-SMOKE_SPEED,SMOKE_SPEED); + ce->velocity[1]+=flrand(-SMOKE_SPEED,SMOKE_SPEED); + ce->velocity[2]+=flrand(-SMOKE_SPEED,SMOKE_SPEED); + + AddParticleToList(dlight, ce); + } +} + +// make the feather float down +static qboolean FXFeatherThink(client_entity_t *self, centity_t *owner) +{ + float scale; + + if (!(--self->SpawnInfo)) + return(false); + + if (self->SpawnInfo < 10) + self->alpha -= 0.1; + + // is the feather on the way down ? + if (self->velocity[2] < 2) + { + // yes, set gravity much lower. + self->acceleration[2] = -1.0; + self->velocity[2] = -13; + // make the x and z motion much less each time + self->velocity[0] -= self->velocity[0] * 0.1; + self->velocity[1] -= self->velocity[1] * 0.1; + // has the feather already hit the horizontal ? + if (self->r.angles[PITCH] == 1.2f) + { + // if its time, reverse the direction of the swing + if (!(--self->LifeTime)) + { + self->LifeTime = FLOAT_TIME; + self->xscale = -self->xscale; + self->yscale = -self->yscale; + } + // add in the feather swing to the origin + scale = sin(self->LifeTime * FLOAT_SLOW); + self->r.origin[0] += (self->xscale * scale); + self->r.origin[1] += (self->yscale * scale); + self->r.origin[2] += (1.4 * scale) - 0.7; + } + // wait till the feather hits the horizontal by itself + else + if ((self->r.angles[PITCH] < 1.3) && (self->r.angles[PITCH] > 1.1) ) + { + self->r.angles[PITCH] = 1.2; + self->yscale = flrand(-2.5,2.5); + self->xscale = flrand(-2.5,2.5); + self->LifeTime = FLOAT_TIME; + } + else + { + // not hit the horizontal yet, so keep it spinning + self->r.angles[YAW] += self->xscale; + self->r.angles[PITCH] += self->yscale; + // this is bogus, but has to be done if the above pitch check is going to work + if (self->r.angles[PITCH] < 0) + self->r.angles[PITCH] += 6.28; + else + if (self->r.angles[PITCH] > 6.28) + self->r.angles[PITCH] -= 6.28; + } + return(true); + } + else + { + // still on the way up, make the feather turn + self->r.angles[PITCH] += self->yscale; + self->r.angles[YAW] += self->xscale; + // this is bogus, but has to be done if the above pitch check is going to work + if (self->r.angles[PITCH] < 0) + self->r.angles[PITCH] += 6.28; + else + if (self->r.angles[PITCH] > 6.28) + self->r.angles[PITCH] -= 6.28; + } + return(true); +} + +// make the feathers zip out of the carcess and float down +void FXChickenExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *feather; + int i; + + //NOTENOTE: CEF_FLAG6 denotes we just want to spawn a couple feathers + if (flags & CEF_FLAG6) + { + i = irand(1,2); + + while (i--) + { + feather = ClientEntity_new(type, flags & ~CEF_OWNERS_ORIGIN , origin, NULL, 40); + feather->radius = 5.0F; + feather->r.model = morph_models + irand(2,3); + feather->r.flags= RF_TRANSLUCENT; + feather->Update = FXFeatherThink; + feather->acceleration[2] = irand(-85, -120); + VectorSet(feather->velocity, flrand(-100,100), flrand(-100,100), flrand(50,150)); + feather->r.scale = flrand(0.5, 1.5); + feather->SpawnInfo = 170; + feather->yscale = flrand(0.05,0.2); + feather->xscale = flrand(-0.2,0.2); + + feather->origin[0] += flrand(-8.0F, 8.0F); + feather->origin[1] += flrand(-8.0F, 8.0F); + feather->origin[2] += flrand(-8.0F, 8.0F); + + AddEffect(NULL, feather); + } + } + else + { + for (i=0; i<20; i++) + { + feather = ClientEntity_new(type, flags & ~CEF_OWNERS_ORIGIN , origin, NULL, 40); + feather->radius = 5.0F; + feather->r.model = morph_models + irand(2,3); + feather->r.flags= RF_TRANSLUCENT; + feather->Update = FXFeatherThink; + feather->acceleration[2] = -85; + VectorSet(feather->velocity, flrand(-FEATH_RAD,FEATH_RAD), flrand(-FEATH_RAD,FEATH_RAD), flrand(80,140)); + feather->r.scale = flrand(0.5, 2.5); + feather->SpawnInfo = 170; + feather->yscale = flrand(0.1,0.3); + feather->xscale = flrand(-0.3,0.3); + AddEffect(NULL, feather); + } + } +} + + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_objects.c b/Toolkit/Programming/GameCode/client effects/fx_objects.c new file mode 100644 index 0000000..c7ecf68 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_objects.c @@ -0,0 +1,125 @@ +// +// fx_objects.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "Utilities.h" +#include "fx_debris.h" +#include "g_playstats.h" +#include "fx_debris.h" + +#define BARREL_EXPLODE_SPEED 80.0 +#define BARREL_EXPLODE_BALLS 3 +#define BARREL_EXPLODE_BITS 16 +#define BARREL_EXPLODE_GRAVITY (-320.0) +#define BARREL_EXPLODE_SCALE 14.0 +#define BARREL_RADIUS 24 + +#define NUM_OBJECT_MODELS 2 + +static struct model_s *obj_models[NUM_OBJECT_MODELS]; + +void PreCacheObjects() +{ + obj_models[0] = fxi.RegisterModel("models/fx/explosion/outer/tris.fm"); + obj_models[1] = fxi.RegisterModel("sprites/fx/halo.sp2"); +} + +extern qboolean FXPhoenixExplosionBallThink(client_entity_t *explosion, centity_t *owner); +extern qboolean FXPhoenixExplosionSmallBallThink(client_entity_t *explosion, centity_t *owner); +extern client_entity_t *CreatePhoenixSmallExplosion(vec3_t ballorigin); + + + + +// ************************************************************************************************ +// FXBarrelExplode +// ************************************************************************************************ +// Create Effect FX_BARREL_EXPLODE +void FXBarrelExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *explosion, *subexplosion; + paletteRGBA_t color; + vec3_t dir={0, 0, 1}; + client_particle_t *spark; + int i; + float ballnum; + vec3_t mins={BARREL_RADIUS, BARREL_RADIUS, BARREL_RADIUS}; + + // Create three smaller explosion spheres. + for (i=0; i < BARREL_EXPLODE_BALLS; i++) + { + ballnum = i; + subexplosion = CreatePhoenixSmallExplosion(origin); + VectorSet(subexplosion->velocity, + flrand(-BARREL_EXPLODE_SPEED, BARREL_EXPLODE_SPEED), + flrand(-BARREL_EXPLODE_SPEED, BARREL_EXPLODE_SPEED), + flrand(-BARREL_EXPLODE_SPEED, BARREL_EXPLODE_SPEED)); + subexplosion->r.scale = 0.1; + subexplosion->d_scale = 3.0 + ballnum; + subexplosion->d_alpha = -1.5 - 0.5*ballnum; + + AddEffect(NULL, subexplosion); + } + + // Create the main big explosion sphere. + explosion = ClientEntity_new(type, flags, origin, NULL, 17); + explosion->r.model = obj_models; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->flags |= CEF_ADDITIVE_PARTS | CEF_PULSE_ALPHA; + explosion->alpha = 0.1; + explosion->r.scale= 0.1; + explosion->d_alpha = 3.0; + explosion->d_scale=5.0; + explosion->radius=128; + explosion->startTime = fxi.cl->time; + explosion->lastThinkTime = fxi.cl->time; + explosion->velocity2[YAW] = flrand(-M_PI, M_PI); + explosion->velocity2[PITCH] = flrand(-M_PI, M_PI); + + color.c = 0xff00ffff; + explosion->dlight = CE_DLight_new(color, 150.0F, 0.0F); + explosion->Update = FXPhoenixExplosionBallThink; + AddEffect(NULL, explosion); + + // Add some glowing blast particles. + VectorScale(dir,BARREL_EXPLODE_SPEED,dir); + for(i = 0; i < BARREL_EXPLODE_BITS; i++) + { + spark = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), color, 2000); + VectorSet(spark->velocity, flrand(-BARREL_EXPLODE_SPEED, BARREL_EXPLODE_SPEED), + flrand(-BARREL_EXPLODE_SPEED, BARREL_EXPLODE_SPEED), + flrand(-BARREL_EXPLODE_SPEED, BARREL_EXPLODE_SPEED)); + VectorAdd(spark->velocity, dir, spark->velocity); + spark->acceleration[2] = BARREL_EXPLODE_GRAVITY; + spark->scale = BARREL_EXPLODE_SCALE; + spark->d_scale = flrand(-20.0, -10.0); + spark->d_alpha = flrand(-400.0, -320.0); + spark->duration = (255.0 * 2000.0) / -spark->d_alpha; // time taken to reach zero alpha + + AddParticleToList(explosion, spark); + } + + // ...and a big-ass flash + explosion = ClientEntity_new(-1, flags, origin, NULL, 250); + explosion->r.model = obj_models + 1; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->r.frame = 1; + explosion->radius=128; + explosion->r.scale=2.0; + explosion->d_alpha=-4.0; + explosion->d_scale=-4.0; + AddEffect(NULL, explosion); + + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("weapons/PhoenixHit.wav"), 1, ATTN_NORM, 0); +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_pespell.c b/Toolkit/Programming/GameCode/client effects/fx_pespell.c new file mode 100644 index 0000000..96489b6 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_pespell.c @@ -0,0 +1,546 @@ +// +// fx_pespell.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "Utilities.h" +#include "fx_debris.h" +#include "g_playstats.h" + +#define SPELL_DELTA_FORWARD 8.0 +#define SPELL_DELTA_THETA 0.12 +#define SPELL_SPIRAL_RAD 0.75 +#define SPELL_SCALE 0.25 + +#define NUM_SPELL_MODELS 5 + +static struct model_s *spell_models[NUM_SPELL_MODELS]; + +void PrecachePESpell() +{ + spell_models[0] = fxi.RegisterModel("Sprites/Spells/flyingfist.sp2"); + spell_models[1] = fxi.RegisterModel("Sprites/Spells/spellhands_red.sp2"); + spell_models[2] = fxi.RegisterModel("Sprites/Spells/halo_ind.sp2"); + spell_models[3] = fxi.RegisterModel("Sprites/Spells/spark_ind.sp2"); + spell_models[4] = fxi.RegisterModel("Sprites/fx/core_b.sp2"); +} + +enum +{ + FX_PE_MAKE_SPELL, + FX_PE_EXPLODE_SPELL, + FX_PE_MAKE_SPELL2, + FX_PE_EXPLODE_SPELL2, + FX_PE_MAKE_SPELL3, + FX_PE_EXPLODE_SPELL3, +}; +// ************************************************************************************************ +// FXPESpellTrailThink +// ************************************************************************************************ + +static qboolean FXPESpellTrailThink(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *TrailEnt; + vec3_t accel_dir; + int i; + + self->updateTime = 20; + + if(self->SpawnInfo > 9) + self->SpawnInfo--; + + i = GetScaledCount( irand(self->SpawnInfo >> 3, self->SpawnInfo >> 2), 0.8 ); + while(i--) + { + TrailEnt = ClientEntity_new(FX_PE_SPELL, 0, self->r.origin, NULL, 1000); + TrailEnt->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + VectorCopy(self->velocity, accel_dir); + VectorNormalize(accel_dir); + + TrailEnt->r.model = spell_models; + TrailEnt->r.scale = SPELL_SCALE + flrand(0.0, 0.05); + + TrailEnt->r.color.r = irand(40, 60); + TrailEnt->r.color.g = irand(245, 255); + TrailEnt->r.color.b = irand(95, 105); + + VectorRandomCopy(self->r.origin, TrailEnt->r.origin, flrand(-5.0, 5.0)); + VectorScale(accel_dir, flrand(-50.0, -400.0), TrailEnt->velocity); + + TrailEnt->d_alpha = flrand(-1.5, -2.0); + TrailEnt->d_scale = flrand(-1.0, -1.25); + TrailEnt->updateTime = (TrailEnt->alpha * 1000.0) / -TrailEnt->d_scale; + TrailEnt->radius = 20.0; + + AddEffect(NULL,TrailEnt); + } + + return(true); +} + +// ************************************************************************************************ +// FXPESpell +// ************************************************************************************************ + +//////////////////////////////////// +// From CreateEffect FX_WEAPON_PESPELL +//////////////////////////////////// +void FXPESpellGo(centity_t *owner, int type, int flags, vec3_t origin, vec3_t vel) +{ + vec3_t dir; + client_entity_t *missile; + paletteRGBA_t LightColor; + float lightsize; + + missile = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 100); + + missile->flags |= CEF_NO_DRAW; + LightColor.c = 0xff20a0ff; // Orange light + lightsize = 120.0; + + VectorCopy(vel, missile->velocity); + VectorNormalize2(vel, dir); + AnglesFromDir(dir, missile->r.angles); + + missile->radius = 128; + if(r_detail->value > DETAIL_NORMAL) + missile->dlight = CE_DLight_new(LightColor, lightsize, 0.0f); + missile->Update = FXPESpellTrailThink; + + missile->SpawnInfo = 32; + + AddEffect(owner, missile); + + fxi.S_StartSound(missile->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("monsters/plagueelf/spell.wav"), + 1, ATTN_NORM, 0); +} + + + +// ************************************************************************************************ +// FXPESpellExplode +// ************************************************************************************************ + +/////////////////////////////////////// +// From CreateEffect FX_WEAPON_PESPELLEXPLODE +/////////////////////////////////////// +void FXPESpellExplode(centity_t *owner,int type,int flags,vec3_t origin, vec3_t dir) +{ + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor; + byte powerup = 0; + float lightrad; + + if(flags & CEF_FLAG6) + { + FXClientScorchmark(origin, dir); + } + + Vec3ScaleAssign(32.0, dir); + + i = GetScaledCount(irand(8, 12), 0.8); + LightColor.c = 0xff20a0ff; + lightrad = 150; + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(type,flags,origin,NULL,500); + else + SmokePuff=ClientEntity_new(type,flags,origin,NULL,1000); + + SmokePuff->r.model = spell_models + 1; + SmokePuff->r.scale=flrand(0.8,1.6); + SmokePuff->d_scale=-2.0; + + VectorRandomCopy(dir, SmokePuff->velocity, 64.0); + SmokePuff->acceleration[0] = flrand(-200, 200); + SmokePuff->acceleration[1] = flrand(-200, 200); + SmokePuff->acceleration[2] = flrand(-40, -60); + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + SmokePuff->r.color.r = irand(40, 60); + SmokePuff->r.color.g = irand(245, 255); + SmokePuff->r.color.b = irand(95, 105); + + SmokePuff->r.frame=0; + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + if(!i) + {//precache this? + fxi.S_StartSound(SmokePuff->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("monsters/plagueelf/spellhit.wav"), + 1, ATTN_NORM, 0); + SmokePuff->dlight=CE_DLight_new(LightColor,lightrad,0.0f); + VectorClear(SmokePuff->velocity); + } + + AddEffect(NULL,SmokePuff); + } +} + +//================================================================================= + +// ************************************************************************************************ +// FXPESpell2TrailThink +// ************************************************************************************************ + +static qboolean FXPESpell2TrailThink(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *TrailEnt; + vec3_t accel_dir; + int i; + + self->updateTime = 20; + + if(self->SpawnInfo > 9) + self->SpawnInfo--; + + i = GetScaledCount( irand(self->SpawnInfo >> 3, self->SpawnInfo >> 2), 0.8 ); + while(i--) + { + TrailEnt = ClientEntity_new(FX_PE_SPELL, 0, self->r.origin, NULL, 1000); + TrailEnt->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + VectorCopy(self->velocity, accel_dir); + VectorNormalize(accel_dir); + + TrailEnt->r.model = spell_models + 2; + TrailEnt->r.frame = irand(0,1); + + TrailEnt->r.scale = SPELL_SCALE + flrand(0.0, 0.05); + + /*TrailEnt->r.color.g = irand(40, 60); + TrailEnt->r.color.b = irand(245, 255); + TrailEnt->r.color.r = irand(95, 105);*/ + + VectorRandomCopy(self->r.origin, TrailEnt->r.origin, flrand(-5.0, 5.0)); + VectorScale(accel_dir, flrand(-50.0, -400.0), TrailEnt->velocity); + + TrailEnt->d_alpha = flrand(-1.5, -2.0); + TrailEnt->d_scale = flrand(-1.0, -1.25); + TrailEnt->updateTime = (TrailEnt->alpha * 1000.0) / -TrailEnt->d_scale; + TrailEnt->radius = 20.0; + + AddEffect(NULL,TrailEnt); + } + + return(true); +} + +// ************************************************************************************************ +// FXPESpell2 +// ************************************************************************************************ + +//////////////////////////////////// +// From CreateEffect FX_WEAPON_PESPELL +//////////////////////////////////// +void FXPESpell2Go(centity_t *owner, int type, int flags, vec3_t origin, vec3_t vel) +{ + vec3_t dir; + client_entity_t *missile; + paletteRGBA_t LightColor; + float lightsize; + + missile = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 100); + + missile->flags |= CEF_NO_DRAW; + LightColor.c = 0xffff0077; // purple + lightsize = 120.0; + + VectorCopy(vel, missile->velocity); + VectorNormalize2(vel, dir); + AnglesFromDir(dir, missile->r.angles); + + missile->radius = 128; + if(r_detail->value > DETAIL_NORMAL) + missile->dlight = CE_DLight_new(LightColor, lightsize, 0.0f); + missile->Update = FXPESpell2TrailThink; + + missile->SpawnInfo = 32; + + AddEffect(owner, missile); + + fxi.S_StartSound(missile->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("monsters/plagueelf/spell2.wav"), + 1, ATTN_NORM, 0); +} + + + +// ************************************************************************************************ +// FXPESpell2Explode +// ************************************************************************************************ + +/////////////////////////////////////// +// From CreateEffect FX_WEAPON_PESPELLEXPLODE +/////////////////////////////////////// +void FXPESpell2Explode(centity_t *owner,int type,int flags,vec3_t origin, vec3_t dir) +{ + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor; + byte powerup = 0; + float lightrad; + + if(flags & CEF_FLAG6) + { + FXClientScorchmark(origin, dir); + } + + Vec3ScaleAssign(32.0, dir); + + i = GetScaledCount(irand(8, 12), 0.8); + LightColor.c = 0xffff0077; // purple + lightrad = 150; + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(type,flags,origin,NULL,500); + else + SmokePuff=ClientEntity_new(type,flags,origin,NULL,1000); + + SmokePuff->r.model = spell_models + 3; + SmokePuff->r.scale=flrand(0.8,1.6); + SmokePuff->d_scale=-2.0; + + VectorRandomCopy(dir, SmokePuff->velocity, 64.0); + SmokePuff->acceleration[0] = flrand(-200, 200); + SmokePuff->acceleration[1] = flrand(-200, 200); + SmokePuff->acceleration[2] = flrand(-40, -60); + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + /* + SmokePuff->r.color.g = irand(40, 60); + SmokePuff->r.color.b = irand(245, 255); + SmokePuff->r.color.r = irand(95, 105);*/ + + SmokePuff->r.frame=0; + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + if(!i) + {//precache this? + fxi.S_StartSound(SmokePuff->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("monsters/plagueelf/spell2hit.wav"), + 1, ATTN_NORM, 0); + SmokePuff->dlight=CE_DLight_new(LightColor,lightrad,0.0f); + VectorClear(SmokePuff->velocity); + } + + AddEffect(NULL,SmokePuff); + } +} + +//===================================================================================== + +// ************************************************************************************************ +// FXPESpell3TrailThink +// ************************************************************************************************ + +static qboolean FXPESpell3TrailThink(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *TrailEnt; + vec3_t accel_dir; + int i; + + self->updateTime = 20; + + if(self->SpawnInfo > 9) + self->SpawnInfo--; + + i = GetScaledCount( irand(self->SpawnInfo >> 3, self->SpawnInfo >> 2), 0.8 ); + while(i--) + { + TrailEnt = ClientEntity_new(FX_PE_SPELL, 0, self->r.origin, NULL, 1000); + TrailEnt->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + VectorCopy(self->velocity, accel_dir); + VectorNormalize(accel_dir); + + TrailEnt->r.model = spell_models; + TrailEnt->r.scale = SPELL_SCALE + flrand(0.0, 0.05); + + /*TrailEnt->r.color.g = irand(40, 60); + TrailEnt->r.color.r = irand(245, 255); + TrailEnt->r.color.b = irand(95, 105);*/ + + VectorRandomCopy(self->r.origin, TrailEnt->r.origin, flrand(-5.0, 5.0)); + VectorScale(accel_dir, flrand(-50.0, -400.0), TrailEnt->velocity); + + TrailEnt->d_alpha = flrand(-1.5, -2.0); + TrailEnt->d_scale = flrand(-1.0, -1.25); + TrailEnt->updateTime = (TrailEnt->alpha * 1000.0) / -TrailEnt->d_scale; + TrailEnt->radius = 20.0; + + AddEffect(NULL,TrailEnt); + } + + return(true); +} + +// ************************************************************************************************ +// FXPESpell3 +// ************************************************************************************************ + +//////////////////////////////////// +// From CreateEffect FX_WEAPON_PESPELL +//////////////////////////////////// +void FXPESpell3Go(centity_t *owner, int type, int flags, vec3_t origin, vec3_t vel) +{ + vec3_t dir; + client_entity_t *missile; + paletteRGBA_t LightColor; + float lightsize; + + missile = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 100); + + missile->flags |= CEF_NO_DRAW; + LightColor.c = 0xffff6611; // cyan + lightsize = 120.0; + + VectorCopy(vel, missile->velocity); + VectorNormalize2(vel, dir); + AnglesFromDir(dir, missile->r.angles); + + missile->radius = 128; + if(r_detail->value > DETAIL_NORMAL) + missile->dlight = CE_DLight_new(LightColor, lightsize, 0.0f); + missile->Update = FXPESpell3TrailThink; + + missile->SpawnInfo = 32; + + AddEffect(owner, missile); + + fxi.S_StartSound(missile->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("monsters/plagueelf/spell3.wav"), + 1, ATTN_NORM, 0); +} + + + +// ************************************************************************************************ +// FXPESpell3Explode +// ************************************************************************************************ + +/////////////////////////////////////// +// From CreateEffect FX_WEAPON_PESPELLEXPLODE +/////////////////////////////////////// +void FXPESpell3Explode(centity_t *owner,int type,int flags,vec3_t origin, vec3_t dir) +{ + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor; + byte powerup = 0; + float lightrad; + + if(flags & CEF_FLAG6) + { + FXClientScorchmark(origin, dir); + } + + Vec3ScaleAssign(32.0, dir); + + i = GetScaledCount(irand(8, 12), 0.8); + LightColor.c = 0xffff6611; // cyan + lightrad = 150; + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(type,flags,origin,NULL,500); + else + SmokePuff=ClientEntity_new(type,flags,origin,NULL,1000); + + SmokePuff->r.model = spell_models + 4; + SmokePuff->r.scale=flrand(1.0, 1.8); + SmokePuff->d_scale=-2.0; + + VectorRandomCopy(dir, SmokePuff->velocity, 64.0); + SmokePuff->acceleration[0] = flrand(-200, 200); + SmokePuff->acceleration[1] = flrand(-200, 200); + SmokePuff->acceleration[2] = flrand(-40, -60); + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + /* + SmokePuff->r.color.g = irand(40, 60); + SmokePuff->r.color.r = irand(245, 255); + SmokePuff->r.color.b = irand(95, 105); + */ + + SmokePuff->r.frame=0; + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + if(!i) + {//precache this? + fxi.S_StartSound(SmokePuff->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("monsters/plagueelf/spell3hit.wav"), + 1, ATTN_NORM, 0); + SmokePuff->dlight=CE_DLight_new(LightColor,lightrad,0.0f); + VectorClear(SmokePuff->velocity); + } + + AddEffect(NULL,SmokePuff); + } +} + +//==================================================================== +// FX_PE_SPELL effect handler +//==================================================================== + +void FXCWStars (centity_t *owner,int type,int flags, vec3_t vel); +void FXPESpell(centity_t *owner, int type, int flags, vec3_t origin) +{ + byte whicheffect = 0; + vec3_t vel; + + fxi.GetEffect(owner, flags, "bv", &whicheffect, vel); + + switch(whicheffect) + { + case FX_PE_MAKE_SPELL: + FXPESpellGo(owner, type, flags, origin, vel); + break; + + case FX_PE_EXPLODE_SPELL: + FXPESpellExplode(owner, type, flags, origin, vel); + break; + + case FX_PE_MAKE_SPELL2: + FXPESpell2Go(owner, type, flags, origin, vel); + break; + + case FX_PE_EXPLODE_SPELL2: + FXPESpell2Explode(owner, type, flags, origin, vel); + break; + + case FX_PE_MAKE_SPELL3: + FXCWStars(owner, type, flags, origin); + //FXPESpell3Go(owner, type, flags, origin, vel); + break; + + case FX_PE_EXPLODE_SPELL3: + FXPESpell3Explode(owner, type, flags, origin, vel); + break; + + default: + Com_Printf("Unknown effect type (%d) for FXSsithraArrow\n", whicheffect); + break; + } +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_phoenix.c b/Toolkit/Programming/GameCode/client effects/fx_phoenix.c new file mode 100644 index 0000000..263427b --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_phoenix.c @@ -0,0 +1,714 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "angles.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "motion.h" +#include "Reference.h" +#include "ce_Dlight.h" +#include "q_Sprite.h" +#include "g_playstats.h" + +#define EXPLODE_SPEED 160.0 +#define EXPLODE_GRAVITY (-320.0) +#define EXPLODE_SCALE 14.0 +#define EXPLODE_NUM_BITS 32 +#define EXPLODE_BALL_SPEED 64.0 +#define EXPLODE_BALL_DELAY 5 +#define EXPLODE_NUM_SMALLBALLS 3 +#define EXPLODE_LIFETIME 50 +#define EXPLODE_TIME_MAX 750 + +#define FIRETRAIL_PARTS 4 +#define FIRETRAIL_RADIUS 6.0 +#define FIRETRAIL_SPEED 16.0 +#define FIRETRAIL_SCALE 12.0 +#define FIRETRAIL_ACCEL 32.0 + +#define SMOKETRAIL_RADIUS 2.0 +#define SMOKETRAIL_SCALE 0.25 +#define SMOKETRAIL_ALPHA 0.5 + +static qboolean FXPhoenixMissilePowerThink(client_entity_t *missile, centity_t *owner); +void FXPhoenixExplodePower(centity_t *owner, int type, int flags, vec3_t origin, vec3_t dir); + + +#define NUM_PHOEN_MODELS 6 +static struct model_s *phoen_models[NUM_PHOEN_MODELS]; +void PreCachePhoenix() +{ + phoen_models[0] = fxi.RegisterModel("sprites/fx/steam_add.sp2"); + phoen_models[1] = fxi.RegisterModel("models/spells/phoenixarrow/tris.fm"); + phoen_models[2] = fxi.RegisterModel("sprites/fx/halo.sp2"); + phoen_models[3] = fxi.RegisterModel("sprites/spells/phoenix.sp2"); + phoen_models[4] = fxi.RegisterModel("models/fx/explosion/inner/tris.fm"); + phoen_models[5] = fxi.RegisterModel("models/fx/explosion/outer/tris.fm"); +} + + +// ----------------------------------------------------------------------------------------- + + +static qboolean FXPhoenixMissileThink(client_entity_t *missile, centity_t *owner) +{ + int i; + int dur; + client_particle_t *flame; + client_entity_t *smoke; + vec3_t angles, fwd, right, smokeorigin; + paletteRGBA_t LightColor={0xff, 0x7f, 0x00, 0xe5}; + + if (r_detail->value == DETAIL_LOW) + dur = 1400; + else + if (r_detail->value == DETAIL_NORMAL) + dur = 1700; + else + dur = 2000; + + // Here we want to shoot out flame to either side + VectorScale(missile->r.angles, 180.0/M_PI, angles); + AngleVectors(angles, fwd, right, NULL); + VectorScale(fwd, -4.0*FIRETRAIL_SPEED, fwd); + VectorScale(right, FIRETRAIL_SPEED, right); + + // Throw smoke to each side, alternating. + if ((missile->LifeTime--)&0x01) + { // to the right + VectorSet( smokeorigin, + flrand(-SMOKETRAIL_RADIUS, SMOKETRAIL_RADIUS), + flrand(-SMOKETRAIL_RADIUS, SMOKETRAIL_RADIUS), + flrand(-SMOKETRAIL_RADIUS/2.0, SMOKETRAIL_RADIUS/2.0)); + VectorAdd( smokeorigin, missile->origin, smokeorigin); + smoke = ClientEntity_new(-1, CEF_DONT_LINK, smokeorigin, NULL, dur); + smoke->r.model = phoen_models; + smoke->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + smoke->radius = 64.0F; + smoke->alpha = SMOKETRAIL_ALPHA; + smoke->r.scale = SMOKETRAIL_SCALE; + smoke->velocity[0] = right[0]*2.0; + smoke->velocity[1] = right[1]*2.0; + smoke->velocity[2] = right[2]*2.0; + smoke->d_scale = 2.0; // Rate of change in scale + smoke->d_alpha = -1.0; + AddEffect(NULL, smoke); // add the smoke as independent world smoke + } + else + { // and to the left + VectorSet( smokeorigin, + flrand(-SMOKETRAIL_RADIUS, SMOKETRAIL_RADIUS), + flrand(-SMOKETRAIL_RADIUS, SMOKETRAIL_RADIUS), + flrand(-SMOKETRAIL_RADIUS/2.0, SMOKETRAIL_RADIUS/2.0)); + VectorAdd( smokeorigin, missile->origin, smokeorigin); + smoke = ClientEntity_new(-1, CEF_DONT_LINK, smokeorigin, NULL, dur); + smoke->r.model = phoen_models; + smoke->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + smoke->radius = 128.0F; + smoke->alpha = SMOKETRAIL_ALPHA; + smoke->r.scale = SMOKETRAIL_SCALE; + smoke->velocity[0] = -right[0]*2.0; + smoke->velocity[1] = -right[1]*2.0; + smoke->velocity[2] = -right[2]*2.0; + smoke->d_scale = 2.0; // Rate of change in scale + smoke->d_alpha = -1.0; + AddEffect(NULL, smoke); // add the smoke as independent world smoke + } + + smoke->flags |= CEF_ADDITIVE_PARTS | CEF_ABSOLUTE_PARTS; + // Burn baby burn add fire to the tail. Attach it to the smoke because it doesn't get out of the fx radius so quickly + for(i = 0; i < FIRETRAIL_PARTS; i++) + { + flame = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), LightColor, dur); + VectorSet( flame->origin, + flrand(-FIRETRAIL_RADIUS, FIRETRAIL_RADIUS), + flrand(-FIRETRAIL_RADIUS, FIRETRAIL_RADIUS), + flrand(-FIRETRAIL_RADIUS/3.0, FIRETRAIL_RADIUS/3.0)); + VectorAdd( missile->origin, flame->origin, flame->origin); + flame->scale = FIRETRAIL_SCALE; + + VectorSet(flame->velocity, + flrand(-FIRETRAIL_SPEED, FIRETRAIL_SPEED), flrand(-FIRETRAIL_SPEED, FIRETRAIL_SPEED), flrand(-1.0, 1.0)); + // Make the fire shoot out the back and to the side + VectorAdd(flame->velocity, fwd, flame->velocity); + // Alternate left and right side of phoenix + if (i&0x01) + VectorAdd(flame->velocity, right, flame->velocity); + else + VectorSubtract(flame->velocity, right, flame->velocity); + flame->acceleration[2] = FIRETRAIL_ACCEL; + flame->d_scale = flrand(-15.0, -10.0); + flame->d_alpha = flrand(-200.0, -160.0); + flame->duration = (255.0 * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + AddParticleToList(smoke, flame); + } + + // Update animation frame. + + // Check if the time is up. + if (fxi.cl->time >= missile->lastThinkTime) + { // Set up animations to go the other direction. + if (missile->NoOfAnimFrames == 7) + { // Set to go backwards to 3. + missile->NoOfAnimFrames = 3; + missile->Scale = -1; + missile->lastThinkTime = fxi.cl->time + (4*50); + missile->r.frame = 7; + } + else + { // Set to go forward to 7 + missile->NoOfAnimFrames = 7; + missile->Scale = -1; + missile->lastThinkTime = fxi.cl->time + (4*50); + missile->r.frame = 3; + } + } + else + { + missile->r.frame = missile->NoOfAnimFrames - (missile->Scale * (int)((missile->lastThinkTime-fxi.cl->time)/50)) - 1; + } + + // Remember for even spread of particles + VectorCopy(missile->r.origin, missile->origin); + return(true); +} + + +/////////////////////////// +// From CreateEffect FX_WEAPON_PHOENIXMISSILE +/////////////////////////// +void FXPhoenixMissile(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *missile; + vec3_t temp; + + missile = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 25); + fxi.GetEffect(owner, flags, "t", missile->velocity); + + if (flags & CEF_FLAG8) + Vec3ScaleAssign(PHOENIX_ARROW_SPEED/2,missile->velocity); + else + Vec3ScaleAssign(PHOENIX_ARROW_SPEED,missile->velocity); + + + VectorCopy(missile->velocity, temp); + VectorNormalize(temp); + AnglesFromDir(temp, missile->r.angles); + + missile->r.model = phoen_models + 1; + missile->flags |= CEF_ADDITIVE_PARTS; + missile->r.frame = 0; + missile->lastThinkTime = fxi.cl->time + (50*7); // Time to play last frame. + missile->NoOfAnimFrames = 7; // End on frame number 7. + missile->Scale = 1; // Positive frame count + missile->r.scale= .8; + if(flags & CEF_FLAG6) + { + missile->Update = FXPhoenixMissilePowerThink; + } + else + { + missile->Update = FXPhoenixMissileThink; + } + missile->radius = 256; + missile->color.c = 0xff00ffff; + if (r_detail->value != DETAIL_LOW) + missile->dlight = CE_DLight_new(missile->color, 150.0F, 00.0F); + missile->LifeTime = 1000; + AddEffect(owner, missile); + +} + +// ----------------------------------------------------------------------------------------- +// This is also exported for use in FXBarrelExplode/ +qboolean FXPhoenixExplosionBallThink(client_entity_t *explosion, centity_t *owner) +{ + float velfactor; + + if (fxi.cl->time-explosion->startTime > EXPLODE_TIME_MAX) + { + return(false); + } + + velfactor = (fxi.cl->time - explosion->lastThinkTime) / 1000.0; + explosion->lastThinkTime = fxi.cl->time; + + // Spin the ball of fire while it expands and fades. + explosion->r.angles[YAW] += explosion->velocity2[YAW] * velfactor; + explosion->r.angles[PITCH] += explosion->velocity2[PITCH] * velfactor; + + if(explosion->dlight->intensity > 0.0F) + explosion->dlight->intensity -= 5.0F; + + return(true); +} + +// This is also exported for use in FXBarrelExplode/ +qboolean FXPhoenixExplosionSmallBallThink(client_entity_t *explosion, centity_t *owner) +{ + float velfactor; + + if (fxi.cl->time-explosion->startTime > EXPLODE_TIME_MAX) + { + return(false); + } + + velfactor = (fxi.cl->time - explosion->lastThinkTime) / 1000.0; + explosion->lastThinkTime = fxi.cl->time; + + // Spin the ball of fire while it expands and fades. + explosion->r.angles[YAW] += explosion->velocity2[YAW] * velfactor; + explosion->r.angles[PITCH] += explosion->velocity2[PITCH] * velfactor; + + return(true); +} + +static qboolean FXPhoenixExplosionBirdThink(client_entity_t *bird, centity_t *owner) +{ + client_entity_t *newbird; + vec3_t pos; + int dur; + + bird->LifeTime--; + if (bird->LifeTime <= 0) + { + return(false); + } + + if(r_detail->value == DETAIL_LOW) + dur = 175; + else + if(r_detail->value == DETAIL_NORMAL) + dur = 210; + else + dur = 250; + + // Spawn another trail bird + VectorSet(pos, flrand(-8, 8), flrand(-8, 8), flrand(-8, 8)); + VectorAdd(pos, bird->r.origin, pos); + newbird = ClientEntity_new(-1, bird->r.flags, pos, NULL, dur); + newbird->r.model = phoen_models + 3; + newbird->r.frame = 1; + newbird->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + newbird->radius = 128; + newbird->r.scale= bird->r.scale; + newbird->alpha = bird->alpha; + newbird->d_alpha= -(newbird->alpha*4.0); + newbird->d_scale= 2.0; + VectorCopy(bird->velocity, newbird->velocity); + AddEffect(NULL, newbird); + + return (true); +} + +// This is also exported for use in FXBarrelExplode +client_entity_t *CreatePhoenixSmallExplosion(vec3_t ballorigin) +{ + client_entity_t *subexplosion; + + subexplosion = ClientEntity_new(FX_WEAPON_PHOENIXEXPLODE, CEF_BROADCAST, ballorigin, NULL, 17); + subexplosion->r.model = phoen_models + 4; + subexplosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + subexplosion->alpha = 1.0; + subexplosion->r.scale = 1.0; + subexplosion->radius=128; + subexplosion->startTime = fxi.cl->time; + subexplosion->lastThinkTime = fxi.cl->time; + subexplosion->velocity2[YAW] = flrand(-M_PI, M_PI); + subexplosion->velocity2[PITCH] = flrand(-M_PI, M_PI); + subexplosion->Update = FXPhoenixExplosionSmallBallThink; + + return(subexplosion); +} + + + +////////////////////////// +// From CreateEffect FX_WEAPON_PHOENIXEXPLODE +////////////////////////// +void FXPhoenixExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *explosion, *subexplosion; + paletteRGBA_t color; + vec3_t dir, sdir; + client_particle_t *spark; + int i; + float ballnum; + int count, dur; + + fxi.GetEffect(owner,flags,"td",dir,sdir); + + // make the scorch mark if we should + if(flags & CEF_FLAG8) + FXClientScorchmark(origin, sdir); + + if(flags & CEF_FLAG6) + { // powered up version + FXPhoenixExplodePower(owner, type, flags, origin, dir); + return; + } + + flags |= CEF_OWNERS_ORIGIN; + + if(r_detail->value != DETAIL_LOW) + { + count = EXPLODE_NUM_SMALLBALLS; + if(r_detail->value == DETAIL_NORMAL) + count = EXPLODE_NUM_SMALLBALLS - 1; + + // Create three smaller explosion spheres. + for (i=0; i < count; i++) + { + ballnum = i; + subexplosion = CreatePhoenixSmallExplosion(origin); + VectorSet(subexplosion->velocity, + flrand(-EXPLODE_BALL_SPEED, EXPLODE_BALL_SPEED) + (dir[0]*EXPLODE_BALL_SPEED), + flrand(-EXPLODE_BALL_SPEED, EXPLODE_BALL_SPEED) + (dir[1]*EXPLODE_BALL_SPEED), + flrand(-EXPLODE_BALL_SPEED, EXPLODE_BALL_SPEED) + (dir[2]*EXPLODE_BALL_SPEED)); + subexplosion->r.scale = 0.1; + subexplosion->d_scale = 3.0 + ballnum; + subexplosion->d_alpha = -1.5 - 0.5*ballnum; + + AddEffect(NULL, subexplosion); + } + } + + // Create the main big explosion sphere. + explosion = ClientEntity_new(type, flags, origin, NULL, 17); + explosion->r.model = phoen_models + 5; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->flags |= CEF_ADDITIVE_PARTS | CEF_PULSE_ALPHA; + explosion->alpha = 0.1; + explosion->r.scale= 0.1; + explosion->d_alpha = 3.0; + explosion->d_scale=5.0; + explosion->radius=128; + explosion->startTime = fxi.cl->time; + explosion->lastThinkTime = fxi.cl->time; + explosion->velocity2[YAW] = flrand(-M_PI, M_PI); + explosion->velocity2[PITCH] = flrand(-M_PI, M_PI); + + color.c = 0xff00ffff; + explosion->dlight = CE_DLight_new(color, 150.0F, 0.0F); + explosion->Update = FXPhoenixExplosionBallThink; + AddEffect(NULL, explosion); + + // Add some glowing blast particles. + VectorScale(dir,EXPLODE_SPEED,dir); + count = GetScaledCount(EXPLODE_NUM_BITS, 0.3); + for(i = 0; i < count; i++) + { + spark = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), color, 2000); + VectorSet(spark->velocity, flrand(-EXPLODE_SPEED, EXPLODE_SPEED), + flrand(-EXPLODE_SPEED, EXPLODE_SPEED), + flrand(-EXPLODE_SPEED, EXPLODE_SPEED)); + VectorAdd(spark->velocity, dir, spark->velocity); + spark->acceleration[2] = EXPLODE_GRAVITY; + spark->scale = EXPLODE_SCALE; + spark->d_scale = flrand(-20.0, -10.0); + spark->d_alpha = flrand(-400.0, -320.0); + spark->duration = (255.0 * 2000.0) / -spark->d_alpha; // time taken to reach zero alpha + + AddParticleToList(explosion, spark); + } + + // ...and a big-ass flash + explosion = ClientEntity_new(-1, flags, origin, NULL, 250); + explosion->r.model = phoen_models + 2; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->r.frame = 1; + explosion->radius=128; + explosion->r.scale=1.5; + explosion->d_alpha=-4.0; + explosion->d_scale=-4.0; + AddEffect(NULL, explosion); + + if(r_detail->value == DETAIL_LOW) + dur = 150; + else + if(r_detail->value == DETAIL_NORMAL) + dur = 125; + else + dur = 100; + + // ...and draw the phoenix rising from the explosion + explosion = ClientEntity_new(type, flags, origin, NULL, dur); + explosion->r.model = phoen_models + 3; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->r.frame = 0; + explosion->radius=128; + explosion->r.scale=0.1; + VectorScale(dir, 0.25, explosion->velocity); + explosion->acceleration[2] = 64; + explosion->alpha = 1.0; + explosion->d_alpha=-1.0; + explosion->d_scale=1.25; + explosion->LifeTime = 10; + explosion->Update = FXPhoenixExplosionBirdThink; + AddEffect(NULL, explosion); + + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("weapons/PhoenixHit.wav"), 1, ATTN_NORM, 0); +} + + + +// end + + +#define PHOENIXPOWER_NUMTRAILS 11 +#define PHOENIXPOWER_PARTS_PER_TRAIL 8 +#define PHOENIXPOWER_RADIUS 72.0 + +static qboolean FXPhoenixExplosionBirdThinkPower(client_entity_t *bird, centity_t *owner) +{ + bird->LifeTime--; + if (bird->LifeTime <= 0) + { + return(false); + } + return (true); +} + +void FXPhoenixExplodePower(centity_t *owner, int type, int flags, vec3_t origin, vec3_t dir) +{ + client_entity_t *explosion, *subexplosion; + paletteRGBA_t color; + client_particle_t *spark; + int i, j; + vec3_t phOrg; + float cosVal, sinVal; + trace_t trace; + vec3_t endPos; + vec3_t minmax = {0, 0, 0}; + int numTrails; + int numParts; + float partHeight; + float detail_scale; + + flags |= CEF_OWNERS_ORIGIN; + + // This isn't actually used but we need something to anchor the particles to + // Create the main big explosion sphere. + explosion = ClientEntity_new(type, flags, origin, NULL, 17); + explosion->r.model = phoen_models + 5; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->flags |= CEF_ADDITIVE_PARTS; + explosion->alpha = 1.0; + explosion->r.scale= .1; + explosion->d_alpha=-2.0/1.5; + explosion->radius=128; + explosion->LifeTime=EXPLODE_LIFETIME; + + color.c = 0xff00ffff; + explosion->dlight = CE_DLight_new(color, 150.0F, 0.0F); + explosion->Update = FXPhoenixExplosionBallThink; + AddEffect(NULL, explosion); + color.c = 0xffffffff; + + numTrails = GetScaledCount(PHOENIXPOWER_NUMTRAILS-4, 0.8) + 4;//4 is the minimum + numParts = GetScaledCount(PHOENIXPOWER_PARTS_PER_TRAIL - 4, .8) + 4;//ditto + + for(i = 0; i < numTrails; i++) + { + cosVal = cos((float)i / (float)numTrails * (M_PI*2)); + sinVal = sin((float)i / (float)numTrails * (M_PI*2)); + + VectorCopy(origin, phOrg); + phOrg[0] += cosVal * PHOENIXPOWER_RADIUS; + phOrg[1] += sinVal * PHOENIXPOWER_RADIUS; + + VectorCopy(phOrg, endPos); + endPos[2] -= 64; + + fxi.Trace( phOrg, minmax, minmax, endPos, CONTENTS_SOLID, CEF_CLIP_TO_WORLD, &trace); + + if(trace.fraction > .99) + { // Burst in the air, no ground found. + subexplosion = ClientEntity_new(-1, flags, phOrg, NULL, 1000); + subexplosion->r.model = phoen_models + 2; + subexplosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + subexplosion->r.frame = 1; + subexplosion->radius=128; + subexplosion->r.scale=1.5; + subexplosion->d_alpha=-1.0; + AddEffect(NULL, subexplosion); + + for(j = 0; j < numParts; j++) + { + partHeight = (j * PHOENIXPOWER_PARTS_PER_TRAIL)/numParts; + + spark = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), color, 1000); + spark->origin[0] = cosVal * 72; + spark->origin[1] = sinVal * 72; + // alternate up and down. + if (j&0x01) + spark->velocity[2] = partHeight * 15.0* (18.0/8.0) + flrand(0, 15); + else + spark->velocity[2] = -partHeight * 15.0* (18.0/8.0) + flrand(0, 15); + spark->scale = 32.0 - (partHeight * (18.0/8.0)/3); + spark->d_scale = -partHeight * (18.0/8.0); + spark->d_alpha = flrand(-400.0, -320.0)/1.3; + spark->duration = (255.0 * 2000.0) / -spark->d_alpha; // time taken to reach zero alpha + + AddParticleToList(explosion, spark); + } + } + else + { + subexplosion = ClientEntity_new(-1, flags, trace.endpos, NULL, 1000); + subexplosion->r.model = phoen_models + 2; + subexplosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + subexplosion->r.frame = 1; + subexplosion->radius=128; + subexplosion->r.scale=1.5; + subexplosion->d_alpha=-1.0; + AddEffect(NULL, subexplosion); + + for(j = 0; j < numParts; j++) + { + partHeight = (j * PHOENIXPOWER_PARTS_PER_TRAIL)/numParts; + + spark = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), color, 1000); + spark->origin[0] = cosVal * 72; + spark->origin[1] = sinVal * 72; + spark->origin[2] = trace.endpos[2] - origin[2]; + spark->velocity[2] = partHeight * 15.0* (18.0/8.0) + flrand(0, 15); + spark->scale = 32.0 - (partHeight * (18.0/8.0)/3); + spark->d_scale = -partHeight * (18.0/8.0); + spark->d_alpha = flrand(-400.0, -320.0)/1.3; + spark->duration = (255.0 * 2000.0) / -spark->d_alpha; // time taken to reach zero alpha + + AddParticleToList(explosion, spark); + } + } + } + + if (r_detail->value == DETAIL_LOW) + detail_scale = 1.5; + else + detail_scale = 2.0; + + // ...and draw the phoenix rising from the explosion + explosion = ClientEntity_new(type, flags, origin, NULL, 100); + explosion->r.model = phoen_models + 3; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->r.frame = 0; + explosion->radius=128; + explosion->r.scale=1.0; + VectorScale(dir, 192.0, explosion->velocity); + explosion->acceleration[2] = 256.0; + explosion->alpha = 1.0; + explosion->d_alpha=-1.5; + explosion->d_scale=detail_scale; + explosion->LifeTime = 6; + explosion->Update = FXPhoenixExplosionBirdThinkPower; + AddEffect(NULL, explosion); + + // inner phoenix + explosion = ClientEntity_new(type, flags, origin, NULL, 100); + explosion->r.model = phoen_models + 3; + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + explosion->r.frame = 0; + explosion->radius=128; + explosion->r.scale=1.0; + VectorScale(dir, 192.0, explosion->velocity); + explosion->acceleration[2] = 256.0; + explosion->alpha = 1.0; + explosion->d_alpha= 0.0; + explosion->d_scale=-1.0/.6; + explosion->LifeTime = 6; + explosion->Update = FXPhoenixExplosionBirdThinkPower; + AddEffect(NULL, explosion); + + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("weapons/PhoenixPowerHit.wav"), 1, ATTN_NORM, 0); +} + +static qboolean FXPhoenixMissilePowerThink(client_entity_t *missile, centity_t *owner) +{ + int i, dur; + client_particle_t *flame; + client_entity_t *smoke; + vec3_t angles, fwd, right, smokeorigin; + paletteRGBA_t LightColor={0xff, 0x7f, 0x00, 0xe5}; + int sideVal; + + if (r_detail->value == DETAIL_LOW) + dur = 1400; + else + if (r_detail->value == DETAIL_NORMAL) + dur = 1700; + else + dur = 2000; + + // Here we want to shoot out flame to either side + VectorScale(missile->r.angles, 180.0/M_PI, angles); + AngleVectors(angles, fwd, right, NULL); + VectorScale(fwd, -4.0*FIRETRAIL_SPEED, fwd); + VectorScale(right, FIRETRAIL_SPEED, right); + + sideVal = (missile->LifeTime&0x1) ? -1:1; + missile->LifeTime--; + // Throw smoke to each side, alternating. + VectorSet( smokeorigin, + flrand(-SMOKETRAIL_RADIUS, SMOKETRAIL_RADIUS), + flrand(-SMOKETRAIL_RADIUS, SMOKETRAIL_RADIUS), + flrand(-SMOKETRAIL_RADIUS/2.0, SMOKETRAIL_RADIUS/2.0)); + VectorAdd( smokeorigin, missile->origin, smokeorigin); + smoke = ClientEntity_new(-1, CEF_DONT_LINK, smokeorigin, NULL, dur); + smoke->r.model = phoen_models; + smoke->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + smoke->radius = 64.0F; + smoke->alpha = SMOKETRAIL_ALPHA; + smoke->r.scale = SMOKETRAIL_SCALE * 2.5; + smoke->velocity[0] = sideVal * right[0]*2.0; + smoke->velocity[1] = sideVal * right[1]*2.0; + smoke->velocity[2] = sideVal * right[2]*2.0; + smoke->d_scale = 2.0; // Rate of change in scale + smoke->d_alpha = -1.0; + AddEffect(NULL, smoke); // add the smoke as independent world smoke + smoke->flags |= CEF_ADDITIVE_PARTS | CEF_ABSOLUTE_PARTS; + + // Burn baby burn add fire to the tail. Attach it to the smoke because it doesn't get out of the fx radius so quickly + for(i = 0; i < FIRETRAIL_PARTS; i++) + { + flame = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), LightColor, dur); + VectorSet( flame->origin, + flrand(-FIRETRAIL_RADIUS/3, FIRETRAIL_RADIUS/3), + flrand(-FIRETRAIL_RADIUS/3, FIRETRAIL_RADIUS/3), + flrand(-FIRETRAIL_RADIUS/3.0, FIRETRAIL_RADIUS/3.0)); + VectorAdd( missile->origin, flame->origin, flame->origin); + flame->scale = FIRETRAIL_SCALE; + + VectorSet(flame->velocity, + flrand(-FIRETRAIL_SPEED/3, FIRETRAIL_SPEED/3), flrand(-FIRETRAIL_SPEED/3, FIRETRAIL_SPEED/3), flrand(-1.0, 1.0)); + // Make the fire shoot out the back and to the side + VectorAdd(flame->velocity, fwd, flame->velocity); + // Alternate left and right side of phoenix + if (i&0x01) + VectorAdd(flame->velocity, right, flame->velocity); + else + VectorSubtract(flame->velocity, right, flame->velocity); + flame->acceleration[2] = FIRETRAIL_ACCEL; + flame->d_scale = flrand(-15.0, -10.0); + flame->d_alpha = flrand(-200.0, -160.0); + flame->duration = (255.0 * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + + AddParticleToList(smoke, flame); + } + + + // Remember for even spread of particles + VectorCopy(missile->r.origin, missile->origin); + return(true); +} + diff --git a/Toolkit/Programming/GameCode/client effects/fx_pickup.c b/Toolkit/Programming/GameCode/client effects/fx_pickup.c new file mode 100644 index 0000000..0ee90e9 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_pickup.c @@ -0,0 +1,50 @@ +// +// fx_pickup.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "ce_DefaultMessageHandler.h" +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "Angles.h" + +#define NUM_PICKUP_MODELS 1 +static struct model_s *pickup_models[NUM_PICKUP_MODELS]; + +void PreCachePickup() +{ + pickup_models[0] = fxi.RegisterModel("sprites/fx/halo.sp2"); +} + +// -------------------------------------------------------------- + +void FXPickup(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *ce; + + ce = ClientEntity_new(type, flags | CEF_DONT_LINK | CEF_PULSE_ALPHA, origin, NULL, 500); + + ce->r.model = pickup_models; + ce->r.frame = 1; + ce->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + ce->r.scale = 0.4; + ce->alpha = .75; + ce->d_scale = 1.0; + ce->d_alpha = 2.5; + ce->color.c = 0xc0ffffff; + ce->radius = 10.0; + ce->alpha = 0.8; + ce->r.origin[2] += 8.0; + + AddEffect(NULL, ce); +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_pickuppuzzle.c b/Toolkit/Programming/GameCode/client effects/fx_pickuppuzzle.c new file mode 100644 index 0000000..db9295e --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_pickuppuzzle.c @@ -0,0 +1,107 @@ +// +// fx_PuzzlePickup.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "ce_DefaultMessageHandler.h" +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "Angles.h" +#include "items.h" + +#define BOB_HEIGHT 6.0 +#define BOB_SPEED ANGLE_10 + +typedef struct PuzzleModel +{ + char *modelName; + struct model_s *model; + float scale; +} PuzzleModel_t; + +PuzzleModel_t PuzzleModels[]= +{ + {"models/items/puzzles/townkey/tris.fm", NULL, 1.5}, // ITEM_TOWNKEY + {"models/items/puzzles/cog/tris.fm", NULL, 1}, // ITEM_COG + {"models/items/puzzles/shield/tris.fm", NULL, 1.5}, // ITEM_SHIELD + {"models/items/puzzles/potion/tris.fm", NULL, .5}, // ITEM_POTION + {"models/items/puzzles/plazajug/tris.fm", NULL, 1}, // ITEM_CONT + {"models/items/puzzles/jugfull/tris.fm", NULL, 1}, // ITEM_SLUMCONT + {"models/items/puzzles/crystalshard/tris.fm", NULL, 1.75}, // ITEM_CRYSTAL + {"models/items/puzzles/hivekey/tris.fm", NULL, 1}, // ITEM_CANKEY + {"models/items/puzzles/amulet/tris.fm", NULL, 1.5}, // ITEM_AMULET + {"models/items/puzzles/spear/tris.fm", NULL, 1}, // ITEM_SPEAR + {"models/items/puzzles/tcheckrikgem/tris.fm", NULL, 1.5}, // ITEM_GEM + {"models/items/puzzles/wheel/tris.fm", NULL, 1.75}, // ITEM_WHEEL + {"models/items/puzzles/oreunrefined/tris.fm", NULL, .5}, // ITEM_ORE + {"models/items/puzzles/orerefined/tris.fm", NULL, .5}, // ITEM_REF_ORE + {"models/items/puzzles/dungeonkey/tris.fm", NULL, .5}, // ITEM_DUNKEY + {"models/items/puzzles/cloudkey/tris.fm", NULL, 1.5}, // ITEM_CLOUDKEY + {"models/items/puzzles/hivekey/tris.fm", NULL, 1}, // ITEM_HIVEKEY + {"models/items/puzzles/hiveidol/tris.fm", NULL, 1}, // ITEM_HPSYM + {"models/items/puzzles/book/tris.fm", NULL, 1}, // ITEM_TOME + {"models/items/puzzles/townkey/tris.fm", NULL, 1.5}, // ITEM_TAVERNKEY +}; + + +void PreCachePuzzleItems() +{ + int i; + + for(i = 0; i < ITEM_TOTAL; ++i) + { + PuzzleModels[i].model = fxi.RegisterModel(PuzzleModels[i].modelName); + } +} + +// -------------------------------------------------------------- + +static qboolean FXPuzzlePickupThink(struct client_entity_s *self, centity_t *owner) +{ + // Rotate and bob + VectorCopy(owner->current.origin, self->r.origin); + self->r.origin[2] += (cos(self->SpawnData) * BOB_HEIGHT); + self->SpawnData += BOB_SPEED; + + return(true); +} + +void FXPuzzlePickup(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *ce; + byte tag; + vec3_t angles; + + fxi.GetEffect(owner, flags, "bv", &tag,&angles); + + flags &= ~CEF_OWNERS_ORIGIN; + ce = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 50); + VectorDegreesToRadians(angles, ce->r.angles); + + VectorCopy(ce->r.origin, ce->origin); + ce->r.model = &PuzzleModels[tag].model; + ce->r.flags = RF_TRANSLUCENT | RF_GLOW; + ce->r.scale = PuzzleModels[tag].scale; + + ce->radius = 10.0; + ce->alpha = 0.8; + ce->Update = FXPuzzlePickupThink; + + if (tag == ITEM_TAVERNKEY) + ce->r.skinnum = 1; + + else if (tag == ITEM_CANKEY) + ce->r.skinnum = 1; + + AddEffect(owner, ce); +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_portal.c b/Toolkit/Programming/GameCode/client effects/fx_portal.c new file mode 100644 index 0000000..ee944f0 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_portal.c @@ -0,0 +1,306 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Random.h" +#include "Vector.h" +#include "string.h" +#include "Utilities.h" +#include "q_Sprite.h" +#include "g_playstats.h" + + +#define SINESCALE (256.0 / (2 * M_PI)) +#define NUM_PORTAL_PARTS 20 +#define PICTURE_RADIUS 55.0 +#define PORTAL_RADIUS 50.0 +#define SCALE 0.01F +#define DELTA_SCALE 1.0F +#define MIN_PART_SCALE 1.0 +#define MAX_PART_SCALE 3.0 + +#define NUM_PORTAL_MODELS 3 + +static struct model_s *portal_models[NUM_PORTAL_MODELS]; + +void PreCachePortal() +{ + portal_models[0] = fxi.RegisterModel("sprites/fx/ripple_add.sp2"); + portal_models[1] = fxi.RegisterModel("sprites/fx/portal1.sp2"); + portal_models[2] = fxi.RegisterModel("sprites/spells/patball.sp2"); +} + +int RandomSparkTypes [9] = +{ + PART_4x4_WHITE, + PART_4x4_BLUE, + PART_4x4_BLUE2, + PART_4x4_BLUE3, + PART_8x8_BLUE_X, + PART_8x8_BLUE_CIRCLE, + PART_8x8_BLUE_DIAMOND, + PART_16x16_STAR, + PART_16x16_SPARK_B, +}; + +qboolean FXMagicPortalThink(client_entity_t *self, centity_t *owner) +{ + client_particle_t *ce; + paletteRGBA_t color; + vec3_t vel, right, up; + int i, part_type; + int count; + client_entity_t *ripple; + client_entity_t *line; + + if (self->LifeTime == 1) + { // already disabled. + if (fxi.cl->time > self->lastThinkTime) + { // Remove it. + return(false); + } + else + { + return(true); + } + } + + if(owner->current.effects&EF_DISABLE_EXTRA_FX || (self->SpawnDelay && self->SpawnDelay < fxi.cl->time)) + { // Start disabling it, but give it a couple of seconds to fitz out. + self->LifeTime = 1; + self->lastThinkTime = fxi.cl->time + 2000; + + return(true); + } + + AngleVectors(self->r.angles, NULL, right, up); + count = GetScaledCount(NUM_PORTAL_PARTS, 0.7); + for(i = 0; i < count; i++) + { + VectorScale(right, flrand(-1, 1), vel); + VectorMA(vel, flrand(-1, 1), up, vel); + if(Vec3IsZero(vel)) + vel[2] = 1.0; // Safety in case flrand gens all zeros (VERY unlikely) + VectorNormalize(vel); + VectorScale(vel, PORTAL_RADIUS, vel); + + color.c = 0xffffffff; + + part_type = irand(0, 8); + ce = ClientParticle_new(RandomSparkTypes[part_type], color, 3000); + VectorCopy(vel, ce->origin); + + VectorScale(vel, flrand(0.0625, 0.125f), ce->velocity); + ce->acceleration[2] = flrand(2, 5); + ce->scale = flrand(MIN_PART_SCALE, MAX_PART_SCALE); + ce->d_scale = -0.2F; + + if(!(self->flags & CEF_NO_DRAW)) + { + ce->color.r = irand(100, 200); + ce->color.g = irand(0, 50); + ce->color.b = irand(100, 200); + } + ce->type |= PFL_ADDITIVE; + +// ce->color.a = irand(128, 255); + ce->color.a = irand(2, 128); + +// ce->d_alpha = flrand(ce->color.a * -0.8f, -ce->color.a); + ce->d_alpha = irand(320, 480); + AddParticleToList(self, ce); + } + + if(self->SpawnInfo == 2) + { + ripple = ClientEntity_new(FX_WATER_ENTRYSPLASH, + 0, + owner->current.origin, + self->direction, + 4000); + + ripple->r.model = portal_models; + //ripple->r.flags |= RF_TRANS_ADD_ALPHA | RF_TRANS_ADD | RF_TRANSLUCENT | RF_FIXED | RF_TRANS_GHOST; + ripple->r.flags |= RF_TRANS_ADD_ALPHA | RF_TRANS_ADD | RF_FIXED | RF_TRANS_GHOST; + ripple->r.scale = 0.1f; + ripple->d_scale = 1.0f; + if(!(self->flags & CEF_NO_DRAW)) + { + ripple->r.color.r = irand(10, 100); + ripple->r.color.g = irand(0, 50); + ripple->r.color.b = irand(10, 100); + ripple->alpha = 0.40f; + ripple->d_alpha = -0.20f; + } + else + { + ripple->alpha = 0.6f; + ripple->d_alpha = -0.30f; + } + //FIXME: calculate correct duration + + AddEffect(owner, ripple); + + self->SpawnInfo = 0; + } + else + self->SpawnInfo++; + + if(!(self->flags & CEF_NO_DRAW)) + { + self->alpha += flrand(-0.02, 0.02); + + if(1) + { + self->r.verts[0][0] += flrand(-1, 1); + self->r.verts[0][1] += flrand(-1, 1); + + self->r.verts[1][0] += flrand(-1, 1); + self->r.verts[1][1] += flrand(-1, 1); + + self->r.verts[2][0] += flrand(-1, 1); + self->r.verts[2][1] += flrand(-1, 1); + + self->r.verts[3][0] += flrand(-1, 1); + self->r.verts[3][1] += flrand(-1, 1); + } + + if(1) + { + //FIXME: scroll based on viewangle to camera viewport - but what about alpha channel??? + self->r.verts[0][2] += flrand(-0.001, 0.001); + self->r.verts[0][3] += flrand(-0.001, 0.001); + + self->r.verts[1][2] += flrand(-0.001, 0.001); + self->r.verts[1][3] += flrand(-0.001, 0.001); + + self->r.verts[2][2] += flrand(-0.001, 0.001); + self->r.verts[2][3] += flrand(-0.001, 0.001); + + self->r.verts[3][2] += flrand(-0.001, 0.001); + self->r.verts[3][3] += flrand(-0.001, 0.001); + } + } + + //=================================================== + + if(r_detail->value > DETAIL_HIGH) + {//Spawn a hit explosion of lines + i = GetScaledCount(16, 0.85); + + while (i--) + { + line=ClientEntity_new(FX_WEAPON_STAFF_STRIKE, 0, owner->current.origin, 0, 600); + + line->r.model = portal_models + 2; + + line->r.spriteType = SPRITE_LINE; + + line->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + line->r.color.c = 0xFFFFFFFF; + line->r.scale = flrand(1.0, 2.5); + line->alpha = flrand(1.0, 0.75); + line->d_alpha = -2.0; + line->d_scale = -1.0; + + line->r.color.r = irand(128, 255); + line->r.color.g = irand(128, 255); + line->r.color.b = 128 + irand(108, 127); + line->r.color.a = 64 + irand(16, 128); + + VectorRandomCopy(self->direction, line->velocity, 1.25); + + VectorCopy(owner->current.origin, line->r.startpos); + VectorMA(line->r.startpos, irand(16,48), line->velocity, line->r.endpos); + + VectorScale(line->velocity, irand(25,100), line->velocity); + VectorSet(line->acceleration, line->velocity[0] * 0.1, line->velocity[1] * 0.1, 0); + + AddEffect(NULL, line); + } + } + + return(true); +} + +// This is the persistant effect for the teleport pad +void FXMagicPortal(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *portal; + vec3_t dir, forward; + byte color, duration; + qboolean special = false; + + fxi.GetEffect(owner, flags, "vbb", dir, &color, &duration); + + AngleVectors(dir, forward, NULL, NULL); + portal = ClientEntity_new(type, (flags) & ~CEF_NOMOVE , origin, forward, 110); + VectorScale(forward, -1, portal->direction); + portal->radius = 1000; + + if(special) + { + portal->flags |= CEF_ADDITIVE_PARTS | CEF_VIEWSTATUSCHANGED; + portal->r.spriteType = SPRITE_DYNAMIC; + portal->r.flags |= RF_FIXED|RF_GLOW|RF_TRANSLUCENT|RF_TRANS_ADD_ALPHA|RF_TRANS_ADD; + portal->alpha = 0.75; + + if(1) + { + //top left + portal->r.verts[0][0] = -PICTURE_RADIUS;// + flrand(-2, 2);//x + portal->r.verts[0][1] = -PICTURE_RADIUS;// + flrand(-2, 2);//y + //top right + portal->r.verts[1][0] = PICTURE_RADIUS;// + flrand(-2, 2);//x + portal->r.verts[1][1] = -PICTURE_RADIUS;// + flrand(-2, 2);//y + //bottom left + portal->r.verts[2][0] = PICTURE_RADIUS;// + flrand(-2, 2);//x + portal->r.verts[2][1] = PICTURE_RADIUS;//+ flrand(-2, 2);//y + //bottom right + portal->r.verts[3][0] = -PICTURE_RADIUS;// + flrand(-2, 2);//x + portal->r.verts[3][1] = PICTURE_RADIUS;// + flrand(-2, 2);//y + } + + if(1) + { + //top left + portal->r.verts[0][2] = 0;//PORTALPIC_SIZE;// + flrand(-2, 2);//u + portal->r.verts[0][3] = 1;//-PORTALPIC_SIZE;// + flrand(-2, 2);//v + //top right + portal->r.verts[1][2] = 1;//PORTALPIC_SIZE;// + flrand(-2, 2);//u + portal->r.verts[1][3] = 1;//PORTALPIC_SIZE;// + flrand(-2, 2);//v + //bottom left + portal->r.verts[2][2] = 1;//-PORTALPIC_SIZE;// + flrand(-2, 2);//u + portal->r.verts[2][3] = 0;//PORTALPIC_SIZE;// + flrand(-2, 2);//v + //bottom right + portal->r.verts[3][2] = 0;//-PORTALPIC_SIZE;// + flrand(-2, 2);//u + portal->r.verts[3][3] = 0;//-PORTALPIC_SIZE;// + flrand(-2, 2);//v + } + + portal->r.model = portal_models + 1; + } + else + portal->flags |= CEF_NO_DRAW; + + VectorCopy(dir, portal->r.angles); + portal->SpawnInfo = 2; + portal->Update = FXMagicPortalThink; + + portal->flags |= CEF_PULSE_ALPHA; + + if (duration==0) + { // Portal stays indefinitely + portal->SpawnDelay = 0; + } + else + { // Portal disappears after so many seconds + portal->SpawnDelay = fxi.cl->time + ((int)duration * 1000); + } + AddEffect(owner, portal); +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_quake.c b/Toolkit/Programming/GameCode/client effects/fx_quake.c new file mode 100644 index 0000000..afd501c --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_quake.c @@ -0,0 +1,22 @@ +// +// fx_quake.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "FX.h" + + + +void FXQuake(centity_t *owner, int type, int flags, vec3_t origin) +{ + byte count,time,dir; + + fxi.GetEffect(owner, flags, "bbb", &count,&time,&dir); + + fxi.Activate_Screen_Shake(count,(time * 100), fxi.cl->time, dir); + +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_redrainglow.c b/Toolkit/Programming/GameCode/client effects/fx_redrainglow.c new file mode 100644 index 0000000..cf4bb78 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_redrainglow.c @@ -0,0 +1,153 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Matrix.h" +#include "random.h" +#include "Utilities.h" +#include "Ambient effects.h" +#include "ce_Dlight.h" +#include "reference.h" +#include "g_playstats.h" + +#define CLOUD_GEN_RAD 30.0 + + +// ------------------------------------------------------- +static qboolean FXRedRainGlowThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *spark; + vec3_t vel, orgleft, orgright, atkvector; + int i; + paletteRGBA_t color; + matrix3_t rotation; + int sparktype; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return true; + + // If we've timed out, stop the effect (allow for fading) + if ( (self->LifeTime > 0) && (self->LifeTime < fxi.cl->time) ) + { + self->Update=RemoveSelfAI; + self->updateTime = fxi.cl->time + 500; + return true; + } + + // Reset update time to regular after game has been given enough time to gen lerp info + if (r_detail->value == DETAIL_LOW) + self->updateTime = 200; + else + if (r_detail->value == DETAIL_NORMAL) + self->updateTime = 150; + else + self->updateTime = 100; + + VectorCopy(owner->origin, self->r.origin); + + // Create a rotation matrix + Matrix3FromAngles(owner->lerp_angles, rotation); + // Let's take the origin and transform it to the proper coordinate offset from the owner's origin. + Matrix3MultByVec3(rotation, owner->referenceInfo->references[CORVUS_LEFTHAND].placement.origin, orgleft); + Matrix3MultByVec3(rotation, owner->referenceInfo->references[CORVUS_RIGHTHAND].placement.origin, orgright); + VectorSubtract(orgleft, orgright, atkvector); + if (self->dlight) + self->dlight->intensity = flrand(140.0, 160.0); + + if (self->SpawnInfo == 1) + { // Powered up, fire sparks + sparktype = PART_16x16_SPARK_G; + } + else + { + sparktype = PART_16x16_SPARK_R; + } + + color.c = 0xffffffff; + for(i = 0; i < 2; i++) + { + // Calc spherical offset around left hand ref point + VectorSet(vel, flrand(-1.0, 1.0), flrand(-1.0, 1.0), flrand(-1.0, 1.0)); + if(Vec3IsZero(vel)) + vel[2] = 1.0; // Safety in case flrand gens all zeros (VERY unlikely) + VectorNormalize(vel); + VectorScale(vel, CLOUD_GEN_RAD, vel); + VectorSubtract(vel, atkvector, vel); + + spark = ClientParticle_new(sparktype, color, 500); + VectorAdd(vel, orgleft, spark->origin); + + VectorScale(vel, -0.125, spark->velocity); + VectorScale(vel, -6.0, spark->acceleration); + + spark->scale = 12.0F; + spark->d_scale = -16.0F; + spark->color.a = 4; + spark->d_alpha = 500.0F; + spark->duration = 500; + + AddParticleToList(self, spark); + } + + // Add the core to the effect + spark = ClientParticle_new(sparktype, color, 500); + VectorCopy(orgleft, spark->origin); + VectorSet(spark->velocity, flrand(-16.0, 16.0), flrand(-16.0, 16.0), flrand(-8.0, 24.0)); + VectorMA(spark->velocity, -1.75, atkvector, spark->velocity); + spark->scale = 10.0F; + spark->d_scale = 10.0F; + spark->d_alpha = -500.0F; + + AddParticleToList(self, spark); + + return(true); +} + + +void FXRedRainGlow(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + vec3_t org; + char lifetime; + + VectorClear(org); + + fxi.GetEffect(owner, flags, "b", &lifetime); + + glow = ClientEntity_new(type, flags | CEF_NO_DRAW, org, 0, Q_ftol(fxi.cls->frametime * 2000.0)); + glow->flags|=CEF_NO_DRAW | CEF_OWNERS_ORIGIN | CEF_ADDITIVE_PARTS; + + glow->Update = FXRedRainGlowThink; + glow->AddToView = LinkedEntityUpdatePlacement; + glow->radius = 128; + if (flags & CEF_FLAG6) + { // powered up, green-yellow glow. + glow->SpawnInfo = 1; + glow->color.c = 0xff00ff80; + } + else + { + glow->color.c = 0xff0000ff; + } + if (r_detail->value != DETAIL_LOW) + glow->dlight = CE_DLight_new(glow->color, 150.0F, 0.0F); + + if (lifetime > 0) + glow->LifeTime = fxi.cl->time + (lifetime * 100); + else + glow->LifeTime = -1; + + + AddEffect(owner, glow); +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_remotecamera.c b/Toolkit/Programming/GameCode/client effects/fx_remotecamera.c new file mode 100644 index 0000000..aab0896 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_remotecamera.c @@ -0,0 +1,53 @@ +// +// fx_remotecamera.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "motion.h" +#include "Utilities.h" + +static qboolean FXRemoteCameraThink(struct client_entity_s *Self,centity_t *Owner) +{ + + + return(false); +} + +void FXRemoteCamera(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + short TargetEntNum; + centity_t *TargetEnt; + vec3_t Forward, + Angles; + client_entity_t *RemoteCamera; + + fxi.GetEffect(Owner,Flags,"s",&TargetEntNum); + + TargetEnt=(&fxi.server_entities[TargetEntNum]); + + VectorSubtract(Owner->origin,TargetEnt->origin,Forward); + + VectorNormalize(Forward); + + vectoangles(Forward,Angles); + + RemoteCamera=ClientEntity_new(Type,Flags|CEF_NOMOVE,Origin,NULL,5000); + + RemoteCamera->radius=10.0; + + VectorCopy(Owner->origin,fxi.cl->refdef.vieworg); + + RemoteCamera->Update=FXRemoteCameraThink; + + AddEffect(NULL,RemoteCamera); +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_rope.c b/Toolkit/Programming/GameCode/client effects/fx_rope.c new file mode 100644 index 0000000..6f5b180 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_rope.c @@ -0,0 +1,470 @@ +// +// fx_rope.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// Implemented by Josh Weier + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "q_Sprite.h" + +#define NUM_ROPE_MODELS 4 +#define ROPE_SEGMENT_LENGTH 64 +#define ROPE_BOTTOM_SEGMENTS 8 + +static struct model_s *rope_models[NUM_ROPE_MODELS]; + + + +/* + + Precache function + +*/ + + + +void PreCacheRope() +{ + rope_models[0] = fxi.RegisterModel("sprites/fx/segment_rope.sp2"); + rope_models[1] = fxi.RegisterModel("sprites/fx/segment_chain.sp2"); + rope_models[2] = fxi.RegisterModel("sprites/fx/segment_vine.sp2"); + rope_models[3] = fxi.RegisterModel("sprites/fx/segment_tendril.sp2"); +} + + + +/* + + Helper function + +*/ + + + +/*----------------------------------------------- + RopeCheckToHide +-----------------------------------------------*/ + +qboolean RopeCheckToHide(struct client_entity_s *self, centity_t *owner) +{ + centity_t *grab; + + //Get the entity + grab = &fxi.server_entities[self->LifeTime]; + + //If the flag isn't set, then we're supposed to disappear + if ( (!(grab->current.effects & EF_ALTCLIENTFX)) && (self->SpawnInfo < fxi.cl->time) ) + { + //Clear this out and kill the effect + self->AddToView = NULL; + return false; + } + + return true; +} + + + +/* + + Attached Rope Segments + +*/ + + + +/*----------------------------------------------- + FXRopeTopDrawAttached +-----------------------------------------------*/ + +static qboolean FXRopeTopDrawAttached(struct client_entity_s *self, centity_t *owner) +{ + qboolean ret; + vec3_t vec; + + ret = RopeCheckToHide(self, owner); + if (!ret) + { + self->flags |= CEF_NO_DRAW; + return ret; + } + + //Get our tile rate + VectorSubtract(self->direction, owner->origin, vec); + self->r.tile = VectorLength(vec) / 64; + + //This places us at the player's top most hand + VectorSet(self->r.endpos, owner->origin[0], owner->origin[1], owner->origin[2] + 32); + + return true; +} + +/*----------------------------------------------- + FXRopeMiddleDrawAttached +-----------------------------------------------*/ + +static qboolean FXRopeMiddleDrawAttached(struct client_entity_s *self, centity_t *owner) +{ + qboolean ret; + + ret = RopeCheckToHide(self, owner); + if (!ret) + { + self->flags |= CEF_NO_DRAW; + return ret; + } + + //These magic numbers place the rope at his hands + VectorSet(self->r.startpos, owner->origin[0], owner->origin[1], owner->origin[2] + 32); + VectorSet(self->r.endpos, owner->origin[0], owner->origin[1], owner->origin[2] + 8); + + //Get the tile rate + self->r.tile = (float) 24.0F / 64.0F; + + //Offset the sprite's tile so that there's no visible gap between the top section and the grab section (slight imprecision) + self->r.tileoffset = (float) (fmod((self->direction[2] - owner->origin[2]), 64.0F) / 64.0F); + + return true; +} + +/*----------------------------------------------- + FXRopeBottomDrawAttached +-----------------------------------------------*/ + +static qboolean FXRopeBottomDrawAttached(struct client_entity_s *self, centity_t *owner) +{ + centity_t *end, *grab; + qboolean ret; + vec3_t diffpos2, vec, c_vec, c_down; + float lerp, oldtime, newtime, dist, c_segs, c_length; + int i; + + ret = RopeCheckToHide(self, owner); + + if (!ret) + { + self->flags |= CEF_NO_DRAW; + return ret; + } + + //Setup our two entities to base positions on + grab = &fxi.server_entities[self->LifeTime]; + end = (centity_t *)self->extra; + + //Setup the start position for the line + VectorSet(self->r.startpos, owner->origin[0], owner->origin[1], owner->origin[2] + 8); + + // Find the lerp factor by determining where in the 1/10 of a second this frame lies. + oldtime = self->lastThinkTime / 100.0F; + newtime = fxi.cl->time / 100.0F; + + if ((int) oldtime < (int) newtime) + { + // Adjust the start and endpos for a new interpolation interval. + VectorCopy(self->endpos2, self->startpos2); + VectorCopy(end->current.origin, self->endpos2); + } + + //Get the lerp increment + lerp = newtime - (int)newtime; + + // Find the difference in position for lerping. + VectorSubtract(self->endpos2, self->startpos2, diffpos2); + + // Now apply the lerp value to get the new endpos. + VectorMA(self->startpos2, lerp, diffpos2, self->r.endpos); + + //Setup the vector to the current position to the goal position + VectorSubtract(self->r.endpos, self->r.startpos, vec); + dist = VectorNormalize(vec); + + //FIXME: This is constant and can be stored (trivial...) + //Find the number of segments, and their lengths + c_segs = ROPE_BOTTOM_SEGMENTS / 2; + c_length = dist / c_segs; //FIXME: Find the actual length with curving + + self->r.tile = c_length / 64.0F; + + //Setup the endpos + VectorSet(self->r.endpos, owner->origin[0], owner->origin[1], owner->origin[2] + 8); + + //Find the vector pointing down through the upper portion of the rope from the connect point of the rope to the player + VectorSubtract(self->direction, owner->origin, c_down); + VectorNormalize(c_down); + + //Set through the curve till we find this segment's position in it + for (i=0; i <= (int) self->SpawnDelay; i++) + { + //Where the last segment ended is where the new one begins + VectorCopy(self->r.endpos, self->r.startpos); + + //Find the angle increment for this segment + VectorScale(c_down, (i / (c_segs + 1)) / 2, c_vec); + + //Get the new vector + VectorAdd(c_vec, vec, c_vec); + + //Find where this segment will end + VectorMA(self->r.startpos, c_length, c_vec, self->r.endpos); + } + + //Store for lerping + self->lastThinkTime = fxi.cl->time; + + return true; +} + + + +/* + + Unattached Rope Segments + +*/ + + + +/*----------------------------------------------- + FXRopeTopDraw +-----------------------------------------------*/ + +static qboolean FXRopeTopDraw(struct client_entity_s *self, centity_t *owner) +{ + float lerp, oldtime, newtime; + //float c_segs; + vec3_t diffpos;//, c_vec; + centity_t *end, *grab; + + end = (centity_t *)self->extra; + grab = &fxi.server_entities[self->LifeTime]; + + //If the rope entity has requested it, hide these segments + if (grab->current.effects & EF_ALTCLIENTFX) + { + self->flags |= CEF_NO_DRAW; + + VectorCopy(self->endpos, self->startpos); + VectorCopy(end->current.origin, self->endpos); + + return true; + } + + //Make sure we're visible + self->flags &= ~CEF_NO_DRAW; + + VectorCopy(self->origin, self->r.startpos); + VectorCopy(end->current.origin, self->r.endpos); + + // Find the linear interpolation factor by determining where in the 1/10 of a second this frame lies. + oldtime = self->lastThinkTime/100.0; + newtime = fxi.cl->time/100.0; + + if ((int)oldtime < (int)newtime) + { // We have crossed the boundary between 1/10 second interval. + // Adjust the start and endpos for a new interpolation interval. + VectorCopy(self->endpos, self->startpos); + VectorCopy(end->current.origin, self->endpos); + } + + lerp = newtime - (int)newtime; + + // Find the difference in position for lerping. + VectorSubtract(self->endpos, self->startpos, diffpos); + + // Now apply the lerp value to get the new endpos. + VectorMA(self->startpos, lerp, diffpos, self->r.endpos); + + //Get our tile rate + VectorSubtract(self->origin, self->r.endpos, diffpos); + self->r.tile = VectorLength(diffpos) / 64; + + //Store for lerping + self->lastThinkTime = fxi.cl->time; + + return true; +} + + +/* + + FXROPE + +*/ + + + +/*----------------------------------------------- + FXRope +-----------------------------------------------*/ + +void FXRope(centity_t *owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *rope, *ropeb, *ropem; + centity_t *grab, *end; + qboolean attached; + vec3_t top, vec, grab_pos, end_pos; + float radius; + short grab_id, end_id; + byte model_type; + int i; + + fxi.GetEffect(owner, CEF_BROADCAST, "ssbvvv", &grab_id, &end_id, &model_type, &top, &grab_pos, &end_pos); + + //This is set if the effect should be attached to something + attached = (Flags & CEF_FLAG6); + + //Setup the entities + end = &fxi.server_entities[end_id]; + grab = &fxi.server_entities[grab_id]; + + //Create the rope piece that hangs from the top to the end of the rope, while the player is NOT on it + + radius = (Q_fabs(grab_pos[2]) + Q_fabs(end_pos[2])) * 2; + + if (!attached) + { + rope=ClientEntity_new( FX_ROPE, + 0, + Origin, + NULL, + 17); + + rope->r.model = rope_models + model_type; + + rope->r.scale = 3; + rope->radius = radius; + + rope->r.spriteType = SPRITE_LINE; + rope->Update = FXRopeTopDraw; + rope->AddToView = FXRopeTopDraw; + + //End of the rope + rope->extra = (void *) &fxi.server_entities[end_id]; + rope->LifeTime = grab_id; + + // Set up the end vector start and endpos, for linear interpolation. + VectorCopy(fxi.server_entities[end_id].current.origin, rope->startpos); + VectorCopy(rope->startpos, rope->endpos); + + rope->lastThinkTime = fxi.cl->time; + + VectorCopy(top, rope->direction); + + AddEffect(NULL, rope); + } + else + { + //Create the fake rope that is attached to the player + + //-------------------- + // + // Top of the rope + + rope=ClientEntity_new( FX_ROPE, + CEF_OWNERS_ORIGIN, + Origin, + NULL, + 1000); + + rope->r.model = rope_models + model_type; + + VectorCopy(top, rope->direction); + + rope->r.scale = 3; + rope->radius = radius; + VectorCopy(top, rope->r.startpos); + + rope->r.spriteType = SPRITE_LINE; + rope->AddToView = FXRopeTopDrawAttached; + rope->Update = RopeCheckToHide; + + VectorSubtract(owner->origin, end_pos, vec); + rope->r.tile = VectorLength(vec); + + rope->SpawnInfo = fxi.cl->time + 1000; + + rope->LifeTime = grab_id; + + AddEffect(owner, rope); + + FXRopeTopDrawAttached(rope, owner); + + //-------------------- + // + // Middle of the rope + + ropem=ClientEntity_new( FX_ROPE, + CEF_OWNERS_ORIGIN, + Origin, + NULL, + 1000); + + ropem->r.model = rope_models + model_type; + + ropem->r.scale = 3; + ropem->radius = radius; + + ropem->r.tile = 1; + ropem->r.spriteType = SPRITE_LINE; + ropem->AddToView = FXRopeMiddleDrawAttached; + ropem->Update = RopeCheckToHide; + ropem->LifeTime = grab_id; + + ropem->SpawnInfo = fxi.cl->time + 1000; + + AddEffect(owner, ropem); + + FXRopeMiddleDrawAttached(ropem, owner); + + //-------------------- + // + // Bottom of the rope + + for (i=0; ir.model = rope_models + model_type; + + ropeb->r.scale = 3; + ropeb->radius = radius; + + ropeb->r.spriteType = SPRITE_LINE; + ropeb->Update = RopeCheckToHide; + ropeb->AddToView = FXRopeBottomDrawAttached; + + //End of the ropeb + ropeb->extra = (void *) &fxi.server_entities[end_id]; + ropeb->LifeTime = grab_id; + + // Set up the end vector start and endpos, for linear interpolation. + VectorCopy(end_pos, ropeb->startpos2); + VectorCopy(ropeb->startpos2, ropeb->endpos2); + + //The segment number of this piece + ropeb->SpawnInfo = fxi.cl->time + 1000; + ropeb->SpawnDelay = (int) i; + + ropeb->lastThinkTime = fxi.cl->time; + + VectorCopy(top, ropeb->direction); + + AddEffect(owner, ropeb); + + FXRopeBottomDrawAttached(ropeb, owner); + } + } +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_scorchmark.c b/Toolkit/Programming/GameCode/client effects/fx_scorchmark.c new file mode 100644 index 0000000..d7c8fbb --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_scorchmark.c @@ -0,0 +1,106 @@ +// +// fx_scorchmark.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Utilities.h" + +#define NUM_SCORCH_MODELS 1 + +static struct model_s *scorch_models[NUM_SCORCH_MODELS]; + +void PreCacheScorch() +{ + scorch_models[0] = fxi.RegisterModel("sprites/fx/scorchmark.sp2"); +} + + +static qboolean EndLessLoop(struct client_entity_s *self, centity_t *owner) +{ + return(true); +} + + +// -------------------------------------------------------------- +// Find exact plane to decal the scorchmark to + +// The origin comes in 8 from the wall +// No scorchmark generated if no wall found (this does happen) + +static qboolean GetTruePlane(vec3_t origin, vec3_t direction) +{ + trace_t trace; + vec3_t end; + vec3_t mins, maxs; + + VectorClear(mins); + VectorClear(maxs); + // Quite a long trace - but its only done once per scorchmark ever + VectorMA(origin, 64.0, direction, end); + + fxi.Trace(origin, mins, maxs, end, MASK_DRIP, CEF_CLIP_TO_WORLD, &trace); + if(trace.fraction != 1.0) + { + // Set the new endpos and plane (should be exact) + VectorCopy(trace.endpos, origin); + VectorCopy(trace.plane.normal, direction); + // Raise the scorchmark slightly off the target wall + VectorMA(origin, 0.5, direction, origin); + return(true); + } + return(false); +} + +void FXClientScorchmark(vec3_t origin, vec3_t dir) +{ + client_entity_t *scorchmark; + + if(GetTruePlane(origin, dir)) + { + scorchmark = ClientEntity_new(FX_SCORCHMARK, CEF_NOMOVE, origin, dir, 1000); + + scorchmark->r.model = scorch_models; + scorchmark->r.flags |= RF_FIXED | RF_TRANSLUCENT; + + scorchmark->radius = 10.0; + scorchmark->r.scale = 0.6; + + scorchmark->Update = EndLessLoop; + + AddEffect(NULL, scorchmark); + InsertInCircularList(scorchmark); + } +} + +void FXScorchmark(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t dir; + client_entity_t *scorchmark; + + fxi.GetEffect(owner, flags, "d", dir); + if(GetTruePlane(origin, dir)) + { + scorchmark = ClientEntity_new(type, flags | CEF_NOMOVE, origin, dir, 1000); + + scorchmark->r.model = scorch_models; + scorchmark->r.flags |= RF_FIXED | RF_TRANSLUCENT; + + scorchmark->radius = 10.0; + scorchmark->r.scale = 0.6; + + scorchmark->Update = EndLessLoop; + + AddEffect(NULL, scorchmark); + InsertInCircularList(scorchmark); + } +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_shadow.c b/Toolkit/Programming/GameCode/client effects/fx_shadow.c new file mode 100644 index 0000000..f2ab51f --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_shadow.c @@ -0,0 +1,218 @@ +// +// fx_shadow.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Angles.h" +#include "Utilities.h" +#include "Matrix.h" +#include "Reference.h" +#include "q_Sprite.h" +#include "q_Surface.h" +#include "PrimitiveDisplayHack.h" +#include "g_playstats.h" + +#include + +#define SHADOW_CHECK_DIST 256.0 +#define SHADOW_REF_CHECK_DIST 64.0 + +#define MAX_SHADOW_DIST 128 +#define SHADOW_HEIGHT 0.5 + +extern int ref_soft; + +#define NUM_SHADOW_MODELS 1 + +static struct model_s *shadow_models[NUM_SHADOW_MODELS]; + +void PrecacheShadow() +{ + shadow_models[0] = fxi.RegisterModel("models/fx/shadow/tris.fm"); +} + +static qboolean FXShadowUpdate(struct client_entity_s *self,centity_t *owner) +{ + vec3_t startpos, endpos; + vec3_t minmax = {0, 0, 0}; + trace_t trace; + + VectorCopy(owner->origin, self->r.origin); + VectorCopy(owner->origin, startpos); + + startpos[2] += 4; + // Now trace from the startpos down + VectorCopy(startpos, endpos); + endpos[2] -= SHADOW_CHECK_DIST; + + //Determine Visibility + fxi.Trace( startpos, + minmax, + minmax, + endpos, + CONTENTS_SOLID, + CEF_CLIP_TO_WORLD, + &trace); + + if (trace.startsolid || trace.fraction >= 1.0) + { // no shadow, in something. + self->alpha = 0.01; + VectorCopy(endpos, self->r.origin); + return true; + } + + // Did hit the ground + self->alpha = (1.0 - trace.fraction) * 0.5 + 0.01; + // if we are in ref soft, bring us out a touch, since we are having z buffer problems + if (ref_soft) + { + // Raise the shadow slightly off the target wall + VectorMA(trace.endpos, 0.9, trace.plane.normal, self->r.origin); + } + else + VectorMA(trace.endpos, 0.2, trace.plane.normal, self->r.origin); + AnglesFromDirI(trace.plane.normal, self->r.angles); + + return true; +} + + + +static qboolean FXShadowReferenceUpdate(struct client_entity_s *self,centity_t *owner) +{ + vec3_t startpos, endpos; + vec3_t minmax = {0, 0, 0}; + trace_t trace; + int refpoint; + matrix3_t rotmatrix; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return true; + + VectorCopy(owner->origin, self->r.origin); + + // take the startpoint from one of the reference points + refpoint = self->refPoint; + + Matrix3FromAngles(owner->lerp_angles,rotmatrix); + + Matrix3MultByVec3(rotmatrix, owner->referenceInfo->references[refpoint].placement.origin, startpos); + + // This may look weird, but by scaling the vector, I bring it closer to the center of the owner. + VectorScale(startpos, 0.5, startpos); + VectorAdd(owner->origin, startpos, startpos); + + // Now trace fromt the startpos down + VectorCopy(startpos, endpos); + endpos[2] -= SHADOW_REF_CHECK_DIST; + + //Determine Visibility + fxi.Trace( startpos, + minmax, + minmax, + endpos, + CONTENTS_SOLID, + CEF_CLIP_TO_WORLD, + &trace); + + if (trace.startsolid || trace.fraction >= 1.0) + { // no shadow, in something. + self->alpha = 0.01; + VectorCopy(endpos, self->r.origin); + return true; + } + + // Did hit the ground + self->alpha = (1.0 - trace.fraction) * 0.8 + 0.01; + self->r.scale = (1.0 - trace.fraction) * 0.8; + if (ref_soft) + { + // Raise the shadow slightly off the target wall + VectorMA(trace.endpos, 0.9, trace.plane.normal, self->r.origin); + } + else + VectorMA(trace.endpos, 0.2, trace.plane.normal, self->r.origin); + AnglesFromDirI(trace.plane.normal, self->r.angles); + + return true; +} + + + + + +void FXShadow(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *self; + float scale; + + fxi.GetEffect(owner, flags, "f", &scale); + + if(r_detail->value < DETAIL_UBERHIGH) + return; + + // Create shadow under the player + self = ClientEntity_new(type, flags, origin, NULL, INT_MAX); + self->nextThinkTime = INT_MAX; + self->r.model = shadow_models; + self->r.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_ALPHA_TEXTURE; + self->radius = SHADOW_CHECK_DIST; + self->r.scale = scale; + self->AddToView = FXShadowUpdate; + + AddEffect(owner, self); + + FXShadowUpdate(self, owner); +} + +// Cast a shadow down from each foot and the player, too +void FXPlayerShadow(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *self; + + // Create shadow under the player + self = ClientEntity_new(type, flags, origin, NULL, INT_MAX); + self->nextThinkTime = INT_MAX; + self->r.model = shadow_models; + self->r.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_ALPHA_TEXTURE; + self->radius = SHADOW_CHECK_DIST; + self->r.scale = 1.0; + self->AddToView = FXShadowUpdate; + AddEffect(owner, self); + FXShadowUpdate(self, owner); + + // Create shadow under the left foot + self = ClientEntity_new(type, flags, origin, NULL, INT_MAX); + self->nextThinkTime = INT_MAX; + self->r.model = shadow_models; + self->r.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_ALPHA_TEXTURE; + self->radius = SHADOW_CHECK_DIST; + self->refPoint = CORVUS_LEFTFOOT; + self->r.scale = 0.8; + self->AddToView = FXShadowReferenceUpdate; + AddEffect(owner, self); + FXShadowUpdate(self, owner); + + // Create shadow under the right foot + self = ClientEntity_new(type, flags, origin, NULL, INT_MAX); + self->nextThinkTime = INT_MAX; + self->r.model = shadow_models; + self->r.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_ALPHA_TEXTURE; + self->radius = SHADOW_CHECK_DIST; + self->refPoint = CORVUS_RIGHTFOOT; + self->r.scale = 0.8; + self->AddToView = FXShadowReferenceUpdate; + AddEffect(owner, self); + FXShadowUpdate(self, owner); +} + + diff --git a/Toolkit/Programming/GameCode/client effects/fx_shield.c b/Toolkit/Programming/GameCode/client effects/fx_shield.c new file mode 100644 index 0000000..4e28f40 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_shield.c @@ -0,0 +1,149 @@ +// +// fx_shield.c +// +// Heretic II +// Copyright 1998 Raven Software +// + + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Matrix.h" +#include "Random.h" +#include "Utilities.h" +#include "Reference.h" +#include "ce_DLight.h" +#include "g_playstats.h" + +#define SHIELD_TRAIL_DELAY 100 +#define SHIELD_RADIUS 32.0 +#define NUM_SHIELD_SPARKS 16 +#define SHIELD_TRAIL_SPEED 32.0 + +extern int ref_soft; + +#define NUM_SHIELD_MODELS 1 +static struct model_s *shield_models[NUM_SHIELD_MODELS]; +void PreCacheShield() +{ + shield_models[0] = fxi.RegisterModel("sprites/spells/spark_blue.sp2"); +} + +static qboolean FXShieldSparkThink(struct client_entity_s *shield,centity_t *owner) +{ + vec3_t angvect; + client_particle_t *spark; + int part; + paletteRGBA_t color; + + // Update the angle of the spark. + VectorMA(shield->direction, (float)(fxi.cl->time-shield->lastThinkTime)/1000.0, shield->velocity2, shield->direction); + + // Update the position of the spark. + AngleVectors(shield->direction, angvect, NULL, NULL); + VectorMA(owner->origin, shield->radius, angvect, shield->r.origin); + + shield->lastThinkTime = fxi.cl->time; + + // Leave a trail sometimes + if (shield->SpawnDelay < fxi.cl->time) + { + part = PART_16x16_SPARK_B; + color.c = 0xffffffff; + // if we are in software, make the blue bits single point particles half the time + if (ref_soft) + { + shield->SpawnInfo++; + if (shield->SpawnInfo & 1) + { + part |= PFL_SOFT_MASK; + color.c = 0xffff0000; + } + } + + spark = ClientParticle_new(part, color, 500); + VectorCopy(shield->r.origin, spark->origin); + spark->scale = 6.0; + spark->d_scale = -10.0; + spark->acceleration[2] = 0.0; // Don't fall due to gravity... + AddParticleToList(shield, spark); + + // Do it again in 1/10 sec. + shield->SpawnDelay = fxi.cl->time + SHIELD_TRAIL_DELAY; + } + + return true; +} + + +static qboolean FXShieldTerminate(struct client_entity_s *shield, centity_t *owner) +{ + // Don't instantly delete yourself. Don't accept any more updates and die out within a second. + shield->d_alpha = -1.2; // Fade out. + shield->SpawnDelay = fxi.cl->time + 2000; // No more particles. + shield->updateTime = 1000; // Die in one second. + shield->Update = RemoveSelfAI; + + return true; +} + + +// ************************************************************************************************ +// FXLightningShield +// ------------ +// ************************************************************************************************ + +// CreateEffect FX_SPELL_LIGHTNINGSHIELD +void FXLightningShield(centity_t *owner,int type,int flags,vec3_t origin) +{ + client_entity_t *shield; + int i; + vec3_t angvect; + int count; + + count = GetScaledCount(NUM_SHIELD_SPARKS, 0.5); + + // Add spinning electrical sparks + for(i=0; iflags |= CEF_ADDITIVE_PARTS | CEF_ABSOLUTE_PARTS; + shield->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + shield->r.model = shield_models; + shield->radius = SHIELD_RADIUS; + shield->AddToView = FXShieldSparkThink; + shield->color.c = 0xffffffff; + shield->alpha = 0.1; + shield->d_alpha = 0.5; + shield->Update = FXShieldTerminate; + + VectorClear(shield->direction); + shield->direction[YAW] = flrand(0, 360.0); // This angle is kept at a constant distance from org. + shield->direction[PITCH] = flrand(0, 360.0); + + shield->velocity2[YAW] = flrand(-180.0, 180.0); + if (shield->velocity2[YAW] < 0) // Assure that the sparks are moving around at a pretty good clip. + shield->velocity2[YAW] -= 180.0; + else + shield->velocity2[YAW] += 180.0; + + shield->velocity2[PITCH] = flrand(-180.0, 180.0); // This is a velocity around the sphere. + if (shield->velocity2[PITCH] < 0) // Assure that the sparks are moving around at a pretty good clip. + shield->velocity2[PITCH] -= 180.0; + else + shield->velocity2[PITCH] += 180.0; + + shield->lastThinkTime = fxi.cl->time; + shield->SpawnDelay = fxi.cl->time + SHIELD_TRAIL_DELAY; + + AngleVectors(shield->direction, angvect, NULL, NULL); + VectorMA(owner->origin, shield->radius, angvect, shield->r.origin); + + AddEffect(owner, shield); + } +} + diff --git a/Toolkit/Programming/GameCode/client effects/fx_shrine.c b/Toolkit/Programming/GameCode/client effects/fx_shrine.c new file mode 100644 index 0000000..33db441 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_shrine.c @@ -0,0 +1,1203 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Random.h" +#include "Vector.h" +#include "string.h" +#include "Utilities.h" +#include "g_playstats.h" + +#define PLAYER_FADE_TIME 14 +#define PLAYER_FADE_AMOUNT 255/ PLAYER_FADE_TIME +#define MANA_RAD 100.0 +#define MANA_HEIGHT 32.0 +#define ARMOR_RAD 35.0 +#define LUNG_RAD 20.0 +#define STAFF_RADIUS 20.0 +#define NUM_OF_MANA_PARTS 16 +#define NUM_OF_ARMOR_PARTS 30 +#define NUM_OF_STAFF_PARTS 6 +#define NUM_OF_LUNG_PARTS 15 +#define TOTAL_STAFF_EFFECTS 30 +#define STAFF_EFFECTS_HEIGHT 70 +#define STAFF_EFFECTS_START_HEIGHT -30 +#define STAFF_HEIGHT_ADD (STAFF_EFFECTS_HEIGHT - STAFF_EFFECTS_START_HEIGHT) / TOTAL_STAFF_EFFECTS +#define STAFF_GREEN_ADD -(255 / (TOTAL_STAFF_EFFECTS -8)) +#define STAFF_BLUE_ADD STAFF_GREEN_ADD * 2 +#define ACCEL_SCALE 3.1 +#define LIGHTNING_START 20 +#define LIGHTNING_MINIMUM 0.15 +#define LIGHTNING_MAXIMUM 0.3 +#define LIGHTNING_SPLIT_RAD 1.3 +#define TOTAL_HEALTH_EFFECTS 8 +#define BALL_RAD 40 +#define BALL_PART_SCALE 10.0 +#define BALL_PART_NUM 4 +#define BALL_EX_PART_NUM 20 +#define LIGHTNING_DUR 100 +#define FLIGHT_RAD 20 +#define TOTAL_FLIGHT_EFFECTS 60 +#define FLIGHT_EFFECTS_HEIGHT 50 +#define FLIGHT_EFFECTS_START_HEIGHT -35 +#define FLIGHT_HEIGHT_ADD (FLIGHT_EFFECTS_HEIGHT - FLIGHT_EFFECTS_START_HEIGHT) / (TOTAL_FLIGHT_EFFECTS - 24) +#define NUM_OF_FLIGHT_PARTS 3 +#define FLIGHT_PLAY_RAD 12 +#define NUM_OF_REFLECT_PARTS 20 +#define REFLECT_RAD 31 +#define TOTAL_REFLECT_EFFECTS 50 +#define REFLECT_EFFECTS_HEIGHT 50 +#define REFLECT_EFFECTS_START_HEIGHT -35 +#define REFLECT_HEIGHT_ADD (REFLECT_EFFECTS_HEIGHT - REFLECT_EFFECTS_START_HEIGHT) / (TOTAL_REFLECT_EFFECTS - 24) +#define TOTAL_POWERUP_EFFECTS 38 +#define POWERUP_EFFECTS_HEIGHT 60 +#define POWERUP_EFFECTS_START_HEIGHT -30 +#define NUM_OF_POWERUP_PARTS 22 +#define POWERUP_RAD 6 +#define POWERUP_HEIGHT_ADD (POWERUP_EFFECTS_HEIGHT - POWERUP_EFFECTS_START_HEIGHT) / (TOTAL_POWERUP_EFFECTS - 24) + +#define NUM_SHRINE_MODELS 6 +static struct model_s *shrine_models[NUM_SHRINE_MODELS]; + +typedef struct +{ + int red; + int green; + int blue; +} tint_tab_t; + +tint_tab_t tint_tab[9] = +{ + { 96, 255, 96 }, + { 96, 255, 255 }, + { 128, 128, 255 }, + { 96, 255, 255 }, + { 255, 255, 96 }, + { 255, 255, 255 }, + { 255, 96, 96 }, + { 255, 96, 96 }, + { 255, 96, 96 }, +}; + +/* +Main Routines +*/ + +void PreCacheShrine() +{ + shrine_models[1] = fxi.RegisterModel("sprites/lens/halo1.sp2"); + shrine_models[5] = fxi.RegisterModel("sprites/fx/halo.sp2"); +} + +/* +---------------------------------------- + +Main Player routine - make large player, and fade it into us + +---------------------------------------- +*/ + + +// kill the expanding player model when it fades away +static qboolean shrine_player_update(struct client_entity_s *self, centity_t *owner) +{ + if (!(--self->SpawnInfo)) + { + self->r.fmnodeinfo = NULL; + return(false); + } + + return(true); +} + +// Create a model of the player, and have it expand and fade, with a tint +void FXShrinePlayerEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *shrine_fx; + byte shrine_type; + + // no longer used - causes really hard to find crashes. + return; + fxi.GetEffect(owner, flags, "b", &shrine_type); + + // push the model slightly up,since we create the model at a larger scale than the original + origin[2] += 60.0; + + // create the player shrine effect around the player to begin with + shrine_fx = ClientEntity_new(type, flags, origin, NULL, 100); + shrine_fx->radius = 20.0F; + if (owner->current.effects & EF_CHICKEN) + shrine_fx->r.model = shrine_models + 4; + else + shrine_fx->r.model = shrine_models; + shrine_fx->d_scale = -1.2; + shrine_fx->r.scale = 3.0; + shrine_fx->velocity[2] = -35.5; + shrine_fx->r.flags = RF_TRANSLUCENT ; + shrine_fx->r.fmnodeinfo = &owner->current.fmnodeinfo[0]; + shrine_fx->Update = shrine_player_update; + shrine_fx->SpawnInfo = PLAYER_FADE_TIME; + shrine_fx->d_alpha = 0.45; + shrine_fx->alpha = 0.05; + shrine_fx->r.frame = owner->current.frame; + shrine_fx->r.color.r = tint_tab[shrine_type].red; + shrine_fx->r.color.g = tint_tab[shrine_type].green; + shrine_fx->r.color.b = tint_tab[shrine_type].blue; + shrine_fx->AddToView = LinkedEntityUpdatePlacement; + VectorDegreesToRadians(&owner->current.angles[0],shrine_fx->r.angles); + + AddEffect(owner, shrine_fx); + +} + + +/* +---------------------------------------- + +Mana effect routine + +---------------------------------------- +*/ + +static qboolean FXShrineManaThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + paletteRGBA_t color; + vec3_t vel, org; + int i; + int count; + + if (!(--self->SpawnInfo)) + { + return(false); + } + + if (self->SpawnInfo >4) + { + count = GetScaledCount(NUM_OF_MANA_PARTS, 0.7); + for(i = 0; i < count; i++) + { + // Calc spherical offset around left hand ref point + VectorSet(vel, flrand(-1.0, 1.0), flrand(-1.0, 1.0), flrand(-1.0, 1.0)); + if(Vec3IsZero(vel)) + org[2] = 1.0; // Safety in case flrand gens all zeros (VERY unlikely) + VectorNormalize(vel); + VectorScale(vel, MANA_RAD, vel); + + color.c = 0xffffffff; + if (i&1) // green parts + ce = ClientParticle_new(PART_16x16_SPARK_G, color, 500); + else // blue parts + ce = ClientParticle_new(PART_16x16_SPARK_B, color, 500); + VectorCopy(vel, ce->origin); + ce->origin[2] += MANA_HEIGHT; + + VectorScale(vel, -0.125, ce->velocity); + VectorScale(vel, -8.0, ce->acceleration); + ce->scale = 20.0F; + ce->d_scale = -30.0F; + ce->color.a = 1; + ce->d_alpha = 400; + AddParticleToList(self, ce); + } + } + return(true); +} + +// make the mana effect go off +void FXShrineManaEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + glow = ClientEntity_new(type, flags | CEF_NO_DRAW |CEF_ADDITIVE_PARTS, origin, 0, 100); + + VectorClear(glow->origin); + glow->Update = FXShrineManaThink; + glow->SpawnInfo = 17; + glow->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner, glow); + +} + +/* +---------------------------------------- + +Armor effect routine + +---------------------------------------- +*/ + + +static qboolean FXShrineArmorThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + paletteRGBA_t color; + vec3_t vel, org; + int i; + int count; + + if (!(--self->SpawnInfo)) + { + return(false); + } + + if (self->SpawnInfo >4) + { + count = GetScaledCount(NUM_OF_ARMOR_PARTS, 0.7); + for(i = 0; i < count; i++) + { + // Calc spherical offset around left hand ref point + VectorSet(vel, flrand(-1.0, 1.0), flrand(-1.0, 1.0), flrand(-1.0, 1.0)); + if(Vec3IsZero(vel)) + org[2] = 1.0; // Safety in case flrand gens all zeros (VERY unlikely) + VectorNormalize(vel); + VectorScale(vel, ARMOR_RAD, vel); + + color.c = 0xffffffff; // The particle is blue + // which type of particle do we use ? Gold or Silver armor ? + if (self->flags & CEF_FLAG6) + ce = ClientParticle_new(PART_16x16_ORANGE_PUFF, color, 500); + else + ce = ClientParticle_new(PART_16x16_BLUE_PUFF, color, 500); + ce->acceleration[2] = 0.0; + VectorCopy(vel, ce->origin); + ce->scale = 30.0F; + ce->d_scale = -60.0F; + ce->color.a = 1; + ce->d_alpha = 400; + AddParticleToList(self, ce); + } + } + return(true); +} + +void FXShrineArmorEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + glow = ClientEntity_new(type, flags | CEF_NO_DRAW |CEF_ADDITIVE_PARTS, origin, 0, 100); + + VectorClear(glow->origin); + glow->Update = FXShrineArmorThink; + glow->SpawnInfo = 18; + glow->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner, glow); + +} + +/* +---------------------------------------- + +Lungs effect routines + +---------------------------------------- +*/ + +static qboolean FXShrineLungsThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + paletteRGBA_t color; + vec3_t vel; + int i; + int count; + + if (!(--self->SpawnInfo)) + { + return(false); + } + + if (self->SpawnInfo >10) + { + count = GetScaledCount(NUM_OF_LUNG_PARTS, 0.7); + for(i = 0; i < count; i++) + { + // Calc spherical offset around left hand ref point + VectorSet(vel, flrand(-1.0, 1.0), flrand(-1.0, 1.0), 0.01); + VectorNormalize(vel); + VectorScale(vel, flrand(1.0,LUNG_RAD), vel); + vel[2] = -30.0; + + color.c = 0xffffff40; + + ce = ClientParticle_new(PART_32x32_STEAM, color, 450); + + VectorCopy(vel, ce->origin); + VectorSet(ce->velocity, 0.0, 0.0, flrand(10.0, 40.0)); + VectorSet(ce->acceleration, 0.0, 0.0, flrand(300.0, 1000.0)); + ce->scale = 8.0F; + AddParticleToList(self, ce); + } + } + return(true); +} + +void FXShrineLungsEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + glow = ClientEntity_new(type, flags | CEF_NO_DRAW , origin, 0, 50); + + VectorClear(glow->origin); + glow->Update = FXShrineLungsThink; + glow->SpawnInfo = 40; + glow->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(owner, glow); + +} + +/* +---------------------------------------- + +Light effect routines + +---------------------------------------- +*/ + +// create the light effect - a big old halo that fades away +void FXShrineLightEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + glow = ClientEntity_new(type, flags, origin, 0, 2000); + + VectorClear(glow->origin); + glow->r.model = shrine_models + 1; + glow->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + glow->AddToView = LinkedEntityUpdatePlacement; + glow->d_scale = 5.0; + glow->r.scale = 0.1; + glow->d_alpha = -0.45; + glow->alpha = 1.0; + + AddEffect(owner, glow); +} + +/* +---------------------------------------- + +Staff Powerup Routines + +---------------------------------------- +*/ + + +// create the two circles that ring the player +static qboolean FXShrineStaffThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + vec3_t vel; + int count; + float curAng; + float new_y; + float rad; + + if (!(--self->SpawnInfo)) + { + return(false); + } + rad = ((TOTAL_STAFF_EFFECTS)-self->SpawnInfo) * (STAFF_RADIUS/(TOTAL_STAFF_EFFECTS-8)); + + if (self->SpawnInfo >8) + { + // figure out how many particles we are going to use + count = GetScaledCount(self->SpawnDelay, 0.7); + // create the ring of particles that goes up + for(curAng = 0.0F; curAng < (M_PI * 2.0F); curAng += (M_PI * 2.0F) / count ) + { + + VectorSet(vel, rad * cos(curAng), rad * sin(curAng), self->SpawnData); + + if(self->flags & CEF_FLAG6) + ce = ClientParticle_new(irand(PART_16x16_FIRE1, PART_16x16_FIRE3), self->r.color, self->LifeTime); + else + ce = ClientParticle_new(PART_16x16_SPARK_B, self->r.color, self->LifeTime); + + ce->acceleration[2] = 0.0; + VectorCopy(vel, ce->origin); + ce->color.a = 118; + ce->scale = 16.0F; + AddParticleToList(self, ce); + } + // create the ring of particles that goes down + new_y = -self->SpawnData; + for(curAng = 0.0F; curAng < (M_PI * 2.0F); curAng += (M_PI * 2.0F) / count ) + { + + VectorSet(vel, rad * cos(curAng), rad * sin(curAng), new_y); + + if(self->flags & CEF_FLAG6) + ce = ClientParticle_new(irand(PART_16x16_FIRE1, PART_16x16_FIRE3), self->r.color, self->LifeTime); + else + ce = ClientParticle_new(PART_16x16_SPARK_B, self->r.color, self->LifeTime); + ce->acceleration[2] = 0.0; + VectorCopy(vel, ce->origin); + ce->color.a = 118; + ce->scale = 16.0F; + AddParticleToList(self, ce); + } + } + + // update the particles colors + if (self->r.color.g > 0) + self->r.color.g += STAFF_GREEN_ADD; + else + self->r.color.g = 0; + + if (self->r.color.b > 0) + self->r.color.b += STAFF_BLUE_ADD; + else + self->r.color.b = 0; + + // move the rings up/down next frame + self->SpawnData += STAFF_HEIGHT_ADD; + + return(true); +} + +// start up the staff power up effect +void FXShrineStaffEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + int line_count, particle_life; + + if(r_detail->value >= DETAIL_HIGH) + { + line_count = NUM_OF_STAFF_PARTS; + particle_life = 2400; + } + else + if(r_detail->value >= DETAIL_NORMAL) + { + line_count = NUM_OF_STAFF_PARTS - 2; + particle_life = 1900; + } + else + { + line_count = NUM_OF_STAFF_PARTS - 3; + particle_life = 1500; + } + glow = ClientEntity_new(type, flags | CEF_NO_DRAW | CEF_ADDITIVE_PARTS, origin, 0,50); + + VectorClear(glow->origin); + glow->Update = FXShrineStaffThink; + glow->SpawnInfo = TOTAL_STAFF_EFFECTS; + glow->AddToView = LinkedEntityUpdatePlacement; + glow->SpawnData = STAFF_EFFECTS_START_HEIGHT; + glow->SpawnDelay = line_count; + glow->LifeTime = particle_life; + + AddEffect(owner, glow); +} + + +/* +---------------------------------------- + +Health Lightning routines + +---------------------------------------- +*/ + +// recursively called to create the lightning effect +void FXLightningSplit(struct client_entity_s *self, vec3_t org, vec3_t dir, int rand_chance, float stop_height) +{ + client_particle_t *ce; + float start_height; + vec3_t dir2; + vec3_t dir_effect; + paletteRGBA_t color; + vec3_t org2; + float stop_height2; + int lightning_part_duration; + + VectorCopy(org, org2); + + start_height = org[2]; + color.c = 0xffffff; + + // create lightning particle + while (org2[2] > stop_height) + { + // if we are the smaller split type, make our life longer, since we fade that much faster than the big particles + if (stop_height != -30) + lightning_part_duration = self->updateTime ; + else + lightning_part_duration = self->updateTime / 1.2 ; + + // create the individual particle + ce = ClientParticle_new(PART_16x16_LIGHTNING, color, lightning_part_duration); + ce->acceleration[2] = 0.0; + VectorCopy(org2, ce->origin); + + // figure out what our scale and alpaha should be based on whether its a small split or not + if (stop_height != -30) + { + ce->scale = 0.5; + ce->color.a = 108; + } + else + { + ce->scale = 1.2; + ce->color.a = 255; + } + AddParticleToList(self, ce); + + // decide if we are splitting + if (!(irand(0,rand_chance))) + { + // decide a new direction for the two halves + dir[1] = flrand(-LIGHTNING_SPLIT_RAD, LIGHTNING_SPLIT_RAD); + dir[0] = flrand(-LIGHTNING_SPLIT_RAD, LIGHTNING_SPLIT_RAD); + + // create the new split + dir2[2] = dir[2]; + dir2[1] = -dir[1]; + dir2[0] = -dir[0]; + rand_chance += 5; + + // if we've split a fair few times already, don't again + if (rand_chance > 125) + rand_chance = 100000; + + // decide if this is a faint split or not + if (irand(0,5)) + stop_height2 = org[2]-25; + else + stop_height2 = stop_height; + + // create split + FXLightningSplit(self, org2, dir2, rand_chance, stop_height2); + } + // update the direction we want to go in + else + { + // figure out values to add to dir + VectorSet(dir_effect, flrand(-LIGHTNING_MINIMUM,LIGHTNING_MINIMUM), flrand(-LIGHTNING_MINIMUM,LIGHTNING_MINIMUM) ,0); + + // add to direction + Vec3AddAssign(dir_effect,dir); + // cap direction + if (dir[1] > LIGHTNING_MAXIMUM) + dir[1] -= LIGHTNING_MINIMUM; + else + if (dir[1] < -LIGHTNING_MAXIMUM) + dir[1] += LIGHTNING_MINIMUM; + + if (dir[0] > LIGHTNING_MAXIMUM) + dir[0] -= LIGHTNING_MINIMUM; + else + if (dir[0] < -LIGHTNING_MAXIMUM) + dir[0] += LIGHTNING_MINIMUM; + } + // update position + org2[2] += dir[2]; + org2[1] += dir[1]; + org2[0] += dir[0]; + } +} + +// create the lightning lines +void FXCreateLightning(struct client_entity_s *self, centity_t *owner) +{ + vec3_t org; + vec3_t dir; + int lightning_count; + float curAng; + + // create the lightning lines + lightning_count = irand(2,3); + for(curAng = 0.0F; curAng < (M_PI * 2.0F); curAng += (M_PI * 2.0F) / lightning_count ) + { + // setup the start of a lightning line + VectorSet(org, LIGHTNING_START * cos(curAng), LIGHTNING_START * sin(curAng),self->SpawnData); + // setup intital direction + VectorSet(dir, flrand(-LIGHTNING_MINIMUM,LIGHTNING_MINIMUM), flrand(-LIGHTNING_MINIMUM,LIGHTNING_MINIMUM) ,-0.5); + // create inital line of lightning + FXLightningSplit(self, org, dir, 60, -30.0f); + } + + self->SpawnData -= 5; + + // if the owner of the lightning is the main client then flash the screen + if (owner->current.number == fxi.cl->playernum + 1) + { + // give a quick screen flash + fxi.Activate_Screen_Flash(0x80ffd0c0); + // make our screen shake a bit + // values are : a, b, c, d + // a = amount of maximum screen shake, in pixels + // b = duration of screen shake in milli seconds + // c = current time - in milli seconds - if this routine is called from the server, remember this + // d = dir of shake - see game_stats.h for definitions + fxi.Activate_Screen_Shake(4,800, fxi.cl->time, SHAKE_ALL_DIR); + } +} + + +// make the lightning effect re-occur +static qboolean FXShrineHealthThink(struct client_entity_s *self, centity_t *owner) +{ + + if (!(--self->SpawnInfo)) + { + return(false); + } + + // create the lightning lines + FXCreateLightning(self, owner); + + self->updateTime = flrand(1, (TOTAL_HEALTH_EFFECTS - self->SpawnInfo)) * 100.0; + + return(true); +} + +// create initial lightning line +void FXShrineHealthEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + // create the entity that the particles are attached to + glow = ClientEntity_new(type, flags | CEF_NO_DRAW | CEF_ADDITIVE_PARTS, origin, 0, LIGHTNING_DUR+20); + glow->SpawnInfo = TOTAL_HEALTH_EFFECTS; + glow->AddToView = LinkedEntityUpdatePlacement; + glow->Update = FXShrineHealthThink; + glow->SpawnData = 70; + AddEffect(owner, glow); + + // start off the lightning effect + FXCreateLightning(glow, owner); + +} + +/* +---------------------------------------- + +Reflect effect routines + +---------------------------------------- +*/ + +// create the two circles that ring the player +static qboolean FXShrineReflectThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + int count, i; + float new_y; + float ang; + float offset_ang; + paletteRGBA_t color; + + if (!(--self->SpawnInfo)) + { + return(false); + } + + if (self->SpawnInfo >24) + { + // create the ring of particles that goes up + color.c = 0xffffff; + color.a = 0xff; + + // figure out how many particles we are going to use + count = GetScaledCount(NUM_OF_FLIGHT_PARTS, 0.7); + offset_ang = 6.28 / count; + ang = self->Scale; + for (i=0; i< count; i++) + { + ang += offset_ang;; + + ce = ClientParticle_new(PART_16x16_SPARK_B, color, 450); + ce->acceleration[2] = 0.0; + VectorSet(ce->origin, FLIGHT_RAD * cos(ang), FLIGHT_RAD * sin(ang), self->SpawnData); + ce->scale = 16.0F; + AddParticleToList(self, ce); + } + // create the ring of particles that goes down + new_y = -self->SpawnData; + + ang = self->Scale; + for (i=0; i< count; i++) + { + ang += offset_ang;; + + ce = ClientParticle_new(PART_16x16_SPARK_B, color, 450); + ce->acceleration[2] = 0.0; + VectorSet(ce->origin, FLIGHT_RAD * cos(ang), FLIGHT_RAD * sin(ang), new_y); + ce->scale = 16.0F; + AddParticleToList(self, ce); + } + // put the sparkle on us + if(self->SpawnInfo > 10) + { + count = irand(3,7); + for (i=0; iacceleration[2] = 0.0; + VectorSet(ce->origin, flrand(-FLIGHT_PLAY_RAD,FLIGHT_PLAY_RAD), flrand(-FLIGHT_PLAY_RAD,FLIGHT_PLAY_RAD), flrand(-30,30) ); + ce->scale = 0.3; + ce->d_scale = flrand(40.0F, 60.0f); + AddParticleToList(self, ce); + } + } + + } + + // move the rings up/down next frame + self->SpawnData += FLIGHT_HEIGHT_ADD; + self->Scale += 0.15; + + return(true); +} + +// create the entity the flight loops are on +void FXShrineReflectEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + glow = ClientEntity_new(type, flags | CEF_NO_DRAW | CEF_ADDITIVE_PARTS, origin, 0, 25); + + VectorClear(glow->origin); + glow->Update = FXShrineReflectThink; + glow->SpawnInfo = TOTAL_FLIGHT_EFFECTS; + glow->AddToView = LinkedEntityUpdatePlacement; + glow->SpawnData = FLIGHT_EFFECTS_START_HEIGHT; + glow->Scale = 0; + + AddEffect(owner, glow); + +} + +/* +---------------------------------------- + +Ghosting effect Routines + +---------------------------------------- +*/ + +// make the glow go away +static qboolean FXShrineGlowThink(struct client_entity_s *self, centity_t *owner) +{ + if (!(--self->SpawnInfo)) + { + return(false); + } + + self->d_alpha = -0.45; + self->d_scale = -1.0; + return(true); +} + +// create the little glow bits.. +static qboolean FXShrineGhostThink(struct client_entity_s *self, centity_t *owner) +{ + int i; + client_entity_t *glow; + vec3_t origin; + + if (!(--self->SpawnInfo)) + { + return(false); + } + + for( i=0; i< irand(3,5); i++) + { + VectorSet(origin, flrand(-20, 20), flrand(-20,20), flrand(-30,40)); + + glow = ClientEntity_new(FX_SHRINE_GHOST, CEF_OWNERS_ORIGIN, origin, 0, 300); + + glow->r.model = shrine_models + 1; + glow->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + glow->SpawnInfo = 2; + glow->AddToView = OffsetLinkedEntityUpdatePlacement; + glow->d_scale = flrand(0.5, 2.0); + glow->r.scale = 0.1; + glow->d_alpha = 1.0; + glow->alpha = 0.1; + glow->Update = FXShrineGlowThink; + + AddEffect(owner, glow); + } + return(true); +} + +// create the inital ghost controlling entity +void FXShrineGhostEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + glow = ClientEntity_new(type, flags|CEF_NO_DRAW, origin, 0, 70); + + glow->SpawnInfo = 20; + glow->Update = FXShrineGhostThink; + + AddEffect(owner, glow); +} + +/* +---------------------------------------- + +Speed effect routine + +---------------------------------------- +*/ + +// create the two circles that ring the player +static qboolean FXShrineSpeedThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + int count, i; + float ang; + float offset_ang; + vec3_t angles; + paletteRGBA_t color; + + if (!(--self->SpawnInfo)) + { + return(false); + } + + color.c = 0xffffff; + color.a = 0xff; + + // figure out how many particles we are going to use + count = GetScaledCount(NUM_OF_REFLECT_PARTS, 0.7); + offset_ang = 6.28 / count; + ang = 0; + for (i=0; i< count; i++) + { + ce = ClientParticle_new(PART_32x32_STEAM, self->r.color, 380); + ce->acceleration[2] = 0.0; + VectorSet(angles, ang, self->Scale, 0); + DirFromAngles(angles, ce->origin); + Vec3ScaleAssign(REFLECT_RAD, ce->origin); + ce->scale = 7.0F; + if (self->SpawnInfo <18) + ce->color.a = (self->SpawnInfo) * (255 / 18); + AddParticleToList(self, ce); + ang += offset_ang;; + } + self->Scale += 0.25; + + // put the sparkle on us + if(self->SpawnInfo > 10) + { + count = irand(3,7); + for (i=0; iacceleration[2] = 0.0; + VectorSet(ce->origin, flrand(-FLIGHT_PLAY_RAD,FLIGHT_PLAY_RAD), flrand(-FLIGHT_PLAY_RAD,FLIGHT_PLAY_RAD), flrand(-30,30) ); + ce->scale = 0.3; + ce->d_scale = flrand(40.0F, 60.0f); + AddParticleToList(self, ce); + } + } + + return(true); +} + +void FXShrineSpeedEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + glow = ClientEntity_new(type, flags | CEF_NO_DRAW, origin, 0, 30); + + VectorClear(glow->origin); + glow->Update = FXShrineSpeedThink; + glow->SpawnInfo = TOTAL_REFLECT_EFFECTS; + glow->AddToView = LinkedEntityUpdatePlacement; + glow->SpawnData = REFLECT_EFFECTS_START_HEIGHT; + glow->r.color.c = 0x604040; + glow->r.color.a = 255; + glow->Scale = 0; + + AddEffect(owner, glow); +} + + +/* +---------------------------------------- + +Weapons Power Up effect routine + +---------------------------------------- +*/ + +// create the two circles that ring the player +static qboolean FXShrinePowerupThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + int count, i; + float ang; + float offset_ang; + paletteRGBA_t color; + + if (!(--self->SpawnInfo)) + { + return(false); + } + + if (self->SpawnInfo >24) + { + // create the ring of particles that goes up + + color.c = 0xffffff; + color.a = 0xff; + + // figure out how many particles we are going to use + count = GetScaledCount(NUM_OF_POWERUP_PARTS, 0.7); + offset_ang = 6.28 / count; + ang = 0; + for (i=0; i< count; i++) + { + ce = ClientParticle_new(PART_16x16_SPARK_G, color, 350); + ce->acceleration[2] = 0.0; + VectorSet(ce->origin, POWERUP_RAD * cos(ang), POWERUP_RAD * sin(ang), self->SpawnData); + ce->scale = 12.0F; + AddParticleToList(self, ce); + VectorScale(ce->origin, 25, ce->velocity); + ce->velocity[2] = 0; + ang += offset_ang;; + } + + // put the sparkle on us + if(self->SpawnInfo > 10) + { + count = irand(3,7); + for (i=0; iacceleration[2] = 0.0; + VectorSet(ce->origin, flrand(-FLIGHT_PLAY_RAD,FLIGHT_PLAY_RAD), flrand(-FLIGHT_PLAY_RAD,FLIGHT_PLAY_RAD), flrand(-30,30) ); + ce->scale = 0.3; + ce->d_scale = flrand(40.0F, 60.0f); + AddParticleToList(self, ce); + } + } + + } + + // move the rings up/down next frame + self->SpawnData += POWERUP_HEIGHT_ADD; + + return(true); +} + +void FXShrinePowerUpEffect(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + glow = ClientEntity_new(type, flags | CEF_NO_DRAW | CEF_ADDITIVE_PARTS, origin, 0, 75); + + glow->Update = FXShrinePowerupThink; + glow->SpawnInfo = TOTAL_POWERUP_EFFECTS; + glow->AddToView = LinkedEntityUpdatePlacement; + glow->SpawnData = POWERUP_EFFECTS_START_HEIGHT; + + AddEffect(owner, glow); +} + +/* +---------------------------------------- + +Persistant shrine ball effect + +---------------------------------------- +*/ + +enum +{ + SHRINEBALL_HEAL = 0, + SHRINEBALL_MANA, + SHRINEBALL_LUNGS, + SHRINEBALL_LIGHT, + SHRINEBALL_POWERUP, + SHRINEBALL_ARMOR, + SHRINEBALL_ARMOR_GOLD, + SHRINEBALL_RANDOM, + SHRINEBALL_REFLECT, + SHRINEBALL_STAFF, + SHRINEBALL_GHOST, + SHRINEBALL_SPEED, + SHRINEBALL_MAX +}; + + + +static short ShrineParticle[12][2] = +{ + { PART_16x16_SPARK_I, PART_16x16_LIGHTNING }, // SHRINEBALL_HEAL, + { PART_16x16_SPARK_G, PART_16x16_SPARK_B }, // SHRINEBALL_MANA, + { PART_16x16_WATERDROP, PART_32x32_WFALL }, // SHRINEBALL_LUNGS, + { PART_4x4_WHITE, PART_32x32_ALPHA_GLOBE }, // SHRINEBALL_LIGHT, + { PART_16x16_SPARK_G, PART_16x16_SPARK_G }, // SHRINEBALL_POWERUP, + { PART_8x8_BLUE_DIAMOND, PART_8x8_BLUE_X }, // SHRINEBALL_ARMOR, + { PART_16x16_SPARK_Y, PART_16x16_SPARK_Y }, // SHRINEBALL_ARMOR_GOLD, + { PART_8x8_RED_X, PART_8x8_CYAN_DIAMOND }, // SHRINEBALL_RANDOM + { PART_8x8_CYAN_DIAMOND, PART_8x8_CYAN_X }, // SHRINEBALL_REFLECT, + { PART_16x16_SPARK_C, PART_32x32_FIREBALL }, // SHRINEBALL_STAFF + { PART_32x32_WFALL, PART_16x16_STAR }, // SHRINEBALL_GHOST, + { PART_32x32_WFALL, PART_32x32_WFALL }, // SHRINEBALL_SPEED, +}; + + +// make the shrine glow ball effect shimmer, and give off steam +static qboolean FXShrineBallThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + paletteRGBA_t color; + int part = 0; + vec3_t rad, fwd; + int i; + int count; + + color.c = 0xffffffff; + count = GetScaledCount(BALL_PART_NUM, 0.4); + + for (i=0; iSpawnInfo >= 0 && self->SpawnInfo < SHRINEBALL_MAX); + if (self->SpawnInfo == SHRINEBALL_RANDOM) + { + part = irand(PART_16x16_SPARK_B, PART_16x16_SPARK_Y); + } + else + part = ShrineParticle[self->SpawnInfo][irand(0,1)]; + + ce = ClientParticle_new(part, color, 1000); + + if(part != PART_32x32_WFALL && part != PART_16x16_WATERDROP) + ce->type |= PFL_ADDITIVE; + + rad[PITCH] = flrand(0, 360.0); + rad[YAW] = flrand(0, 360.0); + rad[ROLL] = 0.0; + AngleVectors(rad, fwd, NULL, NULL); + VectorScale(fwd, BALL_RAD, ce->velocity); + VectorScale(ce->velocity, -1.0, ce->acceleration); + ce->color.a = 245; + ce->scale = BALL_PART_SCALE; + ce->d_scale = -0.5*BALL_PART_SCALE; + AddParticleToList(self, ce); + } + + self->updateTime = 150; + return(true); +} + +// create the floating ball in the middle of the shrine +void FXShrineBall(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + vec3_t offset; + byte shrinetype; + // go get the normalised direction of the shrine object + fxi.GetEffect(owner, flags, "db", &offset, &shrinetype); + + // don't put out effects for shrines that don't exist + if(shrinetype >= SHRINEBALL_MAX) + return; + + // move our starting point out a bit + Vec3ScaleAssign(25,offset); + offset[2] = -10; + Vec3AddAssign(offset, origin); + + // create the dummy entity, so particles can be attached + // | CEF_ADDITIVE_PARTS + glow = ClientEntity_new(type, (flags | CEF_NO_DRAW | CEF_VIEWSTATUSCHANGED) & ~CEF_NOMOVE , origin, 0, 20); + glow->SpawnInfo = shrinetype; + glow->Update = FXShrineBallThink; + glow->radius = 100; + + AddEffect(owner, glow); +} + +/* +---------------------------------------- + +Exploding shrine ball effect + +---------------------------------------- +*/ + +// explode the ball in the middle of the shrine +void FXShrineBallExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_particle_t *ce; + client_entity_t *burst; + vec3_t offset; + int i, count; + paletteRGBA_t color; + byte shrinetype; + int part; + vec3_t rad, fwd; + + color.c = 0xffffffff; + + // go get the normalised direction of the shrine object + fxi.GetEffect(owner, flags, "db", &offset, &shrinetype); + + // move our starting point out a bit + Vec3ScaleAssign(25,offset); + offset[2] = -10; + Vec3AddAssign(offset, origin); + + // create the dummy entity, so particles can be attached + burst = ClientEntity_new(type, (flags | CEF_NO_DRAW | CEF_CHECK_OWNER) & ~CEF_NOMOVE , origin, 0, 1200); + burst->radius = 100; + AddEffect(owner, burst); + + assert(shrinetype >= 0 && shrinetype <= SHRINEBALL_MAX); + count = GetScaledCount(BALL_EX_PART_NUM, 0.4); + // create a bunch of exploding particles + for (i=0; i< count; i++) + { + rad[PITCH] = flrand(0, 360.0); + rad[YAW] = flrand(0, 360.0); + rad[ROLL] = 0.0; + + if (shrinetype == SHRINEBALL_RANDOM) + { + part = irand(PART_16x16_SPARK_B, PART_16x16_SPARK_Y); + } + else + part = ShrineParticle[shrinetype][irand(0,1)]; + + ce = ClientParticle_new(part, color, 1150); + + if(part != PART_32x32_WFALL && part != PART_16x16_WATERDROP) + ce->type |= PFL_ADDITIVE; + + AngleVectors(rad, fwd, NULL, NULL); + VectorScale(fwd, BALL_RAD, ce->velocity); + VectorScale(ce->velocity, -0.7, ce->acceleration); + ce->color.a = 245; + ce->scale = BALL_PART_SCALE; + ce->d_scale = -0.5*BALL_PART_SCALE; + AddParticleToList(burst, ce); + } + + // Add an additional flash as well. + // ...and a big-ass flash + burst = ClientEntity_new(-1, flags, origin, NULL, 250); + burst->r.model = shrine_models + 5; + burst->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT;// | RF_FULLBRIGHT; + burst->r.frame = 1; + burst->radius=64; + burst->r.scale=1.0; + burst->d_alpha=-4.0; + burst->d_scale=-4.0; + AddEffect(NULL, burst); +} + + diff --git a/Toolkit/Programming/GameCode/client effects/fx_smoke.c b/Toolkit/Programming/GameCode/client effects/fx_smoke.c new file mode 100644 index 0000000..775c1f0 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_smoke.c @@ -0,0 +1,127 @@ +// +// fx_smoke.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Angles.h" +#include "Client Entities.h" +#include "Client Effects.h" +#include "q_shared.h" +#include "Vector.h" +#include "EffectFlags.h" +#include "Particle.h" +#include "Random.h" +#include "Motion.h" +#include "Utilities.h" + +#define NUM_SMOKE_MODELS 1 +static struct model_s *smoke_models[NUM_SMOKE_MODELS]; + +void PreCacheSmoke() +{ + smoke_models[0] = fxi.RegisterModel("sprites/fx/steam.sp2"); +} + +// -------------------------------------------------------------- + +void FXDarkSmoke(vec3_t origin, float scale, float range) +{ + client_entity_t *effect; + int duration; + + effect = ClientEntity_new(-1, RF_TRANSLUCENT, origin, NULL, 500); + + effect->r.model = smoke_models; + effect->r.scale = scale; + effect->r.color.c = 0xaa777777; + + duration = Q_ftol(GetTimeToReachDistance(50.0, 0.0, range)); + + VectorSet(effect->velocity, flrand(-10.0, 10.0), flrand(-10.0, 10.0), 50.0); + effect->nextThinkTime = effect->startTime + duration; + effect->alpha = 0.5; + effect->d_alpha = (-effect->alpha * 1000.0) / duration; // Rate of change in transparency + effect->d_scale = 1.0; // Rate of change in scale + + effect->Update = KeepSelfAI; + AddEffect(NULL, effect); // add the effect as independent world effect +} + +void FXSmoke(vec3_t origin, float scale, float range) +{ + client_entity_t *effect; + int duration; + + effect = ClientEntity_new(-1, RF_TRANSLUCENT, origin, NULL, 500); + + effect->r.model = smoke_models; + effect->r.scale = scale; + effect->r.color.c = 0xffffffff; + + duration = Q_ftol(GetTimeToReachDistance(50.0, 0.0, range)); + + VectorSet(effect->velocity, flrand(-10.0, 10.0), flrand(-10.0, 10.0), 50.0); + effect->nextThinkTime = effect->startTime + duration; + effect->alpha = 0.5; + effect->d_alpha = (-effect->alpha * 1000.0) / duration; // Rate of change in transparency + effect->d_scale = 1.0; // Rate of change in scale + + effect->Update = KeepSelfAI; + AddEffect(NULL, effect); // add the effect as independent world effect +} + +static qboolean FXSmokeSpawner(struct client_entity_s *self, centity_t *owner) +{ + FXSmoke(self->r.origin, self->r.scale, self->Scale); + return(true); +} + +static qboolean FXSmokeSpawner2(struct client_entity_s *self, centity_t *owner) +{ + if(self->LifeTime--) + { + FXSmoke(self->r.origin, flrand(0.5, 1.0), flrand(32, 64)); + self->updateTime = 30; + return(true); + } + else + return (false); +} + +//------------------------------------------------------------------ +// FX Smoke spawn function +//------------------------------------------------------------------ + +void FXEnvSmoke(centity_t *owner,int type,int flags,vec3_t origin) +{ + client_entity_t *self; + vec3_t dir; + byte scale; + byte speed,wait,maxrange; + + flags |= CEF_NO_DRAW | CEF_NOMOVE; + self = ClientEntity_new(type, flags, origin, NULL, 17); + + if(flags&CEF_FLAG6) + {//just a hiss and steam + FXSmoke(origin, flrand(0.5, 1.0), flrand(32, 64)); + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("misc/fout.wav"), 1, ATTN_NORM, 0); + self->Update = FXSmokeSpawner2; + self->LifeTime = 33; + AddEffect(NULL, self); + } + else + { + fxi.GetEffect(owner,flags,"bdbbb", &scale, &dir, &speed, &wait, &maxrange); + AnglesFromDir(dir, self->r.angles); + self->velocity[0] = speed * 10; + self->Scale = maxrange; + self->r.scale = 32.0 / scale; + self->updateTime = wait * 1000; + self->Update = FXSmokeSpawner; + AddEffect(owner, self); + } +} + diff --git a/Toolkit/Programming/GameCode/client effects/fx_sound.c b/Toolkit/Programming/GameCode/client effects/fx_sound.c new file mode 100644 index 0000000..08ff449 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_sound.c @@ -0,0 +1,239 @@ +// +// fx_sound.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#define TAG_LEVEL 766 // tags get cleared at each new level + +typedef struct soundthinkinfo_s +{ + int style; + float attenuation; + float volume; + float wait; +} soundthinkinfo_t; + +static qboolean FXSoundthink(struct client_entity_s *self, centity_t *owner) +{ + int chance; + soundthinkinfo_t *soundinfo; + char *soundname; + + soundinfo = (soundthinkinfo_t *) self->extra; + // flag if we are not doing a sound + soundname = NULL; + + // if we are in a cinematic, stop us making noises + // these are peripheral ambient noises + if(!(Cvar_Get("cl_cinematicfreeze","0",0)->value)) + { + switch((int)(soundinfo->style)) + { + case AS_SEAGULLS: + chance = irand(0,2); + if (chance < 1) + soundname = "ambient/gull1.wav"; + else if (chance < 2 ) + soundname = "ambient/gull2.wav"; + else + soundname = "ambient/gull3.wav"; + break; + case AS_BIRDS: + chance = irand(0,10); + if (chance < 1) + soundname = "ambient/bird1.wav"; + else if (chance < 2) + soundname = "ambient/bird2.wav"; + else if (chance < 3) + soundname = "ambient/bird3.wav"; + else if (chance < 4) + soundname = "ambient/bird4.wav"; + else if (chance < 5) + soundname = "ambient/bird5.wav"; + else if (chance < 6) + soundname = "ambient/bird6.wav"; + else if (chance < 7) + soundname = "ambient/bird7.wav"; + else if (chance < 8) + soundname = "ambient/bird8.wav"; + else if (chance < 9) + soundname = "ambient/bird9.wav"; + else + soundname = "ambient/bird10.wav"; + break; + case AS_CRICKETS: + chance = irand(0,2); + if (chance < 1) + soundname = "ambient/cricket1.wav"; + else if (chance < 2) + soundname = "ambient/cricket2.wav"; + else + soundname = "ambient/cricket3.wav"; + break; + case AS_FROGS: + chance = irand(0,1); + if (chance < 1) + soundname = "ambient/frog.wav"; + else + soundname = "ambient/frog2.wav"; + break; + case AS_CRYING: + chance = irand(0,3); + if (chance < 1) + soundname = "ambient/femcry1.wav"; + else if (chance < 2) + soundname = "ambient/femcry2.wav"; + else if (chance < 3) + soundname = "ambient/kidcry1.wav"; + else + soundname = "ambient/kidcry2.wav"; + break; + case AS_MOSQUITOES: + chance = irand(0,1); + if (chance < 1) + soundname = "ambient/insects1.wav"; + else + soundname = "ambient/insects2.wav"; + break; + case AS_BUBBLES: + soundname = "ambient/bubbles.wav"; + break; + case AS_BELL: + soundname = "ambient/bell.wav"; + break; + case AS_FOOTSTEPS: + chance = irand(0,3); + if (chance < 1) + soundname = "ambient/runaway1.wav"; + else if (chance < 2) + soundname = "ambient/runaway2.wav"; + else + soundname = "ambient/sewerrun.wav"; + break; + case AS_MOANS: + chance = irand(0,5); + if (chance < 1) + soundname = "ambient/moan1.wav"; + else if (chance < 2) + soundname = "ambient/moan2.wav"; + else if (chance < 3) + soundname = "ambient/scream1.wav"; + else if (chance < 4) + soundname = "ambient/scream2.wav"; + else + soundname = "ambient/coughing.wav"; + break; + case AS_SEWERDRIPS: + chance = irand(0,3); + if (chance <1) + soundname = "ambient/sewerdrop1.wav"; + else if (chance <2) + soundname = "ambient/sewerdrop2.wav"; + else + soundname = "ambient/sewerdrop3.wav"; + break; + case AS_WATERDRIPS: + chance = irand(0,3); + if (chance <1) + soundname = "ambient/waterdrop1.wav"; + else if (chance <2) + soundname = "ambient/waterdrop2.wav"; + else + soundname = "ambient/waterdrop3.wav"; + break; + case AS_HEAVYDRIPS: + chance = irand(0,3); + if (chance <1) + soundname = "ambient/soliddrop1.wav"; + else if (chance <2) + soundname = "ambient/soliddrop2.wav"; + else + soundname = "ambient/soliddrop3.wav"; + break; + case AS_WINDCHIME: + soundname = "ambient/windchimes.wav"; + break; + case AS_BIRD1: + soundname = "ambient/bird5.wav"; + break; + case AS_BIRD2: + soundname = "ambient/bird8.wav"; + break; + case AS_GONG: + soundname = "ambient/gong.wav"; + break; + case AS_ROCKS: + chance = irand(0,3); + if (chance <1) + soundname = "ambient/rocks1.wav"; + else if (chance <2) + soundname = "ambient/rocks4.wav"; + else + soundname = "ambient/rocks5.wav"; + break; + case AS_CAVECREAK: + chance = irand(0,3); + if (chance <1) + soundname = "ambient/cavecreak1.wav"; + else if (chance <2) + soundname = "ambient/cavecreak1.wav"; + else + soundname = "ambient/cavecreak1.wav"; + break; + default: + Com_DPrintf("ERROR: invalid ambient sound type :%d at x:%f y:%f z:%f\n",soundinfo->style, + self->origin[0],self->origin[1],self->origin[2]); + break; + } + } + + // if we have a sound to do, lets do it. + if (soundname) + { + if (Vec3IsZero(self->origin)) + fxi.S_StartSound(self->origin,owner->current.number, CHAN_WEAPON, fxi.S_RegisterSound(soundname),soundinfo->volume,0, 0); + else + fxi.S_StartSound(self->origin,owner->current.number, CHAN_WEAPON, fxi.S_RegisterSound(soundname),soundinfo->volume,soundinfo->attenuation, 0); + } + + self->updateTime = soundinfo->wait * flrand(.5,1.5); + if (self->updateTime<17) + self->updateTime = 17; + + return(true); // Keep everything around so we can shut them down when needed. +} + +void FXSound(centity_t *owner,int type,int flags,vec3_t origin) +{ + client_entity_t *self; + byte style, wait, attenuation,volume; + soundthinkinfo_t *soundinfo; + + self = ClientEntity_new(type, flags|CEF_NO_DRAW|CEF_NOMOVE, origin, + NULL, 20); + self->flags &= ~CEF_OWNERS_ORIGIN; + + self->extra=fxi.TagMalloc(sizeof(soundthinkinfo_t),TAG_LEVEL); + + fxi.GetEffect(owner, flags, "bbbb", &style,&attenuation,&volume,&wait); + + soundinfo = (soundthinkinfo_t *) self->extra; + soundinfo->style = style; + soundinfo->attenuation = attenuation; + soundinfo->volume = volume/255.0; + soundinfo->wait = wait * 1000; + VectorCopy(origin,self->origin); + self->Update = FXSoundthink; + + AddEffect(owner, self); +} + diff --git a/Toolkit/Programming/GameCode/client effects/fx_sparks.c b/Toolkit/Programming/GameCode/client effects/fx_sparks.c new file mode 100644 index 0000000..a3fd52f --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_sparks.c @@ -0,0 +1,223 @@ +#include "Client Effects.h" +#include "Client Entities.h" +#include "FX.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "Vector.h" +#include "Random.h" +#include "ce_Dlight.h" +#include "q_Sprite.h" +#include "Utilities.h" +#include "reference.h" +#include "Matrix.h" +#include "g_playstats.h" + +enum { + MODEL_SPARKSTREAK, + MODEL_SPARKFIRE, + MODEL_SPARK, + NUM_MODELS +}; + +static struct model_s *spark_models[NUM_MODELS]; + +void PreCacheSparks() +{ + spark_models[0] = fxi.RegisterModel("sprites/fx/bluestreak.sp2"); + spark_models[1] = fxi.RegisterModel("sprites/fx/fire.sp2"); + spark_models[2] = fxi.RegisterModel("sprites/fx/spark.sp2"); +} + +// -------------------------------------------------------------- + +void FireSparks(centity_t *owner, int type, int flags, vec3_t origin, vec3_t dir); + +void GenericSparks(centity_t *owner, int type, int flags, vec3_t origin, vec3_t dir) +{ + client_entity_t *effect; + vec3_t work; + byte count; + int i; + + if (flags & CEF_FLAG7)//fire sparks + { + flags &= ~CEF_FLAG7; + FireSparks(owner, type, flags, origin, dir); + return; + } + + if (flags & CEF_FLAG6) + count = 5; + else + count = irand(2,4); + + //Create spark balls + for(i = 0; i < count; i++) + { + effect = ClientEntity_new(type, flags, origin, NULL, 1000); + + effect->r.model = spark_models + MODEL_SPARK; + effect->r.flags |= RF_TRANS_ADD | RF_TRANSLUCENT | RF_TRANS_ADD_ALPHA; + + VectorRandomCopy(dir, work, 0.5); + VectorScale(work, irand(100.0, 125.0), effect->velocity); + effect->acceleration[2] = flrand(-200.0, -100.0); + effect->r.scale = 0.25; + effect->d_scale = flrand(-0.25, -0.75); + effect->color.c = 0xFFFFFFFF; + + AddEffect(NULL, effect); // add the effect as independent world effect + } + + //Create spark streaks + for(i = 0; i < count; i++) + { + effect = ClientEntity_new(type, flags, origin, NULL, 1000); + + effect->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + effect->r.model = spark_models + MODEL_SPARKSTREAK; + effect->r.spriteType = SPRITE_LINE; + effect->r.tile = 1.0; + effect->r.scale = 2; + effect->alpha = 1.0; + effect->r.scale = flrand(0.5, 1.0); + + VectorRandomCopy(dir, work, 0.5); + VectorScale(work, irand(100.0, 125.0), effect->velocity); + + VectorCopy(origin, effect->r.endpos); + VectorMA(effect->r.endpos, irand(8, 16), work, effect->r.startpos); + + effect->d_alpha = flrand(-2.0, -4.0); + effect->d_scale = flrand(-2.0, -4.0); + + AddEffect(NULL,effect); + } + + VectorMA(origin, -8, dir, origin); + effect = ClientEntity_new(type, flags, origin, NULL, 800); + effect->flags |= CEF_NO_DRAW | CEF_NOMOVE; + effect->color.c = 0xFFFFFFFF; + effect->dlight = CE_DLight_new(effect->color, 80.0F, -35.0F); + AddEffect(NULL, effect); +} + +void FXGenericSparks(centity_t *owner, int type, int flags, vec3_t origin) +{ + vec3_t dir; + + fxi.GetEffect(owner, flags, "d", dir ); // normalized direction vector + GenericSparks(owner, type, flags, origin, dir); +} + +qboolean FireSparkSpawnerUpdate(client_entity_t *spawner, centity_t *owner) +{//fixme- wigs out on hivetrialpit when the sparkers hit ground and seperate? + vec3_t diffvec, pos; + + VectorSubtract(spawner->r.origin, spawner->startpos2, diffvec); + VectorMA(spawner->startpos2, (float)(spawner->LifeTime)/5, diffvec, pos); + + spawner->LifeTime++; + + if(spawner->LifeTime >= 5) + { + FireSparks(NULL, FX_SPARKS, spawner->SpawnInfo, pos, spawner->direction); + spawner->LifeTime = 1; + VectorCopy(spawner->r.origin, spawner->startpos2); + } + else + FireSparks(NULL, FX_SPARKS, 0, pos, spawner->direction); + + VectorCopy(owner->lerp_origin, spawner->r.origin); + return (true); +} + +void FireSparks(centity_t *owner, int type, int flags, vec3_t origin, vec3_t dir) +{ + client_entity_t *effect; + client_particle_t *flame; + vec3_t work; + byte count; + int i; + + if(owner && flags & CEF_FLAG8) + {//spawn a continuous thingy - fixme- dalay 100 so can get a valid origin? + flags &= ~CEF_FLAG8; + effect = ClientEntity_new(type, flags | CEF_NO_DRAW, origin, NULL, 20); + + effect->LifeTime = 1; + VectorCopy(origin, effect->startpos2); + VectorCopy(origin, effect->r.origin); + VectorCopy(dir, effect->direction); + effect->SpawnInfo = flags; + effect->Update = FireSparkSpawnerUpdate; + if(owner->current.effects & EF_MARCUS_FLAG1) + effect->SpawnInfo |= CEF_FLAG7; + + AddEffect(owner, effect); + return; + } + + if (flags & CEF_FLAG6) + {//sound + if(irand(0, 3)) + { + fxi.S_StartSound(origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("ambient/lavadrop%c.wav", irand('1', '3'))), 1, ATTN_NORM, 0); + } + else + { + fxi.S_StartSound(origin, -1, CHAN_AUTO, + fxi.S_RegisterSound("misc/lavaburn.wav"), 1, ATTN_NORM, 0); + } + } + + effect = ClientEntity_new(type, flags|CEF_ADDITIVE_PARTS, origin, NULL, 2000); + effect->flags |= CEF_NO_DRAW | CEF_NOMOVE; + effect->color.c = 0xe5007fff; + + count = irand(7, 13); + for(i = 0; i < count; i++) + { + flame = ClientParticle_new(irand(PART_16x16_FIRE1, PART_16x16_FIRE3), effect->color, 1000); + + VectorRandomCopy(dir, work, 0.5); + + if(flags&CEF_FLAG7)//fireball poofy effect + { + flame->scale = flrand(5, 10); + VectorScale(work, 20.0, flame->velocity); + flame->velocity[2] += 30; + flame->acceleration[2] = 2.0f; + + flame->d_scale = flrand(-10.0, -5.0); + flame->d_alpha = -10.0f; + flame->duration = (flame->color.a * 1000.0) / -flame->d_alpha; // time taken to reach zero alpha + } + else + { + flame->scale = flrand(3, 5); + VectorScale(work, 50.0, flame->velocity); + flame->velocity[2] += 50; + flame->acceleration[2] = -200.0f; + + flame->d_scale = flrand(-2.0, -3.0); + flame->d_alpha = 0.0f; + flame->duration = (flame->scale * 1000.0) / -flame->d_scale; // time taken to reach zero alpha + } + + flame->origin[2] -= 8;//HACK!!!! + + AddParticleToList(effect, flame); + } + + if (flags & CEF_FLAG6) + { + effect->color.c = 0xFF80FFFF; + effect->dlight = CE_DLight_new(effect->color, 80.0F, -35.0F); + } + AddEffect(NULL, effect); +} +// end + diff --git a/Toolkit/Programming/GameCode/client effects/fx_spellchange.c b/Toolkit/Programming/GameCode/client effects/fx_spellchange.c new file mode 100644 index 0000000..a56aca5 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_spellchange.c @@ -0,0 +1,118 @@ +// +// fx_spellchange.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Matrix.h" +#include "Random.h" +#include "Utilities.h" +#include "Reference.h" +#include "ce_DLight.h" +#include "Particle.h" + + +#define NUM_BITS 12 +#define LIGHT_LIFETIME 1000 + +// ************************************************************************************************ +// FXSpellChangePuffThink +// ---------------------------- +// ************************************************************************************************ + +qboolean FXSpellChangeLightThink(struct client_entity_s *self,centity_t *owner) +{ + if (fxi.cl->time - self->startTime > LIGHT_LIFETIME) + { + return(false); + } + + self->dlight->intensity = 200.0 * (float)(LIGHT_LIFETIME - (fxi.cl->time - self->startTime)) / (float)LIGHT_LIFETIME; + + return(true); +} + +// ************************************************************************************************ +// FXSpellChange +// --------------------- +// ************************************************************************************************ + +void FXSpellChange(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + vec3_t dir; + client_entity_t *spellpuff; + client_particle_t *spellbit; + int i; + int spelltype=0; + paletteRGBA_t color; + int part; + + fxi.GetEffect(Owner,Flags,"db",dir,&spelltype); + + switch(spelltype) + { + case 1: // Red/fireball + color.c = 0xFF0000FF; + part = PART_16x16_SPARK_R; + break; + case 2: // Indigo/Array + color.c = 0xFFFF0080; + part = PART_16x16_SPARK_I; + break; + case 3: // Blue/Sphere + color.c = 0xFFFF0000; + part = PART_16x16_SPARK_B; + break; + case 4: // Green/Mace ball + color.c = 0xFF00FF00 ; + part = PART_16x16_SPARK_G; + break; + case 5: // Yellow/Firewall + color.c = 0xFF0080FF; + part = PART_16x16_SPARK_Y; + break; + case 6: // Big red/red rain bow + color.c = 0xFF0000FF; + part = PART_16x16_SPARK_R; + break; + case 7: // Big yellow/Phoenix + color.c = 0xFF00FFFF; + part = PART_32x32_FIRE1; + break; + case 0: // Default color--white + default: + color.c = 0x80FFFFFF; + part = PART_16x16_LIGHTNING; + break; + } + + VectorScale(dir,-32.0,dir); + + // Create the new effect + spellpuff=ClientEntity_new(Type,Flags|CEF_OWNERS_ORIGIN|CEF_NO_DRAW|CEF_ADDITIVE_PARTS, Origin, NULL, 100); + spellpuff->dlight=CE_DLight_new(color,150.0f,0.0f); + spellpuff->startTime=fxi.cl->time; + spellpuff->radius=32.0; + spellpuff->Update=FXSpellChangeLightThink; + + color.c = 0xFFFFFFFF; + // Attach some particles to it. + for(i=0;ivelocity, flrand(-32.0,32.0), flrand(-32.0,32.0), flrand(16.0,64.0)); + VectorAdd(dir,spellbit->velocity, spellbit->velocity); + spellbit->d_scale=-2.0; + spellbit->scale = 6.0; + + AddParticleToList(spellpuff, spellbit); + } + + AddEffect(Owner,spellpuff); +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_spellhands.c b/Toolkit/Programming/GameCode/client effects/fx_spellhands.c new file mode 100644 index 0000000..b4f47cc --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_spellhands.c @@ -0,0 +1,187 @@ +// +// fx_spellhands.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Matrix.h" +#include "Random.h" +#include "Utilities.h" +#include "Reference.h" +#include "ce_DLight.h" +#include "Particle.h" +#include "g_playstats.h" + +// ************************************************************************************************ +// SpellHandsTrails +// ---------------- +// ************************************************************************************************ + +typedef struct +{ + char *SpriteName; + float DeltaForward, + AnimSpeed, + Scale, + DScale; +} trail_t; + +static trail_t SpellHandsTrails[NUM_SPELLHANDS]= +{ + {"sprites/spells/flyingfist.sp2",2.0,0.25,0.3,-1.25}, + {"sprites/spells/spellhands_blue.sp2",1.5,0.25,0.4,-0.25}, + {"sprites/spells/spark_ind.sp2",2.0,0.25,1.0,-1.25}, +}; + +// -------------------------------------------------------------- + +#define NUM_HAND_MODELS 1 + +struct model_s *hands_models[NUM_HAND_MODELS]; + +void PreCacheHands() +{ +} + +// -------------------------------------------------------------- + + +static qboolean FXSpellHandsThink(struct client_entity_s *Self,centity_t *Owner) +{ + int part_type; + vec3_t Trailend,Trailstart; + vec3_t Real_Trailend,Real_Trailstart; + vec3_t TrailDelta; + float TrailLength; + + client_particle_t *ce; + paletteRGBA_t color; + matrix3_t rotation; + + // If we've timed out, stop the effect (allow for fading) + if ( (Self->LifeTime > 0) && (Self->LifeTime < fxi.cl->time) ) + { + Self->Update=RemoveSelfAI; + Self->updateTime = fxi.cl->time + 500; + return true; + } + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(Owner)) + return true; + + // Calculate the end position of the trail. + VectorCopy(Owner->referenceInfo->references[Self->refPoint].placement.origin,Trailend); + + // we now have trail start and trail end in + VectorCopy(Self->origin,Trailstart); + + // update where trail ends + VectorCopy(Trailend,Self->origin); + + // Allow us adequate time to set up valid 'old' data because the reference points lag behind by + // a frame. + if((Self->AnimSpeed+=1.0)<2.0) + return(true); + + // Create a rotation matrix + Matrix3FromAngles(Owner->lerp_angles, rotation); + // make the trail start and end a trail in real space + Matrix3MultByVec3(rotation, Trailstart, Real_Trailstart); + Matrix3MultByVec3(rotation, Trailend, Real_Trailend); + + // figure out the differences between them + VectorSubtract(Real_Trailend, Real_Trailstart, TrailDelta); + + // set the trail length + TrailLength = GetScaledCount(8, 0.75); + + // scale that difference by the number of particles we are going to draw + Vec3ScaleAssign(1.0/TrailLength, TrailDelta); + + // decide which particle type to use + if (Self->SpawnInfo == 0) + part_type = PART_16x16_SPARK_R; + else + if (Self->SpawnInfo == 1) + part_type = PART_16x16_SPARK_B; + else + part_type = PART_16x16_SPARK_I; + + // ensure the particles are completely drawn + color.c = 0xffffffff; + + // Now draw the trail. + while(TrailLength-->0.0f) + { + ce = ClientParticle_new(part_type, color, 400); + VectorCopy(Real_Trailstart,ce->origin); + ce->scale = 8.0F; + ce->acceleration[2] = 0.0f; + + AddParticleToList(Self, ce); + + VectorAdd(Real_Trailstart,TrailDelta,Real_Trailstart); + } + + return(true); +} + +// ************************************************************************************************ +// FXSpellHands +// ------------ +// ************************************************************************************************ + +void FXSpellHands(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + short Refpoints; + client_entity_t *Trail; + char lifetime; + int I; + int cast_speed; + + fxi.GetEffect(Owner, Flags, "b", &lifetime); + + if (Flags & CEF_FLAG6) + Refpoints=(1 << CORVUS_LEFTHAND) | (1 << CORVUS_RIGHTHAND); + else + Refpoints=(1 << CORVUS_RIGHTHAND); + + // Add a fiery trail effect to the player's hands / feet etc. + + if (r_detail->value < DETAIL_NORMAL) + cast_speed = 75; + else + cast_speed = 50; + + for(I=0;I<16;I++) + { + if(!(Refpoints & (1 << I))) + continue; + + Trail=ClientEntity_new(Type,Flags|CEF_NO_DRAW|CEF_ADDITIVE_PARTS,Origin,0,cast_speed); + Trail->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + Trail->Update=FXSpellHandsThink; + Trail->SpawnInfo= ((Flags&(CEF_FLAG7|CEF_FLAG8)) >> 6); + Trail->AddToView = LinkedEntityUpdatePlacement; + + if (lifetime > 0) + Trail->LifeTime = fxi.cl->time + (lifetime * 100); + else + Trail->LifeTime = -1; + + Trail->refPoint = I; + + // Hack: used as a counter. + Trail->AnimSpeed=0.0; + + AddEffect(Owner,Trail); + } +} + diff --git a/Toolkit/Programming/GameCode/client effects/fx_sphereofannihlation.c b/Toolkit/Programming/GameCode/client effects/fx_sphereofannihlation.c new file mode 100644 index 0000000..5c163fa --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_sphereofannihlation.c @@ -0,0 +1,828 @@ +// +// fx_sphereofannihilation.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Matrix.h" +#include "ce_DLight.h" +#include "Random.h" +#include "Utilities.h" +#include "Reference.h" +#include "q_Sprite.h" +#include "g_playstats.h" + +#define NUM_SPHERE_MODELS 8 + +static struct model_s *sphere_models[NUM_SPHERE_MODELS]; + +void PreCacheSphere() +{ + sphere_models[0] = fxi.RegisterModel("sprites/spells/shboom.sp2"); + sphere_models[1] = fxi.RegisterModel("sprites/spells/bluball.sp2"); + sphere_models[2] = fxi.RegisterModel("sprites/spells/glowball.sp2"); + sphere_models[3] = fxi.RegisterModel("models/spells/sphere/tris.fm"); + sphere_models[4] = fxi.RegisterModel("sprites/fx/halo.sp2"); + sphere_models[5] = fxi.RegisterModel("sprites/spells/glowbeam.sp2"); + sphere_models[6] = fxi.RegisterModel("sprites/fx/haloblue.sp2"); + sphere_models[7] = fxi.RegisterModel("sprites/spells/spark_blue.sp2"); +} + +// -------------------------------------------------------------- + +#define FX_SPHERE_FLY_SPEED 600.0 +#define FX_SOFT_SPHERE_AURA_SCALE 0.9 +#define FX_SPHERE_AURA_SCALE 1.2 +#define FX_SPHERE_EXPLOSION_BASE_RADIUS 89.0 + +static qboolean FXSphereOfAnnihilationSphereThink(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXSphereOfAnnihilationAuraElementThink(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXSphereOfAnnihilationAuraThink(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXSphereOfAnnihilationGlowballSparkThink(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXSphereOfAnnihilationGlowballThink(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXSphereOfAnnihilationGlowballSpawnerThink(struct client_entity_s *Self,centity_t *Owner); +static qboolean FXSphereOfAnnihilationSmokePuffThink(struct client_entity_s *Self,centity_t *Owner); + +extern void FXClientLensFlare(centity_t *owner,int Type,int Flags,vec3_t Origin, int lifeTime, paletteRGBA_t *tint); + + +// **************************************************************************** +// FXSphereOfAnnihilationSphereThink - +// **************************************************************************** + +static qboolean FXSphereOfAnnihilationSphereThink(struct client_entity_s *Self,centity_t *Owner) +{ + float detail_scale; + if(r_detail->value == DETAIL_LOW) + detail_scale = 0.7; + else + if(r_detail->value == DETAIL_NORMAL) + detail_scale = 0.85; + else + detail_scale = 1.0; + + Self->r.scale=Owner->current.scale * detail_scale; + + return(true); +} + +// **************************************************************************** +// FXSphereOfAnnihilationAuraThink - +// **************************************************************************** + +static qboolean FXSphereOfAnnihilationAuraThink(struct client_entity_s *Self,centity_t *Owner) +{ + vec3_t TrailStart,Trail; + float TrailLength,DeltaTrailLength; + vec3_t Right,Up; + client_entity_t *TrailEnt; + int i; + int dur; + + // + // no aura trail on low level + if(r_detail->value == DETAIL_LOW) + return(true); + + VectorCopy(Owner->origin,TrailStart); + VectorSubtract(Owner->lerp_origin,Owner->origin,Trail); + + // copy the real origin to the entity origin, so the light will follow us + VectorCopy(Self->r.origin, Self->origin); + + if((TrailLength=VectorNormalize(Trail))<0.001) + { + TrailLength+=2.0; + } + + PerpendicularVector(Right,Trail); + CrossProduct(Trail,Right,Up); + + DeltaTrailLength=FX_SPHERE_FLY_SPEED; + VectorScale(Trail,FX_SPHERE_FLY_SPEED,Trail); + + if(r_detail->value == DETAIL_NORMAL) + dur = 400; + else + dur = 500; + + i=0; + while(TrailLength>0.0) + { + i++; + if (i>=40) + break; + // + + TrailEnt=ClientEntity_new(FX_WEAPON_SPHERE, + Self->flags&~(CEF_OWNERS_ORIGIN|CEF_NO_DRAW), + TrailStart, + NULL, + dur); + + TrailEnt->r.model = sphere_models; + TrailEnt->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + if (r_detail->value < DETAIL_NORMAL) + TrailEnt->Scale=FX_SOFT_SPHERE_AURA_SCALE+flrand(0.0, 0.1); + else + TrailEnt->Scale=FX_SPHERE_AURA_SCALE+flrand(0.0, 0.1); + TrailEnt->color.r=irand(128, 180); + TrailEnt->color.g=irand(128, 180); + TrailEnt->color.b=irand(64, 80); + TrailEnt->alpha = 0.7; + TrailEnt->d_alpha = -1.0; + if (r_detail->value < DETAIL_NORMAL) + TrailEnt->d_scale = -1.0; + else + TrailEnt->d_scale = -0.5; + + TrailEnt->radius=70.0; + + AddEffect(NULL,TrailEnt); + + TrailLength-=DeltaTrailLength; + + VectorAdd(TrailStart,Trail,TrailStart); + } + + return(true); +} + +// **************************************************************************** +// FXSphereOfAnnihilation - +// **************************************************************************** + +void FXSphereOfAnnihilation(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *SphereThinker, + *AuraThinker; + short CasterEntnum; + paletteRGBA_t LightColor={0,0,255,255}; + int caster_update; + + fxi.GetEffect(Owner,Flags,"s",&CasterEntnum); + + // Create a fiery blue aura around the sphere. + + if (r_detail->value < DETAIL_NORMAL) + caster_update = 125; + else + caster_update = 100; + + AuraThinker=ClientEntity_new(Type,Flags,Origin,NULL,caster_update); + + AuraThinker->flags|=CEF_NO_DRAW; + if (r_detail->value != DETAIL_LOW) + AuraThinker->dlight=CE_DLight_new(LightColor,150.0,0.0); + AuraThinker->Update=FXSphereOfAnnihilationAuraThink; + AuraThinker->extra=(void *)(&fxi.server_entities[CasterEntnum]);// The caster's centity_t. + AuraThinker->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(Owner,AuraThinker); + + FXSphereOfAnnihilationAuraThink(AuraThinker,Owner); + + // Create the sphere of annihilation itself. + + SphereThinker = ClientEntity_new(Type, Flags, Origin, NULL, 100); + + SphereThinker->r.model = sphere_models + 1; + SphereThinker->r.flags |= RF_TRANSLUCENT; + SphereThinker->r.scale = Owner->current.scale; + SphereThinker->radius = 70.0; + SphereThinker->Update = FXSphereOfAnnihilationSphereThink; + SphereThinker->AddToView = LinkedEntityUpdatePlacement; + + AddEffect(Owner, SphereThinker); +} + +// **************************************************************************** +// FXSphereOfAnnihilationGlowballThink - +// **************************************************************************** + +static qboolean FXSphereOfAnnihilationGlowballThink(struct client_entity_s *Self,centity_t *Owner) +{ + client_entity_t *Spark; + int dur; + + if((Owner->current.effects&EF_MARCUS_FLAG1)) + Self->color.r++; + + if(r_detail->value == DETAIL_LOW) + dur = 300; + else + if(r_detail->value == DETAIL_NORMAL) + dur = 400; + else + dur = 500; + + + if(Self->color.r>3) + { + // Create a trailing spark. + + Spark=ClientEntity_new(FX_WEAPON_SPHERE, + Self->flags&~(CEF_OWNERS_ORIGIN), + Self->r.origin, + NULL, + dur); + + Spark->r.model = sphere_models + 2; + Spark->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD; + Spark->r.color.r=irand(128, 180); + Spark->r.color.g=irand(128, 180); + Spark->r.color.b=irand(180, 255); + Spark->Scale=flrand(0.8, 1.0); + Spark->radius=20.0; + Spark->d_scale = -1.5; + + AddEffect(NULL,Spark); + } + + // 'Self->extra' refers to the sphere's centity_t. + + if(Self->color.r<16) + { + Self->velocity[0]*=3.0; + Self->velocity[0]+=6.0*(Owner->origin[0]-Self->r.origin[0]); + Self->velocity[0]*=0.265; + + Self->velocity[1]*=3.0; + Self->velocity[1]+=6.0*(Owner->origin[1]-Self->r.origin[1]); + Self->velocity[1]*=0.265; + + Self->velocity[2]*=3.0; + Self->velocity[2]+=6.0*(Owner->origin[2]-Self->r.origin[2]); + Self->velocity[2]*=0.265; + + return(true); + } + else + { + return(false); + } +} + +// **************************************************************************** +// FXSphereOfAnnihilationGlowballSpawnerThink - +// **************************************************************************** + +static qboolean FXSphereOfAnnihilationGlowballSpawnerThink(struct client_entity_s *Self,centity_t *Owner) +{ + client_entity_t *Glowball; + centity_t *controller; + vec3_t Forward,Right, + Forward2,Right2, + Temp, + temp_origin; + matrix3_t RotationMatrix; + + // This tells if we are wasting our time, because the reference points are culled. + if (Self->extra && !RefPointsValid((centity_t *)(Self->extra))) // Only if we were SUPPOSED to have refpoints. + return true; + + // If the spell is still building, create some swirling blue Glowballs. + + if(Owner->current.effects&EF_MARCUS_FLAG1) + { + // 'Self->extra' refers to the caster's centity_t. + + if (Self->extra) + VectorCopy(((centity_t *)(Self->extra))->origin, temp_origin); + else + VectorCopy(Self->r.origin, temp_origin); + + Glowball=ClientEntity_new(FX_WEAPON_SPHEREGLOWBALLS, + Self->flags&~(CEF_NO_DRAW|CEF_OWNERS_ORIGIN), + temp_origin, + NULL, + 50); + + Self->flags|=CEF_DONT_LINK; + + // Make me spawn from my caster's left / right hands (alternating). + // assuming we aren't a reflection type glowball + if (Self->extra) + { + controller = ((centity_t *)(Self->extra)); + VectorCopy(controller->current.angles,Temp); + VectorScale(Temp,180.0/M_PI,Temp); + AngleVectors(Temp,Forward,Right,NULL); + + Matrix3FromAngles(controller->lerp_angles,RotationMatrix); + + if(Self->SpawnInfo) + { + if(!(Self->color.g&1)) + Matrix3MultByVec3(RotationMatrix, + controller->referenceInfo->references[CORVUS_LEFTHAND].placement.origin, + Glowball->r.origin); + else + Matrix3MultByVec3(RotationMatrix, + controller->referenceInfo->references[CORVUS_RIGHTHAND].placement.origin, + Glowball->r.origin); + } + else + { + vec3_t fwd_ofs; + + VectorScale(Forward, 16, fwd_ofs);//Hard-coded for Celestial Watcher(monster_elflord), + Matrix3MultByVec3(RotationMatrix, + fwd_ofs, + Glowball->r.origin); + } + + VectorAdd(controller->origin,Glowball->r.origin,Glowball->r.origin); + } + else + { + VectorCopy(Self->r.angles,Temp); + VectorScale(Temp,180.0/M_PI,Temp); + AngleVectors(Temp,Forward,Right,NULL); + + + VectorSet(Glowball->r.origin, flrand(-10.0, 10.0)+ Self->r.origin[0], + flrand(-10.0, 10.0)+ Self->r.origin[1], + flrand(-10.0, 10.0)+ Self->r.origin[2]); + } + + VectorCopy(Owner->current.angles,Temp); + VectorScale(Temp,180.0/M_PI,Temp); + AngleVectors(Temp,Forward2,Right2,NULL); + + + // Set my velocity and accelaration. + + Glowball->velocity[0]=Forward2[0]*175.0+flrand(-25.0, 25.0); + + if(Self->color.g&1) + Glowball->velocity[0]=-Glowball->velocity[0]; + + Glowball->velocity[1]=Forward2[1]*175.0+flrand(-25.0, 25.0); + + if(!(Self->color.g&1)) + Glowball->velocity[1]=-Glowball->velocity[1]; + + Glowball->velocity[2]=flrand(-200.0, 100.0); + + VectorClear(Glowball->acceleration); + + // Fill in the rest of my info. + + Glowball->r.model = sphere_models + 2; + Glowball->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD; + Glowball->r.color.r= irand(128, 180); + Glowball->r.color.g= irand(128, 180); + Glowball->r.color.b= irand(180, 255); + Glowball->color.r=1; + Glowball->radius=20.0; + Glowball->extra=(void *)Owner; + Glowball->Update=FXSphereOfAnnihilationGlowballThink; + + AddEffect(Owner,Glowball); + + FXSphereOfAnnihilationGlowballThink(Glowball,Owner); + + Self->color.g++; + } + + return(true); +} + +// **************************************************************************** +// FXSphereOfAnnihilationGlowballs - +// **************************************************************************** + +void FXSphereOfAnnihilationGlowballs(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *GlowballSpawner; + short CasterEntnum; + int caster_update; + + // Get the caster's centity_t. + + fxi.GetEffect(Owner,Flags,"s",&CasterEntnum); + + // Create a spawner that will create the glowballs. + + if ((r_detail->value >= DETAIL_NORMAL)) + caster_update = 100; + else + caster_update = 250; + + GlowballSpawner = ClientEntity_new(Type, Flags | CEF_VIEWSTATUSCHANGED, Origin, NULL, caster_update); + + GlowballSpawner->flags|=CEF_NO_DRAW; + GlowballSpawner->color.g=0; + GlowballSpawner->Update = FXSphereOfAnnihilationGlowballSpawnerThink; + GlowballSpawner->AddToView = LinkedEntityUpdatePlacement; + + if(Flags&CEF_FLAG6) + GlowballSpawner->SpawnInfo = false; + else + GlowballSpawner->SpawnInfo = true; + + if (CasterEntnum == -1) + GlowballSpawner->extra=NULL; + else + GlowballSpawner->extra=(void *)(&fxi.server_entities[CasterEntnum]); + + AddEffect(Owner,GlowballSpawner); +} + +// **************************************************************************** +// FXSphereOfAnnihilationSphereExplodeThink - +// **************************************************************************** + +static qboolean FXSphereOfAnnihilationSphereExplodeThink(struct client_entity_s *Self,centity_t *Owner) +{ + float Frac, + Multiplier; + int FrameNo; + + Frac=(fxi.cl->time-Self->startTime)/100.0; + + if(Self->AnimSpeed>0.0) + { + Frac*=Self->AnimSpeed; + } + + if((FrameNo=floor(Frac))>=(Self->NoOfAnimFrames-1)) + { + return(false); + } + else + { + // Spin the ball of blue fire whilst it expands and fades. + + Self->r.angles[0]+=(M_PI/32.0); + + Self->r.angles[1]+=(M_PI/27.0); + + Self->radius=FX_SPHERE_EXPLOSION_BASE_RADIUS*Self->r.scale; + + Multiplier=1.0-Frac/(Self->NoOfAnimFrames-1); + + Self->dlight->intensity=(Self->radius/0.7); + + Self->dlight->color.r=255*Multiplier; + Self->dlight->color.g=255*Multiplier; + Self->dlight->color.b=255*Multiplier; + + Self->alpha=Multiplier; + + return(true); + } +} + +#define SMOKE_SPEED 140 + +// **************************************************************************** +// FXSphereOfAnnihilationExplode - +// **************************************************************************** +void FXSphereOfAnnihilationExplode(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + vec3_t Dir; + byte Size; + client_entity_t *Explosion; + paletteRGBA_t LightColor={255,255,255,255}; + int I, count; + client_particle_t *ce; + + fxi.GetEffect(Owner,Flags,"db",Dir,&Size); + if(Flags & CEF_FLAG6) + { + FXClientScorchmark(Origin, Dir); + } + // Create an expanding ball of blue fire. + Explosion=ClientEntity_new(Type,Flags | CEF_ADDITIVE_PARTS,Origin,NULL,50); + + Explosion->r.model = sphere_models + 3; + Explosion->r.flags=RF_FULLBRIGHT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + Explosion->r.scale=0.01; + Explosion->color.c=0xffffffff; + Explosion->d_scale=2.5; + Explosion->NoOfAnimFrames=(int)Size; + Explosion->AnimSpeed=1.0; + Explosion->radius=FX_SPHERE_EXPLOSION_BASE_RADIUS*Explosion->r.scale; + Explosion->dlight=CE_DLight_new(LightColor,Explosion->radius/0.7,0); + Explosion->Update=FXSphereOfAnnihilationSphereExplodeThink; + + AddEffect(NULL,Explosion); + + FXSphereOfAnnihilationSphereExplodeThink(Explosion,NULL); + // Add some glowing blast particles. + + VectorScale(Dir,SMOKE_SPEED,Dir); + + count = GetScaledCount(40, 0.3); + + for(I=0;Ivelocity); + + ce->scale=flrand(16.0, 32.0); + + ce->velocity[0]+=flrand(-SMOKE_SPEED,SMOKE_SPEED); + ce->velocity[1]+=flrand(-SMOKE_SPEED,SMOKE_SPEED); + ce->velocity[2]+=flrand(-SMOKE_SPEED,SMOKE_SPEED); + AddParticleToList(Explosion, ce); + + } +} + +void FXSphereOfAnnihilationPower(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + vec3_t dir; + byte size; + client_entity_t *exp1, *beam; + paletteRGBA_t LightColor={255,255,255,255}; + int i; + client_particle_t *ce; + vec3_t spot1; + vec3_t tempSpot; + vec3_t fwd, right, up; + vec3_t ang; + byte len2; + int len; + int count; + + fxi.GetEffect(Owner,Flags,"xbb",dir,&size, &len2); + + len = len2*8;// shrunk down so range can be up to 2048 + + // if there is a cheaper way to get ACCURATE right and up, I'd be happy to see it... + vectoangles(dir, ang); + ang[PITCH] *= -1;// something's broken with angle signs somewhere ;( + AngleVectors(ang, fwd, right, up); + + // Only one beam + VectorCopy(Origin, spot1); + + // make the flares at the start + exp1 = ClientEntity_new(Type,Flags | CEF_ADDITIVE_PARTS, spot1, NULL, 500); + exp1->r.model = sphere_models + 6; + exp1->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT; + exp1->r.frame = 0; + exp1->radius=128; + exp1->d_alpha=-4.0; + exp1->r.scale=.25; + exp1->d_scale = -0.5; + if (Flags & CEF_FLAG8) + { + VectorScale(right, -0.4*SPHERE_LASER_SPEED, exp1->velocity); // Move to the left + VectorScale(right, SPHERE_LASER_SPEED, exp1->acceleration); + } + else + { + VectorScale(right, 0.4*SPHERE_LASER_SPEED, exp1->velocity); // Move to the right + VectorScale(right, -SPHERE_LASER_SPEED, exp1->acceleration); + } + AddEffect(NULL, exp1); + + VectorMA(spot1, len, fwd, tempSpot); + //make the line beam down the side + beam = ClientEntity_new(-1, CEF_DONT_LINK, spot1, NULL, 200); + beam->r.model = sphere_models + 5; + beam->r.spriteType = SPRITE_LINE; + beam->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + beam->r.scale = (size-3) * 6; + beam->radius = 256; + beam->alpha = 0.95; + beam->d_alpha = -5.0; + VectorCopy(spot1, beam->r.startpos); + VectorCopy(tempSpot, beam->r.endpos); + if (Flags & CEF_FLAG8) + { + VectorScale(right, -0.4*SPHERE_LASER_SPEED, beam->velocity); // Move to the left + VectorScale(right, SPHERE_LASER_SPEED, beam->acceleration); + } + else + { + VectorScale(right, 0.4*SPHERE_LASER_SPEED, beam->velocity); // Move to the right + VectorScale(right, -SPHERE_LASER_SPEED, beam->acceleration); + } + AddEffect(NULL, beam); + + count = GetScaledCount((int)(25 + size * 2.5), 0.3); + + //make the particles + for(i=0; i < count;i++) + { + ce = ClientParticle_new(PART_16x16_SPARK_B, LightColor, 666); + + ce->scale=flrand(8, 24.0) + size*2; + ce->scale *=0.4; + ce->acceleration[2] = 0; + ce->d_alpha=-768.0; + VectorMA(ce->origin, flrand(0, len), fwd, ce->origin); + VectorMA(ce->velocity, flrand(-15, 15), right, ce->velocity); + VectorMA(ce->velocity, flrand(-15, 15), up, ce->velocity); + VectorMA(ce->origin, flrand(-size*.4, size*.4), right, ce->origin); + VectorMA(ce->origin, flrand(-size*.4, size*.4), up, ce->origin); + AddParticleToList(exp1, ce); + } + if (Flags & CEF_FLAG6) + { + // make the flares at the end of the line + exp1 = ClientEntity_new(Type,Flags | CEF_ADDITIVE_PARTS, tempSpot, NULL, 500); + exp1->r.model = sphere_models + 6; + exp1->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT; + exp1->r.frame = 0; + exp1->radius=128; + exp1->r.scale= 1; + exp1->d_scale = 1; + exp1->d_alpha = -2.0; + AddEffect(NULL, exp1); + } + + // create a scorchmark if necessary +// VectorSubtract(beam->r.endpos, beam->r.startpos, dir); +// VectorNormalize(dir); + + // Looks silly if it makes a burn +// if (Flags & CEF_FLAG7) +// FXClientScorchmark(beam->r.endpos, dir); + +} + + + + +// PLAYER SPHERE OF ANNIHILATION EXPLOSION + +// **************************************************************************** +// FXSpherePlayerExplodeThink - +// **************************************************************************** + +static qboolean FXSpherePlayerExplodeThink(struct client_entity_s *self,centity_t *Owner) +{ + if (fxi.cl->time > self->nextEventTime) + { + self->d_alpha = -5.0; + self->dlight->d_intensity = -self->radius*2.0; + + if (fxi.cl->time > self->nextEventTime + 1000) + { + return false; + } + } + else + { + self->dlight->intensity=(FX_SPHERE_EXPLOSION_BASE_RADIUS*self->r.scale*1.7); + } + + return(true); +} + + +static qboolean FXSpherePlayerExplodeAddToView(struct client_entity_s *self,centity_t *Owner) +{ + self->r.angles[0]+=(M_PI/32.0)*(fxi.cl->time-self->lastThinkTime)/50.0; + self->r.angles[1]+=(M_PI/27.0)*(fxi.cl->time-self->lastThinkTime)/50.0; + + self->lastThinkTime = fxi.cl->time; + + return(true); +} + + +static qboolean FXSpherePlayerExplodeGlowballThink(client_entity_t *glowball,centity_t *owner) +{ + vec3_t angvect; + + // Update the angle of the spark. + VectorMA(glowball->direction, (float)(fxi.cl->time-glowball->lastThinkTime)/1000.0, glowball->velocity2, glowball->direction); + + glowball->radius = ((SPHERE_RADIUS_MAX-SPHERE_RADIUS_MIN) * + ((fxi.cl->time - glowball->SpawnDelay) / 100.0) / (SPHERE_MAX_CHARGES+2)); + + // Update the position of the spark. + AngleVectors(glowball->direction, angvect, NULL, NULL); + + VectorMA(glowball->origin, glowball->radius, angvect, glowball->r.origin); + + glowball->lastThinkTime = fxi.cl->time; + + return true; +} + + +static qboolean FXSpherePlayerExplodeGlowballTerminate(client_entity_t *glowball, centity_t *owner) +{ + // Don't instantly delete yourself. Don't accept any more updates and die out within a second. + glowball->d_alpha = -5.0; // Fade out. + glowball->updateTime = 1000; // Die in one second. + glowball->Update = RemoveSelfAI; + + return true; +} + + + +// **************************************************************************** +// FXSphereOfAnnihilationExplode - +// **************************************************************************** +void FXSpherePlayerExplode(centity_t *Owner, int Type, int Flags, vec3_t Origin) +{ + vec3_t Dir; + byte Size; + client_entity_t *explosion, *glowball; + paletteRGBA_t LightColor={255,255,255,255}, haloColor={100,100,255,64}; + int I, count; + vec3_t angvect; + + fxi.GetEffect(Owner,Flags,"db",Dir,&Size); + // Create an expanding ball of blue fire. + explosion=ClientEntity_new(Type,Flags | CEF_ADDITIVE_PARTS,Origin,NULL,50); + + explosion->r.model = sphere_models + 3; + explosion->r.flags=RF_FULLBRIGHT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + explosion->r.scale=0.01; + explosion->color.c=0xffffffff; + explosion->alpha = 1.0; + explosion->d_alpha = 0.0; + explosion->d_scale=1.5; + explosion->SpawnInfo = (int)Size; + explosion->radius=SPHERE_RADIUS_MIN + ((SPHERE_RADIUS_MAX-SPHERE_RADIUS_MIN) / SPHERE_MAX_CHARGES * explosion->SpawnInfo); + explosion->dlight=CE_DLight_new(LightColor, explosion->radius/0.7 ,0); + explosion->AddToView=FXSpherePlayerExplodeAddToView; + explosion->Update=FXSpherePlayerExplodeThink; + explosion->updateTime = ((explosion->SpawnInfo+1)*100); + explosion->nextEventTime = fxi.cl->time + explosion->updateTime; + explosion->lastThinkTime = fxi.cl->time; + + AddEffect(NULL, explosion); + + FXSpherePlayerExplodeThink(explosion,NULL); + // Add some glowing blast particles. + + VectorScale(Dir,SMOKE_SPEED,Dir); + + count = GetScaledCount(40, 0.3); + + for(I=0;Ir.model = sphere_models + 7; + glowball->r.flags = RF_FULLBRIGHT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + glowball->AddToView = FXSpherePlayerExplodeGlowballThink; + glowball->alpha = 1.0; + glowball->d_alpha = 0.0; + glowball->r.scale = 1.0; + glowball->d_scale = 3.0; + glowball->Update = FXSpherePlayerExplodeGlowballTerminate; + glowball->lastThinkTime = glowball->SpawnDelay = fxi.cl->time; + glowball->nextThinkTime = fxi.cl->time + ((explosion->SpawnInfo+1)*100); + + VectorClear(glowball->direction); + glowball->direction[YAW] = flrand(0, 360.0); // This angle is kept at a constant distance from org. + glowball->direction[PITCH] = flrand(0, 360.0); + + glowball->velocity2[YAW] = flrand(-90.0, 90.0); + if (glowball->velocity2[YAW] < 0) // Assure that the sparks are moving around at a pretty good clip. + glowball->velocity2[YAW] -= 90.0; + else + glowball->velocity2[YAW] += 90.0; + + glowball->velocity2[PITCH] = flrand(-90.0, 90.0); // This is a velocity around the sphere. + if (glowball->velocity2[PITCH] < 0) // Assure that the sparks are moving around at a pretty good clip. + glowball->velocity2[PITCH] -= 90.0; + else + glowball->velocity2[PITCH] += 90.0; + + AngleVectors(glowball->direction, angvect, NULL, NULL); + VectorCopy(Origin, glowball->origin); + VectorCopy(Origin, glowball->r.origin); + + AddEffect(NULL, glowball); + } + + // Now make a big mutha flash + explosion = ClientEntity_new(Type, Flags, Origin, NULL, 250); + explosion->r.model = sphere_models + 4; // hp_halo + explosion->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA | RF_TRANSLUCENT; + explosion->r.frame = 1; + explosion->radius= 128; + explosion->d_alpha= -4.0; + explosion->r.scale= 1.0; + explosion->d_scale = -4.0; + + AddEffect(NULL, explosion); +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_spoo.c b/Toolkit/Programming/GameCode/client effects/fx_spoo.c new file mode 100644 index 0000000..6979edd --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_spoo.c @@ -0,0 +1,145 @@ +// +// fx_flyingfist.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "utilities.h" + +#define NUM_SPOO_MODELS 2 +static struct model_s *spoo_models[NUM_SPOO_MODELS]; +void PreCacheSpoo() +{ + spoo_models[0] = fxi.RegisterModel("sprites/fx/spoo.sp2"); + spoo_models[1] = fxi.RegisterModel("sprites/fx/spoo2.sp2"); +} + +// -------------------------------------------------------------- + +// ************************************************************************************************ +// FXSpooTrailThink +// ************************************************************************************************ + +static qboolean FXSpooTrailThink(struct client_entity_s *self,centity_t *owner) +{ + client_entity_t *TrailEnt; + //vec3_t org, dir; + //float len; + int count; + + count = GetScaledCount(8, 0.85); + + /* + //Setup the common origin + VectorCopy(self->startpos, org); + + //Get the direction + VectorSubtract(owner->current.origin, self->startpos, dir); + len = VectorNormalize(dir); + + //Get the offset increment + len /= count; + + //Get the increment vector + VectorScale(dir, len, dir); + */ + + while (count--) + { + //VectorAdd(org, dir, org); + + TrailEnt=ClientEntity_new(FX_SPOO, + self->flags & ~(CEF_OWNERS_ORIGIN|CEF_NO_DRAW), + owner->origin, + NULL, + 1000); + + TrailEnt->r.model = spoo_models + irand(0,1); + + TrailEnt->r.origin[0] += flrand(-3.0F, 3.0F); + TrailEnt->r.origin[1] += flrand(-3.0F, 3.0F); + TrailEnt->r.origin[2] += flrand(-3.0F, 3.0F); + + VectorSet(TrailEnt->velocity, flrand(-64.0F, 64.0F), flrand(-64.0F, 64.0F), -64.0F); + + TrailEnt->r.scale = 0.65; + TrailEnt->alpha = 1.0f; + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_FULLBRIGHT; + TrailEnt->d_scale = flrand(-4.0, -3.5); + TrailEnt->d_alpha = -2.0f; + TrailEnt->color.c = 0xFFFFFFFF; + TrailEnt->radius=20.0; + + AddEffect(NULL,TrailEnt); + } + + VectorCopy(owner->current.origin, self->startpos); + + return(true); +} + +void FXSpoo(centity_t *owner,int type,int Flags,vec3_t origin) +{ + client_entity_t *Trail; + paletteRGBA_t LightColor={255,153,77,255}; + + Trail=ClientEntity_new(type,Flags,origin,NULL,20); + + Trail->Update=FXSpooTrailThink; + Trail->flags|=CEF_NO_DRAW; + VectorCopy(origin, Trail->startpos); + + AddEffect(owner,Trail); + + FXSpooTrailThink(Trail,owner); +} + +void FXSpooSplat(centity_t *owner,int type,int Flags,vec3_t origin) +{ + client_entity_t *TrailEnt; + vec3_t dir; + int count; + + fxi.GetEffect(owner, Flags, "d", &dir); + + count = GetScaledCount(16, 0.85); + + while (count--) + { + TrailEnt=ClientEntity_new(FX_SPOO, + 0, + origin, + NULL, + 1000); + + TrailEnt->r.model = spoo_models + irand(0,1); + + VectorRandomCopy(dir, TrailEnt->velocity, 16.0f); + VectorNormalize(TrailEnt->velocity); + VectorScale(TrailEnt->velocity, flrand(100.0f, 200.0f), TrailEnt->velocity); + + VectorSet(TrailEnt->acceleration, 0, 0, -128); + + TrailEnt->r.scale = flrand(0.75, 1.0); + TrailEnt->alpha=1.0; + + TrailEnt->r.flags |= RF_TRANSLUCENT; + + TrailEnt->r.frame=0; + TrailEnt->d_scale=flrand( -1.25, -1.0); + TrailEnt->d_alpha=flrand(-1, -0.5); + TrailEnt->color.c = 0xA0FFFFFF; + TrailEnt->radius=20.0; + + AddEffect(NULL,TrailEnt); + } +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_ssarrow.c b/Toolkit/Programming/GameCode/client effects/fx_ssarrow.c new file mode 100644 index 0000000..cc27d92 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_ssarrow.c @@ -0,0 +1,144 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "angles.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "motion.h" +#include "Reference.h" +#include "ce_Dlight.h" + +#define NUM_SSARROW_MODELS 2 +static struct model_s *ssarrow_models[NUM_SSARROW_MODELS]; +void PreCacheSsithraArrow() +{ + ssarrow_models[0] = fxi.RegisterModel("sprites/fx/steampuff.sp2"); + ssarrow_models[1] = fxi.RegisterModel("models/objects/projectiles/sitharrow/tris.fm"); +} + +// -------------------------------------------------------------- + +// Need to create some pretty effect here + +static qboolean FXSsithraArrowGlowThink(struct client_entity_s *self, centity_t *owner) +{ + // Reset update time to regular after game has been given enough time to gen lerp info + self->updateTime = 100; + + self->dlight->intensity = 150.0 + (cos(fxi.cl->time * 0.01) * 20.0); + return(true); +} + +void FXSsithraArrowGlow(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + vec3_t org; + + VectorClear(org); + glow = ClientEntity_new(type, flags | CEF_NO_DRAW, org, 0, Q_ftol(fxi.cls->frametime * 2000.0)); + + glow->color.c = 0xff00ffff; + glow->dlight = CE_DLight_new(glow->color, 150.0F, 0.0F); + glow->Update = FXSsithraArrowGlowThink; + glow->AddToView = OffsetLinkedEntityUpdatePlacement; + glow->refMask = 1 << CORVUS_LEFTHAND; + + AddEffect(owner, glow); +} + +// ----------------------------------------------------------------------------------------- + +#define PART_OFF 5.0 +#define NUM_TRAIL_PARTS 6 + +static qboolean FXSsithraArrowMissileThink(client_entity_t *missile, centity_t *owner) +{ + int i; + client_entity_t *ce; + vec3_t diff, curpos, org; + + VectorSubtract(missile->r.origin, missile->origin, diff); + Vec3ScaleAssign((1.0 / NUM_TRAIL_PARTS), diff); + VectorClear(curpos); + + for(i = 0; i < NUM_TRAIL_PARTS; i++) + { + VectorRandomCopy(missile->origin, org, PART_OFF); + Vec3AddAssign(curpos, org); + ce = ClientEntity_new(-1, 0, org, NULL, 500); + ce->r.model = ssarrow_models; // Can be a particle now + ce->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + ce->r.color = missile->color; + ce->radius = 16.0F; + ce->r.scale = 0.1F; + ce->d_scale = 2.0F; + ce->d_alpha = -2.2F; + AddEffect(NULL, ce); + + Vec3AddAssign(diff, curpos); + } + // Remember for even spread of particles + VectorCopy(missile->r.origin, missile->origin); + return(true); +} + +void FXSsithraArrowMissile(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *missile; + vec3_t temp; + + missile = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 100); + fxi.GetEffect(owner, flags, "v", missile->velocity); + + VectorCopy(missile->velocity, temp); + VectorNormalize(temp); + AnglesFromDir(temp, missile->r.angles); + missile->r.angles[PITCH] -= ANGLE_90; + missile->r.angles[YAW] += ANGLE_90; + + missile->r.model = ssarrow_models + 1; + missile->Update = FXSsithraArrowMissileThink; + missile->radius = 32.0F; + missile->color.c = 0xff00ffff; + missile->dlight = CE_DLight_new(missile->color, 150.0F, 00.0F); + AddEffect(owner, missile); + + fxi.S_StartSound(missile->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("monsters/pssithra/arrow1.wav"), 1, ATTN_NORM, 0); +} + +// ----------------------------------------------------------------------------------------- + +static qboolean FXSsithraArrowDLightThink(client_entity_t *dlight, centity_t *owner) +{ + dlight->dlight->intensity -= 10.0F; + if(dlight->dlight->intensity < 0.0F) + return(false); + + return(true); +} + +void FXSsithraArrowExplode(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *dlight; + paletteRGBA_t color; + + dlight = ClientEntity_new(-1, CEF_NO_DRAW | CEF_NOMOVE, origin, NULL, 100); + color.c = 0xff00ffff; + dlight->dlight = CE_DLight_new(color, 150.0F, 0.0F); + dlight->Update = FXSsithraArrowDLightThink; + AddEffect(NULL, dlight); + +//NOTE: depends on impacted surface & material and if exploding arrow + fxi.S_StartSound(origin, -1, CHAN_AUTO, fxi.S_RegisterSound("weapons/ramphit1.wav"), 1, ATTN_NORM, 0); +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_ssithra.c b/Toolkit/Programming/GameCode/client effects/fx_ssithra.c new file mode 100644 index 0000000..7fafb8a --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_ssithra.c @@ -0,0 +1,310 @@ +// +// fx_ssithra.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "ce_DLight.h" +#include "random.h" +#include "Utilities.h" +#include "fx_debris.h" + +#define ARROW_DELTA_FORWARD 8.0 +#define ARROW_DELTA_THETA 0.12 +#define ARROW_SPIRAL_RAD 0.75 +#define ARROW_SCALE 0.25 + +#define NUM_ARROW_MODELS 3 + +static struct model_s *arrow_models[NUM_ARROW_MODELS]; + +void PrecacheSsithraArrow() +{ + arrow_models[0] = fxi.RegisterModel("sprites/fx/steam.sp2");//unpowered trail + arrow_models[1] = fxi.RegisterModel("sprites/fx/fire.sp2");//powered trail + arrow_models[2] = fxi.RegisterModel("models/objects/projectiles/sitharrow/tris.fm");//projectile model +} + +enum +{ + FX_SS_MAKE_ARROW, + FX_SS_MAKE_ARROW2, + FX_SS_EXPLODE_ARROW, + FX_SS_EXPLODE_ARROW2 +}; +// ************************************************************************************************ +// FXSsithraArrowTrailThink +// ************************************************************************************************ + +static qboolean FXSsithraArrowTrailThink(struct client_entity_s *self, centity_t *owner) +{ + client_entity_t *TrailEnt; + vec3_t accel_dir; + int i; + + self->updateTime = 20; + + self->r.angles[ROLL] += 10; + + if(self->SpawnInfo > 9) + self->SpawnInfo--; + + i = GetScaledCount( irand(self->SpawnInfo >> 3, self->SpawnInfo >> 2), 0.8 ); + while(i--) + { + TrailEnt = ClientEntity_new(FX_SSITHRA_ARROW, 0, self->r.origin, NULL, 1000); + + VectorCopy(self->velocity, accel_dir); + VectorNormalize(accel_dir); + + if (self->flags & CEF_FLAG7) + {//powered + TrailEnt->r.flags |= (RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA); + TrailEnt->r.model = arrow_models + 1; + TrailEnt->r.scale = (ARROW_SCALE + flrand(0.0, 0.05)); + VectorRandomCopy(self->r.origin, TrailEnt->r.origin, flrand(-8.0, 8.0)); + VectorScale(accel_dir, flrand(-100.0, -400.0), TrailEnt->velocity); + } + else + { + //make this use tinting instead of darken? + TrailEnt->r.flags |= RF_TRANSLUCENT;//darken + TrailEnt->r.color.r = 75; + TrailEnt->r.color.g = 50; + TrailEnt->r.color.b = 100; + TrailEnt->r.color.a = 100; + TrailEnt->r.model = arrow_models; + TrailEnt->r.scale = ARROW_SCALE + flrand(-0.2, 0.2); + VectorRandomCopy(self->r.origin, TrailEnt->r.origin, flrand(-5.0, 5.0)); + VectorScale(accel_dir, flrand(-50.0, -400.0), TrailEnt->velocity); + } + TrailEnt->d_alpha = flrand(-1.5, -2.0); + TrailEnt->d_scale = flrand(-1.0, -1.25); + TrailEnt->updateTime = (TrailEnt->alpha * 1000.0) / -TrailEnt->d_scale; + TrailEnt->radius = 20.0; + + AddEffect(NULL,TrailEnt); + } + + return(true); +} + +// ************************************************************************************************ +// FXSsithraArrow +// ************************************************************************************************ + +//////////////////////////////////// +// From CreateEffect FX_WEAPON_SSITHRAARROW +//////////////////////////////////// +void FXDoSsithraArrow(centity_t *owner, int type, int flags, vec3_t origin, vec3_t vel) +{ + vec3_t dir; + client_entity_t *missile; + paletteRGBA_t LightColor; + float lightsize; + + missile = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 100); + + missile->r.flags |= RF_GLOW; + missile->r.model = arrow_models + 2; + missile->r.skinnum = 0; + missile->r.scale = 1.0; + LightColor.c = 0xff2040ff; // Orange light + lightsize = 120.0; + + VectorCopy(vel, missile->velocity); + VectorNormalize2(vel, dir); + AnglesFromDir(dir, missile->r.angles); + + missile->radius = 128; + missile->dlight = CE_DLight_new(LightColor, lightsize, 0.0f); + missile->Update = FXSsithraArrowTrailThink; + + missile->SpawnInfo = 32; + + AddEffect(owner, missile); +} + +void FXDoSsithraArrow2(centity_t *owner, int type, int flags, vec3_t origin, vec3_t vel) +{ + vec3_t dir; + client_entity_t *missile; + paletteRGBA_t LightColor; + float lightsize; + + missile = ClientEntity_new(type, flags | CEF_DONT_LINK, origin, NULL, 100); + + missile->r.flags |= RF_GLOW; + missile->flags |= CEF_FLAG7; + missile->r.model = arrow_models + 2; + missile->r.skinnum = 0; + missile->r.scale = 1.5; + LightColor.c = 0xff0000ff; // Red light + lightsize = 160.0; + + VectorCopy(vel, missile->velocity); + VectorNormalize2(vel, dir); + AnglesFromDir(dir, missile->r.angles); + + missile->radius = 128; + missile->dlight = CE_DLight_new(LightColor, lightsize, 0.0f); + missile->Update = FXSsithraArrowTrailThink; + + missile->SpawnInfo = 32; + + AddEffect(owner, missile); +} + + + +// ************************************************************************************************ +// FXSsithraArrowExplode +// ************************************************************************************************ + +/////////////////////////////////////// +// From CreateEffect FX_WEAPON_SSITHRAARROWEXPLODE +/////////////////////////////////////// +void FXSsithraArrowBoom(centity_t *owner,int type,int flags,vec3_t origin, vec3_t dir) +{ + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor; + float lightrad; + + Vec3ScaleAssign(32.0, dir); + + i = GetScaledCount(irand(8, 12), 0.8); + LightColor.c = 0xff2040ff; + lightrad = 150; + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(type,flags,origin,NULL,500); + else + SmokePuff=ClientEntity_new(type,flags,origin,NULL,1000); + + SmokePuff->r.model = arrow_models; + SmokePuff->r.scale=flrand(0.8,1.6); + SmokePuff->d_scale=-2.0; + + VectorRandomCopy(dir, SmokePuff->velocity, 64.0); + SmokePuff->acceleration[0] = flrand(-200, 200); + SmokePuff->acceleration[1] = flrand(-200, 200); + SmokePuff->acceleration[2] = flrand(-40, -60); + + //make this use tinting instead of darken? + SmokePuff->r.flags |= RF_TRANSLUCENT; + SmokePuff->r.color.r = 75; + SmokePuff->r.color.g = 50; + SmokePuff->r.color.b = 100; + SmokePuff->r.color.a = 100; + + SmokePuff->r.frame=0; + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + if(!i) + { + fxi.S_StartSound(SmokePuff->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/SsithraArrowImpact.wav"), + 1, ATTN_NORM, 0); + SmokePuff->dlight=CE_DLight_new(LightColor,lightrad,0.0f); + VectorClear(SmokePuff->velocity); + } + + AddEffect(NULL,SmokePuff); + } +} + +void FXSsithraArrow2Boom(centity_t *owner,int type,int flags,vec3_t origin, vec3_t dir) +{ + vec3_t mins; + client_entity_t *SmokePuff; + int i; + paletteRGBA_t LightColor; + float lightrad; + + Vec3ScaleAssign(32.0, dir); + + i = GetScaledCount(irand(12, 16), 0.8); + LightColor.c = 0xff0000ff; + lightrad = 200; + + while(i--) + { + if (!i) + SmokePuff=ClientEntity_new(type,flags,origin,NULL,500); + else + SmokePuff=ClientEntity_new(type,flags,origin,NULL,1000); + + SmokePuff->r.model = arrow_models + 1; + SmokePuff->r.scale=flrand(1.2,2.0); + SmokePuff->d_scale=-2.0; + + VectorRandomCopy(dir, SmokePuff->velocity, 200); + SmokePuff->velocity[2] += 100.0; + SmokePuff->acceleration[2] = -400.0; + + SmokePuff->r.flags |=RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + SmokePuff->r.frame=0; + + SmokePuff->d_alpha= -0.4; + + SmokePuff->radius=20.0; + + if(!i) + { + fxi.S_StartSound(SmokePuff->r.origin, -1, CHAN_WEAPON, fxi.S_RegisterSound("weapons/FireballPowerImpact.wav"), + 1, ATTN_NORM, 0); + SmokePuff->dlight=CE_DLight_new(LightColor,lightrad,0.0f); + VectorClear(SmokePuff->velocity); + } + + AddEffect(NULL,SmokePuff); + } + + VectorSet(dir, 0.0, 0.0, 1.0); + VectorSet(mins, 2.0, 2.0, 2.0); // because SpawnChunks needs a value for bounding box + //clear out cef_flag# stuff, means different stuff to debris + FXDebris_SpawnChunks(type, flags & ~(CEF_FLAG6|CEF_FLAG7|CEF_FLAG8), origin, 5, MAT_GREYSTONE, dir, 80000.0f, mins, 1.0, false); +} + +void FXSsithraArrow(centity_t *owner, int type, int flags, vec3_t origin) +{ + byte whicheffect = 0; + vec3_t vel; + + fxi.GetEffect(owner, flags, "bv", &whicheffect, vel); + + switch(whicheffect) + { + case FX_SS_MAKE_ARROW: + FXDoSsithraArrow(owner, type, flags, origin, vel); + break; + + case FX_SS_MAKE_ARROW2: + FXDoSsithraArrow2(owner, type, flags, origin, vel); + break; + + case FX_SS_EXPLODE_ARROW: + FXSsithraArrowBoom(owner, type, flags, origin, vel); + break; + + case FX_SS_EXPLODE_ARROW2: + FXSsithraArrow2Boom(owner, type, flags, origin, vel); + break; + + default: + Com_Printf("Unknown effect type (%d) for FXSsithraArrow\n", whicheffect); + break; + } +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_staff.c b/Toolkit/Programming/GameCode/client effects/fx_staff.c new file mode 100644 index 0000000..d417863 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_staff.c @@ -0,0 +1,1116 @@ +// +// fx_staff.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Matrix.h" +#include "Random.h" +#include "Utilities.h" +#include "Reference.h" +#include "ce_DLight.h" +#include "q_Sprite.h" +#include "particle.h" +#include "g_playstats.h" + +enum +{ + STAFF_TRAIL, + STAFF_HALO, + STAFF_TRAIL2, + STAFF_TRAIL_SMOKE, + STAFF_TRAIL3, + NUM_MODELS +}; + +static struct model_s *staff_models[NUM_MODELS]; +static struct model_s *staffhit_models[4]; + +void PreCacheStaffHit() +{ + staffhit_models[0] = fxi.RegisterModel("sprites/spells/patball.sp2"); + staffhit_models[1] = fxi.RegisterModel("sprites/fx/halo.sp2"); + staffhit_models[2] = fxi.RegisterModel("sprites/fx/firestreak.sp2"); + staffhit_models[3] = fxi.RegisterModel("sprites/fx/steam.sp2"); +} + +void PreCacheStaff() +{ + staff_models[0] = fxi.RegisterModel("sprites/spells/patball.sp2"); + staff_models[1] = fxi.RegisterModel("sprites/fx/halo.sp2"); + staff_models[2] = fxi.RegisterModel("sprites/spells/wflame2.sp2"); + staff_models[3] = fxi.RegisterModel("sprites/fx/steam.sp2"); + staff_models[4] = fxi.RegisterModel("sprites/fx/haloblue.sp2"); +} + +// -------------------------------------------------------------- + +#define SCALE .2 +#define STAFF_LENGTH 27 + +#define STAFF_TYPE_SWORD 3 +#define STAFF_TYPE_HELL 4 + +// Just wanted to put a note in here to Josh. This is one of the coolest effects I've seen in a game in a long +// time. You should be extremely proud of this. I for one am very impressed. Jake. + +void FXStaffStrike(centity_t *owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *TrailEnt; + vec3_t dir; + byte powerlevel; + int i, white; + + fxi.GetEffect(owner,Flags,"db", &dir, &powerlevel); + + switch( powerlevel) + { + case 1: + break; + + case 3: + //Spawn a bright flash at the core of the explosion + TrailEnt=ClientEntity_new(FX_WEAPON_STAFF_STRIKE, Flags & ~CEF_NO_DRAW, Origin, 0, 1000); + + TrailEnt->r.model = staffhit_models + 1; + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.scale = flrand(0.75, 1.0); + TrailEnt->alpha = 0.75; + TrailEnt->d_alpha = -2.0; + TrailEnt->d_scale = -2.0; + TrailEnt->r.frame = 1; + + white = irand(8, 16); + + TrailEnt->r.color.r = 128 + irand(108, 127); + TrailEnt->r.color.g = 64 + white; + TrailEnt->r.color.b = 16 + white; + TrailEnt->r.color.a = 64 + irand(16, 128); + + TrailEnt->dlight = CE_DLight_new(TrailEnt->r.color, 150.0F, -100.0F); + + AddEffect(NULL, TrailEnt); + + //Spawn an explosion of lines + i = GetScaledCount(16, 0.85); + + while (i--) + { + TrailEnt=ClientEntity_new(FX_WEAPON_STAFF_STRIKE, Flags & ~CEF_NO_DRAW, Origin, 0, 500); + + TrailEnt->r.model = staffhit_models + 2; + + TrailEnt->r.spriteType = SPRITE_LINE; + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.color.c = 0xFFFFFFFF; + TrailEnt->r.scale = flrand(1.0, 2.5); + TrailEnt->alpha = 1.0; + TrailEnt->d_alpha = -1.0; + TrailEnt->d_scale = -1.0; + + white = irand(128, 255); + + TrailEnt->r.color.r = white; + TrailEnt->r.color.g = white; + TrailEnt->r.color.b = 128 + irand(108, 127); + TrailEnt->r.color.a = 64 + irand(16, 128); + + VectorRandomCopy(dir, TrailEnt->velocity, 1.25); + + VectorCopy(Origin, TrailEnt->r.endpos); + VectorMA(TrailEnt->r.endpos, irand(8,16), TrailEnt->velocity, TrailEnt->r.startpos); + + VectorScale(TrailEnt->velocity, irand(100,200), TrailEnt->velocity); + + AddEffect(NULL, TrailEnt); + } + + //Spawn smoke + i = GetScaledCount(4, 0.85); + + while (i--) + { + TrailEnt=ClientEntity_new(FX_WEAPON_STAFF_STRIKE, Flags & ~CEF_NO_DRAW, Origin, 0, 1000); + + TrailEnt->r.model = staffhit_models + 3; + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.scale = flrand(0.25, 0.5); + TrailEnt->alpha = 0.9; + TrailEnt->d_alpha = -2.0; + TrailEnt->d_scale = 2.0; + + white = irand(32, 64); + + TrailEnt->r.color.r = TrailEnt->r.color.g = TrailEnt->r.color.b = white; + TrailEnt->r.color.a = 128; + + VectorRandomCopy(dir, TrailEnt->velocity, 1.25); + + VectorCopy(Origin, TrailEnt->r.endpos); + VectorMA(TrailEnt->r.endpos, irand(16,48), TrailEnt->velocity, TrailEnt->r.startpos); + + VectorScale(TrailEnt->velocity, irand(10,50), TrailEnt->velocity); + TrailEnt->velocity[2] += 64; + + AddEffect(NULL, TrailEnt); + } + + break; + + case 2: + if (r_detail->value >= DETAIL_NORMAL) + fxi.Activate_Screen_Flash(0x30FFFFFF); + + //Spawn a bright flash at the core of the explosion + TrailEnt=ClientEntity_new(FX_WEAPON_STAFF_STRIKE, Flags & ~CEF_NO_DRAW, Origin, 0, 1000); + + TrailEnt->r.model = staffhit_models + 1; + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.scale = flrand(0.75, 1.0); + TrailEnt->alpha = 0.75; + TrailEnt->d_alpha = -2.0; + TrailEnt->d_scale = -2.0; + TrailEnt->r.frame = 1; + TrailEnt->r.color.c = 0xFF888888; + + TrailEnt->dlight = CE_DLight_new(TrailEnt->r.color, 150.0F, -100.0F); + + AddEffect(NULL, TrailEnt); + + //Spawn a hit explosion of lines + i = GetScaledCount(64, 0.85); + + while (i--) + { + TrailEnt=ClientEntity_new(FX_WEAPON_STAFF_STRIKE, Flags & ~CEF_NO_DRAW, Origin, 0, 500); + + TrailEnt->r.model = staffhit_models; + + TrailEnt->r.spriteType = SPRITE_LINE; + + TrailEnt->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + TrailEnt->r.color.c = 0xFFFFFFFF; + TrailEnt->r.scale = flrand(1.0, 2.5); + TrailEnt->alpha = flrand(1.0, 0.75); + TrailEnt->d_alpha = -2.0; + TrailEnt->d_scale = -1.0; + + white = irand(128, 255); + + TrailEnt->r.color.r = white; + TrailEnt->r.color.g = white; + TrailEnt->r.color.b = 128 + irand(108, 127); + TrailEnt->r.color.a = 64 + irand(16, 128); + + VectorRandomCopy(dir, TrailEnt->velocity, 1.25); + + VectorCopy(Origin, TrailEnt->r.startpos); + VectorMA(TrailEnt->r.startpos, irand(16,48), TrailEnt->velocity, TrailEnt->r.endpos); + + VectorScale(TrailEnt->velocity, irand(200,300), TrailEnt->velocity); + VectorSet(TrailEnt->acceleration, TrailEnt->velocity[0] * 0.1, TrailEnt->velocity[1] * 0.1, 0); + + AddEffect(NULL, TrailEnt); + } + + break; + } +} + + +// ************************************************************************************************ +// FXStaffElementThink +// ------------------------ +// ************************************************************************************************ + +static qboolean FXStaffElementThink(struct client_entity_s *Self,centity_t *owner) +{ + float Frac, + Multiplier; + int FrameNo; + + Frac=(fxi.cl->time-Self->startTime)/100.0; + + if(Self->AnimSpeed>0.0) + { + Frac*=Self->AnimSpeed; + } + + if((FrameNo=floor(Frac))>=(Self->NoOfAnimFrames-1)) + { + return(false); + } + else + { + Multiplier=1.0-Frac/(Self->NoOfAnimFrames-1); + + Self->r.color.r=Self->color.r*Multiplier; + Self->r.color.b=Self->color.g*Multiplier; + Self->r.color.g=Self->color.b*Multiplier; + + Self->r.frame=FrameNo+1; + + return(true); + } +} + +// ************************************************************************************************ +// FXStaffThink +// ----------------- +// ************************************************************************************************ + +static qboolean FXTrailLevel2ThinkBurn(struct client_entity_s *Self,centity_t *owner) +{ + return true; +} + +static qboolean FXStaffLevel2Think(struct client_entity_s *Self,centity_t *owner) +{ + int I; + int NoOfIntervals, white; + client_entity_t *TrailEnt; + paletteRGBA_t color; + vec3_t dpivot, curpivot; + vec3_t dnormal, curnormal, adjnormal; + vec3_t diff, newpoint; + int model; + + matrix3_t rotation; + vec3_t origin; + + // If we've timed out, stop the effect (allow for fading) + if ( (Self->LifeTime > 0) && (Self->LifeTime < fxi.cl->time) ) + { + Self->Update=RemoveSelfAI; + Self->updateTime = fxi.cl->time + 500; + return true; + } + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return false; // Remove the effect in this case. + + I=Self->NoOfAnimFrames; + + // If this reference point hasn't changed since the last frame, return. + VectorSubtract( owner->referenceInfo->references[I].placement.origin, + owner->referenceInfo->oldReferences[I].placement.origin, + diff); + + if (Q_fabs(diff[0] + diff[1] + diff[2]) < .1) + return(true); + + NoOfIntervals=(int)(VectorLength(diff)*.5); + + // Average out the two right hand positions to get a pivot point. + VectorCopy(owner->referenceInfo->oldReferences[CORVUS_RIGHTHAND].placement.origin, curpivot); + VectorSubtract(owner->referenceInfo->references[CORVUS_RIGHTHAND].placement.origin, curpivot, dpivot); + VectorScale(dpivot, 1.0/NoOfIntervals, dpivot); + + VectorCopy(owner->referenceInfo->oldReferences[I].placement.direction, curnormal); + VectorSubtract(owner->referenceInfo->references[I].placement.direction, curnormal, dnormal); + VectorScale(dnormal, 1.0/NoOfIntervals, dnormal); + VectorCopy(curnormal, adjnormal); // This rides on the assumption that the normal given is already a unit norm. + + //FIXME: The above assumption isn't working! + VectorNormalize(adjnormal); + if(NoOfIntervals > 40) + return(false); + + while (NoOfIntervals >= 0) + { + VectorMA(curpivot, STAFF_LENGTH, adjnormal, newpoint); + + TrailEnt=ClientEntity_new(FX_SPELLHANDS, Self->flags & ~CEF_NO_DRAW, newpoint, 0, 2000); + + VectorCopy(newpoint, TrailEnt->origin); + + model = irand(0,100); + + TrailEnt->r.model = staff_models + STAFF_TRAIL2; + + TrailEnt->r.frame = 0; + + TrailEnt->r.flags=RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + TrailEnt->r.scale = flrand(0.2, 0.3); + TrailEnt->d_scale = flrand(-0.5, -1.0); + + TrailEnt->velocity[0] = irand(-8, 8); + TrailEnt->velocity[1] = irand(-8, 8); + TrailEnt->velocity[2] += irand(64, 128); + + TrailEnt->origin[0] += irand(-1, 1); + TrailEnt->origin[1] += irand(-1, 1); + TrailEnt->origin[2] += irand(-1, 1); + + TrailEnt->alpha = 1.0; + TrailEnt->d_alpha = -2.0; + + //Attach a dynamic light to the last one + if (NoOfIntervals==1 && (r_detail->value >= DETAIL_NORMAL)) + { + white = irand(8, 16); + + color.r = 128 + irand(108, 127); + color.g = 64 + white; + color.b = 16 + white; + color.a = 64 + irand(16, 128); + + TrailEnt->dlight = CE_DLight_new(color, irand(50.0f, 150.0F), -100.0F); + } + + Matrix3FromAngles(owner->lerp_angles, rotation); + + Matrix3MultByVec3(rotation, TrailEnt->origin, origin); + + TrailEnt->r.origin[0] = owner->origin[0] + origin[0]; + TrailEnt->r.origin[1] = owner->origin[1] + origin[1]; + TrailEnt->r.origin[2] = owner->origin[2] + origin[2]; + + AddEffect(NULL,TrailEnt); + + if (!irand(0,3)) + { + TrailEnt=ClientEntity_new(FX_SPELLHANDS, Self->flags & ~CEF_NO_DRAW, newpoint, 0, 5000); + + TrailEnt->r.model = staff_models + STAFF_TRAIL_SMOKE; + + TrailEnt->r.frame = 0; + + TrailEnt->r.flags=RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + TrailEnt->r.scale = flrand(0.1, 0.15); + TrailEnt->d_scale = 1.0; + + TrailEnt->alpha = 0.75; + TrailEnt->d_alpha = -1.0; + + TrailEnt->velocity[0] = irand(-16, 16); + TrailEnt->velocity[1] = irand(-16, 16); + TrailEnt->velocity[2] += irand(64, 128); + + white = irand(32, 64); + + TrailEnt->r.color.r = TrailEnt->r.color.g = TrailEnt->r.color.b = white; + TrailEnt->r.color.a = 128; + + //Attach a dynamic light to the last one + if (NoOfIntervals==1 && (r_detail->value >= DETAIL_NORMAL)) + { + white = irand(8, 16); + + color.r = 128 + irand(108, 127); + color.g = 64 + white; + color.b = 16 + white; + color.a = 64 + irand(16, 128); + + TrailEnt->dlight = CE_DLight_new(color, irand(50.0f, 150.0F), -100.0F); + } + + Matrix3FromAngles(owner->lerp_angles, rotation); + + Matrix3MultByVec3(rotation, TrailEnt->origin, origin); + + TrailEnt->r.origin[0] = owner->origin[0] + origin[0]; + TrailEnt->r.origin[1] = owner->origin[1] + origin[1]; + TrailEnt->r.origin[2] = owner->origin[2] + origin[2]; + + AddEffect(NULL,TrailEnt); + } + + VectorAdd(curpivot, dpivot, curpivot); + VectorAdd(curnormal, dnormal, curnormal); + VectorNormalize2(curnormal, adjnormal); + NoOfIntervals--; + } + + return true; +} + +static qboolean FXStaffLevel3Think(struct client_entity_s *Self,centity_t *owner) +{ + int I; + int NoOfIntervals, white; + client_entity_t *TrailEnt; + vec3_t dpivot, curpivot; + vec3_t dnormal, curnormal, adjnormal; + vec3_t diff, newpoint; + + // If we've timed out, stop the effect (allow for fading) + if ( (Self->LifeTime > 0) && (Self->LifeTime < fxi.cl->time) ) + { + Self->Update=RemoveSelfAI; + Self->updateTime = fxi.cl->time + 500; + return true; + } + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return false; // Remove the effect in this case. + + I=Self->NoOfAnimFrames; + + // If this reference point hasn't changed since the last frame, return. + VectorSubtract( owner->referenceInfo->references[I].placement.origin, + owner->referenceInfo->oldReferences[I].placement.origin, + diff); + + if (Q_fabs(diff[0] + diff[1] + diff[2]) < .1) + return(true); + + NoOfIntervals=(int)(VectorLength(diff)*.5); + + // Take the before and after points and try to draw an arc. + + // Average out the two right hand positions to get a pivot point. + VectorCopy(owner->referenceInfo->oldReferences[CORVUS_RIGHTHAND].placement.origin, curpivot); + VectorSubtract(owner->referenceInfo->references[CORVUS_RIGHTHAND].placement.origin, curpivot, dpivot); + VectorScale(dpivot, 1.0/NoOfIntervals, dpivot); + + VectorCopy(owner->referenceInfo->oldReferences[I].placement.direction, curnormal); + VectorSubtract(owner->referenceInfo->references[I].placement.direction, curnormal, dnormal); + VectorScale(dnormal, 1.0/NoOfIntervals, dnormal); + VectorCopy(curnormal, adjnormal); // This rides on the assumption that the normal given is already a unit norm. + + //FIXME: The above assumption isn't working! + VectorNormalize(adjnormal); + if(NoOfIntervals > 40) + return(false); + + while (NoOfIntervals >= 0) + { + VectorMA(curpivot, STAFF_LENGTH, adjnormal, newpoint); + + TrailEnt=ClientEntity_new(FX_SPELLHANDS, Self->flags & ~CEF_NO_DRAW, newpoint, 0, 500); + + VectorCopy(newpoint, TrailEnt->origin); + + TrailEnt->r.model = staff_models + STAFF_TRAIL3; + + TrailEnt->r.frame = 0; + + TrailEnt->r.flags=RF_TRANSLUCENT | RF_TRANS_ADD; + + TrailEnt->r.scale = 0.3; + TrailEnt->d_scale = -0.75; + + TrailEnt->alpha = 0.75; + TrailEnt->d_alpha = -4; + + if (owner->current.effects & EF_ALTCLIENTFX) + TrailEnt->r.color.c = 0x50000018; + else + { + white = irand(128, 208); + + TrailEnt->r.color.r = white; + TrailEnt->r.color.g = white; + TrailEnt->r.color.b = 128 + irand(108, 127); + TrailEnt->r.color.a = 64 + irand(16, 128); + } + + //Attach a dynamic light to the last one + if (NoOfIntervals==1 && (r_detail->value >= DETAIL_NORMAL)) + { + TrailEnt->dlight = CE_DLight_new(TrailEnt->r.color, 100.0F, -100.0F); + } + + TrailEnt->AddToView=OffsetLinkedEntityUpdatePlacement; + + AddEffect(owner,TrailEnt); + + VectorAdd(curpivot, dpivot, curpivot); + VectorAdd(curnormal, dnormal, curnormal); + VectorNormalize2(curnormal, adjnormal); + NoOfIntervals--; + } + + return true; +} + +static qboolean FXStaffThink(struct client_entity_s *Self,centity_t *owner) +{ + int I; + int NoOfIntervals; + client_entity_t *TrailEnt; + vec3_t dpivot, curpivot; + vec3_t dnormal, curnormal, adjnormal; + vec3_t diff, newpoint; + + // If we've timed out, stop the effect (allow for fading) + if ( (Self->LifeTime > 0) && (Self->LifeTime < fxi.cl->time) ) + { + Self->Update=RemoveSelfAI; + Self->updateTime = fxi.cl->time + 500; + return true; + } + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return false; // Remove the effect in this case. + + Self->updateTime = 17; // FIXME : With a next think time this effect does not look right + + I=Self->NoOfAnimFrames; + + // If this reference point hasn't changed since the last frame, return. + VectorSubtract( owner->referenceInfo->references[I].placement.origin, + owner->referenceInfo->oldReferences[I].placement.origin, + diff); + + if (Q_fabs(diff[0] + diff[1] + diff[2]) < .1) + return(true); + + NoOfIntervals=(int)(VectorLength(diff)*.75); + + // Take the before and after points and try to draw an arc. + + // Average out the two right hand positions to get a pivot point. + VectorCopy(owner->referenceInfo->oldReferences[CORVUS_RIGHTHAND].placement.origin, curpivot); + VectorSubtract(owner->referenceInfo->references[CORVUS_RIGHTHAND].placement.origin, curpivot, dpivot); + VectorScale(dpivot, 1.0/NoOfIntervals, dpivot); + + VectorCopy(owner->referenceInfo->oldReferences[I].placement.direction, curnormal); + VectorSubtract(owner->referenceInfo->references[I].placement.direction, curnormal, dnormal); + VectorScale(dnormal, 1.0/NoOfIntervals, dnormal); + VectorCopy(curnormal, adjnormal); // This rides on the assumption that the normal given is already a unit norm. + + VectorNormalize(adjnormal); + + if(NoOfIntervals > 40) + return(false); + + while (NoOfIntervals >= 0) + { + //Get the position of this sprite + VectorMA(curpivot, STAFF_LENGTH, adjnormal, newpoint); + + TrailEnt=ClientEntity_new(FX_SPELLHANDS, Self->flags & ~CEF_NO_DRAW, newpoint, 0, 1500); + + VectorCopy(newpoint, TrailEnt->origin); + + TrailEnt->r.model = staff_models; + TrailEnt->r.frame = 1; + + TrailEnt->r.flags = RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + + TrailEnt->d_scale = -0.5; + TrailEnt->alpha = 0.5; + TrailEnt->d_alpha = -1.0; + + if (owner->current.effects & EF_ALTCLIENTFX) + { + TrailEnt->r.color.c=0x50000018; + TrailEnt->r.scale=Self->xscale*2.0; + } + else + { + TrailEnt->r.color = Self->color; + TrailEnt->r.scale=Self->xscale; + } + + TrailEnt->AddToView=OffsetLinkedEntityUpdatePlacement; + + AddEffect(owner,TrailEnt); + + // + VectorAdd(curpivot, dpivot, curpivot); + VectorAdd(curnormal, dnormal, curnormal); + VectorNormalize2(curnormal, adjnormal); + NoOfIntervals--; + } + + return true; +} + +// ************************************************************************************************ +// FXStaff +// ------------ +// ************************************************************************************************ + +// This effect spawns 70+ client fx which will cause problems + +void FXStaff(centity_t *owner,int Type,int Flags,vec3_t Origin) +{ + short Refpoints; + client_entity_t *trail; + int I; + byte powerlevel; + char lifetime; + + Refpoints=0; + + fxi.GetEffect(owner,Flags,"bb", &powerlevel, &lifetime); + Refpoints = (1<flags |= CEF_NO_DRAW; + trail->NoOfAnimFrames = I; + + switch(powerlevel) + { + case 1: // Blue + default: + trail->Update = FXStaffThink; + trail->color.c = 0x02201010; + trail->xscale = .175; + break; + + //NOTENOTE: These were swapped after the functions were created + case 2: // Fire + trail->Update = FXStaffLevel3Think; + trail->color.c = 0xffffffff; + trail->xscale = .200; + break; + + case 3: // Energy Blast + case 4: + trail->Update = FXStaffLevel2Think; + trail->color.c = 0xffffffff; + trail->xscale = .225; + break; + } + trail->SpawnData = powerlevel; + + if (lifetime > 0) + trail->LifeTime = fxi.cl->time + (lifetime * 100); + else + trail->LifeTime = lifetime; + + AddEffect(owner,trail); + } +} + +// ************************************************************************************************ +// FXStaffCreateThink +// ----------------- +// ************************************************************************************************ + +static qboolean FXStaffCreateThink(struct client_entity_s *Self,centity_t *owner) +{ + int NoOfIntervals; + client_entity_t *TrailEnt; + vec3_t startpt, endpt; + vec3_t diff, curpt; + int color; + + Self->updateTime = 17; // FIXME : With a next think time this effect does not look right + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return false; // Remove the effect in this case. + + // If this reference point hasn't changed since the last frame, return. + switch(Self->refPoint) + { + case STAFF_TYPE_HELL: + VectorAdd(owner->referenceInfo->references[CORVUS_RIGHTHAND].placement.origin, owner->referenceInfo->references[CORVUS_STAFF].placement.origin, startpt); + VectorScale(startpt, 0.5, startpt); + VectorCopy(owner->referenceInfo->references[CORVUS_HELL_HEAD].placement.origin, endpt); + color = 0xff2020ff; + break; + case STAFF_TYPE_SWORD: + default: + VectorCopy(owner->referenceInfo->references[CORVUS_STAFF].placement.origin, startpt); + VectorCopy(owner->referenceInfo->references[CORVUS_BLADE].placement.origin, endpt); + color = 0xff20ff20; + break; + } + + VectorSubtract(endpt, startpt, diff); + NoOfIntervals=(int)(VectorLength(diff)*.5); + + VectorScale(diff, 1.0/NoOfIntervals, diff); + VectorCopy(startpt, curpt); // This rides on the assumption that the normal given is already a unit norm. + + if(NoOfIntervals > 40) + return(false); + + while (NoOfIntervals >= 0) + { + TrailEnt=ClientEntity_new(FX_SPELLHANDS, Self->flags & ~CEF_NO_DRAW, curpt, 0, 100); + VectorCopy(curpt, TrailEnt->origin); + TrailEnt->r.model = staff_models + Self->classID; + TrailEnt->alpha=0.8 - (Self->NoOfAnimFrames*0.1); + TrailEnt->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + TrailEnt->AddToView=OffsetLinkedEntityUpdatePlacement; + if(Self->classID == STAFF_TRAIL || Self->refPoint == STAFF_TYPE_HELL) + { + TrailEnt->r.frame=1; + TrailEnt->d_scale=-0.25; + TrailEnt->d_alpha=-0.1; + TrailEnt->color.c=color; + TrailEnt->r.scale=Self->NoOfAnimFrames*.05; + TrailEnt->AnimSpeed=0.20; + TrailEnt->NoOfAnimFrames=2; + TrailEnt->Update=FXStaffElementThink; + + AddEffect(owner,TrailEnt); + + FXStaffElementThink(TrailEnt,owner); + } + else if(Self->classID == STAFF_TRAIL2) + { + TrailEnt->r.frame = 0; + + TrailEnt->r.flags=RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + TrailEnt->r.scale = flrand(0.1, 0.2); + TrailEnt->d_scale = flrand(-0.25, -0.5); + + TrailEnt->velocity[0] = irand(-8, 8); + TrailEnt->velocity[1] = irand(-8, 8); + TrailEnt->velocity[2] += irand(64, 128); + + TrailEnt->origin[0] += irand(-1, 1); + TrailEnt->origin[1] += irand(-1, 1); + TrailEnt->origin[2] += irand(-1, 1); + + TrailEnt->alpha = 1.0; + TrailEnt->d_alpha = -2.0; + + AddEffect(owner,TrailEnt); + } + else if(Self->classID == STAFF_TRAIL3) + { + TrailEnt->r.frame = 0; + + TrailEnt->r.flags=RF_TRANSLUCENT | RF_TRANS_ADD; + + TrailEnt->r.scale = 0.2; + TrailEnt->d_scale = -0.35; + + TrailEnt->alpha = 0.75; + TrailEnt->d_alpha = -4; + + if (owner->current.effects & EF_ALTCLIENTFX) + TrailEnt->r.color.c = 0x50000018; + else + { + int white; + + white = irand(128, 208); + + TrailEnt->r.color.r = white; + TrailEnt->r.color.g = white; + TrailEnt->r.color.b = 128 + irand(108, 127); + TrailEnt->r.color.a = 64 + irand(16, 128); + } + + AddEffect(owner,TrailEnt); + } + // + VectorAdd(curpt, diff, curpt); + NoOfIntervals--; + } + Self->NoOfAnimFrames-=1.0; + if (Self->NoOfAnimFrames <= 0.0) + return(false); + else + return(true); +} + +// ************************************************************************************************ +// FXStaffCreate +// ------------ +// ************************************************************************************************ + +// This effect spawns 80+ client fx which will cause problems + +void FXStaffCreate(centity_t *owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *stafffx; + byte fxtype; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return; // Abandon the effect in this case. + + if (Flags & CEF_FLAG6) + fxtype = STAFF_TYPE_HELL; + else + fxtype = STAFF_TYPE_SWORD; + + stafffx = ClientEntity_new(Type, Flags, Origin, 0, 17); + + if(Flags & CEF_FLAG7)//blue + stafffx->classID = STAFF_TRAIL3; + else if(Flags & CEF_FLAG8)//flames + stafffx->classID = STAFF_TRAIL2; + else//normal + stafffx->classID = STAFF_TRAIL; + + stafffx->Update = FXStaffCreateThink; + stafffx->flags |= CEF_NO_DRAW; + stafffx->NoOfAnimFrames=7; + stafffx->refPoint = fxtype; + + AddEffect(owner, stafffx); +} + + +qboolean FXSpellChangePuffThink(struct client_entity_s *Self,centity_t *owner); + +// ************************************************************************************************ +// FXStaffCreatePoof +// ------------ +// ************************************************************************************************ + +void FXStaffCreatePoof(centity_t *owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *stafffx; + vec3_t spawnpt; + paletteRGBA_t LightColor; + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return; // Remove the effect in this case. + + if(Flags & CEF_FLAG6) + { + VectorCopy(owner->referenceInfo->references[CORVUS_HELL_HEAD].placement.origin, spawnpt); + LightColor.c = 0xff2020ff; + } + else + { + VectorCopy(owner->referenceInfo->references[CORVUS_BLADE].placement.origin, spawnpt); + LightColor.c = 0xffff5050; + } + + stafffx=ClientEntity_new(FX_SPELLHANDS, Flags & ~CEF_NO_DRAW, spawnpt, 0, 100); + VectorCopy(spawnpt, stafffx->origin); + stafffx->r.model = staff_models + STAFF_HALO; + stafffx->alpha=.75; + stafffx->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + stafffx->r.frame=1; + stafffx->d_scale=-0.3; + stafffx->d_alpha=-0.2; + stafffx->color.r=255; + stafffx->color.g=255; + stafffx->color.b=255; + stafffx->r.scale=0.5; + stafffx->AnimSpeed=0.20; + stafffx->NoOfAnimFrames=2; + stafffx->Update=FXStaffElementThink; + stafffx->AddToView=OffsetLinkedEntityUpdatePlacement; + AddEffect(owner,stafffx); + FXStaffElementThink(stafffx,owner); + + + if(!(Flags & CEF_FLAG6)) // Just for the sword staff + { + VectorCopy(owner->referenceInfo->references[CORVUS_STAFF].placement.origin, spawnpt); + + stafffx=ClientEntity_new(FX_SPELLHANDS, Flags & ~CEF_NO_DRAW, spawnpt, 0, 100); + VectorCopy(spawnpt, stafffx->origin); + stafffx->r.model = staff_models + STAFF_HALO; + stafffx->alpha=.75; + stafffx->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + stafffx->r.frame=1; + stafffx->d_scale=-0.3; + stafffx->d_alpha=-0.2; + stafffx->color.r=255; + stafffx->color.g=255; + stafffx->color.b=255; + stafffx->r.scale=0.5; + stafffx->AnimSpeed=0.20; + stafffx->NoOfAnimFrames=2; + stafffx->Update=FXStaffElementThink; + stafffx->AddToView=OffsetLinkedEntityUpdatePlacement; + AddEffect(owner,stafffx); + FXStaffElementThink(stafffx,owner); + } +} + + + +// ************************************************************************************************ +// FXStaffRemoveThink +// ----------------- +// ************************************************************************************************ + +static qboolean FXStaffRemoveThink(struct client_entity_s *Self,centity_t *owner) +{ + int NoOfIntervals; + client_entity_t *TrailEnt; + vec3_t startpt, endpt; + vec3_t diff, curpt; + int color; + + Self->updateTime = 17; // FIXME : With a next think time this effect does not look right + + // This tells if we are wasting our time, because the reference points are culled. + if (!RefPointsValid(owner)) + return false; // Remove the effect in this case. + + // If this reference point hasn't changed since the last frame, return. + switch(Self->refPoint) + { + case STAFF_TYPE_HELL: + VectorAdd(owner->referenceInfo->references[CORVUS_RIGHTHAND].placement.origin, owner->referenceInfo->references[CORVUS_STAFF].placement.origin, startpt); + VectorScale(startpt, 0.5, startpt); + VectorCopy(owner->referenceInfo->references[CORVUS_HELL_HEAD].placement.origin, endpt); + color = 0xff2020ff; + break; + case STAFF_TYPE_SWORD: + default: + VectorCopy(owner->referenceInfo->references[CORVUS_STAFF].placement.origin, startpt); + VectorCopy(owner->referenceInfo->references[CORVUS_BLADE].placement.origin, endpt); + color = 0xff20ff20; + break; + } + + VectorSubtract(endpt, startpt, diff); + NoOfIntervals=(int)(VectorLength(diff)*.5); + + VectorScale(diff, 1.0/NoOfIntervals, diff); + VectorCopy(startpt, curpt); // This rides on the assumption that the normal given is already a unit norm. + + if(NoOfIntervals > 40) + return(false); + + while (NoOfIntervals >= 0) + { + TrailEnt=ClientEntity_new(FX_SPELLHANDS, Self->flags & ~CEF_NO_DRAW, curpt, 0, 100); + VectorCopy(curpt, TrailEnt->origin); + TrailEnt->r.model = staff_models + Self->classID; + TrailEnt->alpha=0.6 - (Self->NoOfAnimFrames*0.1); + TrailEnt->r.flags=RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + TrailEnt->AddToView=OffsetLinkedEntityUpdatePlacement; + if(Self->classID == STAFF_TRAIL || Self->refPoint == STAFF_TYPE_HELL) + { + TrailEnt->r.frame=1; + TrailEnt->d_scale=-0.25; + TrailEnt->d_alpha=-0.1; + TrailEnt->color.c=color; + TrailEnt->r.scale=Self->NoOfAnimFrames*.05; + TrailEnt->AnimSpeed=0.20; + TrailEnt->NoOfAnimFrames=2; + TrailEnt->Update=FXStaffElementThink; + + AddEffect(owner,TrailEnt); + FXStaffElementThink(TrailEnt,owner); + } + else if(Self->classID == STAFF_TRAIL2) + { + TrailEnt->r.frame = 0; + + TrailEnt->r.flags=RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + + TrailEnt->r.scale = flrand(0.1, 0.2); + TrailEnt->d_scale = flrand(-0.5, -1.0); + + TrailEnt->velocity[0] = irand(-8, 8); + TrailEnt->velocity[1] = irand(-8, 8); + TrailEnt->velocity[2] += irand(64, 128); + + TrailEnt->origin[0] += irand(-1, 1); + TrailEnt->origin[1] += irand(-1, 1); + TrailEnt->origin[2] += irand(-1, 1); + + TrailEnt->alpha = 1.0; + TrailEnt->d_alpha = -2.0; + + AddEffect(owner,TrailEnt); + } + else if(Self->classID == STAFF_TRAIL3) + { + TrailEnt->r.frame = 0; + + TrailEnt->r.flags=RF_TRANSLUCENT | RF_TRANS_ADD; + + TrailEnt->r.scale = 0.2; + TrailEnt->d_scale = -0.35; + + TrailEnt->alpha = 0.75; + TrailEnt->d_alpha = -4; + + if (owner->current.effects & EF_ALTCLIENTFX) + TrailEnt->r.color.c = 0x50000018; + else + { + int white; + + white = irand(128, 208); + + TrailEnt->r.color.r = white; + TrailEnt->r.color.g = white; + TrailEnt->r.color.b = 128 + irand(108, 127); + TrailEnt->r.color.a = 64 + irand(16, 128); + } + + AddEffect(owner,TrailEnt); + } + + // + VectorAdd(curpt, diff, curpt); + NoOfIntervals--; + } + Self->NoOfAnimFrames+=1.0; + if (Self->NoOfAnimFrames > 5.0) + return(false); + else + return(true); +} + +// ************************************************************************************************ +// FXStaffRemove +// ------------ +// ************************************************************************************************ + +// This effect spawns 150+ client fx which will cause problems + +void FXStaffRemove(centity_t *owner,int Type,int Flags,vec3_t Origin) +{ + client_entity_t *stafffx; + byte fxtype; + + if (Flags & CEF_FLAG6) + fxtype = STAFF_TYPE_HELL; + else + fxtype = STAFF_TYPE_SWORD; + + if(!ReferencesInitialized(owner)) + { + return; + } + + stafffx = ClientEntity_new(Type, Flags, Origin, 0, 17); + + if(Flags & CEF_FLAG7)//blue + stafffx->classID = STAFF_TRAIL3; + else if(Flags & CEF_FLAG8)//flames + stafffx->classID = STAFF_TRAIL2; + else//normal + stafffx->classID = STAFF_TRAIL; + + stafffx->Update = FXStaffRemoveThink; + stafffx->flags |= CEF_NO_DRAW; + stafffx->NoOfAnimFrames=1; + stafffx->refPoint = fxtype; + + AddEffect(owner, stafffx); +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_tbeast.c b/Toolkit/Programming/GameCode/client effects/fx_tbeast.c new file mode 100644 index 0000000..16dc92f --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_tbeast.c @@ -0,0 +1,110 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// Created by JDW + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "random.h" +#include "Utilities.h" + +enum +{ + FX_TB_PUFF, + FX_TB_SNORT, +}; + + +#define NUM_BEAST_MODELS 1 +static struct model_s *tb_dustpuff_models[NUM_BEAST_MODELS]; +void PreCacheTB(void) +{ + tb_dustpuff_models[0] = fxi.RegisterModel("sprites/fx/steam_add.sp2"); +} + +static qboolean FXTBDustPuffThink(client_entity_t *DustPuff, centity_t *owner) +{ + DustPuff->flags &= ~CEF_DISAPPEARED; + + if (DustPuff->alpha <= 0) + return false; + + return(true); +} + +void FXTBDustPuff(int type, int flags, vec3_t origin,float inangle) +{ + client_entity_t *DustPuff; + vec3_t angles, forward; + + VectorSet(angles, 0, inangle, 0); + DustPuff = ClientEntity_new(type, flags, origin, NULL, 100); + + DustPuff->r.model = tb_dustpuff_models; + DustPuff->r.flags |= RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + DustPuff->Update = FXTBDustPuffThink; + DustPuff->radius = 1.0F; + DustPuff->alpha = 0.5F; + AngleVectors(angles, forward, NULL, NULL); + VectorScale(forward, flrand(30.0F, 100.0F), DustPuff->velocity); + DustPuff->velocity[2] = flrand(25.0F, 75.0F); + DustPuff->acceleration[2] = DustPuff->velocity[2] * -1.23F; + DustPuff->r.scale = flrand(0.15, 0.3); + DustPuff->d_scale = 0.75F; + DustPuff->d_alpha = -1.0F; + + AddEffect(NULL, DustPuff); +} + + +void FXTBDustPuffOnGround(centity_t *owner, int type, int flags, vec3_t origin) +{ + int i; + + for (i = 0; i < 8; i++) + { + FXTBDustPuff(type,flags,origin, i * flrand(30, 60)); + } +} + + +void FXTBSnort(centity_t *owner, int type, int flags, vec3_t origin) +{ +} + +/*=============================== + + Trial Beast's FX handler + + ===============================*/ + +void FXTBEffects(centity_t *owner,int type,int flags, vec3_t org) +{ + paletteRGBA_t LightColor={0,0,255,255}; + vec3_t vel; + byte fx_index; + + fxi.GetEffect(owner, flags, "bv", &fx_index, &vel);//fixme- make this 1 dir and 1 float + + switch (fx_index) + { + case FX_TB_PUFF: + FXTBDustPuffOnGround(owner, type, flags, org); + break; + + case FX_TB_SNORT: + FXTBSnort(owner, type, flags, org); + break; + + default: + break; + } +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_teleport.c b/Toolkit/Programming/GameCode/client effects/fx_teleport.c new file mode 100644 index 0000000..b591d90 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_teleport.c @@ -0,0 +1,213 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Random.h" +#include "Vector.h" +#include "string.h" +#include "Utilities.h" + +#define TELEPORT_RADIUS 400.0 +#define TELEPORT_RADIUS_IN 70.0 +#define ACCEL_SCALE 3.1 +#define ACCEL_SCALE_IN 12.0 + +#define NUM_TELE_PARTS 250 +#define NUM_OF_TELE_PARTS 4 +#define TELE_HEIGHT 10.0 +#define TELE_RAD 50.0 + +#define NUM_TELEPORT_MODELS 2 +static struct model_s *tele_models[NUM_TELEPORT_MODELS]; +void PreCacheTeleport() +{ + tele_models[0] = fxi.RegisterModel("sprites/spells/teleport_1.sp2"); + tele_models[1] = fxi.RegisterModel("sprites/spells/teleport_2.sp2"); +} + +// ----------------------------------------------------------------- + +void PlayerTeleportin(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *teleport_fx; + int i, temp_col; + client_particle_t *p; + paletteRGBA_t color; + int particle_type; + vec3_t angles; + byte *col1; + byte *col2; + byte *col3; + int count; + + // create the teleport effect around the player to begin with + teleport_fx = ClientEntity_new(type, flags, origin, NULL, 410); + teleport_fx->radius = 20.0F; + teleport_fx->AddToView = LinkedEntityUpdatePlacement; + + // determine if this teleport is a spell, or a pad + // set up our colors appropriately + if (!(flags & CEF_FLAG6)) + { + col1 = &color.b; + col2 = &color.g; + col3 = &color.r; + teleport_fx->r.model = tele_models; + } + else + { + col1 = &color.b; + col2 = &color.r; + col3 = &color.g; + teleport_fx->r.model = tele_models + 1; + } + + teleport_fx->r.flags = RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + teleport_fx->r.frame = 0; + teleport_fx->r.scale = 1.8; + teleport_fx->d_scale = -3.0; + + AddEffect(owner, teleport_fx); + + // Use single point particles if we are in software + particle_type = PART_4x4_WHITE | PFL_SOFT_MASK; + + // spawn particles + count = GetScaledCount(NUM_TELE_PARTS, 0.3); + for(i = 0; i < count; i++) + { + temp_col = irand(0, 255); + *col1 = *col2 = temp_col; + *col3 = 255; + color.a = 255; + p = ClientParticle_new(particle_type, color, 400); + + VectorSet(p->velocity, 1.0,1.0,1.0); + VectorSet(angles, flrand(0, 6.28), flrand(0, 6.28), flrand(0, 6.28)); + DirFromAngles(angles,p->velocity); + Vec3ScaleAssign(flrand(TELEPORT_RADIUS-30,TELEPORT_RADIUS), p->velocity); + VectorScale(p->velocity, -ACCEL_SCALE, p->acceleration); + + AddParticleToList(teleport_fx, p); + } +} + + +void PlayerTeleportout(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *teleport_fx; + int i, temp_col; + client_particle_t *p; + paletteRGBA_t color; + int particle_type; + vec3_t angles; + byte *col1; + byte *col2; + byte *col3; + int count; + + // create the teleport effect around the player to begin with + teleport_fx = ClientEntity_new(type, flags, origin, NULL, 410); + teleport_fx->radius = 20.0F; + teleport_fx->AddToView = LinkedEntityUpdatePlacement; + + // determine if this teleport is a spell, or a pad + // set up our colors appropriately + if (!(flags & CEF_FLAG6)) + { + col1 = &color.b; + col2 = &color.g; + col3 = &color.r; + teleport_fx->r.model = tele_models; + } + else + { + col1 = &color.b; + col2 = &color.r; + col3 = &color.g; + teleport_fx->r.model = tele_models + 1; + } + + teleport_fx->r.flags = RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + teleport_fx->r.frame = 0; + teleport_fx->r.scale = 0.5; + teleport_fx->d_scale = 3.0; + + AddEffect(owner, teleport_fx); + + // Use single point particles if we are in software + particle_type = PART_4x4_WHITE | PFL_SOFT_MASK; + + // spawn particles + count = GetScaledCount(NUM_TELE_PARTS, 0.3); + for(i = 0; i < count; i++) + { + temp_col = irand(0, 255); + *col1 = *col2 = temp_col; + *col3 = 255; + color.a = 1; + p = ClientParticle_new(particle_type, color, 400); + + p->d_alpha = 300; + VectorSet(p->origin, 1.0,1.0,1.0); + VectorSet(angles, flrand(0, 6.28), flrand(0, 6.28), flrand(0, 6.28)); + DirFromAngles(angles,p->origin); + Vec3ScaleAssign(flrand(TELEPORT_RADIUS_IN-10,TELEPORT_RADIUS_IN), p->origin); + VectorScale(p->origin, -ACCEL_SCALE_IN, p->acceleration); + + AddParticleToList(teleport_fx, p); + } +} + + +static qboolean FXteleportPadThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *ce; + paletteRGBA_t color; + vec3_t vel, org; + int i; + int count; + + count = GetScaledCount(NUM_OF_TELE_PARTS, 0.7); + for(i = 0; i < count; i++) + { + // Calc spherical offset around left hand ref point + VectorSet(vel, flrand(-1.0, 1.0), flrand(-1.0, 1.0), flrand(-1.0, 1.0)); + if(Vec3IsZero(vel)) + org[2] = 1.0; // Safety in case flrand gens all zeros (VERY unlikely) + VectorNormalize(vel); + VectorScale(vel, TELE_RAD, vel); + + color.c = 0xffffffff; + ce = ClientParticle_new(PART_16x16_SPARK_R | PFL_NEARCULL, color, 400); + VectorCopy(vel, ce->origin); + ce->origin[2] += TELE_HEIGHT; + + VectorScale(vel, -0.125, ce->velocity); + VectorScale(vel, -12.0, ce->acceleration); + ce->scale = 18.0F; + ce->d_scale = -30.0F; + ce->color.a = 1; + ce->d_alpha = 400; + AddParticleToList(self, ce); + } + return(true); +} + +// This is the persistant effect for the teleport pad +void FXTeleportPad(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *glow; + + flags |= CEF_NO_DRAW | CEF_ADDITIVE_PARTS | CEF_VIEWSTATUSCHANGED | CEF_NOMOVE; + glow = ClientEntity_new(type, flags, origin, 0, 110); + glow->Update = FXteleportPadThink; + glow->radius = 100; + AddEffect(owner, glow); +} diff --git a/Toolkit/Programming/GameCode/client effects/fx_tome.c b/Toolkit/Programming/GameCode/client effects/fx_tome.c new file mode 100644 index 0000000..84ded58 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_tome.c @@ -0,0 +1,255 @@ +// +// fx_tome.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Reference.h" +#include "Utilities.h" +#include "ce_dlight.h" + +#define TOME_RADIUS 5.0 +#define TOME_SCALE 10.0 +#define TOME_ACCEL (-64.0) +#define TOME_ORBIT_DIST 20.0 +#define TORCH_ORBIT_DIST 38.0 +#define TOME_ORBIT_SCALE 0.0025 +#define TORCH_ORBIT_SCALE 0.0025 +#define TOME_SPIN_FACTOR 0.004 + +#define DURATION_OF_TORCH 450 +#define TIME_TO_FADE_TORCH 50 +#define TIME_TO_FADE_TOME 30 +#define TOME_INCOMING_ORBIT TOME_ORBIT_DIST/TIME_TO_FADE_TOME +#define TORCH_INCOMING_ORBIT TORCH_ORBIT_DIST/TIME_TO_FADE_TORCH +#define AMOUNT_TO_FADE_TORCH 255/TIME_TO_FADE_TORCH + +#define NUM_TORCH_MODELS 2 +static struct model_s *torch_models[NUM_TORCH_MODELS]; +void PreCacheTorch() +{ + torch_models[0] = fxi.RegisterModel("sprites/lens/halo1.sp2"); + torch_models[1] = fxi.RegisterModel("models/Spells/book/tris.fm"); +} + +// update the position of the Tome of power relative to its owner +qboolean FXROTTomeAddToView(client_entity_t *tome, centity_t *owner) +{ + float difftime; + + VectorSet(tome->r.origin, + cos(fxi.cl->time*TOME_ORBIT_SCALE)*TOME_ORBIT_DIST, + sin(fxi.cl->time*TOME_ORBIT_SCALE)*TOME_ORBIT_DIST, + (15.0 + sin(fxi.cl->time*0.0015)*12.0)); + VectorAdd(owner->origin, tome->r.origin, tome->r.origin); + VectorCopy(tome->r.origin, tome->origin); + + // Set up the last think time. + difftime = fxi.cl->time - tome->SpawnData; + tome->SpawnData = fxi.cl->time; + + // Rotate the book + tome->r.angles[YAW] += difftime*TOME_SPIN_FACTOR; + + return(true); +} + +// update the position of the Tome of power relative to its owner +qboolean FXHomeTomeAddToView(client_entity_t *tome, centity_t *owner) +{ + float tome_orbit; + float difftime; + + tome_orbit = tome->SpawnInfo * TOME_INCOMING_ORBIT; + + VectorSet(tome->r.origin, + cos(fxi.cl->time*TOME_ORBIT_SCALE)*tome_orbit, + sin(fxi.cl->time*TOME_ORBIT_SCALE)*tome_orbit, + (15.0 + sin(fxi.cl->time*0.0015)*12.0)*tome->SpawnInfo/TIME_TO_FADE_TOME); + VectorAdd(owner->origin, tome->r.origin, tome->r.origin); + VectorCopy(tome->r.origin, tome->origin); + + // Set up the last think time. + difftime = fxi.cl->time - tome->SpawnData; + tome->SpawnData = fxi.cl->time; + + // Rotate the book + tome->r.angles[YAW] += difftime*TOME_SPIN_FACTOR; + + return(true); +} + +// update that Tome of power, so that more sparkles zip out of it, and the light casts pulses +qboolean FXTomeThink(client_entity_t *tome, centity_t *owner) +{ + client_particle_t *spark; + int i; + + // are we waiting for the shrine light to vanish ? + if (tome->SpawnInfo) + { + if(!(--tome->SpawnInfo)) + return(false); + } + // no, could either be no light, or light still active + else + { + tome->dlight->intensity = 150.0 + (cos(fxi.cl->time * 0.01) * 20.0); + if (!(owner->current.effects & EF_POWERUP_ENABLED)) + { + tome->AddToView = FXHomeTomeAddToView; + tome->SpawnInfo = TIME_TO_FADE_TOME; + tome->d_alpha = -0.18; + } + } + +// Brian P wanted this removed. I thought it was cool though. Jake + return(true); + for(i = 0; i < 4; i++) + { + spark = ClientParticle_new(PART_16x16_STAR, tome->color, 2000); + + VectorSet(spark->origin, flrand(-TOME_RADIUS, TOME_RADIUS), flrand(-TOME_RADIUS, TOME_RADIUS), flrand(-TOME_RADIUS, TOME_RADIUS)); + VectorAdd(tome->origin, spark->origin, spark->origin); + spark->scale = TOME_SCALE; + VectorSet(spark->velocity, flrand(-20.0, 20.0), flrand(-20.0, 20.0), flrand(-10.0, 10.0)); + spark->acceleration[2] = TOME_ACCEL; + spark->d_scale = flrand(-20.0, -15.0); + spark->d_alpha = flrand(-500.0, -400.0); + spark->duration = 1000; + + AddParticleToList(tome, spark); + } + return(true); +} + +// original version of the tome of power. Casts a blue light etc +void FXTomeOfPower(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *tome; + + tome = ClientEntity_new(type, flags, origin, NULL, 100); + + // Test model + tome->r.model = torch_models + 1; + tome->r.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + tome->flags |= CEF_ADDITIVE_PARTS | CEF_ABSOLUTE_PARTS; + tome->r.scale = 0.55; + tome->color.c = 0xe5ff2020; + tome->radius = 128; + tome->Update = FXTomeThink; + tome->AddToView = FXROTTomeAddToView; + tome->dlight = CE_DLight_new(tome->color, 150.0F, 00.0F); + tome->SpawnData = fxi.cl->time; + tome->SpawnInfo = 0; + + AddEffect(owner, tome); +} + + +/////////// TORCH STUFF + +// update the position of the Tome of power relative to its owner +qboolean FXROTTorchAddToView(client_entity_t *tome, centity_t *owner) +{ + float difftime; + + VectorSet(tome->r.origin, + cos(fxi.cl->time*TORCH_ORBIT_SCALE)*TORCH_ORBIT_DIST, + sin(fxi.cl->time*TORCH_ORBIT_SCALE)*TORCH_ORBIT_DIST, + (25.0 + sin(fxi.cl->time*0.0015)*16.0)); + VectorAdd(owner->origin, tome->r.origin, tome->r.origin); + VectorCopy(tome->r.origin, tome->origin); + + // Set up the last think time. + difftime = fxi.cl->time - tome->SpawnData; + tome->SpawnData = fxi.cl->time; + + // Rotate the book + tome->r.angles[YAW] += difftime*TOME_SPIN_FACTOR; + + return(true); +} + + +// update the position of the Tome of power relative to its owner +qboolean FXHomeTorchAddToView(client_entity_t *tome, centity_t *owner) +{ + float tome_orbit; + float difftime; + + tome_orbit = tome->SpawnInfo * TORCH_INCOMING_ORBIT; + + VectorSet(tome->r.origin, + cos(fxi.cl->time*TORCH_ORBIT_SCALE)*tome_orbit, + sin(fxi.cl->time*TORCH_ORBIT_SCALE)*tome_orbit, + (25.0 + sin(fxi.cl->time*0.0015)*16.0)*tome->SpawnInfo/TIME_TO_FADE_TORCH); + VectorAdd(owner->origin, tome->r.origin, tome->r.origin); + VectorCopy(tome->r.origin, tome->origin); + + // Set up the last think time. + difftime = fxi.cl->time - tome->SpawnData; + tome->SpawnData = fxi.cl->time; + + // Rotate the book + tome->r.angles[YAW] += difftime*TOME_SPIN_FACTOR; + + return(true); +} + + +// make the light follow us +static FXplayertorch_think(struct client_entity_s *self,centity_t *owner) +{ + // kill us if we are done + if (owner->current.effects & EF_LIGHT_ENABLED) + return(true); + else + if (!(self->SpawnInfo)) + { + self->AddToView = FXHomeTorchAddToView; + self->SpawnInfo = TIME_TO_FADE_TORCH; + self->d_alpha = -0.18; + return(true); + } + + if (!(--self->SpawnInfo)) + return(false); + + // decrement the amount of light the torch gives out + if (self->SpawnInfo < TIME_TO_FADE_TORCH) + self->dlight->intensity -= AMOUNT_TO_FADE_TORCH; + + return (true); +} + +// light that the player gives off when he has this powerup +void FXplayertorch(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *effect; + + effect = ClientEntity_new(type, flags, origin, NULL, 100); + effect->r.model = torch_models; + effect->r.flags |= RF_FULLBRIGHT | RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + effect->r.scale = .35; + effect->color.c = 0xffffff; + effect->dlight = CE_DLight_new(effect->color, 250.0F, 0.0F); + effect->Update = FXplayertorch_think; + effect->AddToView = FXROTTorchAddToView; + effect->SpawnData = fxi.cl->time; + effect->alpha = 0.7; + AddEffect(owner, effect); + effect->d_alpha = 0; + +} + + +// end diff --git a/Toolkit/Programming/GameCode/client effects/fx_wall.c b/Toolkit/Programming/GameCode/client effects/fx_wall.c new file mode 100644 index 0000000..920bd08 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_wall.c @@ -0,0 +1,778 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "ce_DefaultMessageHandler.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "angles.h" +#include "Vector.h" +#include "Matrix.h" +#include "Random.h" +#include "Utilities.h" +#include "motion.h" +#include "Reference.h" +#include "ce_Dlight.h" +#include "q_Sprite.h" +#include "g_playstats.h" + + +#define NUM_WALL_MODELS 3 + +static struct model_s *wall_models[NUM_WALL_MODELS]; + +void PreCacheWall() +{ + wall_models[0] = fxi.RegisterModel("sprites/spells/wflame.sp2"); + wall_models[1] = fxi.RegisterModel("sprites/spells/wflame2.sp2"); + wall_models[2] = fxi.RegisterModel("sprites/fx/halo.sp2"); +} + + + + +// ***************************************************************** +// The fire wall +// Powered up +// ***************************************************************** + + +#define FIREWORM_LIFETIME 1.0 +#define FIREWORM_BLASTLIFE 0.25 +#define FIREWORM_LIFETIME_MS (FIREWORM_LIFETIME * 1000) +#define FIREWORM_ACCEL (-1000.0) +#define FIREWORM_INITVEL (-0.5 * FIREWORM_LIFETIME * FIREWORM_ACCEL) +#define FIREWORM_TRAILVEL 128 +#define FIREWORM_BLASTVEL 128 +#define FIREWORM_BLASTNUM 12 +#define FIREWORM_BLASTRAD 32 + +static qboolean FXFireWormThink(client_entity_t *worm, centity_t *owner) +{ + client_entity_t *blast; + client_particle_t *spark, *spark2; + vec3_t diffpos; + float dtime, dtime2; + float anginc, ang; + int i; + paletteRGBA_t color; + + dtime = (fxi.cl->time - worm->startTime)/FIREWORM_LIFETIME_MS; + dtime2 = dtime * dtime * 0.5; + + color.c = 0xffffffff; + + if (dtime > FIREWORM_LIFETIME) + { // Impact at the centerpoint. + if (worm->SpawnInfo == 0 || dtime > FIREWORM_LIFETIME+FIREWORM_BLASTLIFE) + { // Do nothing, wait for blast to expire. + worm->nextThinkTime = fxi.cl->time + 500; + worm->Update = RemoveSelfAI; + return true; + } + else + { + blast = ClientEntity_new(FX_WEAPON_FIREWAVE, CEF_ADDITIVE_PARTS, worm->endpos, NULL, 500); + blast->r.model = wall_models + 2; + blast->r.frame = 2; // Circular halo for blast. + blast->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + blast->alpha = 0.95; + blast->d_alpha = -0.5; + blast->r.scale = 0.25*worm->r.scale; + blast->d_scale = -3.0*worm->r.scale; + VectorSet(blast->velocity, + flrand(-0.25*FIREWORM_BLASTVEL*worm->r.scale, 0.25*FIREWORM_BLASTVEL*worm->r.scale), + flrand(-0.25*FIREWORM_BLASTVEL*worm->r.scale, 0.25*FIREWORM_BLASTVEL*worm->r.scale), + flrand(0, 0.25*FIREWORM_BLASTVEL*worm->r.scale)); + AddEffect(NULL, blast); + + // Spray out in a big ring + ang = flrand(0, M_PI*2.0); + anginc = (M_PI * 2.0) / FIREWORM_BLASTNUM; + for (i=0; i<8; i++) + { + diffpos[0] = cos(ang); + diffpos[1] = sin(ang); + diffpos[2] = 0; + ang += anginc; + + // Higher particle + spark = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), color, 500); + + VectorScale(diffpos, FIREWORM_BLASTRAD*worm->r.scale, spark->origin); + VectorScale(diffpos, flrand(0.45, 0.5)*FIREWORM_BLASTVEL*worm->r.scale, spark->velocity); + spark->velocity[2] += flrand(0.80, 1.0)*FIREWORM_BLASTVEL*worm->r.scale; + + spark->color.a = 254; + spark->d_alpha = flrand(-512.0, -768.0); + spark->scale = 16.0*worm->r.scale; + spark->d_scale = flrand(8.0, 16.0)*worm->r.scale; + + AddParticleToList(blast, spark); + + // Lower to ground particle + spark2 = ClientParticle_new(irand(PART_16x16_FIRE1, PART_16x16_FIRE3), color, 500); + + VectorCopy(spark->origin, spark2->origin); + VectorCopy(spark->velocity, spark2->velocity); + spark2->velocity[2] *= 0.33; + + spark2->color.a = 254; + spark2->d_alpha = flrand(-512.0, -768.0); + spark2->scale = 16.0*worm->r.scale; + spark2->d_scale = flrand(8.0, 16.0)*worm->r.scale; + + AddParticleToList(blast, spark2); + } + + // Spray up in a little fountain too. + for (i=0; i<4; i++) + { + spark = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), color, 500); + + VectorSet(spark->velocity, + flrand(-0.1*FIREWORM_BLASTVEL*worm->r.scale, 0.1*FIREWORM_BLASTVEL*worm->r.scale), + flrand(-0.1*FIREWORM_BLASTVEL*worm->r.scale, 0.1*FIREWORM_BLASTVEL*worm->r.scale), + flrand(-0.2*FIREWORM_BLASTVEL*worm->r.scale, 0.2*FIREWORM_BLASTVEL*worm->r.scale)); + spark->velocity[2] += FIREWORM_BLASTVEL; + + spark->color.a = 254; + spark->d_alpha = flrand(-512.0, -768.0); + spark->scale = 16.0*worm->r.scale; + spark->d_scale = flrand(-8.0, -16.0); + + AddParticleToList(blast, spark); + } + } + + return true; + } + + // Continue snaking to target. + +// VectorSubtract(worm->endpos, worm->startpos, diffpos); + + // Move linearly to the target. +// VectorMA(worm->startpos, dtime, diffpos, worm->r.origin); + // Now add in an additional arc. +// worm->r.origin[2] += FIREWORM_INITVEL*dtime + FIREWORM_ACCEL*dtime2; +// worm->velocity[2] = (diffpos[2]/FIREWORM_LIFETIME) + FIREWORM_INITVEL + FIREWORM_ACCEL*dtime; + + // Add a trail entity and particle trail segment. + blast = ClientEntity_new(FX_WEAPON_FIREWAVE, CEF_NO_DRAW | CEF_ADDITIVE_PARTS, worm->r.origin, NULL, 500); + VectorClear(blast->velocity); + AddEffect(NULL, blast); + + for (i=0; i<4; i++) + { +// spark = ClientParticle_new(irand(PART_16x16_FIRE1, PART_16x16_FIRE3), color, 500); + spark = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), color, 500); + + VectorSet(spark->velocity, + flrand(-0.25*FIREWORM_TRAILVEL, 0.25*FIREWORM_TRAILVEL), + flrand(-0.25*FIREWORM_TRAILVEL, 0.25*FIREWORM_TRAILVEL), + flrand(-0.25*FIREWORM_TRAILVEL, 0.25*FIREWORM_TRAILVEL)); + VectorMA(spark->velocity, 0.5, worm->velocity, spark->velocity); + VectorScale(spark->velocity, -2.0, spark->acceleration); + + spark->color.a = 254; + spark->d_alpha = flrand(-512.0, -768.0); + spark->scale = 20.0*worm->r.scale; + spark->d_scale = flrand(8.0, 16.0)*worm->r.scale; + + AddParticleToList(blast, spark); + } + + return true; +} + + +#define FIREWAVE_TRACEDOWN (128) +#define FIREWAVE_WORM_TIME (0.5*1000) +#define FIREWAVE_BLAST_NUM 4 +#define FIREWAVE_IMPACT_NUM 2 + +static FXFireWaveImpact(client_entity_t *wall) +{ + client_entity_t *blast; + vec3_t blastpt, spawnvel; + int i; + + VectorScale(wall->direction, -48.0, blastpt); + VectorAdd(blastpt, wall->r.origin, blastpt); + VectorScale(wall->direction, -64.0, spawnvel); + + // Add some blasty bits along a line + for (i=0; ir.model = wall_models+2; + blast->r.frame = 2; + blast->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + blast->radius = 64.0; + + blast->alpha = 0.95; + blast->r.scale = 1.6; + blast->d_scale = -2.0; + blast->d_alpha = -2.0; + + VectorMA(spawnvel, flrand(-0.2, -0.1), wall->velocity, blast->velocity); + + AddEffect(NULL, blast); + } +} + + +static qboolean FXFireWaveThink(client_entity_t *wall, centity_t *owner) +{ + client_entity_t *blast, *worm; + vec3_t destpt, spawnpt, spawnvel, bottom, minmax={0,0,0}; + trace_t trace; + qboolean hitground=false; + int i; + float value, scale, detailscale; + + switch((int)(r_detail->value)) + { + case DETAIL_LOW: + detailscale = 0.5; + break; + case DETAIL_HIGH: + detailscale = 0.9; + break; + case DETAIL_UBERHIGH: + detailscale = 1.0; + break; + case DETAIL_NORMAL: + default: + detailscale = 0.7; + break; + } + + if (owner->current.effects & EF_ALTCLIENTFX) + { // Time for this wall to die. + if (wall->SpawnInfo != 1) + { + // Wait one second before disappearing. + VectorClear(wall->velocity); + wall->lastThinkTime = fxi.cl->time + 1000; + wall->SpawnInfo = 1; + FXFireWaveImpact(wall); + return true; + } + else if (wall->lastThinkTime > fxi.cl->time) + { // Still some time left to live... + wall->dlight->intensity -= 20.0; + return true; + } + else + { // Time's up + return false; + } + } + + // Update radius + wall->radius = FIREWAVE_RADIUS + (fxi.cl->time - wall->startTime)*(FIREWAVE_DRADIUS/1000.0); + if (wall->dlight->intensity < 250.0) + wall->dlight->intensity += 15.0; + + // Add some blasty bits along a line + for (i=0; iradius, wall->right, spawnpt); + VectorSet(spawnvel, flrand(-16.0,16.0), flrand(-16.0,16.0), 0.0); + scale = 1-value; + break; + case 1: // Throw blast right + value = flrand(0.2, 0.8); + VectorMA(spawnpt, value*wall->radius, wall->right, spawnpt); + VectorSet(spawnvel, flrand(-16.0,16.0), flrand(-16.0,16.0), 0.0); + scale = 1-value; + break; + case 2: // Blast about at the center + spawnpt[2] -= flrand(0, 0.2)*FIREWAVE_DOWN; + scale = 0.8; + break; + case 3: + default: // Throw blast down + VectorMA(spawnpt, flrand(-0.4,0.4)*wall->radius, wall->right, spawnpt); + spawnpt[2] -= flrand(0.3,0.6)*FIREWAVE_DOWN; + scale = 0.8; + break; + } + + VectorAdd(spawnpt, wall->r.origin, spawnpt); + // vary a bit above or below the wall as well... + spawnpt[2] += FIREWAVE_UP; + + blast = ClientEntity_new(FX_WEAPON_FIREWAVE, CEF_PULSE_ALPHA, spawnpt, NULL, 500); + blast->r.model = wall_models; + blast->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + blast->radius = 64.0; + + VectorMA(spawnvel, flrand(0.1, 0.2), wall->velocity, blast->velocity); + blast->acceleration[2] += -300.0; + blast->alpha = 0.01; + blast->d_alpha = flrand(4.0, 5.0); + blast->r.scale = scale*detailscale; + blast->d_scale = scale*detailscale * flrand(-1.0, -1.5); + + AddEffect(NULL, blast); + + // Spawn along the bottom line of the wall + VectorSet(spawnpt, flrand(-6.0,6.0), flrand(-6.0,6.0), flrand(-6.0,6.0)); + switch(i) + { + case 0: // Throw blast left + value = flrand(0.2, 0.8); + VectorMA(spawnpt, -value*wall->radius, wall->right, spawnpt); + VectorSet(spawnvel, flrand(-16.0,16.0), flrand(-16.0,16.0), 0.0); + scale = 1-value; + break; + case 1: // Throw blast right + value = flrand(0.2, 0.8); + VectorMA(spawnpt, value*wall->radius, wall->right, spawnpt); + VectorSet(spawnvel, flrand(-16.0,16.0), flrand(-16.0,16.0), 0.0); + scale = 1-value; + break; + case 2: // Blast about at the center + spawnpt[2] += flrand(0, 0.2)*FIREWAVE_DOWN; + scale = 0.8; + break; + case 3: + default: // Throw blast down + VectorMA(spawnpt, flrand(-0.4,0.4)*wall->radius, wall->right, spawnpt); + spawnpt[2] += flrand(0.3,0.6)*FIREWAVE_DOWN; + scale = 0.8; + break; + } + + VectorAdd(spawnpt, wall->r.origin, spawnpt); + // vary a bit above or below the wall as well... + spawnpt[2] -= FIREWAVE_DOWN; + + blast = ClientEntity_new(FX_WEAPON_FIREWAVE, CEF_PULSE_ALPHA, spawnpt, NULL, 500); + blast->r.model = wall_models; + blast->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + blast->radius = 64.0; + + VectorMA(spawnvel, flrand(0.1, 0.2), wall->velocity, blast->velocity); + blast->acceleration[2] += 300.0; + blast->alpha = 0.01; + blast->d_alpha = flrand(4.0, 5.0); + blast->r.scale = scale*detailscale; + blast->d_scale = scale*detailscale * flrand(-1.0, -1.5); + + AddEffect(NULL, blast); + } + + if (fxi.cl->time >= wall->nextEventTime) + { // Spawn a worm. + + // Find a random spot somewhere to have a fire worm hit. + VectorMA(wall->r.origin, flrand(-1.0,1.0) * wall->radius, wall->right, destpt); + + // Trace back a little bit and spawn the fire worm there. + VectorMA(destpt, -0.5*FIREWORM_LIFETIME, wall->velocity, spawnpt); + + // Trace down a bit to look for a nice place to spawn stuff. + VectorCopy(destpt, bottom); + bottom[2] -= FIREWAVE_TRACEDOWN; + fxi.Trace(destpt, minmax, minmax, bottom, CONTENTS_SOLID, CEF_CLIP_TO_WORLD, &trace); + + if(trace.fraction < .99) + { // Hit the ground, smack it!!! + VectorCopy(trace.endpos, destpt); + hitground = true; + } + + worm = ClientEntity_new(FX_WEAPON_FIREWAVE, CEF_ADDITIVE_PARTS, spawnpt, NULL, 75); + worm->r.model = wall_models+2; + worm->r.frame = 2; + worm->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + worm->radius = 64.0; + + VectorCopy(spawnpt, worm->startpos); + VectorCopy(destpt, worm->endpos); + worm->alpha = 0.95; + + // New worm, but a small one. + worm->r.scale = 0.5*detailscale; + + worm->Update = FXFireWormThink; + worm->color.c = 0xff0080ff; + worm->dlight = CE_DLight_new(worm->color, 128.0, 0.0); + VectorCopy(wall->velocity, worm->velocity); + worm->velocity[2] += FIREWORM_INITVEL; + worm->acceleration[2] = FIREWORM_ACCEL; + + if (hitground) + worm->SpawnInfo = 1; + + AddEffect(NULL, worm); + + FXFireWormThink(worm, NULL); + + wall->nextEventTime = fxi.cl->time + (flrand(0.8,1.2)*FIREWAVE_WORM_TIME); + } + + return true; +} + + +// Create Effect FX_WEAPON_FIREWAVE +void FXFireWave(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *wall; + + wall = ClientEntity_new(type, flags | CEF_NO_DRAW | CEF_DONT_LINK, origin, NULL, 150); + fxi.GetEffect(owner, flags, "ff", &wall->r.angles[YAW], &wall->r.angles[PITCH]); + AngleVectors(wall->r.angles, wall->direction, wall->right, NULL); + + if (flags & CEF_FLAG8) // Since we're in deathmatch, throw it faster. + VectorScale(wall->direction, FIREWAVE_DM_SPEED, wall->velocity); + else + VectorScale(wall->direction, FIREWAVE_SPEED, wall->velocity); + + if (flags&CEF_FLAG6) + { // Add a tad of left velocity + VectorMA(wall->velocity, -FIREWAVE_DRADIUS, wall->right, wall->velocity); + } + else if (flags&CEF_FLAG7) + { // Add a tad of right velocity + VectorMA(wall->velocity, FIREWAVE_DRADIUS, wall->right, wall->velocity); + } + + wall->Update = FXFireWaveThink; + wall->radius = FIREWAVE_RADIUS; + wall->color.c = 0xff00afff; + wall->dlight = CE_DLight_new(wall->color, 120.0F, 0.0F); + wall->nextEventTime = fxi.cl->time + (flrand(0,1.0)*FIREWAVE_WORM_TIME); + wall->SpawnInfo = 0; + + AddEffect(owner, wall); +} + + + +// Create Effect FX_WEAPON_FIREWAVEWORM +void FXFireWaveWorm(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *worm; + vec3_t fwd, spawnpt; + vec3_t bottom, minmax={0,0,0}; + trace_t trace; + float detailscale; + + switch((int)(r_detail->value)) + { + case DETAIL_LOW: + detailscale = 0.5; + break; + case DETAIL_HIGH: + detailscale = 0.9; + break; + case DETAIL_UBERHIGH: + detailscale = 1.0; + break; + case DETAIL_NORMAL: + default: + detailscale = 0.7; + break; + } + + fxi.GetEffect(owner, flags, "t", fwd); // Gets the movedir of the wall. + + // Trace back half a second and get the proper spawn location. + VectorMA(origin, -0.5*FIREWORM_LIFETIME*FIREWAVE_SPEED, fwd, spawnpt); + + // Trace down a bit to look for a nice place to spawn stuff. + VectorCopy(spawnpt, bottom); + bottom[2] -= FIREWAVE_TRACEDOWN; + fxi.Trace(spawnpt, minmax, minmax, bottom, CONTENTS_SOLID, CEF_CLIP_TO_WORLD, &trace); + + if(trace.fraction < .99) + { // Hit the ground, smack it!!! + VectorCopy(trace.endpos, spawnpt); + } + + worm = ClientEntity_new(FX_WEAPON_FIREWAVE, flags | CEF_ADDITIVE_PARTS, spawnpt, NULL, 75); + worm->r.model = wall_models+2; + worm->r.frame = 2; + worm->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + worm->radius = 64.0; + + VectorCopy(spawnpt, worm->startpos); + VectorCopy(origin, worm->endpos); + worm->alpha = 0.95; + worm->r.scale = 1.5*detailscale; + worm->Update = FXFireWormThink; + worm->color.c = 0xff0080ff; + worm->dlight = CE_DLight_new(worm->color, 128.0, 0.0); + VectorScale(fwd, FIREWAVE_SPEED, worm->velocity); + worm->velocity[2] += FIREWORM_INITVEL; + worm->acceleration[2] = FIREWORM_ACCEL; + + worm->SpawnInfo = 1; + + AddEffect(NULL, worm); + + FXFireWormThink(worm, NULL); +} + + + + + +// ***************************************************************** +// The fire blast +// Unpowered +// ***************************************************************** + +static FXFireBurstImpact(client_entity_t *wall) +{ + client_entity_t *blast; + vec3_t blastpt, spawnvel, blastvel; + int i; + + VectorScale(wall->direction, -48.0, blastpt); + VectorAdd(blastpt, wall->r.origin, blastpt); + VectorScale(wall->direction, -64.0, spawnvel); + + // Add some blasty bits along a line + for (i=0; iright, blastvel); + } + else + { // Throw blast to the left + VectorMA(spawnvel, -128.0, wall->right, blastvel); + } + + blast = ClientEntity_new(FX_WEAPON_FIREBURST, 0, blastpt, NULL, 500); + blast->r.model = wall_models+2; + blast->r.frame = 2; + blast->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + blast->radius = 64.0; + + blast->alpha = 0.95; + blast->r.scale = 1.2; + blast->d_scale = -2.0; + blast->d_alpha = -2.0; + + VectorMA(blastvel, flrand(-0.2, -0.1), wall->velocity, blast->velocity); + + AddEffect(NULL, blast); + } +} + + + +#define FIREBURST_PART_SPEED 160 + +static qboolean FXFireBurstThink(client_entity_t *wall, centity_t *owner) +{ + client_entity_t *burst; + + vec3_t newDir; + vec3_t origin, org; + int i, j; + float ang2; + float numFlameColumns; + int edgeVal; + paletteRGBA_t color; + float dtime, detailscale; + + if (owner->current.effects & EF_ALTCLIENTFX) + { // Time for this wall to die. + if (wall->SpawnInfo != 1) + { + // Wait one second before disappearing. + VectorClear(wall->velocity); + wall->lastThinkTime = fxi.cl->time + 1000; + wall->SpawnInfo = 1; + FXFireBurstImpact(wall); + return true; + } + else if (wall->lastThinkTime > fxi.cl->time) + { // Still some time left to live... + wall->dlight->intensity -= 20.0; + return true; + } + else + { // Time's up + return false; + } + } + + switch((int)(r_detail->value)) + { + case DETAIL_LOW: + detailscale = 0.6; + break; + case DETAIL_HIGH: + detailscale = 0.9; + break; + case DETAIL_UBERHIGH: + detailscale = 1.0; + break; + case DETAIL_NORMAL: + default: + detailscale = 0.75; + break; + } + + color.c = 0xe5007fff; + if (wall->dlight->intensity < 250.0) + wall->dlight->intensity += 15.0; + + dtime = 1.0 + ((fxi.cl->time - wall->lastThinkTime) * (FIREBLAST_DRADIUS/1000.0)); + wall->radius = FIREBLAST_RADIUS*dtime; + + VectorMA(wall->r.origin, -24, wall->direction, origin); + + numFlameColumns = GetScaledCount(8, 0.8) + 4; + + for(i = 0; i < numFlameColumns; i++) + { + ang2 = (M_PI) * (float)i/((float)numFlameColumns-1); + + VectorScale(wall->right, cos(ang2)*dtime, newDir); + VectorMA(newDir, sin(ang2), wall->direction, newDir); + + VectorCopy(origin, org); + org[2] -= 16; + VectorMA(org, 16.0, newDir, org); + + edgeVal = abs((numFlameColumns/2)-i)*(12.0/numFlameColumns); + + j=1; +// for(j = 0; j < 2; j++) + { + burst = ClientEntity_new(FX_WEAPON_FIREBURST, 0, org, NULL, 1000); + + burst->r.model = wall_models + 1; + + burst->r.flags = RF_TRANSLUCENT | RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + burst->r.frame = 0; + + VectorScale(newDir, FIREBURST_PART_SPEED + irand(0, 40) - (edgeVal*10) + (j*20), burst->velocity); + burst->velocity[2] += j * (90 - (edgeVal*9)) + flrand(0, 10); + + if(i&1) + { + burst->velocity[2] *= .5; + } + + burst->r.scale = flrand(0.5, 0.75)*detailscale; + burst->radius = 20.0; + burst->d_scale = 1.0; + burst->d_alpha = -2.5; + + burst->origin[0] += irand(-32, 32); + burst->origin[1] += irand(-32, 32); + burst->origin[2] += irand(-16, 16); + + burst->acceleration[2] = flrand(16, 64); + burst->velocity[2] += flrand(16, 64); + + AddEffect(NULL,burst); + + if(((i == 0)||(i == numFlameColumns-1))&&(j == 1)) + { + burst->dlight = CE_DLight_new(color, 150.0F, -250.0F); + } + } + } + + return true; +} + + +// Create effect FX_WEAPON_FIREBURST +void FXFireBurst(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *wall; + client_particle_t *spark; + vec3_t fwd; + int i; + + wall = ClientEntity_new(type, flags | CEF_NO_DRAW | CEF_ADDITIVE_PARTS | CEF_ABSOLUTE_PARTS | CEF_DONT_LINK, origin, NULL, 150); + fxi.GetEffect(owner, flags, "ff", &wall->r.angles[YAW], &wall->r.angles[PITCH]); + + // The Build the velocity out of the fwd vector constructed from the two angles given. + AngleVectors(wall->r.angles, fwd, wall->right, NULL); + VectorScale(fwd, FIREBLAST_SPEED, wall->velocity); + + // Zero out the direction Z velocity because it isn't used during the think. + VectorCopy(fwd, wall->direction); + wall->direction[2] = 0.0; + wall->right[2] = 0.0; + +// wall->r.model = wall_models + 1; +// wall->alpha = 0.01; + + wall->Update = FXFireBurstThink; + wall->radius = FIREBLAST_RADIUS; + wall->color.c = 0xff00afff; +// wall->r.scale = 8.0; +// wall->d_scale = 56.0; + wall->dlight = CE_DLight_new(wall->color, 150.0F, 0.0F); + wall->lastThinkTime = fxi.cl->time; + + AddEffect(owner, wall); + + // Okay, this weapon feels REALLY weak at launch, so I'm going to add a little punch to it. + + // Add a big ol' flash. + wall = ClientEntity_new(type, flags | CEF_ADDITIVE_PARTS, origin, NULL, 1000); + wall->r.model = wall_models + 2; // The starry halo. + wall->r.flags |= RF_TRANS_ADD | RF_TRANS_ADD_ALPHA; + wall->radius = 64.0; + + wall->r.scale = 0.1; + wall->d_scale = 4.0; + wall->alpha = 0.95; + wall->d_alpha = -2.0; + wall->color.c = 0xffffffff; + VectorScale(fwd, FIREBLAST_SPEED*0.15, wall->velocity); + + AddEffect(NULL, wall); + + // And add a bunch o' particle blasty bits to it + for (i=0; i<25; i++) + { + spark = ClientParticle_new(irand(PART_32x32_FIRE0, PART_32x32_FIRE2), wall->color, 1000); + VectorSet(spark->velocity, + flrand(-0.1*FIREBLAST_SPEED, 0.1*FIREBLAST_SPEED), + flrand(-0.1*FIREBLAST_SPEED, 0.1*FIREBLAST_SPEED), + flrand(-0.1*FIREBLAST_SPEED, 0.1*FIREBLAST_SPEED)); + VectorAdd(wall->velocity, spark->velocity, spark->velocity); + spark->d_alpha = flrand(-256.0, -512.0); + spark->scale = 4.0; + spark->d_scale = flrand(8.0, 16.0); + + AddParticleToList(wall, spark); + } +} + diff --git a/Toolkit/Programming/GameCode/client effects/fx_waterentrysplash.c b/Toolkit/Programming/GameCode/client effects/fx_waterentrysplash.c new file mode 100644 index 0000000..339d932 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_waterentrysplash.c @@ -0,0 +1,235 @@ +// +// fx_waterentrysplash.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" + +#define NUM_SPLASH_MODELS 2 +static struct model_s *water_models[NUM_SPLASH_MODELS]; +void PreCacheWaterSplash() +{ + water_models[0] = fxi.RegisterModel("sprites/fx/waterentryripple.sp2"); + water_models[1] = fxi.RegisterModel("sprites/fx/wfall.sp2"); +} + +// ----------------------------------------------------------------- + +#define SCALE 0.3 +#define SPLASH_RADIUS 20 + +static qboolean FXWaterEntrySplashThinkerThink(struct client_entity_s *Self,centity_t *Owner); +static void WaterEntryParticles(struct client_entity_s *Owner, float Radius, int NumParticles); + +// ************************************************************************************************ +// FXWaterEntryRippleThinkerThink +// ------------------------------ +// ************************************************************************************************ + +static qboolean FXWaterEntrySplashThinkerThink(struct client_entity_s *Self,centity_t *Owner) +{ + client_entity_t *EntryRipple; + + // Have enough ripples been created yet? If not, create one, else free myself. + + if(Self->NoOfAnimFrames>0) + { + // Create a water entry ripple. + + EntryRipple=ClientEntity_new(FX_WATER_ENTRYSPLASH, + Self->flags&~(CEF_OWNERS_ORIGIN|CEF_NO_DRAW), + Self->origin, + Self->direction, + 1200); + + EntryRipple->r.model = water_models; + EntryRipple->r.scale=SCALE; + EntryRipple->r.frame=0; + EntryRipple->r.flags=RF_FIXED | RF_TRANSLUCENT | RF_ALPHA_TEXTURE; + EntryRipple->alpha=0.6; + EntryRipple->d_scale=1.0; + EntryRipple->d_alpha=Self->d_alpha; + + AddEffect(NULL,EntryRipple); + + Self->NoOfAnimFrames--; + return(true); + } + else + return(false); +} + +// ************************************************************************************************ +// WaterEntryParticles +// ------------------- +// ************************************************************************************************ + +static void WaterEntryParticles(struct client_entity_s *Owner,float Radius,int NumParticles) +{ + float Theta,DeltaTheta; + client_particle_t *Particle; + paletteRGBA_t color; + + if (NumParticles<1||NumParticles>500) + return; + DeltaTheta=(2*M_PI)/NumParticles; + + for(Theta=0.0;Theta<(2*M_PI);Theta+=DeltaTheta) + { + color.c=0xffffffff; + color.a = irand(128, 200); + + Particle=ClientParticle_new(PART_4x4_WHITE,color,1000); + + Particle->origin[0]=Radius*cos(Theta); + Particle->origin[1]=Radius*sin(Theta); + Particle->origin[2]=0.0; + + Particle->velocity[0]=flrand(0.0,50.0)*Particle->origin[0]*0.05; + Particle->velocity[1]=flrand(0.0,50.0)*Particle->origin[1]*0.05; + Particle->velocity[2]=flrand(50.0,120.0); + + Particle->acceleration[0]=0.0; + Particle->acceleration[1]=0.0; + Particle->acceleration[2]=-PARTICLE_GRAVITY*3.5; + + Particle->scale=flrand(0.5, 0.7); + Particle->d_alpha=-255.0; + Particle->d_scale=-0.25; + + AddParticleToList(Owner,Particle); + } +} + +// ************************************************************************************************ +// FXWaterEntrySplash +// ------------------ +// ************************************************************************************************ + +void FXDoWaterEntrySplash(centity_t *Owner,int Type,int Flags,vec3_t Origin, byte SplashSize, vec3_t Dir) +{ + byte NoOfRipples; + client_entity_t *EntrySplashThinker, + *splash; + float Theta,DeltaTheta; + + if (SplashSize >= 128) + NoOfRipples = 4; + else + if (SplashSize >= 96) + NoOfRipples = 3; + else + if (SplashSize >= 64) + NoOfRipples = 2; + else + NoOfRipples = 1; + + + if(Flags&CEF_FLAG6) + {//they want a sound too + fxi.S_StartSound(Origin, -1, CHAN_AUTO, + fxi.S_RegisterSound(va("misc/splish%c.wav", irand('2', '3'))), 1, ATTN_STATIC, 0); + } + + // Create a water entry ripple THINKER that will create the actual water entry ripples. + + EntrySplashThinker=ClientEntity_new(Type,Flags,Origin,Dir,200); + + EntrySplashThinker->flags|=CEF_NO_DRAW; + EntrySplashThinker->NoOfAnimFrames=(int)NoOfRipples; + EntrySplashThinker->Update=FXWaterEntrySplashThinkerThink; + EntrySplashThinker->d_alpha=-0.8-(0.2-(0.2*((1.0/127.0)*(SplashSize&127)))); + + AddEffect(NULL,EntrySplashThinker); + + // Create water entry particle splash if required. + + if (SplashSize&128) + { + DeltaTheta=(2*M_PI)/12; + for(Theta=0.0;Theta<(2*M_PI);Theta+=DeltaTheta) + { + splash = ClientEntity_new(Type,Flags,Origin,Dir,500); + splash->r.model = water_models + 1; + splash->r.scale = flrand(0.15, 0.25); + splash->r.flags = RF_TRANSLUCENT; + splash->r.frame = 1; + splash->radius = 2.0; + splash->d_alpha=-2.0; + splash->d_scale=1.0; + + splash->origin[0]=SPLASH_RADIUS*cos(Theta); + splash->origin[1]=SPLASH_RADIUS*sin(Theta); + splash->origin[2]=0.0; + + splash->velocity[0]=flrand(4.0,6.0)*splash->origin[0]; + splash->velocity[1]=flrand(4.0,6.0)*splash->origin[1]; + splash->velocity[2]=flrand(30.0,40.0); + + splash->acceleration[0]=0.0; + splash->acceleration[1]=0.0; + splash->acceleration[2]=-250; + + AddEffect(NULL, splash); + } + + DeltaTheta=(2*M_PI)/6; + for(Theta=0.0;Theta<(2*M_PI);Theta+=DeltaTheta) + { + splash = ClientEntity_new(Type,Flags,Origin,Dir,800); + splash->r.model = water_models + 1; + splash->r.scale = flrand(0.1, 0.2); + splash->r.flags = RF_TRANSLUCENT; + splash->r.frame = 1; + splash->radius = 2.0; + splash->d_alpha=-1.0; + splash->d_scale=-0.5; + + splash->origin[0]=SPLASH_RADIUS*cos(Theta); + splash->origin[1]=SPLASH_RADIUS*sin(Theta); + splash->origin[2]=0.0; + + splash->velocity[0]=flrand(1.0,2.0)*splash->origin[0]; + splash->velocity[1]=flrand(1.0,2.0)*splash->origin[1]; + splash->velocity[2]=flrand(100.0,150.0); + + splash->acceleration[0]=0.0; + splash->acceleration[1]=0.0; + splash->acceleration[2]=-525; + + AddEffect(NULL, splash); + } + + // Create a water entry ripple. + + splash=ClientEntity_new(FX_WATER_ENTRYSPLASH, Flags&(~CEF_OWNERS_ORIGIN), Origin, Dir, 1200); + + splash->r.model = water_models; + splash->r.scale=SCALE*2.0; + splash->r.frame=0; + splash->r.flags |= RF_FIXED|RF_TRANSLUCENT|RF_ALPHA_TEXTURE; + splash->alpha=0.6; + splash->d_scale=2.0; + splash->d_alpha=EntrySplashThinker->d_alpha; + + AddEffect(NULL,splash); + } +} + +void FXWaterEntrySplash(centity_t *Owner,int Type,int Flags,vec3_t Origin) +{ + byte SplashSize; + vec3_t Dir; + + fxi.GetEffect(Owner,Flags,"bd",&SplashSize,Dir); + + FXDoWaterEntrySplash(Owner, Type, Flags, Origin, SplashSize, Dir); +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_waterwake.c b/Toolkit/Programming/GameCode/client effects/fx_waterwake.c new file mode 100644 index 0000000..73f3c3a --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_waterwake.c @@ -0,0 +1,68 @@ +// +// fx_waterwake.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "angles.h" + +#define NUM_WAKE_MODELS 1 +static struct model_s *wake_models[NUM_WAKE_MODELS]; +void PreCacheWake() +{ + wake_models[0] = fxi.RegisterModel("sprites/fx/wake_add.sp2"); +} + +// ----------------------------------------------------------------- + +void FXWaterWake(centity_t *owner, int type, int flags, vec3_t origin) +{ + short CreatorEntNum; + centity_t *CreatorClientEntity; + float YawAngle; + vec3_t dir = {0.0, 0.0, 1.0}, Velocity; + client_entity_t *self; + float len; + byte blah; + + fxi.GetEffect(owner, flags, "sbv", &CreatorEntNum, &blah, Velocity); + + YawAngle = (blah /255.0) * 6.283185; + + CreatorClientEntity=&fxi.server_entities[CreatorEntNum]; + + // Create a water wake. + + self=ClientEntity_new(FX_WATER_WAKE,flags,origin,dir,5000); + + self->r.model = wake_models; + self->r.origin[1]=CreatorClientEntity->origin[1]; + self->r.origin[0]=CreatorClientEntity->origin[0]; + self->alpha=0.7; + self->r.scale=0.3; + self->r.flags |= RF_FIXED|RF_TRANSLUCENT|RF_TRANS_ADD|RF_TRANS_ADD_ALPHA; + self->r.angles[YAW]=YawAngle; + + len = VectorNormalize(Velocity)-30.0; + + if(len > 50.0) + { + len = 50.0; + } + + VectorScale(Velocity, len, self->velocity); + + self->velocity[2] = 0.0; + + self->d_scale=1.1; + self->d_alpha=-0.8; + + AddEffect(NULL, self); +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/client effects/fx_weaponpickup.c b/Toolkit/Programming/GameCode/client effects/fx_weaponpickup.c new file mode 100644 index 0000000..f2752a7 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/fx_weaponpickup.c @@ -0,0 +1,138 @@ +// +// fx_WeaponPickup.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "ce_DefaultMessageHandler.h" +#include "Client Effects.h" +#include "Client Entities.h" +#include "Particle.h" +#include "ResourceManager.h" +#include "FX.h" +#include "Vector.h" +#include "Random.h" +#include "Utilities.h" +#include "Angles.h" +#include "g_items.h" + +#define BOB_HEIGHT 6.0 +#define BOB_SPEED ANGLE_10 +#define WP_PART_RADIUS 16.0 + +#define NUM_ITEMWEAPONS 7 + +extern int ref_soft; + +static struct model_s *weapon_models[NUM_ITEMWEAPONS]; + +void PreCacheItemWeapons() +{ + weapon_models[0] = fxi.RegisterModel("models/items/weapons/hellstaff/tris.fm"); // ITEM_WEAPON_HELLSTAFF + weapon_models[1] = fxi.RegisterModel("models/items/weapons/array/tris.fm"); // ITEM_WEAPON_MAGICMISSILE + weapon_models[2] = fxi.RegisterModel("models/items/weapons/bow/tris.fm"); // ITEM_WEAPON_REDRAINBOW + weapon_models[3] = fxi.RegisterModel("models/items/weapons/sphere/tris.fm"); // ITEM_WEAPON_SPHEREOFANNIHILIATION + weapon_models[4] = fxi.RegisterModel("models/items/weapons/bow/tris.fm"); // ITEM_WEAPON_PHOENIXBOW + weapon_models[5] = fxi.RegisterModel("models/items/weapons/maceballs/tris.fm"); // ITEM_WEAPON_MACEBALLS + weapon_models[6] = fxi.RegisterModel("models/items/weapons/firewall/tris.fm"); // ITEM_WEAPON_FIREWALL +} + +// -------------------------------------------------------------- + +static qboolean FXWeaponPickupThink(struct client_entity_s *self, centity_t *owner) +{ + client_particle_t *spark; + paletteRGBA_t color; + int part; + + // Rotate and bob + self->r.angles[YAW] += ANGLE_15; + VectorCopy(owner->current.origin, self->r.origin); + self->r.origin[2] += (cos(self->SpawnData) * BOB_HEIGHT); + self->SpawnData += BOB_SPEED; + + switch(self->SpawnInfo) + { + case 0: // Hellstaff + part = PART_16x16_SPARK_R; + color.c = 0xff0000ff; + break; + case 1: // Magic Missile + part = PART_16x16_SPARK_G; + color.c = 0xff00ff00; + break; + case 2: // Red rain bow + part = PART_16x16_SPARK_R; + color.c = 0xff0000ff; + break; + case 3: // Sphere + part = PART_16x16_SPARK_B; + color.c = 0xffff0000; + break; + case 4: // Phoenix bow + part = irand(PART_32x32_FIRE0, PART_32x32_FIRE2); + color.c = 0xff0080ff; + break; + case 5: // Maceballs + part = PART_16x16_SPARK_G; + color.c = 0xff00ff00; + break; + case 6: // firewall + part = irand(PART_16x16_FIRE1, PART_16x16_FIRE3); + color.c = 0xff0080ff; + break; + default: + return true; // No effect + break; + } + + if (ref_soft) + part |= PFL_SOFT_MASK; + else + color.c = 0xffffffff; + + spark = ClientParticle_new(part, color, 500); + spark->origin[0] = cos(self->SpawnData*4.0) * WP_PART_RADIUS; + spark->origin[1] = sin(self->SpawnData*4.0) * WP_PART_RADIUS; + spark->origin[2] = -cos(self->SpawnData) * BOB_HEIGHT; + spark->acceleration[2] = flrand(128.0, 256.0); + spark->scale = 6.0; + AddParticleToList(self, spark); + + return(true); +} + +void FXWeaponPickup(centity_t *owner, int type, int flags, vec3_t origin) +{ + client_entity_t *ce; + byte tag; + + fxi.GetEffect(owner, flags, "b", &tag); + + flags &= ~CEF_OWNERS_ORIGIN; + ce = ClientEntity_new(type, flags | CEF_DONT_LINK | CEF_CHECK_OWNER | CEF_ADDITIVE_PARTS | CEF_VIEWSTATUSCHANGED, origin, NULL, 50); + + VectorCopy(ce->r.origin, ce->origin); + ce->r.flags = RF_TRANSLUCENT | RF_GLOW; + if(!tag)//sorry bob, just temporary... + ce->flags|=CEF_NO_DRAW; + else + ce->r.model = weapon_models + (tag -2); + ce->r.scale = 0.5; + ce->radius = 10.0; + ce->alpha = 0.8; + ce->Update = FXWeaponPickupThink; + + if (tag == ITEM_WEAPON_FIREWALL) + ce->r.scale = 1; + + if (tag == ITEM_WEAPON_PHOENIXBOW) + ce->r.skinnum = 1; + + ce->SpawnInfo = tag-2; + + AddEffect(owner, ce); +} + +// end diff --git a/Toolkit/Programming/GameCode/client effects/levelmaps.c b/Toolkit/Programming/GameCode/client effects/levelmaps.c new file mode 100644 index 0000000..58f7e58 --- /dev/null +++ b/Toolkit/Programming/GameCode/client effects/levelmaps.c @@ -0,0 +1,112 @@ +#include "client.h" +#include "cl_strings.h" + +#define MAX_MAPS 26 + +int coords_swamp[] = +{ + 196, 193, + 202, 193, + 209, 197, + 213, 209, + 216, 216, + 222, 219 +}; + +int coords_caves[] = +{ + 243, 220, + 249, 220, + 256, 219, + 264, 224, + 268, 226, + 275, 228, + 281, 231, + 287, 234, + 293, 234 +}; + +int coords_canyon[] = +{ + 299, 238, + 300, 244, + 303, 250, + 300, 257, + 299, 266, + 300, 273, + 300, 281, + 306, 286, + 312, 292, + 317, 297, + 319, 305 +}; + +int coords_mine1[] = +{ + 387, 323, + 390, 317, + 393, 312, + 388, 306, + 383, 300, + 381, 293 +}; + +int coords_mine2[] = +{ + 387, 287, + 380, 280, + 383, 275, + 384, 268, + 389, 266, + 396, 269 +}; + +level_map_info_t LevelMaps[MAX_MAPS] = +{ + 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, // level 0 - undefined + 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, // level 0 - undefined + + 1, LMI_DRAW, "book/back/b_worldmap.bk", "book/back/b_ssmap.bk", 0, 0,187, 191, 0, NULL, // SSDocks + 1, 0, "book/back/b_worldmap.bk", "book/back/b_ssmap.bk", 0, 0,0, 0, 0, NULL, // SSWarehouse + 1, 0, "book/back/b_worldmap.bk", "book/back/b_ssmap.bk", 0, 0,0, 0, 0, NULL, // SSTown + 1, 0, "book/back/b_worldmap.bk", "book/back/b_ssmap.bk", 0, 0,0, 0, 0, NULL, // SSPalace + + 2, LMI_PROGRESS, "book/back/b_worldmap.bk", NULL, GM_M_DARKMIRE, 0,0, 0, 6, coords_swamp, // Dmireswamp + + 3, LMI_DRAW, "book/back/b_worldmap.bk", "book/back/b_andmap.bk", 0, 0,232, 218, 0, NULL, // Andhealer + 3, 0, "book/back/b_worldmap.bk", "book/back/b_andmap.bk", 0, 0,0, 0, 0, NULL, // AndSlums + 3, 0, "book/back/b_worldmap.bk", "book/back/b_andmap.bk", 0, 0,0, 0, 0, NULL, // Andplaza + 3, 0, "book/back/b_worldmap.bk", "book/back/b_andmap.bk", 0, 0,0, 0, 0, NULL, // AndAcademic + + 4, LMI_PROGRESS, "book/back/b_worldmap.bk", NULL, GM_M_KELLCAVES, 0, 0, 0, 9, coords_caves, // Kellcaves + 4, LMI_PROGRESS, "book/back/b_worldmap.bk", NULL, GM_M_KATLITK, 0, 0, 0, 11, coords_canyon, // Canyon + + 5, LMI_DRAW, "book/back/b_worldmap.bk", "book/back/b_hivemap.bk", 0, 0, 332, 307, 0, NULL, // Hive1 + 5, 0, "book/back/b_worldmap.bk", "book/back/b_hivemap.bk", 0, 0, 0, 0, 0, NULL, // Hive2 + 5, 0, "book/back/b_worldmap.bk", "book/back/b_hivemap.bk", 0, 0, 0, 0, 0, NULL, // Gauntlet + 5, 0, "book/back/b_worldmap.bk", "book/back/b_hivemap.bk", 0, 0, 0, 0, 0, NULL, // Trialpit + 5, 0, "book/back/b_worldmap.bk", "book/back/b_hivemap.bk", 0, 0, 0, 0, 0, NULL, // Hivepriestess + + 6, LMI_PROGRESS, "book/back/b_worldmap.bk", NULL, GM_M_MINES, 0,0, 0, 6, coords_mine1, // OgleMine1 + 6, LMI_PROGRESS, "book/back/b_worldmap.bk", NULL, GM_M_MINES, 0, 0, 0, 6, coords_mine2, // OgleMine2 + 6, 0, "book/back/b_worldmap.bk", NULL, GM_M_DUNGEON, 0, 0, 0, 0, NULL, // Dungeon + + 7, LMI_DRAW, "book/back/b_worldmap.bk", NULL, GM_M_CLOUD, 0, 405, 268, 0, NULL, // Cloudhub + 7, 0, "book/back/b_worldmap.bk", NULL, GM_M_CLOUD, 0, 0, 0, 0, NULL, // Cloudlabs + 7, 0, "book/back/b_worldmap.bk", NULL, GM_M_CLOUD, 0, 0, 0, 0, NULL, // Cloudquarters + 7, 0, "book/back/b_worldmap.bk", NULL, GM_M_CLOUD, 0, 0, 0, 0, NULL, // Cloudsanctum + + 0, LMI_NODRAW, "book/back/b_worldmap.bk", NULL, 0, 0,0, 0, 0, 0, // Tutorial level +}; + +level_map_info_t *GetLMI() +{ + return(LevelMaps); +} + +int GetLMIMax() +{ + return(MAX_MAPS); +} + +// end diff --git a/Toolkit/Programming/GameCode/client/cdaudio.h b/Toolkit/Programming/GameCode/client/cdaudio.h new file mode 100644 index 0000000..9b5b9e4 --- /dev/null +++ b/Toolkit/Programming/GameCode/client/cdaudio.h @@ -0,0 +1,7 @@ + +int CDAudio_Init(void); +void CDAudio_Shutdown(void); +void CDAudio_Play(int track, qboolean looping); +void CDAudio_Stop(void); +void CDAudio_Update(void); +void CDAudio_Activate (qboolean active); diff --git a/Toolkit/Programming/GameCode/client/client.h b/Toolkit/Programming/GameCode/client/client.h new file mode 100644 index 0000000..73dacea --- /dev/null +++ b/Toolkit/Programming/GameCode/client/client.h @@ -0,0 +1,646 @@ +// client.h -- primary header for client + +//define PARANOID // speed sapping error checking + +#include +#include +#include +#include +#include +#include "ref.h" + +#include "vid.h" +#include "screen.h" +#include "input.h" +#include "keys.h" +#include "console.h" +#include "cdaudio.h" +#include "q_ClientServer.h" +#include "p_types.h" +#include "LevelMaps.h" + +// ******************************************************************************************** +// flags for the client side entity to know if its been deleted on the server, or is server culled +// ------- +// ******************************************************************************************** +#define CF_INUSE 0x00000001 +#define CF_SERVER_CULLED 0x00000002 + +#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems + +// ******************************************************************************************** +// frame_t +// ------- +// ******************************************************************************************** + +typedef struct +{ + qboolean valid; // cleared if delta parsing was invalid + int serverframe; + int servertime; // server time the message is valid for (msec) + int deltaframe; + byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits + player_state_t playerstate; + int num_entities; + int parse_entities; // non-masked index into cl_parse_entities array +} frame_t; + +// ******************************************************************************************** +// centity_t +// --------- +// ******************************************************************************************** + +typedef struct +{ + entity_state_t baseline; // delta from this if not from a previous frame + entity_state_t current; + entity_state_t prev; // always valid, but may just be a copy of current + + int serverframe; // if not current, this ent isn't in the frame + + int flags; // What freaking flags go in here??!?! + + vec3_t lerp_origin; // previous interpolated origin + vec3_t origin; // current interpolated origin + + vec3_t lerp_angles; // current interpolated angles + + struct entity_s *entity; // so client fx can play with its owners entity + + struct client_entity_s *effects; // client effects, only has meaning within the + // Client Effects DLL + + struct LERPedReferences_s *referenceInfo; + + // This stuff should be removed at a later date - the predictinfo_t struct is what will be + // passed to the AddServerEntities() func. Don't want to make Gil's task any more awkward + // than it is by screwing with that function until later when all works. + + float playerlerp; // Used only by the player's entity for prediction purposes. + int Effects, + renderfx, + skinnum; + +} centity_t; + +// ******************************************************************************************** +// predictinfo_t +// ------------- +// Repositiory for all elements of player rendering that need to be predicted. When prediction +// is active, the values below are written by CL_DoPrediction() and read by AddServerEntities() +// instead of using values derived from server sent data. +// ******************************************************************************************** + +typedef struct +{ + int prevFrame,currFrame, + prevSwapFrame,currSwapFrame; + vec3_t prevAngles,currAngles; + float playerLerp; + int effects, + renderfx, + skinnum; + fmnodeinfo_t fmnodeinfo[MAX_FM_MESH_NODES]; +} predictinfo_t; + +// ******************************************************************************************** +// clientinfo_t +// ------------ +// ******************************************************************************************** + +typedef struct +{ + char name[MAX_QPATH]; + struct image_s *skin; + struct image_s *icon; + char iconname[MAX_QPATH]; + struct model_s **model; + vec3_t origin; +} clientinfo_t; + +// ******************************************************************************************** +// client_state_t +// -------------- +// Wiped completely at every server map change. +// ******************************************************************************************** + +typedef struct +{ + int timeoutcount; + + int timedemo_frames; + int timedemo_start; + + qboolean refresh_prepped; // false if on new level or new ref dll + qboolean sound_prepped; // ambient sounds can start + qboolean force_refdef; // vid has changed, so we can't use a paused refdef + + int parse_entities; // index (not anded off) into cl_parse_entities[] + + usercmd_t cmd; + usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds + int cmd_time[CMD_BACKUP]; // time sent, for calculating pings + short predicted_origins[CMD_BACKUP][3]; // for debug comparing against server + + float predicted_step; // for stair up smoothing + unsigned predicted_step_time; + + vec3_t predicted_origin; // generated by CL_PredictMovement + vec3_t predicted_angles; + vec3_t prediction_error; + + frame_t frame; // received from server +#if 0 + int surpressCount; // number of messages rate supressed +#endif + frame_t frames[UPDATE_BACKUP]; + + // The client maintains its own idea of view angles in 'viewangles', which is sent to the + // server each client-frame. It is cleared to 0 upon entering each level. The server sends a + // delta each server-frame which is added to the locally tracked view angles to account for + // standing on rotating objects, and teleport direction changes. + + vec3_t inputangles,delta_inputangles,old_delta_inputangles, + viewangles, + lookangles; + + // Client camera vieworigin and viewangles sent to server so it can do accurate(ish) culling. + + vec3_t camera_vieworigin,camera_viewangles; + + // The time value that the client is rendering at. This is always <= cls.realtime. + + int time; + + // Between oldframe and frame. + + float lerpfrac; + + refdef_t refdef; + + vec3_t v_forward, v_right, v_up; // set when refdef.angles is set + + // + // transient data from server + // + + char layout[1024]; // general 2D overlay + int inventory[MAX_ITEMS]; + + int cinematictime; + // + // server state information + // + qboolean attractloop; // running the attract loop, any key will menu + int servercount; // server identification for prespawns + char gamedir[MAX_QPATH]; + int playernum; + + char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]; + + // + // locally derived information from server state + // + struct model_s *model_draw[MAX_MODELS]; + struct cmodel_s *model_clip[MAX_MODELS]; + + struct sfx_s *sound_precache[MAX_SOUNDS]; + struct image_s *image_precache[MAX_IMAGES]; + + clientinfo_t clientinfo[MAX_CLIENTS]; + clientinfo_t baseclientinfo; + + int lastanimtime; + int PIV; + + playerinfo_t playerinfo; + + predictinfo_t predictinfo; +} client_state_t; + +GAME_DECLSPEC extern client_state_t cl; + +/* +================================================================== + +the client_static_t structure is persistant through an arbitrary number +of server connections + +================================================================== +*/ + +typedef enum { + ca_uninitialized, + ca_disconnected, // not talking to a server + ca_connecting, // sending request packets to the server + ca_connected, // netchan_t established, waiting for svc_serverdata + ca_active // game views should be displayed +} connstate_t; + +typedef enum { + dl_none, + dl_model, + dl_sound, + dl_skin, + dl_single +} dltype_t; // download type + +typedef enum {key_game, key_console, key_message, key_menu} keydest_t; + +typedef struct +{ + connstate_t state; + keydest_t key_dest; + + int framecount; + int realtime; // allways increasing, no clamping, etc + float frametime; // seconds since last frame + float framemodifier; // variable to mod cfx by + + int startmenu; // time when the menu came up + int startmenuzoom; // time from menu start + int m_menustate; + float m_menualpha; + float m_menuscale; + + byte esc_cinematic; // Flag to show player wants to leave cinematic + +// screen rendering information + float disable_screen; // showing loading plaque between levels + // or changing rendering dlls + // if time gets > 30 seconds ahead, break it + int disable_servercount; // when we receive a frame and cl.servercount + // > cls.disable_servercount, clear disable_screen + + int r_numentities; + entity_t *r_entities[MAX_ENTITIES]; + + int r_num_alpha_entities; + entity_t *r_alpha_entities[MAX_ALPHA_ENTITIES]; + + int r_numdlights; + dlight_t r_dlights[MAX_DLIGHTS]; + + lightstyle_t r_lightstyles[MAX_LIGHTSTYLES]; + + int r_numparticles; + particle_t r_particles[MAX_PARTICLES]; + + int r_anumparticles; + particle_t r_aparticles[MAX_PARTICLES]; + +// connection information + char servername[MAX_OSPATH]; // name of server from original connect + float connect_time; // for connection retransmits + + int quakePort; // a 16 bit value that allows quake servers + // to work around address translating routers + netchan_t netchan; + int serverProtocol; // in case we are doing some kind of version hack + + int challenge; // from the server to use for connecting + + FILE *download; // file transfer from server + char downloadtempname[MAX_OSPATH]; + char downloadname[MAX_OSPATH]; + int downloadnumber; + dltype_t downloadtype; + int downloadpercent; + +// demo recording info must be here, so it isn't cleared on level change + qboolean demorecording; + qboolean demosavingok; + qboolean demowaiting; // don't record until a non-delta message is received + FILE *demofile; +} client_static_t; + +GAME_DECLSPEC extern client_static_t cls; + +#define FX_API_VERSION 1 + +// +// these are the data and functions exported by the client fx module +// +typedef struct +{ + // if api_version is different, the dll cannot be used + int api_version; + + void (*Init)(); + void (*ShutDown)(); + + void (*Clear)(); + + void (*RegisterSounds)(); + void (*RegisterModels)(); + + void (*ParseClientEffects)(centity_t *cent); + void (*RemoveClientEffects)(centity_t *cent); + + void (*AddPacketEntities)(frame_t *frame); + void (*AddEffects)(qboolean freeze); + void (*UpdateEffects)(); + + void (*SetLightstyle)(int i); + level_map_info_t *(*GetLMI)(); + int (*GetLMIMax)(); + +} client_fx_export_t; + +extern client_fx_export_t fxe; + +// +// these are the data and functions imported by the client fx module +// +typedef struct +{ + client_state_t *cl; + client_static_t *cls; + centity_t *server_entities; // client versions of the game entities + entity_state_t *parse_entities; + sizebuf_t *net_message; + entity_t **PlayerEntPtr; + cvar_t *cl_predict; + predictinfo_t *predictinfo; + struct ResourceManager_s *FXBufMngr; + + void (*Sys_Error) (int err_level, char *str, ...); + void (*Com_Error) (int code, char *fmt, ...); + void (*Con_Printf) (int print_level, char *str, ...); + + cvar_t *(*Cvar_Get) (char *name, char *value, int flags); + cvar_t *(*Cvar_Set)( char *name, char *value ); + void (*Cvar_SetValue)( char *name, float value ); + + // allow the screen flash to be controlled from within the client effect DLL rather than going through the server. + // this means we get 60 hz (hopefully) screen flashing, rather than 10 hz + void (*Activate_Screen_Flash)(int color); + + // allow the client to call a screen shake - done within the camera code, so we can shake the screen at 60hz + void (*Activate_Screen_Shake)(float intensity, float duration, float current_time, int flags); + + qboolean (*Get_Crosshair)(vec3_t origin, byte *type); + +/* void (*Cmd_AddCommand) (char *name, void(*cmd)(void)); + void (*Cmd_RemoveCommand) (char *name); + int (*Cmd_Argc) (void); + char *(*Cmd_Argv) (int i); + void (*Cmd_ExecuteText) (int exec_when, char *text);*/ +// JAKE START + void (*S_StartSound)(vec3_t origin, int entnum, int entchannel, struct sfx_s *sfx, float fvol, int attenuation, float timeofs); +// JAKE END + struct sfx_s *(*S_RegisterSound)(char *name); + struct model_s *(*RegisterModel) (char *name); + + int (*GetEffect)(centity_t *ent, int flags, char *format, ...); + + void *(*TagMalloc)(int size, int tag); + void (*TagFree)(void *block); + void (*FreeTags)(int tag); + + void (*Trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int brushmask, + int flags, trace_t *t); + qboolean (*InCameraPVS)(vec3_t point); + + int (*GetReferencedID) (struct model_s *model); + + int (*FindSurface)(vec3_t start, vec3_t end, struct Surface_s *surface); + +} client_fx_import_t; + + +// this is the only function actually exported at the linker level +typedef client_fx_export_t (*GetfxAPI_t) (client_fx_import_t); + +// +// cvars +// +extern cvar_t *cl_stereo_separation; +extern cvar_t *cl_stereo; + +extern cvar_t *cl_gun; +extern cvar_t *cl_add_blend; +extern cvar_t *cl_add_lights; +extern cvar_t *cl_add_particles; +extern cvar_t *cl_add_entities; + +extern cvar_t *cl_predict; +extern cvar_t *cl_predict_local; +extern cvar_t *cl_predict_remote; + +extern cvar_t *cl_footsteps; + +extern cvar_t *cl_noskins; +extern cvar_t *cl_autoskins; + +extern cvar_t *cl_maxfps; +extern cvar_t *cl_frametime; + +extern cvar_t *cl_yawspeed; +extern cvar_t *cl_pitchspeed; + +extern cvar_t *cl_run; + +extern cvar_t *cl_anglespeedkey; + +extern cvar_t *cl_shownet; +extern cvar_t *cl_showmiss; +extern cvar_t *cl_showclamp; + +extern cvar_t *freelook; +extern cvar_t *lookspring; +extern cvar_t *lookstrafe; +extern cvar_t *mouse_sensitivity_x; +extern cvar_t *mouse_sensitivity_y; + +extern cvar_t *doubletap_speed; + +extern cvar_t *m_pitch; +extern cvar_t *m_yaw; +extern cvar_t *m_forward; +extern cvar_t *m_side; + +extern cvar_t *cl_lightlevel; // FIXME HACK + +GAME_DECLSPEC extern cvar_t *cl_paused; +extern cvar_t *cl_freezeworld; +extern cvar_t *cl_timedemo; + +extern cvar_t *cl_camera_clipdamp; +extern cvar_t *cl_camera_combat; +extern cvar_t *cl_camera_dampfactor; +extern cvar_t *cl_camera_fpoffs; +extern cvar_t *cl_camera_freeze; +extern cvar_t *cl_camera_under_surface; +extern cvar_t *cl_camera_viewdist; +extern cvar_t *cl_camera_viewmin; +extern cvar_t *cl_camera_viewmax; + +extern cvar_t *cl_cinematicfreeze; +extern cvar_t *shownames; +extern cvar_t *autoweapon; +extern cvar_t *cl_showcaptions; + +extern cvar_t *colour_obituary; +extern cvar_t *colour_chat; +extern cvar_t *colour_teamchat; +extern cvar_t *colour_level; +extern cvar_t *colour_game; + +typedef struct +{ + int key; // so entities can reuse same entry + vec3_t color; + vec3_t origin; + float radius; + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less +} cdlight_t; + +GAME_DECLSPEC extern centity_t cl_entities[MAX_NETWORKABLE_EDICTS]; +extern cdlight_t cl_dlights[MAX_DLIGHTS]; + +// the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of +// entities, so that when a delta compressed message arives from the server +// it can be un-deltad from the original +#define MAX_PARSE_ENTITIES 1024 +GAME_DECLSPEC extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; + +//============================================================================= + +#define ENTITY_FX_BUF_BLOCK_SIZE 128 + +extern struct ResourceManager_s cl_FXBufMngr; + +extern netadr_t net_from; +extern sizebuf_t net_message; + +void DrawString (int x, int y, char *s, unsigned int color, int maxlen); +qboolean CL_CheckOrDownloadFile (char *filename); + +void CL_AddNetgraph (void); + +//int CL_ParseEntityBits (__int64 *bits); +int CL_ParseEntityBits (unsigned char *bf,unsigned char* bfNonZero); +//void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, __int64 bits); +void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, unsigned char *bf); +void CL_ParseFrame (void); + +//================================================= + +void CL_PrepRefresh (void); +void CL_RegisterSounds (void); + +void CL_Quit_f (void); + +void IN_Accumulate (void); + +void CL_ParseLayout (void); + + +// +// cl_main +// +extern refexport_t re; // interface to refresh .dll + +void CL_Init (void); +char *CL_GetGameString(int i); +char *CL_GetGameWav(int i); +char *CL_GetLevelString(int i); +char *CL_GetLevelWav(int i); +void CL_LoadStrings(void); + +void CL_Disconnect (void); +void CL_Disconnect_f (void); +void CL_GetChallengePacket (void); +void CL_PingServers_f (void); +void CL_Snd_Restart_f (void); +void CL_Snd_Restart_f_nocfx (void); + +// +// cl_input +// +typedef struct +{ + int down[2]; // key nums holding it down + unsigned downtime; // msec timestamp + unsigned msec; // msec down this frame + int state; +} kbutton_t; + +extern kbutton_t in_mlook, in_klook; +extern kbutton_t in_strafe; +extern kbutton_t in_speed; +extern kbutton_t in_lookaround; + +void CL_InitInput (void); +void CL_SendCmd (void); +void CL_SendMove (usercmd_t *cmd); + +void CL_ClearState (void); + +void CL_ReadPackets (void); + +int CL_ReadFromServer (void); +void CL_WriteToServer (usercmd_t *cmd); +void CL_BaseMove (usercmd_t *cmd); + +void IN_CenterView (void); + +float CL_KeyState (kbutton_t *key); +char *Key_KeynumToString (int keynum); + +// +// cl_demo.c +// +void CL_ParseDemoClientEffects (void); +void CL_WriteDemoMessage (void); +void CL_Stop_f (void); +void CL_Record_f (void); + +// +// cl_parse.c +// +extern char *svc_strings[256]; + +void CL_ParseServerMessage (void); +void CL_LoadClientinfo (clientinfo_t *ci, char *s); +void SHOWNET(char *s); +void CL_ParseClientinfo (int player); +int COLOUR(cvar_t *cvar); + +void V_Init (void); +void V_RenderView( float stereo_separation ); + +// +// cl_pred.c +// +void CL_InitPrediction (void); +void CL_PredictMove (void); +void CL_CheckPredictionError (void); + +// +// menus +// +void M_Init (void); +void M_Keydown (int key); +void M_Draw (void); +void M_Menu_Main_f (void); +void M_ForceMenuOff (void); +void MenuUnsetMode(void); +void M_AddToServerList (netadr_t adr, char *info); + +// +// cl_inv.c +// +void CL_ParseInventory (void); +void CL_KeyInventory (int key); +void CL_DrawInventory (void); + +// +// cl_pred.c +// +void CL_PredictMovement(void); +void CL_ClipMoveToEntities(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,trace_t *tr); + diff --git a/Toolkit/Programming/GameCode/client/console.h b/Toolkit/Programming/GameCode/client/console.h new file mode 100644 index 0000000..a61c6d4 --- /dev/null +++ b/Toolkit/Programming/GameCode/client/console.h @@ -0,0 +1,43 @@ + +// +// console +// + +#define NUM_CON_TIMES 8 +#define CON_TEXTSIZE 32768 +#define MAX_LINES ((CON_TEXTSIZE / 38) + 8) + +typedef struct +{ + qboolean initialized; + + char text[CON_TEXTSIZE]; + int current; // line where next message will be printed + int x; // offset in current line for next print + int display; // bottom of console displays this line + + int linewidth; // characters across screen + int totallines; // total lines in console scrollback + paletteRGBA_t color[MAX_LINES]; + paletteRGBA_t current_color; + + float cursorspeed; + int vislines; + + float times[NUM_CON_TIMES]; // cls.realtime time the line was generated + // for transparent notify lines +} console_t; + +extern console_t con; + +void Con_DrawCharacter (int cx, int line, int num); + +void Con_CheckResize (void); +void Con_Init (void); +void Con_DrawConsole (float frac); +void Con_Print (char *txt); +void Con_CenteredPrint (char *text); +void Con_Clear_f (void); +void Con_DrawNotify (void); +void Con_ClearNotify (void); +void Con_ToggleConsole_f (void); diff --git a/Toolkit/Programming/GameCode/client/input.h b/Toolkit/Programming/GameCode/client/input.h new file mode 100644 index 0000000..0f8a7a9 --- /dev/null +++ b/Toolkit/Programming/GameCode/client/input.h @@ -0,0 +1,15 @@ +// input.h -- external (non-keyboard) input devices + +void IN_Init (void); + +void IN_Shutdown (void); + +void IN_Commands (void); +// oportunity for devices to stick commands on the script buffer + +void IN_Frame (void); + +void IN_Move (usercmd_t *cmd); +// add additional movement on top of the keyboard move cmd + +void IN_Activate (qboolean active); diff --git a/Toolkit/Programming/GameCode/client/keys.h b/Toolkit/Programming/GameCode/client/keys.h new file mode 100644 index 0000000..db4a986 --- /dev/null +++ b/Toolkit/Programming/GameCode/client/keys.h @@ -0,0 +1,132 @@ + +// +// these are the key numbers that should be passed to Key_Event +// +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 + +// normal keys should be passed as lowercased ascii + +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 + +#define K_ALT 132 +#define K_CTRL 133 +#define K_SHIFT 134 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 + +#define K_KP_HOME 160 +#define K_KP_UPARROW 161 +#define K_KP_PGUP 162 +#define K_KP_LEFTARROW 163 +#define K_KP_5 164 +#define K_KP_RIGHTARROW 165 +#define K_KP_END 166 +#define K_KP_DOWNARROW 167 +#define K_KP_PGDN 168 +#define K_KP_ENTER 169 +#define K_KP_INS 170 +#define K_KP_DEL 171 +#define K_KP_SLASH 172 +#define K_KP_MINUS 173 +#define K_KP_PLUS 174 +#define K_KP_NUMLOCK 175 + +#define K_CAPSLOCK 254 +#define K_PAUSE 255 + +// +// mouse buttons generate virtual keys +// +#define K_MOUSE1 200 +#define K_MOUSE2 201 +#define K_MOUSE3 202 + +// +// joystick buttons +// +#define K_JOY1 203 +#define K_JOY2 204 +#define K_JOY3 205 +#define K_JOY4 206 + +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// +#define K_AUX1 207 +#define K_AUX2 208 +#define K_AUX3 209 +#define K_AUX4 210 +#define K_AUX5 211 +#define K_AUX6 212 +#define K_AUX7 213 +#define K_AUX8 214 +#define K_AUX9 215 +#define K_AUX10 216 +#define K_AUX11 217 +#define K_AUX12 218 +#define K_AUX13 219 +#define K_AUX14 220 +#define K_AUX15 221 +#define K_AUX16 222 +#define K_AUX17 223 +#define K_AUX18 224 +#define K_AUX19 225 +#define K_AUX20 226 +#define K_AUX21 227 +#define K_AUX22 228 +#define K_AUX23 229 +#define K_AUX24 230 +#define K_AUX25 231 +#define K_AUX26 232 +#define K_AUX27 233 +#define K_AUX28 234 +#define K_AUX29 235 +#define K_AUX30 236 +#define K_AUX31 237 +#define K_AUX32 238 + +#define K_MWHEELDOWN 239 +#define K_MWHEELUP 240 + +extern char *keybindings[256]; +extern char *keybindings_double[256]; +extern int key_repeats[256]; + +extern qboolean anykeydown; +extern char chat_buffer[]; +extern int chat_bufferlen; +extern qboolean chat_team; + +void Key_Event (int key, qboolean down, unsigned time); +void Key_Init (void); +void Key_WriteBindings (FILE *f); +void Key_WriteBindings_Double (FILE *f); +void Key_SetBinding (int keynum, char *binding); +void Key_SetDoubleBinding (int keynum, char *binding); +void Key_ClearStates (void); +int Key_GetKey (void); + diff --git a/Toolkit/Programming/GameCode/client/ref.h b/Toolkit/Programming/GameCode/client/ref.h new file mode 100644 index 0000000..19a4e12 --- /dev/null +++ b/Toolkit/Programming/GameCode/client/ref.h @@ -0,0 +1,274 @@ +#include "qcommon.h" + +// these are the maximum number that maybe rendered on any given frame +#define MAX_DLIGHTS 32 +#define MAX_ENTITIES 128 +#define MAX_ALPHA_ENTITIES MAX_ENTITIES*2 +#define MAX_SERVER_ENTITIES MAX_ENTITIES +#define MAX_PARTICLES 4096 +#define MAX_LIGHTSTYLES 256 + +#define NUM_PARTICLE_TYPES 62 // This doesn't use the macro because of referencing weirdness. + +typedef struct entity_s +{ + struct model_s **model; // opaque type outside refresh + float angles[3]; + + float origin[3]; + int frame; + + float scale; // model scale + + float cl_scale; // scale of model - but only for client entity models - not server side models + // required for scaling mins and maxs that are used to cull models - mins and maxs + // are scaled on the server side, but not on the client side when the models are loaded in + + float depth; // distance to the camera origin, gets set every + // frame by AddEffectsToView + + paletteRGBA_t color; + + int flags; + + + union { + int rootJoint; // rootJoint of the entities skeleton + int spriteType; + }; + + union { + + // info for fmodels and bmodels + struct { + + float oldorigin[3]; + int oldframe; + + float backlerp; // 0.0 = current, 1.0 = old + + int skinnum; + struct image_s *skin; // NULL for inline skin + char skinname[MAX_QPATH]; // For specific path to skin + + paletteRGB_t absLight; + byte padFor_3byte_absLight; + + fmnodeinfo_t *fmnodeinfo; // client entities which use a flexible model will need + // to fill this in, and then release it when they die + // happily most client entities are sprites + + int swapCluster; // cluster to swap on + + int swapFrame; // frame to swap clustered verts in for + int oldSwapFrame; // previous frame to swap clustered verts in for + + struct LERPedReferences_s *referenceInfo; + struct LERPedReferences_s *oldReferenceInfo; + + int padToUnionSize[4]; // use this space up to add any more nonsprite fields that may be needed + + }; + + // info for dynamic sprites + float verts[4][4]; // verts for dynamic sprites + // 0 x + // 1 y + // 2 s + // 3 t + + // info for variable sprites + struct { + float (*verts_p)[4]; // pointer to verts for variable sprites + int numVerts; + int padToUnionSize2[11]; // use this space up to add any more variable sprite fields + }; + + // info for line sprites + struct { + float startpos[3]; + float endpos[3]; + float scale2; + float tile, tileoffset; + int padToUnionSize3[7]; // use this space up to add any more line sprite fields + }; + + + }; + +} entity_t; + +#define ENTITY_FLAGS 68 + +typedef struct +{ + vec3_t origin; + paletteRGBA_t color; + float intensity; +} dlight_t; + +typedef struct +{ + float rgb[3]; // 0.0 - 2.0 + float white; // highest of rgb +} lightstyle_t; + +typedef struct +{ + vec3_t origin; + paletteRGBA_t color; + float scale; + int type; +} particle_t; + +typedef struct +{ + int x, y, width, height, area;// in virtual screen coordinates + float fov_x, fov_y; + float vieworg[3]; + float viewangles[3]; + float blend[4]; // rgba 0-1 full screen blend + float time; // time is uesed to auto animate + int rdflags; // RDF_UNDERWATER, etc + + byte *areabits; // if not NULL, only areas with set bits will be drawn + + lightstyle_t *lightstyles; // [MAX_LIGHTSTYLES] + + int num_entities; + entity_t **entities; + + int num_alpha_entities; + entity_t **alpha_entities; + + int num_dlights; + dlight_t *dlights; + + int num_particles; + particle_t *particles; + + int anum_particles; + particle_t *aparticles; + +} refdef_t; + +#define API_VERSION 3 + +// +// these are the functions exported by the refresh module +// +typedef struct +{ + // if api_version is different, the dll cannot be used + int api_version; + + // Set this to false if you don`t want any rendering commands issued + qboolean render; + + // called when the library is loaded + qboolean (*Init) ( void *hinstance, void *wndproc ); + + // called before the library is unloaded + void (*Shutdown) (void); + + // All data that will be used in a level should be + // registered before rendering any frames to prevent disk hits, + // but they can still be registered at a later time + // if necessary. + // + // EndRegistration will free any remaining data that wasn't registered. + // Any model_s or skin_s pointers from before the BeginRegistration + // are no longer valid after EndRegistration. + // + // Skins and images need to be differentiated, because skins + // are flood filled to eliminate mip map edge errors, and pics have + // an implicit "pics/" prepended to the name. (a pic name that starts with a + // slash will not use the "pics/" prefix or the ".pcx" postfix) + void (*BeginRegistration) (char *map); + struct model_s *(*RegisterModel) (char *name); + struct image_s *(*RegisterSkin) (char *name); + struct image_s *(*RegisterPic) (char *name); + void (*SetSky) (char *name, float rotate, vec3_t axis); + void (*EndRegistration) (void); + + int (*GetReferencedID) (struct model_s *model); + + int (*RenderFrame) (refdef_t *fd); + + void (*DrawGetPicSize) (int *w, int *h, char *name); + void (*DrawPic) (int x, int y, char *name, float alpha); + void (*DrawStretchPic) (int x, int y, int w, int h, char *name, float alpha, qboolean scale); + void (*DrawChar) (int x, int y, int c, paletteRGBA_t color); + void (*DrawTileClear) (int x, int y, int w, int h, char *name); + void (*DrawFill) (int x, int y, int w, int h, byte r, byte g, byte b); + void (*DrawFadeScreen) (paletteRGBA_t color); + void (*DrawBigFont) (int x, int y, char *text, float alpha); + int (*BF_Strlen) (char *text); + void (*BookDrawPic) (int w, int h, char *name, float scale); + + // Draw images for cinematic rendering (which can have a different palette). Note that calls + void (*DrawInitCinematic) (int w, int h, char *overlay, char *backdrop); + void (*DrawCloseCinematic) (); + void (*DrawCinematic) (int cols, int rows, byte *data, paletteRGB_t *palette, float alpha); + void (*Draw_Name) (vec3_t origin, char *Name); + + /* + ** video mode and refresh state management entry points + */ + void (*BeginFrame)( float camera_separation ); + void (*EndFrame) (void); + + void (*AppActivate)( qboolean activate ); + + int (*FindSurface)(vec3_t start, vec3_t end, struct Surface_s *surface); +} refexport_t; + +// +// these are the functions imported by the refresh module +// +typedef struct +{ + struct CL_SkeletalJoint_s *skeletalJoints; + struct ArrayedListNode_s *jointNodes; + + void (*Sys_Error) (int err_level, char *str, ...); + void (*Com_Error) (int code, char *fmt, ...); + void (*Con_Printf) (int print_level, char *str, ...); + + cvar_t *(*Cvar_Get) (char *name, char *value, int flags); + cvar_t *(*Cvar_FullSet) (char *name, char *value, int flags); + cvar_t *(*Cvar_Set)( char *name, char *value ); + void (*Cvar_SetValue)( char *name, float value ); + + void (*Cmd_AddCommand) (char *name, void(*cmd)(void)); + void (*Cmd_RemoveCommand) (char *name); + int (*Cmd_Argc) (void); + char *(*Cmd_Argv) (int i); + void (*Cmd_ExecuteText) (int exec_when, char *text); + + // this is used for the screen flash - there is a reason for doing this... + int (*Is_Screen_Flashing) (void); + void (*Deactivate_Screen_Flash) (void); + + // files will be memory mapped read only + // the returned buffer may be part of a larger pak file, + // or a discrete file from anywhere in the quake search path + // a -1 return means the file does not exist + // NULL can be passed for buf to just determine existance + int (*FS_LoadFile) (char *name, void **buf); + void (*FS_FreeFile) (void *buf); + + // gamedir will be the current directory that generated + // files should be stored to, ie: "f:\quake\id1" + char *(*FS_Gamedir) (void); + char *(*FS_Userdir) (void); + void (*FS_CreatePath) (char *path); + + qboolean (*Vid_GetModeInfo)( int *width, int *height, int mode ); + void (*Vid_MenuInit)( void ); + void (*Vid_NewWindow)( int width, int height ); +} refimport_t; + + +// this is the only function actually exported at the linker level +typedef refexport_t (*GetRefAPI_t) (refimport_t); diff --git a/Toolkit/Programming/GameCode/client/screen.h b/Toolkit/Programming/GameCode/client/screen.h new file mode 100644 index 0000000..66f1fb4 --- /dev/null +++ b/Toolkit/Programming/GameCode/client/screen.h @@ -0,0 +1,43 @@ +// screen.h + +void SCR_Init (void); + +void SCR_UpdateScreen (void); + +void SCR_SizeUp (void); +void SCR_SizeDown (void); +void SCR_CenterPrint (char *str, PalIdx_t colour); +void SCR_CaptionPrint (char *str); +void SCR_ObituaryPrint (char *str, byte client1, byte client2, unsigned int colour); +void SCR_BeginLoadingPlaque (void); +void SCR_EndLoadingPlaque (void); + +void SCR_TouchPics (void); + +void SCR_RunConsole (void); + +extern float scr_con_current; +extern float scr_conlines; // lines of console to display + +extern int sb_lines; + +extern cvar_t *scr_viewsize; +extern cvar_t *crosshair; + +extern vrect_t scr_vrect; // position of render window + +//extern char crosshair_pic[MAX_QPATH]; +//extern int crosshair_width, crosshair_height; + +void SCR_AddDirtyPoint (int x, int y); +void SCR_DirtyScreen (void); + +// +// scr_cin.c +// +void SCR_PlayCinematic (char *name); +qboolean SCR_DrawCinematic (void); +void SCR_RunCinematic (void); +void SCR_FinishCinematic (void); +void SCR_StopCinematic(); + diff --git a/Toolkit/Programming/GameCode/client/vid.h b/Toolkit/Programming/GameCode/client/vid.h new file mode 100644 index 0000000..3acd2d6 --- /dev/null +++ b/Toolkit/Programming/GameCode/client/vid.h @@ -0,0 +1,33 @@ +// vid.h -- video driver defs + +#define MIN_GAMMA 0.1 // These also need to be defined in gl_local.h +#define MAX_GAMMA 4.0 + +#define DEF_WIDTH 640 +#define DEF_HEIGHT 480 + +typedef struct vrect_s +{ + int x,y,width,height; +} vrect_t; + +typedef struct +{ + int width; + int height; + byte *pixels; +} viddef_t; + +extern viddef_t viddef; // global video state + +// Video module initialisation etc +void VID_Init (void); +void VID_Shutdown (void); +void VID_CheckChanges (void); + +void VID_MenuInit( void ); +void VID_PreMenuInit( void ); +void __stdcall VID_MenuDraw(); +char * __stdcall VID_MenuKey( int ); + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/GameEntity.c b/Toolkit/Programming/GameCode/game/GameEntity.c new file mode 100644 index 0000000..41a28d0 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/GameEntity.c @@ -0,0 +1,2 @@ +#include "GameEntity.h" + diff --git a/Toolkit/Programming/GameCode/game/GameEntity.h b/Toolkit/Programming/GameCode/game/GameEntity.h new file mode 100644 index 0000000..f3aa9fc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/GameEntity.h @@ -0,0 +1,88 @@ +#include "g_local.h" + +typedef struct sv_entity_s +{ + entity_state_t s; + struct gclient_s *client; // NULL if not a player + // the server expects the first part + // of gclient_s to be a player_state_t + // but the rest of it is opaque + +// qboolean inuse; // replace with svflags & SVF_INUSE + + int linkcount; + + // FIXME: move these fields to a server private sv_entity_t (probably not necessary) + link_t area; // linked to a division node or leaf (zeroed in g_save.c is currently the only use of this in the Game DLL) + + int num_clusters; // if -1, use headnode instead (not referenced in Game DLL) + int clusternums[MAX_ENT_CLUSTERS]; // (not referenced in Game DLL) + int headnode; // unused if num_clusters != -1 (not referenced in Game DLL) + int areanum, areanum2; // (areanum is checked in g_ai.c) + + int svflags; + vec3_t mins, maxs; + vec3_t absmin, absmax, size; + solid_t solid; + int clipmask; + struct sv_entity_s *owner; +} sv_entity_t; + +typedef struct g_PolyInfo_s +{ + char *message; // text printed to con for door, polys, triggers, etc. + +} g_PolyInfo_t; + +typedef struct g_PhysicsInfo_s +{ + int movetype; // used by physics, set on everything + + float speed; // used by physics + + vec3_t velocity; + vec3_t avelocity; +} g_PhysicsInfo_t; + +#if 0 +typedef struct g_PlayerInfo_s +{ +} g_PlayerInfo_s; + +typedef struct g_MonsterInfo_s +{ +} g_MonsterInfo_s; + +typedef struct g_ActorInfo_s +{ +} g_ActorInfo_s; + +typedef struct g_ItemInfo_s +{ +} g_ItemInfo_t; +#endif + +typedef struct GameEntity_s +{ + MsgQueue_t msgQ; + G_MessageHandler_t msgHandler; + + int classID; + + void (*think)(struct GameEntity_s *self); + + int flags; + + int spawnflags; // this is being used in a rather nasty way, + // being & with magic numbers all over the place + + union + { + float nextthink; + float freetime; // sv.time when the object was freed + // set in G_FreeEdict and used in G_Spawn only + }; + + char *classname; + +} GameEntity_t; \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/ICScript.h b/Toolkit/Programming/GameCode/game/ICScript.h new file mode 100644 index 0000000..950a63f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/ICScript.h @@ -0,0 +1,19 @@ +#ifndef ICSCRIPT_H +#define ICSCRIPT_H + +typedef int qboolean; + +typedef struct ICScript_s +{ + int startFrame; + char *buf; + int bufSize; + int count; +} ICScript_t; + +void ICScript_Con(ICScript_t *this_ptr, char *name); +void RunICScript(); +void KillICScript(); + + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/Script.c b/Toolkit/Programming/GameCode/game/Script.c new file mode 100644 index 0000000..aaea025 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/Script.c @@ -0,0 +1,142 @@ +// +// Script.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#include "ICScript.h" +#include "g_local.h" +#include "SinglyLinkedList.h" + +void ICScript_Con(ICScript_t *this_ptr, char *name) +{ + char path[1024]; + + this_ptr->startFrame = level.framenum; + + sprintf(path, "cinematics/%s.ics", name); + + this_ptr->bufSize = gi.FS_LoadFile(path, &this_ptr->buf); + + this_ptr->count = 0; +} + +void ICScript_Des(ICScript_t *this) +{ + gi.FS_FreeFile(this->buf); +} + +static qboolean ICScript_Advance(ICScript_t *this) +{ + int i, frame, msgFrame, msgID; + char entityName[64]; + char format[64]; + size_t size; + G_Message_t *newMsg; + SinglyLinkedList_t *parms; + edict_t *ent = NULL; + + frame = level.framenum - this->startFrame; + + while(this->count < this->bufSize) + { + size = sizeof(int); + memcpy(&msgFrame, this->buf + this->count, size); + + if(msgFrame > frame) + break; + + this->count += size; + + i = 0; + + do + { + entityName[i] = *(this->buf + this->count); + ++i; + }while(*(this->buf + this->count++)); + + size = sizeof(int); + memcpy(&msgID, this->buf + this->count, size); + this->count += size; + + i = 0; + + do + { + format[i] = *(this->buf + this->count); + ++i; + }while(*(this->buf + this->count++)); + + i = 0; + + newMsg = G_Message_new(msgID, PRI_SYSTEM); + + parms = &newMsg->parms; + + if(format[0]) + { + this->count += SetParms(&newMsg->parms, format, this->buf + this->count, true); + } + + // this sucks, sticking each string field that gets searched on into a binary search + // tree or a hash table would probably be a good idea + // That would a little overhead when an entity is created or destroyed, but it should + // be worth it for the vastly improved search time + ent = G_Find (ent, FOFS(targetname), entityName); + +#ifdef _DEBUG + if(ent) + { + edict_t *ent2 = NULL; + + ent2 = G_Find (ent, FOFS(targetname), entityName); + + assert(!ent2); // each entityName should be unique!!! + } +#endif + + if(ent) + { + QueueMessage(&ent->msgQ, newMsg); + } + else + { + G_Message_delete(newMsg); + } + + assert(this->count <= this->bufSize); + } + + if(this->count >= this->bufSize) + { + return true; + } + else + { + return false; + } +} + +void RunICScript() +{ + if(level.cinActive) + { + if(ICScript_Advance(&level.inGameCin)) + { + ICScript_Des(&level.inGameCin); + level.cinActive = false; + } + } +} + +void KillICScript() +{ + if(level.cinActive) + { + ICScript_Des(&level.inGameCin); + level.cinActive = false; + } +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/Utilities.c b/Toolkit/Programming/GameCode/game/Utilities.c new file mode 100644 index 0000000..dbea9ed --- /dev/null +++ b/Toolkit/Programming/GameCode/game/Utilities.c @@ -0,0 +1,946 @@ +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN + +#include +#include +#include +#include + +#include "Utilities.h" +#include "Angles.h" +#include "g_local.h" +#include "Vector.h" +#include "g_HitLocation.h" +#include "g_Physics.h" +#include "Random.h" +#include "FX.H" +#include "p_main2.h" + +//kill specific entitys at the begining of a cinematic +void remove_non_cinematic_entites(edict_t *owner) +{ + int i; + edict_t *ent = NULL; + + // firstly, search for RED RAIN DAMAGE entites + while (1) + { + ent = G_Find (ent, FOFS(classname), "Spell_RedRain"); + if (!ent) + break; + if (!owner || (ent->owner && (ent->owner == owner))) + { + // kill the rain sound + gi.sound(ent, CHAN_VOICE, gi.soundindex("misc/null.wav"), 1, ATTN_NORM,0); + // remove the entity + gi.RemoveEffects(&ent->s, FX_WEAPON_REDRAIN); + G_SetToFree(ent); + } + } + + // then remove red rain arrows - in case of hitting something and starting the red rain + ent = NULL; + while (1) + { + ent = G_Find (ent, FOFS(classname), "Spell_RedRainArrow"); + if (!ent) + break; + if (!owner || (ent->owner && (ent->owner == owner))) + { + // kill the rain arrow travel sound + gi.sound(ent, CHAN_VOICE, gi.soundindex("misc/null.wav"), 1, ATTN_NORM,0); + // remove the entity + gi.RemoveEffects(&ent->s, FX_WEAPON_REDRAINMISSILE); + G_SetToFree(ent); + } + } + + // look for Powered up Mace balls - they've got to go too. + ent = NULL; + while (1) + { + ent = G_Find (ent, FOFS(classname), "Spell_Maceball"); + if (!ent) + break; + if (!owner || (ent->owner && (ent->owner == owner))) + { + // remove the entity + G_SetToFree(ent); + } + } + + // look for Phoenix arrows - we should remove them + ent = NULL; + while (1) + { + ent = G_Find (ent, FOFS(classname), "Spell_PhoenixArrow"); + if (!ent) + break; + if (!owner || (ent->owner && (ent->owner == owner))) + { + // kill the phoneix arrow travel sound + gi.sound(ent, CHAN_WEAPON, gi.soundindex("misc/null.wav"), 1, ATTN_NORM,0); + // remove the entity + G_SetToFree(ent); + } + } + + // look for Sphere - we should remove them + ent = NULL; + while (1) + { + ent = G_Find (ent, FOFS(classname), "Spell_SphereOfAnnihilation"); + if (!ent) + break; + if (!owner || (ent->owner && (ent->owner == owner))) + { + // kill the sphere grow sound + gi.sound(ent, CHAN_WEAPON, gi.soundindex("misc/null.wav"), 1, ATTN_NORM,0); + // remove the entity + G_SetToFree(ent); + } + } + + // look for meteor barriers - we should remove them + ent = NULL; + while (1) + { + ent = G_Find (ent, FOFS(classname), "Spell_MeteorBarrier"); + if (!ent) + break; + if (!owner || (ent->owner && (ent->owner == owner))) + { + // remove any persistant meteor effects + if (ent->PersistantCFX) + { + gi.RemovePersistantEffect(ent->PersistantCFX); + gi.RemoveEffects(&ent->owner->s, FX_SPELL_METEORBARRIER+ent->health); + ent->PersistantCFX = 0; + } + // kill the meteorbarrier ambient sound + ent->owner->client->Meteors[ent->health] = NULL; + + // now we've been cast, remove us from the count of meteors the caster owns, and turn off his looping sound if need be + ent->owner->client->playerinfo.meteor_count &= ~(1<health); + if (!ent->owner->client->playerinfo.meteor_count) + ent->owner->s.sound = 0; + + // remove the entity + G_SetToFree(ent); + } + } + + // Hide all other players and make them not clip + ent = NULL; + for (i=0 ; ivalue ; i++) + { + ent = g_edicts + 1 + i; + if (!ent->inuse || !ent->client) + continue; + + ent->client->playerinfo.cinematic_starttime = level.time; + + if (ent->client->playerinfo.powerup_timer > ent->client->playerinfo.cinematic_starttime) + gi.RemoveEffects(&ent->s, FX_TOME_OF_POWER); + + if (ent->client->playerinfo.shield_timer > ent->client->playerinfo.leveltime) + { + gi.RemoveEffects(&ent->s, FX_SPELL_LIGHTNINGSHIELD); + ent->client->playerinfo.cin_shield_timer = ent->client->playerinfo.shield_timer; + ent->client->playerinfo.shield_timer = 0; + } + + // No looping sound attached. + ent->s.sound = 0; + + ent->curr_model = ent->s.modelindex; // Temp holder, should be fine because player isn't doing anything during cinematics + ent->client->playerinfo.c_mode = 1; // Show it's in cinematic mode + ent->s.modelindex = 0; + ent->solid = SOLID_NOT; + } + +} +void player_shrine_light_effect(edict_t *self); +void shrine_light_core(edict_t *self, edict_t *other); + +void reinstate_non_cinematic_entites(edict_t *owner) +{ + int i; + edict_t *ent = NULL; + + // Put client entities back in game + ent = NULL; + for (i=0 ; ivalue ; i++) + { + ent = g_edicts + 1 + i; + if (!ent->inuse || !ent->client) + continue; + + if (level.time > ent->client->playerinfo.cinematic_starttime) + { + + if (ent->client->playerinfo.light_timer > ent->client->playerinfo.cinematic_starttime) + { + ent->client->playerinfo.light_timer += level.time - ent->client->playerinfo.cinematic_starttime; + ent->s.effects |= EF_LIGHT_ENABLED; + gi.CreateEffect(&ent->s, FX_PLAYER_TORCH, CEF_OWNERS_ORIGIN, NULL, ""); + } + + if (ent->client->playerinfo.reflect_timer > ent->client->playerinfo.cinematic_starttime) + { + ent->client->playerinfo.reflect_timer += level.time - ent->client->playerinfo.cinematic_starttime; + ent->s.renderfx |= RF_REFLECTION; + } + + if (ent->client->playerinfo.ghost_timer > ent->client->playerinfo.cinematic_starttime) + { + ent->client->playerinfo.ghost_timer += level.time - ent->client->playerinfo.cinematic_starttime; + ent->s.renderfx |= RF_TRANS_GHOST; + } + + if (ent->client->playerinfo.powerup_timer > ent->client->playerinfo.cinematic_starttime) + { + ent->client->playerinfo.powerup_timer += level.time - ent->client->playerinfo.cinematic_starttime; + ent->s.effects |= EF_POWERUP_ENABLED; + ent->client->playerinfo.effects |= EF_POWERUP_ENABLED; + gi.CreateEffect(&ent->s, FX_TOME_OF_POWER, CEF_OWNERS_ORIGIN, NULL, ""); + } + + if (ent->client->playerinfo.cin_shield_timer > ent->client->playerinfo.cinematic_starttime) + { + ent->client->playerinfo.shield_timer = + ent->client->playerinfo.cin_shield_timer + level.time - ent->client->playerinfo.cinematic_starttime; + ent->PersistantCFX = gi.CreatePersistantEffect(&ent->s, FX_SPELL_LIGHTNINGSHIELD, CEF_OWNERS_ORIGIN|CEF_BROADCAST, NULL, ""); + } + + if (ent->client->playerinfo.speed_timer > ent->client->playerinfo.cinematic_starttime) + { + ent->client->playerinfo.speed_timer += level.time - ent->client->playerinfo.cinematic_starttime; + ; // Insert effect code here + } + + // since we messed around with model stuff, like armor nodes and the like, lets update the model. + SetupPlayerinfo_effects(ent); + PlayerUpdateModelAttributes(&ent->client->playerinfo); + WritePlayerinfo_effects(ent); + + } + + ent->client->playerinfo.c_mode = 0; // Show cinematic mode is off + ent->s.modelindex = ent->curr_model; + ent->solid = SOLID_BBOX; + } + +} + +void GetEdictCenter(edict_t *self, vec3_t out) +{ + VectorAverage(self->mins, self->maxs, out); + Vec3AddAssign(self->s.origin, out); +} + +float NormalizeAngle(float angle) +{ +#if 1 + // Returns the remainder + angle = fmod(angle, ANGLE_360); + // Makes the angle signed + if(angle >= ANGLE_180) + { + angle -= ANGLE_360; + } + if(angle <= -ANGLE_180) + { + angle += ANGLE_360; + } +#else + if (Q_fabs(angle) > 15 * ANGLE_360) + { + angle = (float)atan2(sin(angle), cos(angle)); + + return angle; + } + + while (angle < -ANGLE_180) + { + angle += ANGLE_360; + } + + while (angle >= ANGLE_180) + { + angle -= ANGLE_360; + } +#endif + return angle; +} + +float AddNormalizedAngles(float angle1, float angle2) +{ + float sum; + + if(angle1 >= 0) + { + if(angle2 >= 0) + { + sum = angle1 + angle2; + + if(sum >= ANGLE_180) + { + return (sum - ANGLE_360); + } + } + else + { + return (angle1 + angle2); + } + } + else + { + if(angle2 < 0) + { + sum = angle1 + angle2; + + if(sum < -ANGLE_180) + { + return (sum + ANGLE_360); + } + } + else + { + return (angle1 + angle2); + } + } + + return sum; +} + +qboolean ok_to_autotarget(edict_t *shooter, edict_t *target) +{ + if((!target->inuse)||(target->solid==SOLID_NOT)||(target->health<=0)||(target==shooter)||(target->svflags&SVF_NO_AUTOTARGET)) + return(false); + + // Don't allow us to find our caster , if there is one. + + if (shooter->owner) + { + if (target == shooter->owner) + return(false); + } + + // Now test against single player / deathmatch / coop specifics. + + if(deathmatch->value) + { + // Only want to find other clients in deathmatch. + + if(!target->client) + return(false); + } + else + { + // Find just monsters in single player / coop. + + if((!(target->svflags&SVF_MONSTER))&&(!(target->svflags&SVF_ALLOW_AUTO_TARGET))) + return(false); + } + + return(true); +} + +// ************************************************************************************************ +// FindNearestVisibleActorInFrustum +// -------------------------------- +// I copied FindNearestActorInFrustum() and modified it so that it can take line-of-sight into +// account if specified (i.e. LOSStartPos is not NULL). Additionally I relaxed the constraint that +// the horizontal search arc has to be [-180.0<=hFOV<=+180.0] so that homing missiles can see all +// around themselves when looking for a targetet 'lock'. -Marcus +// ************************************************************************************************ + +#define NEW_FINDNEAR (0) + +#if !NEW_FINDNEAR + + +edict_t *FindNearestVisibleActorInFrustum(edict_t *Finder,vec3_t FinderAngles, + float nearDist,float farDist, + double hFOV,double vFOV, + long Flags, + vec3_t LOSStartPos, + vec3_t BBMin,vec3_t BBMax) +{ + vec3_t distVect, + _BBMin,_BBMax, + TempVec; + edict_t *end,*best,*ent; + float curDist,nearDist2, + bestDist, + curYaw,curPitch, + minHFOV,maxHFOV,minVFOV,maxVFOV; + float baseYaw,distTemp,mag; + trace_t Trace; + + assert(nearDist>=0.0); + + if(LOSStartPos) + { + if(!BBMin) + VectorClear(_BBMin); + else + VectorCopy(BBMin,_BBMin); + + if(!BBMax) + VectorClear(_BBMax); + else + VectorCopy(BBMax,_BBMax); + } + + bestDist = farDist * farDist; + nearDist2 = nearDist * nearDist; + + minHFOV = -hFOV * 0.5; + maxHFOV = -minHFOV; + + minVFOV = -vFOV * 0.5; + maxVFOV = -minVFOV; + + baseYaw = NormalizeAngle(FinderAngles[YAW] * ANGLE_TO_RAD); + best = NULL; + + end = &g_edicts[globals.num_edicts]; + + for(ent = g_edicts + 1; ent < end; ent++) + { + // Ignore certain entities altogether. + if(!ok_to_autotarget(Finder, ent)) + continue; + + // don't target ghosting players. + if (ent->client && (ent->client->playerinfo.ghost_timer > level.time)) + continue; + + // Get the center (in world terms) of the entity (actually the center according to it's + // bounding box). + GetEdictCenter(ent, TempVec); + + // Ok, we can see the entity (or don't care whether we can or can't) so make the checks to + // see if it lies within the specified frustum parameters. + + VectorSubtract(TempVec, Finder->s.origin, distVect); + + distTemp = distVect[Y] * distVect[Y] + distVect[X] * distVect[X]; + curDist = distTemp + distVect[Z] * distVect[Z]; + + if((curDist >= nearDist2) && (curDist <= bestDist)) + { + mag = sqrt(distTemp); + + curYaw = atan2(distVect[Y]/mag,distVect[X]/mag); + + curYaw = AddNormalizedAngles(curYaw,-baseYaw); + + if((curYaw>=minHFOV)&&(curYaw<=maxHFOV)) + { + mag=sqrt(distVect[Y]*distVect[Y]+distVect[Z]*distVect[Z]); + + curPitch=asin(distVect[Z]/mag); + + if((curPitch>=minVFOV)&&(curPitch<=maxVFOV)) + { + // If LOSStartPos is not NULL, we need a line of sight to the entity (see above), else + // skip to the next entity. + + if(LOSStartPos) + { + if(gi.inPVS(LOSStartPos, TempVec)) + {//cheaper than a trace + gi.trace(LOSStartPos, // Start pos. + _BBMin, // Bounding box min. + _BBMax, // Bounding box max. + TempVec, // End pos. + Finder, // Ignore this edict. + CONTENTS_SOLID,&Trace); // Contents mask. + + if((Trace.fraction!=1.0)||(Trace.startsolid)) + { + continue; + } + } + else + continue; + } + + bestDist=curDist; + best=ent; + } + } + } + } + + return(best); +} + +#else + + +static float *SortOrigin; + +int DistSort (void const *a, void const *b) +{ + vec3_t tmp; + float da,db; + edict_t *e; + + e=*(edict_t **)a; + VectorSubtract(e->s.origin,SortOrigin,tmp); + da=DotProduct(tmp,tmp); + e=*(edict_t **)b; + VectorSubtract(e->s.origin,SortOrigin,tmp); + db=DotProduct(tmp,tmp); + + if (da < db) + return -1; + if (da > db) + return 1; + return 0; +} + +edict_t *FindNearestVisibleActorInFrustum(edict_t *Finder,vec3_t FinderAngles, + float nearDist,float farDist, + double hFOV,double vFOV, + long Flags, + vec3_t LOSStartPos, + vec3_t BBMin,vec3_t BBMax) +{ + edict_t *touchlist[MAX_EDICTS]; + int i,num; + vec3_t minBox,maxBox; + vec3_t distVect, + _BBMin,_BBMax, + TempVec; + edict_t *best,*ent; + float curDist,nearDist2, + bestDist, + curYaw,curPitch, + minHFOV,maxHFOV,minVFOV,maxVFOV; + float baseYaw,distTemp,mag; + trace_t Trace; + + assert(nearDist>=0.0); + + if(LOSStartPos) + { + if(!BBMin) + VectorClear(_BBMin); + else + VectorCopy(BBMin,_BBMin); + + if(!BBMax) + VectorClear(_BBMax); + else + VectorCopy(BBMax,_BBMax); + } + + bestDist = farDist * farDist; + nearDist2 = nearDist * nearDist; + + minHFOV = -hFOV * 0.5; + maxHFOV = -minHFOV; + + minVFOV = -vFOV * 0.5; + maxVFOV = -minVFOV; + + baseYaw = NormalizeAngle(FinderAngles[YAW] * ANGLE_TO_RAD); + best = NULL; + + for (i=0;i<3;i++) + { + minBox[i]=Finder->s.origin[i]-farDist; + maxBox[i]=Finder->s.origin[i]+farDist; + } + num = gi.BoxEdicts(minBox,maxBox, touchlist, MAX_EDICTS, AREA_SOLID); + if (!num) + return 0; + SortOrigin=Finder->s.origin; + qsort(touchlist,num,sizeof(edict_t *),DistSort); + + for(i=0;is.origin, distVect); + + distTemp = distVect[Y] * distVect[Y] + distVect[X] * distVect[X]; + curDist = distTemp + distVect[Z] * distVect[Z]; + + if((curDist >= nearDist2) && (curDist <= bestDist)) + { + mag = sqrt(distTemp); + + curYaw = atan2(distVect[Y]/mag,distVect[X]/mag); + + curYaw = AddNormalizedAngles(curYaw,-baseYaw); + + if((curYaw>=minHFOV)&&(curYaw<=maxHFOV)) + { + mag=sqrt(distVect[Y]*distVect[Y]+distVect[Z]*distVect[Z]); + + curPitch=asin(distVect[Z]/mag); + + if((curPitch>=minVFOV)&&(curPitch<=maxVFOV)) + { + // If LOSStartPos is not NULL, we need a line of sight to the entity (see above), else + // skip to the next entity. + + if(LOSStartPos) + { + gi.trace(LOSStartPos, // Start pos. + _BBMin, // Bounding box min. + _BBMax, // Bounding box max. + TempVec, // End pos. + Finder, // Ignore this edict. + CONTENTS_SOLID,&Trace); // Contents mask. + + if((Trace.fraction!=1.0)||(Trace.startsolid)) + { + continue; + } + } + + bestDist=curDist; + best=ent; + break; + } + } + } + } + + return(best); +} + + +#endif + + +edict_t *FindSpellTargetInRadius(edict_t *searchent, float radius, vec3_t searchpos, + vec3_t mins, vec3_t maxs) +{ + vec3_t distVect, + _mins,_maxs, + entpos; + edict_t *ent,*best; + float curDist, bestDist; + trace_t Trace; + + assert(radius>=0.0); + assert(searchpos); + + if(!mins) + VectorClear(_mins); + else + VectorCopy(mins, _mins); + + if(!maxs) + VectorClear(_maxs); + else + VectorCopy(maxs, _maxs); + + bestDist = radius * radius; + + best = NULL; + ent = NULL; + while(ent = findradius(ent, searchpos, radius)) + { + // Ignore certain entities altogether. + if (ent == searchent || ent == searchent->owner) + continue; + + if (!ent->takedamage && ent->health <= 0) + continue; + + if(!ok_to_autotarget(searchent, ent)) + continue; + + // don't target ghosting players, or target players in coop. + if (ent->client && ((ent->client->playerinfo.ghost_timer > level.time) || coop->value)) + continue; + + // Get the center (in world terms) of the entity (actually the center according to it's + // bounding box). + GetEdictCenter(ent, entpos); + + // Ok, we can see the entity (or don't care whether we can or can't) so make the checks to + // see if it lies within the specified frustum parameters. + + VectorSubtract(entpos, searchpos, distVect); + + curDist = distVect[Y] * distVect[Y] + distVect[X] * distVect[X] + distVect[Z] * distVect[Z]; + + if(curDist <= bestDist) + { + if(gi.inPVS(searchpos, entpos)) + {//cheaper than a trace + gi.trace(searchpos, // Start pos. + _mins, // Bounding box min. + _maxs, // Bounding box max. + entpos, // End pos. + searchent, // Ignore this edict. + CONTENTS_SOLID, &Trace); // Contents mask. + + if((Trace.fraction!=1.0)||(Trace.startsolid)) + { + continue; + } + else + { + bestDist=curDist; + best=ent; + } + } + } + } + + return(best); +} + + + + + + + +// Pretty much the same as the above routine +// Except it is only for client to client + +#define MAX_PLAYER_VIEW 1024.0F + +// FIXME : Need to use cameras origin, not players origin + +void CalculatePIV(edict_t *player) +{ + int i, PIV; + edict_t *target; + float FOV; + vec3_t endpos, dist, movedir; + vec3_t mins, maxs, angles, org; + trace_t trace; + int frameidx, playeridx; + + // if we have no names on through deathmatch flags, don't send them down + if(deathmatch->value && ((int)dmflags->value & DF_NONAMES)) + { + player->client->ps.PIV = 0; + return; + } + + // Only update data once every 8 frames + frameidx = level.framenum & 7; + playeridx = (player->s.number - 1) & 7; + if(frameidx != playeridx) + { + return; + } + + + PIV = 0; + FOV = cos(player->client->ps.fov * ANGLE_TO_RAD * 0.5); + + // Grab camera angles + angles[0] = SHORT2ANGLE(player->client->playerinfo.pcmd.camera_viewangles[0]); + angles[1] = SHORT2ANGLE(player->client->playerinfo.pcmd.camera_viewangles[1]); + angles[2] = SHORT2ANGLE(player->client->playerinfo.pcmd.camera_viewangles[2]); + AngleVectors(angles, movedir, NULL, NULL); + + // Grab camera coords + org[0] = player->client->playerinfo.pcmd.camera_vieworigin[0] * 0.125F; + org[1] = player->client->playerinfo.pcmd.camera_vieworigin[1] * 0.125F; + org[2] = player->client->playerinfo.pcmd.camera_vieworigin[2] * 0.125F; + + VectorScale(player->mins, 0.25F, mins); + VectorScale(player->maxs, 0.25F, maxs); + + // FIXME : Need some way of knowing whether client is valid or not + for(i = 0, target = g_edicts + 1; i < game.maxclients; i++, target++) + { + assert(target->client); + // Don`t do an in view check on yourself + if(player == target) + { + continue; + } + if(!target->inuse) + { + continue; + } + if (target->s.renderfx & RF_TRANS_GHOST) + { // Can't target ghosts. + continue; + } + if (target->light_level < 16) + { // Too dark to see + continue; + } + // Get center of enemy + GetEdictCenter(target, endpos); + VectorSubtract(endpos, org, dist); + + // Check range to other player + if(VectorNormalize(dist) > MAX_PLAYER_VIEW) + { + continue; + } + // Check in players FOV + if(DotProduct(dist, movedir) < FOV) + { + continue; + } + if(!gi.inPVS(org, endpos)) + { + continue; + } + gi.trace(org, mins, maxs, endpos, player, MASK_PLAYERSOLID,&trace); + if(trace.ent == target) + { + PIV |= 1 << i; + } + } + player->client->ps.PIV = PIV; +} + +void GetVectorsToActor(edict_t *self, edict_t *actor, vec3_t vec) +{ + vec3_t dest, source; + + GetEdictCenter(self, source); + GetEdictCenter(actor, dest); + VectorSubtract(dest, source, vec); + VectorNormalize(vec); +} + +void QPlaySound(edict_t *self, int sound, int channel) +{ + gi.sound (self, channel, classStatics[self->classID].resInfo->sounds[sound], 1, ATTN_NORM, 0); +} + +void StartICScript(char *name) +{ + assert(!level.cinActive); + + level.cinActive = true; + + ICScript_Con(&level.inGameCin, name); +} + +#define EXTRA_KNOCKBACK_PRE_MULT 2 +#define EXTRA_KNOCKBACK_POST_Z_MULT 1.25 + +void CalculateKnockBack(vec3_t dir, float knockback, int flags, float mass, vec3_t vel) +{ + if(flags & DAMAGE_EXTRA_KNOCKBACK) + { + knockback *= EXTRA_KNOCKBACK_PRE_MULT; + } + + VectorScale(dir, (KNOCK_BACK_MULTIPLIER * (float)knockback) / mass, vel); + + if(flags & DAMAGE_EXTRA_KNOCKBACK) + { + vel[2] *= EXTRA_KNOCKBACK_POST_Z_MULT; + } +} + +void PostKnockBack(edict_t *target, vec3_t dir, float knockback, int flags) +{ + vec3_t vel; + + CalculateKnockBack(dir, knockback, flags, target->mass, vel); + + QPostMessage(target, G_MSG_KNOCKEDBACK, PRI_PHYSICS, "fffi", vel[0], vel[1], vel[2], flags); +} + + +// Gets aiming vector to enemy or uses default aimangles + +void GetAimVelocity(edict_t *enemy, vec3_t org, vec_t speed, vec3_t AimAngles, vec3_t out) +{ + float h_offs, v_offs; + + if(enemy) + { + VectorAverage(enemy->mins, enemy->maxs, out); // Get center of model + + if(skill->value) + {//if skill = 0, aim for center of chest, otherwise, offset it some + h_offs = enemy->maxs[0] * 0.75; + v_offs = enemy->maxs[2] * 0.5; + out[0] += flrand(-h_offs, h_offs); + out[1] += flrand(-h_offs, h_offs); + out[2] += flrand(-v_offs, v_offs); + } + else + out[2] += enemy->maxs[2] /2; + + Vec3AddAssign(enemy->s.origin, out); + Vec3SubtractAssign(org, out); + VectorNormalize(out); + } + else + { + AngleVectors(AimAngles, out, NULL, NULL); + } + Vec3ScaleAssign(speed, out); +} + +void SetAnim(edict_t *self, int anim) +{ + monsterinfo_t *monsterinfo = &self->monsterinfo; + + assert(classStatics[self->classID].resInfo); + assert(classStatics[self->classID].resInfo->animations); + + monsterinfo->currentmove = classStatics[self->classID].resInfo->animations[anim]; + + //only reset the anim index if the new anim is diff. from your + //current anim + if(self->curAnimID != anim) + { + monsterinfo->currframeindex = 0; + monsterinfo->nextframeindex = 0; + } + + self->lastAnimID = self->curAnimID; + + self->curAnimID = anim; +} + +// Returns true if it is time to think + +qboolean ThinkTime(edict_t *self) +{ + if(!self->think) + { + return(false); + } + if(self->nextthink <= TIME_EPSILON) + { + return(false); + } + // Need an epsilon value to account for floating point error + // The epsilon can be large because level.time goes up in increments of 0.1 + if((self->nextthink - level.time) > TIME_EPSILON) + { + return(false); + } + return(true); +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/Utilities.h b/Toolkit/Programming/GameCode/game/Utilities.h new file mode 100644 index 0000000..9a63c2d --- /dev/null +++ b/Toolkit/Programming/GameCode/game/Utilities.h @@ -0,0 +1,47 @@ +#include "g_Typedef.h" + +#define X 0 +#define Y 1 +#define Z 2 + +#define LUNG_AIRTIME 12 +#define GILL_AIRTIME 18 + +#define KNOCK_BACK_MULTIPLIER 1000.0 + +float NormalizeAngle(float angle); +float AddNormalizedAngles(float angle1, float angle2); + +extern edict_t *FindNearestVisibleActorInFrustum(edict_t *Finder,vec3_t FinderAngles, + float nearDist,float farDist, + double hFOV,double vFOV, + long Flags, + vec3_t LOSStartPos, + vec3_t BBMin,vec3_t BBMax); + +extern edict_t *FindSpellTargetInRadius(edict_t *searchent, float radius, vec3_t searchpos, + vec3_t mins, vec3_t maxs); + +extern void GetVectorsToActor(edict_t *self, edict_t *actor, vec3_t vec); +extern void QPlaySound(edict_t *self, int sound, int channel); + +extern void SetAnim(edict_t *self, int anim); + +extern void SpawnBlood(edict_t *target, edict_t *inflictor, vec3_t point, vec3_t normal, + int damage); +extern void CalculateKnockBack(vec3_t dir, float knockback, int flags, float mass, vec3_t vel); +extern void PostKnockBack(edict_t *target, vec3_t dir, float knockback, int flags); +extern void DoDamage(edict_t *target, edict_t *inflictor, edict_t *attacker, vec3_t dir, + vec3_t point, vec3_t normal, int damage, int knockback, int flags, HitLocation_t hitLocation); +extern void CheckForEnviromentDamage(edict_t *self); +extern void DefaultApplyKnockBack(edict_t *self, vec3_t vel); +extern int CategorizeDirection(int stepDOF, float stepDir); + +void StartICScript(char *name); +void GetAimVelocity(edict_t *enemy, vec3_t org, vec_t speed, vec3_t AimAngles, vec3_t out); +void remove_non_cinematic_entites(edict_t *owner); + +qboolean ok_to_autotarget(edict_t *shooter, edict_t *target); +qboolean ThinkTime(edict_t *self); + + diff --git a/Toolkit/Programming/GameCode/game/buoy.c b/Toolkit/Programming/GameCode/game/buoy.c new file mode 100644 index 0000000..a72406f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/buoy.c @@ -0,0 +1,918 @@ +// **************************************************************************** +// BUOYAH! Navigation System +// +// Heretic II +// Copyright 1998 Raven Software +// +// Mike Gummelt & Josh Weier +// **************************************************************************** + +#include "g_local.h" +#include "buoy.h" +#include "vector.h" +#include "random.h" +#include "fx.h" +#include "m_stats.h" + +#define SF_JUMP 1//make monster jump +#define SF_ACTIVATE 2//turn something on +#define SF_TURN 4 +#define SF_ONEWAY 8//don't back-link + +#define SF_BROKEN 64//a bad bad buoy +#define SF_DONT_TRY 128//don't allow monster to head here + +#define BUOY_PRINT_INFO_DIST 64 +#define MAX_BUOY_BRANCH_CHECKS 1024//only check 1024 branches before giving up +#define MAX_PROGRESSIVE_CHECK_DEPTH 20//only search 20 buoys deep if doing a progressive depth check + +static int check_depth; +static int buoy_depth; +static int branch_counter;//short circuit check if 1024 + +//Returns the buoy's id +int insert_buoy(edict_t *self) +{ + buoy_t *buoy = &level.buoy_list[level.active_buoys]; + int i; + + //Init these values to -1 so we know what's filled + for (i=0;inextbuoy[i] = NULL_BUOY; + buoy->jump_target_id = NULL_BUOY; + + //Copy all the other important info + buoy->opflags = self->ai_mood_flags; + buoy->modflags = self->spawnflags; + if(buoy->modflags & BUOY_JUMP) + { + buoy->jump_target = self->jumptarget; + buoy->jump_fspeed = self->speed; + buoy->jump_yaw = self->s.angles[YAW]; + buoy->jump_uspeed = self->movedir[2]; + } + else + { + buoy->jump_fspeed = buoy->jump_yaw = buoy->jump_uspeed = 0; + } + VectorCopy(self->s.origin, buoy->origin); + + //Get the contents so that we know if this is a water buoy or not + buoy->contents = gi.pointcontents(buoy->origin); + //are we going to be opening anything? + buoy->pathtarget = self->pathtarget; + + //save the connections for easier debugging + buoy->target = self->target; + buoy->jump_target = self->jumptarget; + buoy->targetname = self->targetname; + + buoy->wait = self->wait; + buoy->delay = self->delay; + +// Gil suggestion: unimplemented +// buoy->failed_depth = 999999999; + + //Post incremented on purpose, thank you + buoy->id = level.active_buoys++; + //when done, level.active_buoys will be the total number of buoys, + //level.active_buoys - 1 will be the last valid buoy + + return buoy->id; +} + +void assign_nextbuoy(edict_t *self, edict_t *ent) +{ + buoy_t *buoy = &level.buoy_list[self->count]; + int i; + + for (i = 0; i < MAX_BUOY_BRANCHES; i++) + { + if (buoy->nextbuoy[i] > NULL_BUOY) + { + if (i==2) + { + gi.dprintf("G.D.E. FAULT: Buoy %d: Too many connections on buoy %s (%s)\n", self->count, self->targetname, vtos(self->s.origin)); + self->ai_mood_flags |= SF_BROKEN; + return; + } + + continue; + } + + buoy->nextbuoy[i] = ent->count; + return; + } + + return; +} + +void assign_jumpbuoy(edict_t *self, edict_t *ent) +{//self is supposed to make monsters jump at ent + buoy_t *buoy = &level.buoy_list[self->count]; + int i; + + for (i = 0; i < MAX_BUOY_BRANCHES; i++) + { + if (buoy->jump_target_id > NULL_BUOY) + { + gi.dprintf("G.D.E. FAULT: Buoy %s (%s): already has a jump_target(%s), tried to assign another %s!\n", buoy->targetname, vtos(buoy->origin), buoy->jump_target, ent->targetname); + self->ai_mood_flags |= SF_BROKEN; + return; + continue; + } + + buoy->jump_target_id = ent->count; + return; + } + + return; +} + +// **************************************************************************** +// Link the buoys after all entities have been spawned +// **************************************************************************** +void info_buoy_link(edict_t *self) +{ + edict_t *ent = NULL; + int i; + + if(self->spawnflags & BUOY_ACTIVATE) + { + if(!self->pathtarget) + { + if (BUOY_DEBUG) + { + gi.dprintf("G.D.E. FAULT: Buoy %s at %s is an ACTIVATE buoy but has no pathtarget!!!\n", self->targetname, vtos(self->s.origin)); + self->ai_mood_flags |= SF_BROKEN; + } + self->spawnflags &= ~BUOY_ACTIVATE; + } + } + + //Make sure we have a target to link to + if (self->target) + { + ent = NULL; + ent = G_Find(ent, FOFS(targetname), self->target); + + if (ent == NULL) + { + if (BUOY_DEBUG) + { + gi.dprintf("G.D.E. FAULT: info_buoy_link: %s(%s) failed to find target buoy %s\n", self->targetname, vtos(self->s.origin), self->target); + self->ai_mood_flags |= SF_BROKEN; + } + } + else if(ent == self) + { + gi.dprintf("G.D.E. FAULT: info_buoy_link: %s(%s) target(%s) is self!!!\n", self->targetname, vtos(self->s.origin), self->target); + self->ai_mood_flags |= SF_BROKEN; + } + else + { + if (BUOY_DEBUG) + gi.dprintf("info_buoy_link: linked %s to %s\n", self->targetname, ent->targetname); + + //Link this buoy to it's target + assign_nextbuoy(self, ent); + + if(BUOY_DEBUG > 1) + { + gi.CreatePersistantEffect(NULL, + FX_M_EFFECTS,//green arrows + CEF_BROADCAST, + self->s.origin, + "bv", + FX_BUOY_PATH, + ent->s.origin); + } + //If it's not one way, then back link it as well + if(!(self->spawnflags&SF_ONEWAY)) + assign_nextbuoy(ent, self); + } + } + + //Also check for a secondary target + if (self->target2) + { + if ( (self->target) && (!stricmp(self->target2, self->target)) ) + { + if (BUOY_DEBUG) + { + gi.dprintf("G.D.E. FAULT: info_buoy_link2: %s(%s) has target2 same as target %s\n", self->targetname, vtos(self->s.origin), self->target2); + self->ai_mood_flags |= SF_BROKEN; + } + } + else + { + ent = NULL; + ent = G_Find(ent, FOFS(targetname), self->target2); + + if (ent == NULL) + { + if (BUOY_DEBUG) + { + gi.dprintf("G.D.E. FAULT: info_buoy_link2: %s(%s) failed to find target2 buoy %s\n", self->targetname, vtos(self->s.origin), self->target2); + self->ai_mood_flags |= SF_BROKEN; + } + } + else if(ent == self) + { + gi.dprintf("G.D.E. FAULT: info_buoy_link2: %s(%s) target2(%s) is self!!!\n", self->targetname, vtos(self->s.origin), self->target2); + self->ai_mood_flags |= SF_BROKEN; + } + else + { + //Link this buoy to it's target + assign_nextbuoy(self, ent); + + if(BUOY_DEBUG > 1) + { + gi.CreatePersistantEffect(NULL, + FX_M_EFFECTS,//green arrows + CEF_BROADCAST, + self->s.origin, + "bv", + FX_BUOY_PATH, + ent->s.origin); + } + //If it's not one way, then back link it as well + if(!(self->spawnflags&SF_ONEWAY)) + assign_nextbuoy(ent, self); + } + } + } + + if(self->spawnflags&BUOY_JUMP) + { + if(!self->jumptarget) + { + if (BUOY_DEBUG) + { + gi.dprintf("G.D.E. FAULT: Buoy %s at %s is a JUMP buoy but has no jumptarget!!!\n", self->targetname, vtos(self->s.origin)); + self->ai_mood_flags |= SF_BROKEN; + } + self->spawnflags &= ~BUOY_JUMP; + } + else + { + ent = NULL; + if(ent = G_Find(ent, FOFS(targetname), self->jumptarget)) + { + assign_jumpbuoy(self, ent); + if(BUOY_DEBUG>1) + { + gi.CreatePersistantEffect(NULL, + FX_M_EFFECTS,//blue particles + CEF_FLAG8|CEF_BROADCAST, + ent->s.origin, + "bv", + FX_BUOY, + vec3_origin); + } + } + else if(BUOY_DEBUG) + { + gi.dprintf("G.D.E. FAULT: Buoy %s(%s) could not find jumptarget buoy %s\n", self->targetname, vtos(self->s.origin), self->jumptarget); + self->ai_mood_flags |= SF_BROKEN; + } + } + } + + if(self->ai_mood_flags & SF_BROKEN) + {//put an effect on broken buoys? + level.buoy_list[self->count].opflags |= SF_BROKEN; + level.fucked_buoys++; + } + + if(self->count == level.active_buoys - 1) + { + for(i = 0; i < level.active_buoys; i++) + {//see if any buoys are loners + if(!level.buoy_list[i].nextbuoy[0]&& + !level.buoy_list[i].nextbuoy[1]&& + !level.buoy_list[i].nextbuoy[2]) + { + gi.dprintf("G.D.E. WARNING: buoy %s(%s) has no connections\n", level.buoy_list[i].targetname, vtos(level.buoy_list[i].origin)); + } + } + Com_Printf("%d buoys processed by BUOYAH! Navigation System(tm) (%d bad : %d fixed)\n", level.active_buoys, level.fucked_buoys, level.fixed_buoys); + } + + if(!BUOY_DEBUG) + { + G_SetToFree(self); + } + else + {//buoys don't need to think + self->think = NULL; + self->nextthink = -1; + } +} + +void PrintLocalBuoyInfo(vec3_t org) +{ + int i, j; + vec3_t dir; + float dist; + + for(i = 0; i NULL_BUOY) + { + if(j!=0) + gi.dprintf(", "); + gi.dprintf("%s", level.buoy_list[level.buoy_list[i].nextbuoy[j]].targetname); + } + } + gi.dprintf("\n"); + + + if(level.buoy_list[i].modflags & BUOY_JUMP) + { + gi.dprintf("\nJUMP\n"); + gi.dprintf("jump_target buoy: %s\n", level.buoy_list[i].jump_target); + gi.dprintf("angle: %4.2f\n", level.buoy_list[i].jump_yaw); + gi.dprintf("height: %4.2f\n", level.buoy_list[i].jump_uspeed); + gi.dprintf("speed: %4.2f\n", level.buoy_list[i].jump_fspeed); + level.buoy_list[i].print_debounce_time = level.time + 1; + } + + if(level.buoy_list[i].modflags & BUOY_ACTIVATE) + { + edict_t *found; + + gi.dprintf("\nACTIVATE\n"); + gi.dprintf("pathtarget: %s\n", level.buoy_list[i].pathtarget); + if(found = G_Find(NULL, FOFS(pathtargetname), level.buoy_list[i].pathtarget)) + gi.dprintf("entity to activate: %s\n", found->classname); + else + gi.dprintf("ERROR: no entity found to activate!!!\n"); + gi.dprintf("wait: %4.2f\n", level.buoy_list[i].wait); + gi.dprintf("delay: %4.2f\n", level.buoy_list[i].delay); + level.buoy_list[i].print_debounce_time = level.time + 1; + } + + if(level.buoy_list[i].modflags & SF_ONEWAY) + { + gi.dprintf("\nONE WAY\n"); + level.buoy_list[i].print_debounce_time = level.time + 1; + } + gi.dprintf("==============================\n"); + } + } + } +} +/*QUAKED info_buoy(0.6 0 0.8) (-24 -24 -24) (24 24 24) JUMP ACTIVATE TURN ONEWAY +BUOYAH! Navigation System +Mike Gummelt & Josh Weier + +THOU SHALT NOT COMMIT GRIEVOUS DESIGN ERRORS FOR THEY ARE AN ABOMINATION BEFORE THE EYES OF THE PROGRAMMER AND THE PROGRAMMER'S WORD IS INFALLIBLE! + +THE BUOY TEN COMMANDMENTS as Handed Down to M0535 on Mount Sine-AI: + 0) Thou shalt not give a buoy more than one targetname + 1) Thou shalt have a buoy target up to two OTHER buoies + therefore: + 2) Thou shalt connect each buoy to up to three other buoies (only three lines can come off a buoy) + 3) Thou shalt knowest that direction of connection does not matter unless you are trying to make a one-way buoy (see ONEWAY) below + 4) Thou shalt place thine buoy in an area that a monster can fit into + 5) Thou shalt place thine buoies such that each buoy can "see" each buoy it's conencted to (have a clear line of sight) + 6) Thou shalt knowest that buoies do not need to be placed throughout wide open areas, monsters can get around fine there. + 7) Thou shalt not place buoies in the ground or walls or any other world object + 8) Thou shalt not give any two buoies the same targetname, and each buoy should have a targetname, even if it is not targeted (this is for debug purposes) + 9) Thou shalt not have any other AI system above the BUOYAH! Navigation System. + +Keep in mind that when choosing a buoy, monsters need to be able to find a buoy withing 1024 map units of them. So make sure buoies are placed so that wherever they can get, they are within 1024 of a buoy. + +"showbuoys" - At the console, setting "showbuoys" to 1 and restarting the map will allow you to see each buoy. The flags you will see are each monster's indicator of where they are trying to go at the minute. In addition you will get buoy debug messages on the console in this mode, telling you if a monster has a hard time getting to a buoy (it times out) or if, for some reason, a connection cannot be made between two buoies. +"cheating_monsters" - At the console, set this to 1 to allow monsters to teleport to a buoy it's having a hard time getting to. + +Lots of info and useful instructions here: +JUMP - Will make monster jump ("angle" is the direction to go in (default = 0), "speed" if the forward velocity in this dir (default = 400), "height" is the height of the jump (default = 400)) +ACTIVATE - Will allow monster to activate doors, triggers, plats, etc. NOTE: the activated object's "pathtargetname" must match the buoy's "pathtarget" field. +(not implemented) TURN - Will make monster turn to buoy's angles +ONEWAY - This buoy will not allow buoys it's targeting to send monsters backwards along the path. Basically, does not back-link, paths from it to buoys it's targeting become one-way. + +"jumptarget" - used with JUMP - this buoy will only make monsters jump at the buoy whose "targetname" is the same as "jumpbuoy"- without this, the buoy WILL NOT MAKE MONSTERS JUMP! +"wait" - used with ACTIVATE- will make the buoy wait this many seconds before allowing a monster to activate the targeted ent again +"delay" - used with ACTIVATE - will make the monster stand and wait this long after activating the target ent (so it stands and waits on a lift or for the door to open) + +NOTE: AVOID GRIEVOUS DESIGN ERRORS! + +DEBUG INFO: +For "showbuoys" = 2, in addition to the arrow paths indicating target->targetname direction, particles appear on buoys, here's what each color indicates: +red - the buoy a monster has determined is your closest buoy +green - the buoy a monster has determined is it's next buoy to get to +cyan - this buoy has a jump flag +blue - this buoy is the jumptarget of a jump flagged buoy +magenta - this buoy has an activate flag +white - this buoy has an oneway flag + +Standing over a buoy that has a spawnflag of BUOY_JUMP or BUOY_ACTIVATE and hitting "action" will print it's info to the console is in "showbuoys" mode +*/ + +void SP_info_buoy(edict_t *self) +{ + int i; + + if(!level.active_buoys) + {//1st buoy, initialize a couple arrays + for(i = 0; i < MAX_CLIENTS; i++) + { + level.player_buoy[i] = NULL_BUOY; //stores current bestbuoy for a player enemy (if any) + level.player_last_buoy[i] = NULL_BUOY; //when player_buoy is invalid, saves it here so monsters can check it first instead of having to do a whole search + } + } + + if(self->spawnflags&BUOY_JUMP) + { + if (!self->speed) + self->speed = 400; + + if (!st.height) + st.height = 400; + + if (self->s.angles[YAW] == 0) + self->s.angles[YAW] = 360; + + self->movedir[2] = st.height; + + if(BUOY_DEBUG>1) + { + gi.CreatePersistantEffect(NULL, + FX_M_EFFECTS,//cyan particles + CEF_FLAG7|CEF_BROADCAST, + self->s.origin, + "bv", + FX_BUOY, + vec3_origin); + } + } + + if(BUOY_DEBUG>1) + { + if(self->spawnflags&BUOY_ACTIVATE) + { + gi.CreatePersistantEffect(NULL, + FX_M_EFFECTS, + CEF_DONT_LINK|CEF_BROADCAST,//magenta particles + self->s.origin, + "bv", + FX_BUOY, + vec3_origin); + } + + if(self->spawnflags&SF_ONEWAY) + { + vec3_t extra_shit; + + VectorSet(extra_shit, 1, 0, 0);//really hacky way to send a diff effect + gi.CreatePersistantEffect(NULL, + FX_M_EFFECTS, + CEF_BROADCAST, + self->s.origin, + "bv", + FX_BUOY, + extra_shit);//white particles + } + } + + if(!self->targetname) + { + if (BUOY_DEBUG) + gi.dprintf("Buoy with no targetname at %s!!!\n", vtos(self->s.origin)); + } + + //make sure it's not in the ground at all + if(gi.pointcontents(self->s.origin)&CONTENTS_SOLID) + { + gi.dprintf("G.D.E. FAULT: Buoy %s(%s) in ground!!!\n", self->targetname, vtos(self->s.origin)); + self->ai_mood_flags |= SF_BROKEN; + } + else + {//check down against world- does not check against entities! Does not check up against cieling (why would they put one close to a cieling???) + vec3_t top, bottom, mins, maxs; + trace_t trace; + + VectorCopy(self->s.origin, top); + VectorCopy(self->s.origin, bottom); + bottom[2] += 23; + bottom[2] -= 24; + + VectorSet(mins, -24, -24, 0); + VectorSet(maxs, 24, 24, 1); + + gi.trace(top, mins, maxs, bottom, self, MASK_SOLID,&trace); + if(trace.allsolid || trace.startsolid)//bouy in solid, can't be fixed + { + gi.dprintf("G.D.E. FAULT: Buoy %s(%s) in solid(%s)!!!\n", self->targetname, vtos(self->s.origin), trace.ent->classname); + self->ai_mood_flags |= SF_BROKEN; + } + else if(trace.fraction<1.0) + {//buoy is in the ground + VectorCopy(trace.endpos, bottom); + bottom[2] += 24; + gi.dprintf("G.D.E. FAULT: Buoy %s was in ground(%s), moved it from %s to %s...\n", self->targetname, trace.ent->classname, vtos(self->s.origin), vtos(bottom)); + VectorCopy(bottom, self->s.origin); + self->ai_mood_flags |= SF_BROKEN; + level.fixed_buoys++; + } + } + + self->movetype=PHYSICSTYPE_NONE; + + self->solid = SOLID_NOT; + self->clipmask = 0; + + self->classname = "info_buoy"; + + if (BUOY_DEBUG) + { + self->s.renderfx = RF_GLOW; + self->s.angles[2] = 180; + self->s.modelindex = gi.modelindex("models/objects/lights/bug/tris.fm"); + } + + self->think = info_buoy_link; + self->nextthink = level.time + FRAMETIME; + + if ((self->count = insert_buoy(self)) == NULL_BUOY) + gi.dprintf("ERROR! SP_info_buoy : Failed to insert buoy into map list!\n"); + + gi.linkentity(self); +} + +qboolean check_buoy_path(edict_t *self, int lb_id, int sb_id, int fb_id) +{ + buoy_t *check_buoy = NULL; + buoy_t *last_buoy, *start_buoy, *final_buoy; + int i, branch; + qboolean branch_checked[MAX_BUOY_BRANCHES]; + int num_branches_checked = 0; + int infinite_loop_short_circuit = 0; + + if(branch_counter++ >= MAX_BUOY_BRANCH_CHECKS) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("Passed MAX_BUOY_DEPTH %d!!!\n", branch_counter); + else +#endif + return false;//going too deep into buoys + } + + if(check_depth < buoy_depth+1) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("Hit max buoy check_depth (%d/%d) & failed\n", check_depth, buoy_depth); +#endif + return false;//going too deep into buoys + } + + for(i = 0; i < MAX_BUOY_BRANCHES; i++) + branch_checked[i] = false; + + last_buoy = &level.buoy_list[lb_id]; + start_buoy = &level.buoy_list[sb_id]; + final_buoy = &level.buoy_list[fb_id]; + + start_buoy->opflags |= SF_DONT_TRY; + + buoy_depth++;//add a level to buoy search depth + + for (i = 0; num_branches_checked < MAX_BUOY_BRANCHES; i++) + { + do + { + if(infinite_loop_short_circuit++ > 1000) + assert(0); + + branch = irand(0, MAX_BUOY_BRANCHES - 1); + } + while(branch_checked[branch] == true); + + branch_checked[branch] = true; + num_branches_checked++; + + if (start_buoy->nextbuoy[branch] == NULL_BUOY) + { +#ifdef _DEVEL + if (BUOY_DEBUG>2) + gi.dprintf("No #%d Branch off of %s\n", branch + 1, start_buoy->targetname); +#endif + if(num_branches_checked == MAX_BUOY_BRANCHES) + { + start_buoy->opflags &= ~SF_DONT_TRY; + buoy_depth--;//take last level off + return false; + } + else + continue;//check others + } + + check_buoy = &level.buoy_list[start_buoy->nextbuoy[branch]]; + +#ifdef _DEVEL + if(BUOY_DEBUG>2) + gi.dprintf("Checking buoy %s off of %s\n", check_buoy->targetname, start_buoy->targetname); +#endif + + if (check_buoy == final_buoy) + { +#ifdef _DEVEL + if (BUOY_DEBUG) + gi.dprintf("buoy found...\n"); +#endif + start_buoy->opflags &= ~SF_DONT_TRY; + return true; + } + + if ((check_buoy->opflags&SF_DONT_TRY)) +// Gil suggestion: unimplemented +// || check_buoy->failed_depth <= buoy_depth) + { +#ifdef _DEVEL + if(BUOY_DEBUG>2) + gi.dprintf("Buoy %s marked as don't try, skipping\n", check_buoy->targetname); +#endif + continue; + } + + if (check_buoy == last_buoy) + { + continue; + } + + if(check_buoy_path(self, start_buoy->id, check_buoy->id, final_buoy->id)) + { + start_buoy->opflags &= ~SF_DONT_TRY; + return true; + } + +// Gil suggestion: unimplemented +/* + //this buoy cannot reach goal at this depth, so don't try it again this search unless come across it at a lower depth + if(BUOY_DEBUG>2) + gi.dprintf("Buoy %s marked as failed at depth %d, will skip for rest of checks of lower depth\n", check_buoy->targetname, buoy_depth); + //NOTE: EXPERIMENTAL - remove if can't prove it works! + check_buoy->failed_depth = buoy_depth; +*/ + } + + start_buoy->opflags &= ~SF_DONT_TRY; + buoy_depth--;//take last level off + return false; +} + +buoy_t *find_next_buoy_2(edict_t *self, int sb_id, int fb_id) +{ + buoy_t *check_buoy = NULL, *save_buoy = NULL, *start_buoy, *final_buoy; + int i, branch; + qboolean branch_checked[MAX_BUOY_BRANCHES]; + int num_branches_checked = 0; + int infinite_loop_short_circuit = 0; + + for(i = 0; i < MAX_BUOY_BRANCHES; i++) + branch_checked[i] = false; + + start_buoy = &level.buoy_list[sb_id]; + final_buoy = &level.buoy_list[fb_id]; + + buoy_depth = 1; + start_buoy->opflags |= SF_DONT_TRY; + if(self->lastbuoy > NULL_BUOY) + {//don't loop back around, the save_buoy last branch check will be a shorter path +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("Last buoy was %s...\n", level.buoy_list[self->lastbuoy].targetname); +#endif + level.buoy_list[self->lastbuoy].opflags |= SF_DONT_TRY; + } + +//fixme: make my last_buoy also a dont_try? + + for (i = 0; num_branches_checked < MAX_BUOY_BRANCHES; i++) + { + do + { + if(infinite_loop_short_circuit++ > 1000) + assert(0); + + branch = irand(0, MAX_BUOY_BRANCHES - 1); + } + while(branch_checked[branch] == true); + + branch_checked[branch] = true; + num_branches_checked++; + + if (start_buoy->nextbuoy[branch] == NULL_BUOY) + { + if(num_branches_checked == MAX_BUOY_BRANCHES) + { + start_buoy->opflags &= ~SF_DONT_TRY; + if(self->lastbuoy > NULL_BUOY) + level.buoy_list[self->lastbuoy].opflags &= ~SF_DONT_TRY; + return NULL;//hasn't found one before here, and last branch was false and next is null, failed! + } + else + continue;//check others + } + + if(self->lastbuoy == start_buoy->nextbuoy[branch]) + { +#ifdef _DEVEL + if (BUOY_DEBUG>2) + gi.dprintf("Saving %s's last (previous) buoy %s for last path check\n", self->classname, level.buoy_list[self->lastbuoy].targetname); +#endif + save_buoy = &level.buoy_list[self->lastbuoy]; + continue; + } + + check_buoy = &level.buoy_list[start_buoy->nextbuoy[branch]]; + +#ifdef _DEVEL + if(BUOY_DEBUG>2) + gi.dprintf("(Start) Checking buoy %s off of %s\n", check_buoy->targetname, start_buoy->targetname); +#endif + if (check_buoy == final_buoy) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s FOUND CONNECTION FROM %s TO %s IN 1 STEP, %d BRANCHES CHECKED\n", self->classname, start_buoy->targetname, final_buoy->targetname, branch_counter); +#endif + start_buoy->opflags &= ~SF_DONT_TRY; + if(self->lastbuoy > NULL_BUOY) + level.buoy_list[self->lastbuoy].opflags &= ~SF_DONT_TRY; + return check_buoy; + } + + if ((check_buoy->opflags & SF_DONT_TRY)) +// Gil suggestion: unimplemented +// || check_buoy->failed_depth <= buoy_depth) + { +#ifdef _DEVEL + if(BUOY_DEBUG>2) + gi.dprintf("Buoy %s marked as don't try, skipping\n", check_buoy->targetname); +#endif + continue; + } + + if(check_buoy_path(self, start_buoy->id, check_buoy->id, final_buoy->id)) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s FOUND CONNECTION FROM %s TO %s IN %d STEPS, %d BRANCHES CHECKED\n", self->classname, start_buoy->targetname, final_buoy->targetname, buoy_depth, branch_counter); +#endif + start_buoy->opflags &= ~SF_DONT_TRY; + if(self->lastbuoy > NULL_BUOY) + level.buoy_list[self->lastbuoy].opflags &= ~SF_DONT_TRY; + + if(check_buoy->id == self->lastbuoy) + assert(0);//should NEVER happen!!! + + return check_buoy; + } + else + continue; + } + + if(save_buoy) + { + save_buoy->opflags &= ~SF_DONT_TRY; + check_buoy = save_buoy; + +#ifdef _DEVEL + if (BUOY_DEBUG>2) + gi.dprintf("Now checking saved buoy %s for last path check\n", check_buoy->targetname); +#endif + if (check_buoy == final_buoy) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s FOUND CONNECTION FROM %s TO %s IN 1 STEP, %d BRANCHES CHECKED\n", self->classname, start_buoy->targetname, final_buoy->targetname, branch_counter); +#endif + start_buoy->opflags &= ~SF_DONT_TRY; + if(self->lastbuoy > NULL_BUOY) + level.buoy_list[self->lastbuoy].opflags &= ~SF_DONT_TRY; + + return check_buoy; + } + + if (!(check_buoy->opflags & SF_DONT_TRY)) +// Gil suggestion: unimplemented +// && check_buoy->failed_depth > buoy_depth) + { + if(check_buoy_path(self, start_buoy->id, check_buoy->id, final_buoy->id)) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s FOUND CONNECTION FROM %s TO %s IN %d STEPS, %d BRANCHES CHECKED\n", self->classname, start_buoy->targetname, final_buoy->targetname, buoy_depth, branch_counter); +#endif + start_buoy->opflags &= ~SF_DONT_TRY; + if(self->lastbuoy > NULL_BUOY) + level.buoy_list[self->lastbuoy].opflags &= ~SF_DONT_TRY; + + return check_buoy; + } + } + } + + start_buoy->opflags &= ~SF_DONT_TRY; + if(self->lastbuoy > NULL_BUOY) + level.buoy_list[self->lastbuoy].opflags &= ~SF_DONT_TRY; + + return NULL; +} + +buoy_t *find_next_buoy(edict_t *self, int sb_id, int fb_id) +{ + buoy_t *found = NULL, *start_buoy, *final_buoy; + int i; + + if(!self->mintel) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("Can't use buoys- no mintel!...\n"); +#endif + return NULL; + } + + start_buoy = &level.buoy_list[sb_id]; + final_buoy = &level.buoy_list[fb_id]; + +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("********************************************************\n %s Beginning search from %s to %s\n********************************************************\n", self->classname, start_buoy->targetname, final_buoy->targetname); +#endif + branch_counter = 0; + + if(irand(0, 1)) + {//progressive_depth- finds shortest +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s starting progressive depth buoy path check\n", self->classname); +#endif + check_depth = 0; + + while(check_depth < self->mintel && check_depth < MAX_PROGRESSIVE_CHECK_DEPTH) + {//only search to max of 20 buoys deep if doing a progressive depth check + check_depth++; + found = find_next_buoy_2(self, start_buoy->id, final_buoy->id); + if(found) + { + check_depth = 0; + return found; + } + } + } + else + {//start at max depth- finds first +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s starting max depth(%d) buoy path check\n", self->classname, self->mintel); +#endif + check_depth = self->mintel; + found = find_next_buoy_2(self, start_buoy->id, final_buoy->id); + if(found) + { + check_depth = 0; + return found; + } + } + + for(i = 0; i <= level.active_buoys; i++) + { + level.buoy_list[i].opflags &= ~SF_DONT_TRY; +// Gil suggestion: unimplemented +// level.buoy_list[i].failed_depth = 999999999; + } + +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + if(check_depth == self->mintel) + gi.dprintf("Hit my max buoy depth (%d) & failed\n", check_depth); +#endif +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("Path from buoy %s(%s) to buoy %s(%s) not possible at depth of %d!\n", start_buoy->targetname, vtos(start_buoy->origin), final_buoy->targetname, vtos(final_buoy->origin), check_depth); +#endif + check_depth = 0; + return NULL; +} diff --git a/Toolkit/Programming/GameCode/game/buoy.h b/Toolkit/Programming/GameCode/game/buoy.h new file mode 100644 index 0000000..8d565c6 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/buoy.h @@ -0,0 +1,63 @@ +#ifndef BUOY_H +#define BUOY_H + +#define BUOY_JUMP 1 +#define BUOY_ACTIVATE 2 +#define BUOY_TURN 4 + +#define PATHDIR_ERROR -1 +#define PATHDIR_FORWARD 0 +#define PATHDIR_BACKWARD 1 +#define PATHDIR_FORKED 2 + +#define SEARCH_COMMON 0 +#define SEARCH_BUOY 1 +#define SEARCH_WAYPOINT 2 +#define SEARCH_STAND 3 +#define SEARCH_TARGET 4 + +#define MAX_BUOY_DIST 1024 +#define MAX_MAP_BUOYS 256 +#define MAX_BUOY_BRANCHES 3 + +#define NF_FORK 1 + +#define NULL_BUOY -1 + +typedef struct buoy_s buoy_t; + +struct buoy_s +{ + int nextbuoy[MAX_BUOY_BRANCHES]; //Linking buoys (index inside array) + int modflags, opflags; //modflags replaces spawnflags, opflags hold SF_DONT_TRY and the like + vec3_t origin; //Where it is in the world + int contents; //If buoy is in water or not (actual return from a pointcontents call) + int id; //This buoy's id number + char *pathtarget; + float wait; + float delay; + float temp_dist,temp_e_dist; //sfs--to be used by ents searching for a buoy; no need to init or cleanup + // since the vals will just be used immediately & forgotten-- + // er, if this is wasteful (for savegames, dunno if whole buoy + // struct is dumped into savegame, or each field specifically + // handled), these should be changed to a static array of floats + // in mg_guide. + float jump_fspeed; + float jump_yaw; + float jump_uspeed; + int jump_target_id; //This buoy's id number + char *target; //saving these two to make debugging info + char *targetname; //useful to the designer + char *jump_target; //keep around for debug + float print_debounce_time; //wait between +action print info + +// Gil suggestion: unimplemented +// int failed_depth; //depth at which this buoy failed +}; + +void info_buoy_link(edict_t *self); +int info_buoy_find_dir(edict_t *self, edict_t *pos1, edict_t *pos2); +void SP_info_buoy(edict_t *self); +void MG_RemoveBuoyEffects(edict_t *self); + +#endif // G_BUOY_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/c_ai.c b/Toolkit/Programming/GameCode/game/c_ai.c new file mode 100644 index 0000000..c88f8aa --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_ai.c @@ -0,0 +1,303 @@ +//============================================================================== +// +// c_ai.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "g_DefaultMessageHandler.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW +#include "fx.h" +#include "g_monster.h" +#include "vector.h" +#include "g_misc.h" +#include "c_corvus1_anim.h" +#include "p_main2.h" + + + +trace_t MG_MoveStep (edict_t *self, vec3_t move, qboolean relink); + +#define NUM_C_SOUNDS 2 + +static char *c_wavname[NUM_C_SOUNDS] = +{ +"", +"Cinematics/Dranor/19-316.wav", +}; + + + +void ai_c_wav (edict_t *self,float wav_num) +{ + gi.sound (self, CHAN_WEAPON, gi.soundindex(c_wavname[(int)wav_num]), 1, ATTN_NORM, 0); +} + + +void ai_c_readmessage(edict_t *self, G_Message_t *msg) +{ + int turning; + int repeat; + + ParseMsgParms(msg, "iiige", &self->monsterinfo.c_dist,&turning,&repeat, + &self->monsterinfo.c_callback,&self->monsterinfo.c_ent); + + self->monsterinfo.c_repeat = repeat; + self->ideal_yaw = anglemod(self->s.angles[YAW] + turning); +} + + + +// This is called at the end of each anim cycle +void ai_c_cycleend (edict_t *self) +{ + // A movement action that still has a distance to walk + if ((self->monsterinfo.c_anim_flag & C_ANIM_MOVE) && ((self->monsterinfo.c_dist) || (self->s.angles[YAW] != self->ideal_yaw))) + return; + + // A repeating action that still has to repeat + if ((self->monsterinfo.c_anim_flag & C_ANIM_REPEAT) && (self->monsterinfo.c_repeat)) + { + --self->monsterinfo.c_repeat; + if (self->monsterinfo.c_repeat) + return; + } + + if (self->monsterinfo.c_anim_flag & C_ANIM_DONE) + { + self->nextthink = -1; + self->think = NULL; + + if (self->monsterinfo.c_callback) // Was a callback specified? + self->monsterinfo.c_callback(self); + + return; + } + + // This anim is all done + if (self->monsterinfo.c_callback) // Was a callback specified? + self->monsterinfo.c_callback(self); + else // Well then just sit there if you aren't already + { + if (!(self->monsterinfo.c_anim_flag & C_ANIM_IDLE)) // + QPostMessage(self, MSG_C_IDLE1, PRI_DIRECTIVE, "iiige",0,0,0,NULL,NULL); + } +} + + +void ai_c_move (edict_t *self,float forward,float right,float up) +{ + vec3_t move; + float yaw; + float dist; + + dist = forward; + + M_ChangeYaw(self); + + if (dist == 0) // Just standing there + { + return; + } + + // Is the distance desired to move in the next frame past what it should be? + if (Q_fabs(dist) > abs(self->monsterinfo.c_dist)) + { + dist = self->monsterinfo.c_dist; + } + + + yaw = self->s.angles[YAW]*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + MG_MoveStep(self, move, true); + +// if (dist <0) +// self->monsterinfo.c_dist += dist; +// else + self->monsterinfo.c_dist -= dist; + + // If this cycle gets stopped by finishing a distance, then kill it. + if ((!self->monsterinfo.c_dist) && (self->monsterinfo.c_anim_flag & C_ANIM_MOVE)) + ai_c_cycleend(self); +} + +void c_swapplayer(edict_t *Self,edict_t *Cinematic) +{ + int i; + + if (!Self->client) // What are you trying to do? Exchange a non-player for Corvus? + return; + + if (Cinematic==NULL) + { +// gi.dprintf("Trying to swap Corvus for a non-existent cinematic version\n"); + return; + } + + PlayerUpdateModelAttributes(&Self->client->playerinfo); + + Cinematic->s.skinnum = Self->client->playerinfo.skinnum; + + for (i=0;is.fmnodeinfo[i].flags = Self->s.fmnodeinfo[i].flags; + Cinematic->s.fmnodeinfo[i].skin = Self->s.fmnodeinfo[i].skin; + } + + // Open up hands + if (Cinematic->s.fmnodeinfo[MESH__RHANDHI].flags & FMNI_NO_DRAW) + Cinematic->s.fmnodeinfo[MESH__RHANDHI].flags &= ~FMNI_NO_DRAW; + + if (Cinematic->s.fmnodeinfo[MESH__LHANDHI].flags & FMNI_NO_DRAW) + Cinematic->s.fmnodeinfo[MESH__LHANDHI].flags &= ~FMNI_NO_DRAW; + + // If bow is active put it on his back + if (!(Cinematic->s.fmnodeinfo[MESH__BOWACTV].flags & FMNI_NO_DRAW)) + Cinematic->s.fmnodeinfo[MESH__BOFF].flags &= ~FMNI_NO_DRAW; + + // If staff is active put it on his hip + if (!(Cinematic->s.fmnodeinfo[MESH__STAFACTV].flags & FMNI_NO_DRAW)) + Cinematic->s.fmnodeinfo[MESH__STOFF].flags &= ~FMNI_NO_DRAW; + + + // Get rid of all weapons in the hands + Cinematic->s.fmnodeinfo[MESH__BLADSTF].flags |= FMNI_NO_DRAW; + Cinematic->s.fmnodeinfo[MESH__HELSTF].flags |= FMNI_NO_DRAW; + Cinematic->s.fmnodeinfo[MESH__BOWACTV].flags |= FMNI_NO_DRAW; + Cinematic->s.fmnodeinfo[MESH__STAFACTV].flags |= FMNI_NO_DRAW; +} + +#define ENT_INVISIBLE 1 + +vec3_t c_mins = {-16, -16, -34}; +vec3_t c_maxs = {16, 16, 25}; + +void c_corvus_init(edict_t *self,int classId) +{ + self->classID = classId; + self->s.modelindex = classStatics[classId].resInfo->modelIndex; + + if (!monster_start(self)) // Failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->think = walkmonster_start_go; + + if (!self->health) + { + self->health = 30; + } + + self->mass = 300; + self->yaw_speed = 20; + VectorClear(self->knockbackvel); + + VectorCopy (c_mins, self->mins); + VectorCopy (c_maxs, self->maxs); + VectorCopy (c_mins, self->intentMins); + VectorCopy (c_maxs, self->intentMaxs); + self->viewheight = self->maxs[2]*0.8; + + + if (!self->monsterinfo.scale) + { + self->s.scale = self->monsterinfo.scale = 1; + } + + self->materialtype = MAT_FLESH; + self->clipmask = MASK_MONSTERSOLID; + self->count = self->s.modelindex; + self->takedamage = DAMAGE_NO; + + if (self->spawnflags & ENT_INVISIBLE) + { + self->s.modelindex = 0; + self->solid = SOLID_NOT; + self->movetype = PHYSICSTYPE_NONE; + } + else + { + self->solid=SOLID_BBOX; + self->movetype = PHYSICSTYPE_STEP; + } + + //set up my mood function + MG_InitMoods(self); + VectorClear(self->knockbackvel); + + self->monsterinfo.c_mode = 1; +} + + +void c_character_init(edict_t *self,int classId) +{ + self->classID = classId; + self->s.modelindex = classStatics[classId].resInfo->modelIndex; + + if (!monster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->think = walkmonster_start_go; + + self->viewheight = self->maxs[2]*0.8; + + if (!self->health) + { + self->health = 30; + } + + self->mass = 300; + self->yaw_speed = 20; + + VectorClear(self->knockbackvel); + + if (!self->monsterinfo.scale) + { + self->s.scale = self->monsterinfo.scale = 1; + } + + self->count = self->s.modelindex; + self->clipmask = MASK_MONSTERSOLID; + self->materialtype = MAT_FLESH; + self->takedamage = DAMAGE_NO; + + if (self->spawnflags & ENT_INVISIBLE) + { + self->s.modelindex = 0; + self->solid = SOLID_NOT; + self->movetype = PHYSICSTYPE_NONE; + } + else + { + self->solid=SOLID_BBOX; + self->movetype = PHYSICSTYPE_STEP; + } + + BboxYawAndScale(self); + + //set up my mood function + MG_InitMoods(self); + + self->monsterinfo.c_mode = 1; + QPostMessage(self, MSG_C_IDLE1, PRI_DIRECTIVE, "iiige",0,0,0,NULL,NULL); + +} + +void ai_c_gib(edict_t *self, G_Message_t *msg) +{ + gi.sound(self, CHAN_BODY, gi.soundindex("monsters/plagueElf/gib2.wav"), 1, ATTN_NORM, 0); + self->think = BecomeDebris; + self->nextthink = level.time + 0.1; +} diff --git a/Toolkit/Programming/GameCode/game/c_ai.h b/Toolkit/Programming/GameCode/game/c_ai.h new file mode 100644 index 0000000..d423cbb --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_ai.h @@ -0,0 +1,22 @@ +// +// c_ai.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef C_AI_H +#define C_AI_H + +void ai_c_cycleend (edict_t *self); +void ai_c_gib(edict_t *self, G_Message_t *msg); +void ai_c_move (edict_t *self,float x,float y,float z); +void ai_c_readmessage(edict_t *self, G_Message_t *msg); +void ai_c_stand (edict_t *self,float forward,float right,float up); +void ai_c_wav (edict_t *self,float wav_num); + +void c_corvus_init(edict_t *self,int classId); +void c_character_init(edict_t *self,int classId); + + +#endif diff --git a/Toolkit/Programming/GameCode/game/c_corvus1.c b/Toolkit/Programming/GameCode/game/c_corvus1.c new file mode 100644 index 0000000..87f65cc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus1.c @@ -0,0 +1,194 @@ +/*------------------------------------------------------------------- +c_corvus1.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "c_corvus1.h" +#include "c_corvus1_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + Corvus1 Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + // Cinematics + &corvus_move_c_action1, + &corvus_move_c_action2, + &corvus_move_c_action3, + &corvus_move_c_action4, + &corvus_move_c_idle1, + &corvus_move_c_idle2, + &corvus_move_c_strafeleft, + &corvus_move_c_straferight, + &corvus_move_c_walkstart, + &corvus_move_c_walk1, + &corvus_move_c_walk2, + &corvus_move_c_walkstop1, + &corvus_move_c_walkstop2, + &corvus_move_c_pivotleftgo, + &corvus_move_c_pivotleft, + &corvus_move_c_pivotleftstop, + &corvus_move_c_pivotrightgo, + &corvus_move_c_pivotright, + &corvus_move_c_pivotrightstop, +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + corvus_c_anims +-------------------------------------------------------------------------*/ +void corvus_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_PIVOTLEFTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTGO; + break; + case MSG_C_PIVOTLEFT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTLEFT; + break; + case MSG_C_PIVOTLEFTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTSTOP; + break; + case MSG_C_PIVOTRIGHTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTGO; + break; + case MSG_C_PIVOTRIGHT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTRIGHT; + break; + case MSG_C_PIVOTRIGHTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTSTOP; + break; + case MSG_C_STEPLEFT: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_STRAFELEFT; + break; + case MSG_C_STEPRIGHT: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_STRAFERIGHT; + break; + case MSG_C_WALKSTART: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTART; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + case MSG_C_WALKSTOP1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP1; + break; + case MSG_C_WALKSTOP2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP2; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + PlagueElfStaticsInit +-------------------------------------------------------------------------*/ +void CorvusStaticsInit() +{ + + classStatics[CID_CORVUS].msgReceivers[MSG_C_ACTION1] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_ACTION2] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_ACTION3] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_ACTION4] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_IDLE1] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_IDLE2] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_WALKSTART] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_WALK1] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_WALK2] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_PIVOTLEFTGO] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_PIVOTLEFT] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_PIVOTLEFTSTOP] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_PIVOTRIGHTGO] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_PIVOTRIGHT] = corvus_c_anims; + classStatics[CID_CORVUS].msgReceivers[MSG_C_PIVOTRIGHTSTOP] = corvus_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/player/victim_scene/tris.fm"); + + classStatics[CID_CORVUS].resInfo = &resInfo; + +} + + + +/*QUAKED character_corvus1 (1 .5 0) (-17 -25 -32) (22 12 32) INVISIBLE +The cinematic corvus for the torture victim +*/ +void SP_character_corvus1 (edict_t *self) +{ + c_corvus_init(self,CID_CORVUS); +} diff --git a/Toolkit/Programming/GameCode/game/c_corvus1.h b/Toolkit/Programming/GameCode/game/c_corvus1.h new file mode 100644 index 0000000..8a04b73 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus1.h @@ -0,0 +1,47 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_STRAFELEFT, + ANIM_C_STRAFERIGHT, + ANIM_C_WALKSTART, + ANIM_C_WALK1, + ANIM_C_WALK2, + ANIM_C_WALKSTOP1, + ANIM_C_WALKSTOP2, + ANIM_C_PIVOTLEFTGO, + ANIM_C_PIVOTLEFT, + ANIM_C_PIVOTLEFTSTOP, + ANIM_C_PIVOTRIGHTGO, + ANIM_C_PIVOTRIGHT, + ANIM_C_PIVOTRIGHTSTOP, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t corvus_move_c_action1; +extern animmove_t corvus_move_c_action2; +extern animmove_t corvus_move_c_action3; +extern animmove_t corvus_move_c_action4; +extern animmove_t corvus_move_c_idle1; +extern animmove_t corvus_move_c_idle2; +extern animmove_t corvus_move_c_strafeleft; +extern animmove_t corvus_move_c_straferight; +extern animmove_t corvus_move_c_walkstart; +extern animmove_t corvus_move_c_walk1; +extern animmove_t corvus_move_c_walk2; +extern animmove_t corvus_move_c_walkstop1; +extern animmove_t corvus_move_c_walkstop2; +extern animmove_t corvus_move_c_pivotleftgo; +extern animmove_t corvus_move_c_pivotleft; +extern animmove_t corvus_move_c_pivotleftstop; +extern animmove_t corvus_move_c_pivotrightgo; +extern animmove_t corvus_move_c_pivotright; +extern animmove_t corvus_move_c_pivotrightstop; + + diff --git a/Toolkit/Programming/GameCode/game/c_corvus1_anim.c b/Toolkit/Programming/GameCode/game/c_corvus1_anim.c new file mode 100644 index 0000000..401339b --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus1_anim.c @@ -0,0 +1,366 @@ +//============================================================================== +// +// m_corvus_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_corvus1_anim.h" +#include "c_corvus1.h" + +#include "g_monster.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_action1 [] = +{ + FRAME_c_wheelA1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelA2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelA3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelA4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus_move_c_action1 = {4, corvus_frames_c_action1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_action2 [] = +{ + FRAME_c_wheelB1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_wheelB22, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus_move_c_action2 = {22, corvus_frames_c_action2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_action3 [] = +{ + FRAME_c_idleA1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleA2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleA3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleA4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleA5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleA6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleA7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleA8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleA9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleA10, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus_move_c_action3 = {10, corvus_frames_c_action3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_action4 [] = +{ + FRAME_plagued1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_plagued40, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus_move_c_action4 = {40, corvus_frames_c_action4, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_idle1 [] = +{ + FRAME_breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus_move_c_idle1 = {23, corvus_frames_c_idle1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_idle2 [] = +{ + FRAME_c_idleB1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_c_idleB20, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus_move_c_idle2 = {20, corvus_frames_c_idle2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_walk1 [] = +{ + FRAME_jog1, ai_c_move, 10, 10, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 16, 10, 0, NULL, 0, NULL, + FRAME_jog3, ai_c_move, 15, 10, 0, NULL, 0, NULL, + FRAME_jog4, ai_c_move, 16, 10, 0, NULL, 0, NULL, + FRAME_jog5, ai_c_move, 17, 10, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 16, 10, 0, NULL, 0, NULL, + FRAME_jog7, ai_c_move, 15, 10, 0, NULL, 0, NULL, + FRAME_jog8, ai_c_move, 16, 10, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_walk1 = {8, corvus_frames_c_walk1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_strafeleft [] = +{ + FRAME_Lstep1, ai_c_move, 0, 6, 0, NULL, 0, NULL, + FRAME_Lstep2, ai_c_move, 0, 6, 0, NULL, 0, NULL, + FRAME_Lstep3, ai_c_move, 0, 6, 0, NULL, 0, NULL, + FRAME_Lstep4, ai_c_move, 0, 6, 0, NULL, 0, NULL, + FRAME_Lstep5, ai_c_move, 0, 6, 0, NULL, 0, NULL, +}; + +animmove_t corvus_move_c_strafeleft = {5, corvus_frames_c_strafeleft, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_straferight [] = +{ + FRAME_Rstep1, ai_c_move, 0, 6, 0, NULL, 0, NULL, + FRAME_Rstep2, ai_c_move, 0, 6, 0, NULL, 0, NULL, + FRAME_Rstep3, ai_c_move, 0, 6, 0, NULL, 0, NULL, + FRAME_Rstep4, ai_c_move, 0, 6, 0, NULL, 0, NULL, + FRAME_Rstep5, ai_c_move, 0, 6, 0, NULL, 0, NULL, +}; + + +animmove_t corvus_move_c_straferight = {5, corvus_frames_c_straferight, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_walk2 [] = +{ + FRAME_cinewalk1, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, 4, 6, 0, NULL, 0, NULL, + FRAME_cinewalk16, ai_c_move, 4, 6, 0, NULL, 0, NULL, +}; + +animmove_t corvus_move_c_walk2 = {16, corvus_frames_c_walk2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - starting his walk anims +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_walkstart [] = +{ + FRAME_gorun2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_gorun3, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_walkstart = {2, corvus_frames_c_walkstart, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with right foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_walkstop1 [] = +{ + FRAME_jog1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_walkstop1 = {2, corvus_frames_c_walkstop1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with left foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_walkstop2 [] = +{ + FRAME_jog5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_walkstop2 = {2, corvus_frames_c_walkstop2, ai_c_cycleend}; + + + + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the left +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_pivotleftgo [] = +{ + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_pivotleftgo = {2, corvus_frames_c_pivotleftgo, ai_c_cycleend}; + +animframe_t corvus_frames_c_pivotleft [] = +{ + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_pivotleft = {2, corvus_frames_c_pivotleft, ai_c_cycleend}; + + +animframe_t corvus_frames_c_pivotleftstop [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_pivotleftstop = {1, corvus_frames_c_pivotleftstop, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the right +-----------------------------------------------------------------------*/ +animframe_t corvus_frames_c_pivotrightgo [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_pivotrightgo = {2, corvus_frames_c_pivotrightgo, ai_c_cycleend}; + +animframe_t corvus_frames_c_pivotright [] = +{ + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_pivotright = {2, corvus_frames_c_pivotright, ai_c_cycleend}; + + +animframe_t corvus_frames_c_pivotrightstop [] = +{ + FRAME_Lpivot1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus_move_c_pivotrightstop = {1, corvus_frames_c_pivotrightstop, ai_c_cycleend}; + + diff --git a/Toolkit/Programming/GameCode/game/c_corvus1_anim.h b/Toolkit/Programming/GameCode/game/c_corvus1_anim.h new file mode 100644 index 0000000..491690c --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus1_anim.h @@ -0,0 +1,208 @@ +// R:\Art\models/player\cinematic + +// This file generated by qdata - Do NOT Modify + +#define FRAME_breath1 0 +#define FRAME_breath2 1 +#define FRAME_breath3 2 +#define FRAME_breath4 3 +#define FRAME_breath5 4 +#define FRAME_breath6 5 +#define FRAME_breath7 6 +#define FRAME_breath8 7 +#define FRAME_breath9 8 +#define FRAME_breath10 9 +#define FRAME_breath11 10 +#define FRAME_breath12 11 +#define FRAME_breath13 12 +#define FRAME_breath14 13 +#define FRAME_breath15 14 +#define FRAME_breath16 15 +#define FRAME_breath17 16 +#define FRAME_breath18 17 +#define FRAME_breath19 18 +#define FRAME_breath20 19 +#define FRAME_breath21 20 +#define FRAME_breath22 21 +#define FRAME_breath23 22 +#define FRAME_jog1 23 +#define FRAME_jog2 24 +#define FRAME_jog3 25 +#define FRAME_jog4 26 +#define FRAME_jog5 27 +#define FRAME_jog6 28 +#define FRAME_jog7 29 +#define FRAME_jog8 30 +#define FRAME_c_idleA1 31 +#define FRAME_c_idleA2 32 +#define FRAME_c_idleA3 33 +#define FRAME_c_idleA4 34 +#define FRAME_c_idleA5 35 +#define FRAME_c_idleA6 36 +#define FRAME_c_idleA7 37 +#define FRAME_c_idleA8 38 +#define FRAME_c_idleA9 39 +#define FRAME_c_idleA10 40 +#define FRAME_c_idleB1 41 +#define FRAME_c_idleB2 42 +#define FRAME_c_idleB3 43 +#define FRAME_c_idleB4 44 +#define FRAME_c_idleB5 45 +#define FRAME_c_idleB6 46 +#define FRAME_c_idleB7 47 +#define FRAME_c_idleB8 48 +#define FRAME_c_idleB9 49 +#define FRAME_c_idleB10 50 +#define FRAME_c_idleB11 51 +#define FRAME_c_idleB12 52 +#define FRAME_c_idleB13 53 +#define FRAME_c_idleB14 54 +#define FRAME_c_idleB15 55 +#define FRAME_c_idleB16 56 +#define FRAME_c_idleB17 57 +#define FRAME_c_idleB18 58 +#define FRAME_c_idleB19 59 +#define FRAME_c_idleB20 60 +#define FRAME_c_wheelA1 61 +#define FRAME_c_wheelA2 62 +#define FRAME_c_wheelA3 63 +#define FRAME_c_wheelA4 64 +#define FRAME_c_wheelB1 65 +#define FRAME_c_wheelB2 66 +#define FRAME_c_wheelB3 67 +#define FRAME_c_wheelB4 68 +#define FRAME_c_wheelB5 69 +#define FRAME_c_wheelB6 70 +#define FRAME_c_wheelB7 71 +#define FRAME_c_wheelB8 72 +#define FRAME_c_wheelB9 73 +#define FRAME_c_wheelB10 74 +#define FRAME_c_wheelB11 75 +#define FRAME_c_wheelB12 76 +#define FRAME_c_wheelB13 77 +#define FRAME_c_wheelB14 78 +#define FRAME_c_wheelB15 79 +#define FRAME_c_wheelB16 80 +#define FRAME_c_wheelB17 81 +#define FRAME_c_wheelB18 82 +#define FRAME_c_wheelB19 83 +#define FRAME_c_wheelB20 84 +#define FRAME_c_wheelB21 85 +#define FRAME_c_wheelB22 86 +#define FRAME_Lstep1 87 +#define FRAME_Lstep2 88 +#define FRAME_Lstep3 89 +#define FRAME_Lstep4 90 +#define FRAME_Lstep5 91 +#define FRAME_Rstep1 92 +#define FRAME_Rstep2 93 +#define FRAME_Rstep3 94 +#define FRAME_Rstep4 95 +#define FRAME_Rstep5 96 +#define FRAME_cinewalk1 97 +#define FRAME_cinewalk2 98 +#define FRAME_cinewalk3 99 +#define FRAME_cinewalk4 100 +#define FRAME_cinewalk5 101 +#define FRAME_cinewalk6 102 +#define FRAME_cinewalk7 103 +#define FRAME_cinewalk8 104 +#define FRAME_cinewalk9 105 +#define FRAME_cinewalk10 106 +#define FRAME_cinewalk11 107 +#define FRAME_cinewalk12 108 +#define FRAME_cinewalk13 109 +#define FRAME_cinewalk14 110 +#define FRAME_cinewalk15 111 +#define FRAME_cinewalk16 112 +#define FRAME_gorun2 113 +#define FRAME_gorun3 114 +#define FRAME_Lpivot1 115 +#define FRAME_Lpivot2 116 +#define FRAME_Lpivot3 117 +#define FRAME_Lpivot4 118 +#define FRAME_stance1 119 +#define FRAME_stance2 120 +#define FRAME_stance3 121 +#define FRAME_stance4 122 +#define FRAME_stance5 123 +#define FRAME_stance6 124 +#define FRAME_stance7 125 +#define FRAME_stance8 126 +#define FRAME_stance9 127 +#define FRAME_stance10 128 +#define FRAME_stance11 129 +#define FRAME_stance12 130 +#define FRAME_stance13 131 +#define FRAME_stance14 132 +#define FRAME_stance15 133 +#define FRAME_stance16 134 +#define FRAME_stance17 135 +#define FRAME_stance18 136 +#define FRAME_stance19 137 +#define FRAME_stance20 138 +#define FRAME_stance21 139 +#define FRAME_stance22 140 +#define FRAME_stance23 141 +#define FRAME_stance24 142 +#define FRAME_plagued1 143 +#define FRAME_plagued2 144 +#define FRAME_plagued3 145 +#define FRAME_plagued4 146 +#define FRAME_plagued5 147 +#define FRAME_plagued6 148 +#define FRAME_plagued7 149 +#define FRAME_plagued8 150 +#define FRAME_plagued9 151 +#define FRAME_plagued10 152 +#define FRAME_plagued11 153 +#define FRAME_plagued12 154 +#define FRAME_plagued13 155 +#define FRAME_plagued14 156 +#define FRAME_plagued15 157 +#define FRAME_plagued16 158 +#define FRAME_plagued17 159 +#define FRAME_plagued18 160 +#define FRAME_plagued19 161 +#define FRAME_plagued20 162 +#define FRAME_plagued21 163 +#define FRAME_plagued22 164 +#define FRAME_plagued23 165 +#define FRAME_plagued24 166 +#define FRAME_plagued25 167 +#define FRAME_plagued26 168 +#define FRAME_plagued27 169 +#define FRAME_plagued28 170 +#define FRAME_plagued29 171 +#define FRAME_plagued30 172 +#define FRAME_plagued31 173 +#define FRAME_plagued32 174 +#define FRAME_plagued33 175 +#define FRAME_plagued34 176 +#define FRAME_plagued35 177 +#define FRAME_plagued36 178 +#define FRAME_plagued37 179 +#define FRAME_plagued38 180 +#define FRAME_plagued39 181 +#define FRAME_plagued40 182 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_corvus2.c b/Toolkit/Programming/GameCode/game/c_corvus2.c new file mode 100644 index 0000000..25af3f9 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus2.c @@ -0,0 +1,177 @@ +/*------------------------------------------------------------------- +c_corvus.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "g_Skeletons.h" +#include "c_corvus2.h" +#include "c_corvus2_anim.h" +#include "g_HitLocation.h" +#include "g_misc.h" +#include "angles.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[NUM_ANIMS] = +{ + // Cinematics + &corvus2_move_c_action1, + &corvus2_move_c_idle1, + &corvus2_move_c_idle2, + &corvus2_move_c_idle3, + &corvus2_move_c_walkstart, + &corvus2_move_c_walk1, + &corvus2_move_c_walk2, + &corvus2_move_c_walkstop1, + &corvus2_move_c_walkstop2, + &corvus2_move_c_pivotleftgo, + &corvus2_move_c_pivotleft, + &corvus2_move_c_pivotleftstop, + &corvus2_move_c_pivotrightgo, + &corvus2_move_c_pivotright, + &corvus2_move_c_pivotrightstop +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + corvus2_c_anims +-------------------------------------------------------------------------*/ +void corvus2_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + self->monsterinfo.c_dist = 64; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_PIVOTLEFTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTGO; + break; + case MSG_C_PIVOTLEFT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTLEFT; + break; + case MSG_C_PIVOTLEFTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTSTOP; + break; + case MSG_C_PIVOTRIGHTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTGO; + break; + case MSG_C_PIVOTRIGHT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTRIGHT; + break; + case MSG_C_PIVOTRIGHTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTSTOP; + break; + case MSG_C_WALKSTART: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTART; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + case MSG_C_WALKSTOP1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP1; + break; + case MSG_C_WALKSTOP2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP2; + break; + + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + PlagueElfStaticsInit +-------------------------------------------------------------------------*/ +void Corvus2StaticsInit() +{ + classStatics[CID_CORVUS2].msgReceivers[MSG_C_ACTION1] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_IDLE1] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_IDLE2] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_IDLE3] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_WALKSTART] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_WALK1] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_WALK2] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_WALKSTOP1] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_WALKSTOP2] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_PIVOTLEFTGO] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_PIVOTLEFT] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_PIVOTLEFTSTOP] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_PIVOTRIGHTGO] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_PIVOTRIGHT] = corvus2_c_anims; + classStatics[CID_CORVUS2].msgReceivers[MSG_C_PIVOTRIGHTSTOP] = corvus2_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/player/watcher_scene/tris.fm"); + + classStatics[CID_CORVUS2].resInfo = &resInfo; + +} + +/*QUAKED character_corvus2 (1 .5 0) (-17 -25 -32) (22 12 32) INVISIBLE +The cinematic Corvus for the celestial watcher scene +*/ +void SP_character_corvus2 (edict_t *self) +{ + c_corvus_init(self,CID_CORVUS2); +} diff --git a/Toolkit/Programming/GameCode/game/c_corvus2.h b/Toolkit/Programming/GameCode/game/c_corvus2.h new file mode 100644 index 0000000..4e1cef7 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus2.h @@ -0,0 +1,37 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_WALKSTART, + ANIM_C_WALK1, + ANIM_C_WALK2, + ANIM_C_WALKSTOP1, + ANIM_C_WALKSTOP2, + ANIM_C_PIVOTLEFTGO, + ANIM_C_PIVOTLEFT, + ANIM_C_PIVOTLEFTSTOP, + ANIM_C_PIVOTRIGHTGO, + ANIM_C_PIVOTRIGHT, + ANIM_C_PIVOTRIGHTSTOP, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t corvus2_move_c_action1; +extern animmove_t corvus2_move_c_idle1; +extern animmove_t corvus2_move_c_idle2; +extern animmove_t corvus2_move_c_idle3; +extern animmove_t corvus2_move_c_walkstart; +extern animmove_t corvus2_move_c_walk1; +extern animmove_t corvus2_move_c_walk2; +extern animmove_t corvus2_move_c_walkstop1; +extern animmove_t corvus2_move_c_walkstop2; +extern animmove_t corvus2_move_c_pivotleftgo; +extern animmove_t corvus2_move_c_pivotleft; +extern animmove_t corvus2_move_c_pivotleftstop; +extern animmove_t corvus2_move_c_pivotrightgo; +extern animmove_t corvus2_move_c_pivotright; +extern animmove_t corvus2_move_c_pivotrightstop; diff --git a/Toolkit/Programming/GameCode/game/c_corvus2_anim.c b/Toolkit/Programming/GameCode/game/c_corvus2_anim.c new file mode 100644 index 0000000..8c384d4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus2_anim.c @@ -0,0 +1,333 @@ +//============================================================================== +// +// c_corvus2_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_corvus2_anim.h" +#include "c_corvus2.h" + +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_idle1 [] = +{ + FRAME_Breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus2_move_c_idle1 = {23, corvus2_frames_c_idle1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_idle2 [] = +{ + FRAME_Wchrtk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus2_move_c_idle2 = {2, corvus2_frames_c_idle2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_idle3 [] = +{ + FRAME_Wchrtk106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk106, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus2_move_c_idle3 = {2, corvus2_frames_c_idle3, ai_c_cycleend}; + + +animframe_t corvus2_frames_c_action1 [] = +{ + FRAME_Wchrtk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk20, ai_c_move, 4, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk21, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk22, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk23, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk24, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk25, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk26, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk27, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk28, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk29, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk30, ai_c_move, 4, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk31, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk32, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk33, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk34, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk35, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Wchrtk101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Wchrtk106, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus2_move_c_action1 = { 106, corvus2_frames_c_action1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the left +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_pivotleftgo [] = +{ + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_pivotleftgo = {2, corvus2_frames_c_pivotleftgo, ai_c_cycleend}; + +animframe_t corvus2_frames_c_pivotleft [] = +{ + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_pivotleft = {2, corvus2_frames_c_pivotleft, ai_c_cycleend}; + + +animframe_t corvus2_frames_c_pivotleftstop [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_pivotleftstop = {1, corvus2_frames_c_pivotleftstop, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the right +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_pivotrightgo [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_pivotrightgo = {2, corvus2_frames_c_pivotrightgo, ai_c_cycleend}; + +animframe_t corvus2_frames_c_pivotright [] = +{ + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_pivotright = {2, corvus2_frames_c_pivotright, ai_c_cycleend}; + + +animframe_t corvus2_frames_c_pivotrightstop [] = +{ + FRAME_Lpivot1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_pivotrightstop = {1, corvus2_frames_c_pivotrightstop, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_walk1 [] = +{ + FRAME_jog1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog3, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog4, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog5, ai_c_move, 17, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog7, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog8, ai_c_move, 16, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_walk1 = {8, corvus2_frames_c_walk1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_walk2 [] = +{ + FRAME_cinewalk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus2_move_c_walk2 = {16, corvus2_frames_c_walk2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - starting his walk anims +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_walkstart [] = +{ + FRAME_gorun2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_gorun3, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_walkstart = {2, corvus2_frames_c_walkstart, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with right foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_walkstop1 [] = +{ + FRAME_jog1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_walkstop1 = {2, corvus2_frames_c_walkstop1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with left foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus2_frames_c_walkstop2 [] = +{ + FRAME_jog5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus2_move_c_walkstop2 = {2, corvus2_frames_c_walkstop2, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/c_corvus2_anim.h b/Toolkit/Programming/GameCode/game/c_corvus2_anim.h new file mode 100644 index 0000000..fb44602 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus2_anim.h @@ -0,0 +1,186 @@ +// R:\Art\models/player\c_watcher + +// This file generated by qdata - Do NOT Modify + +#define FRAME_Breath1 0 +#define FRAME_Breath2 1 +#define FRAME_Breath3 2 +#define FRAME_Breath4 3 +#define FRAME_Breath5 4 +#define FRAME_Breath6 5 +#define FRAME_Breath7 6 +#define FRAME_Breath8 7 +#define FRAME_Breath9 8 +#define FRAME_Breath10 9 +#define FRAME_Breath11 10 +#define FRAME_Breath12 11 +#define FRAME_Breath13 12 +#define FRAME_Breath14 13 +#define FRAME_Breath15 14 +#define FRAME_Breath16 15 +#define FRAME_Breath17 16 +#define FRAME_Breath18 17 +#define FRAME_Breath19 18 +#define FRAME_Breath20 19 +#define FRAME_Breath21 20 +#define FRAME_Breath22 21 +#define FRAME_Breath23 22 +#define FRAME_cinewalk1 23 +#define FRAME_cinewalk2 24 +#define FRAME_cinewalk3 25 +#define FRAME_cinewalk4 26 +#define FRAME_cinewalk5 27 +#define FRAME_cinewalk6 28 +#define FRAME_cinewalk7 29 +#define FRAME_cinewalk8 30 +#define FRAME_cinewalk9 31 +#define FRAME_cinewalk10 32 +#define FRAME_cinewalk11 33 +#define FRAME_cinewalk12 34 +#define FRAME_cinewalk13 35 +#define FRAME_cinewalk14 36 +#define FRAME_cinewalk15 37 +#define FRAME_cinewalk16 38 +#define FRAME_cluster 39 +#define FRAME_gorun1 40 +#define FRAME_gorun2 41 +#define FRAME_gorun3 42 +#define FRAME_jog1 43 +#define FRAME_jog2 44 +#define FRAME_jog3 45 +#define FRAME_jog4 46 +#define FRAME_jog5 47 +#define FRAME_jog6 48 +#define FRAME_jog7 49 +#define FRAME_jog8 50 +#define FRAME_Lpivot1 51 +#define FRAME_Lpivot2 52 +#define FRAME_Lpivot3 53 +#define FRAME_Lpivot4 54 +#define FRAME_Wchrtk1 55 +#define FRAME_Wchrtk2 56 +#define FRAME_Wchrtk3 57 +#define FRAME_Wchrtk4 58 +#define FRAME_Wchrtk5 59 +#define FRAME_Wchrtk6 60 +#define FRAME_Wchrtk7 61 +#define FRAME_Wchrtk8 62 +#define FRAME_Wchrtk9 63 +#define FRAME_Wchrtk10 64 +#define FRAME_Wchrtk11 65 +#define FRAME_Wchrtk12 66 +#define FRAME_Wchrtk13 67 +#define FRAME_Wchrtk14 68 +#define FRAME_Wchrtk15 69 +#define FRAME_Wchrtk16 70 +#define FRAME_Wchrtk17 71 +#define FRAME_Wchrtk18 72 +#define FRAME_Wchrtk19 73 +#define FRAME_Wchrtk20 74 +#define FRAME_Wchrtk21 75 +#define FRAME_Wchrtk22 76 +#define FRAME_Wchrtk23 77 +#define FRAME_Wchrtk24 78 +#define FRAME_Wchrtk25 79 +#define FRAME_Wchrtk26 80 +#define FRAME_Wchrtk27 81 +#define FRAME_Wchrtk28 82 +#define FRAME_Wchrtk29 83 +#define FRAME_Wchrtk30 84 +#define FRAME_Wchrtk31 85 +#define FRAME_Wchrtk32 86 +#define FRAME_Wchrtk33 87 +#define FRAME_Wchrtk34 88 +#define FRAME_Wchrtk35 89 +#define FRAME_Wchrtk36 90 +#define FRAME_Wchrtk37 91 +#define FRAME_Wchrtk38 92 +#define FRAME_Wchrtk39 93 +#define FRAME_Wchrtk40 94 +#define FRAME_Wchrtk41 95 +#define FRAME_Wchrtk42 96 +#define FRAME_Wchrtk43 97 +#define FRAME_Wchrtk44 98 +#define FRAME_Wchrtk45 99 +#define FRAME_Wchrtk46 100 +#define FRAME_Wchrtk47 101 +#define FRAME_Wchrtk48 102 +#define FRAME_Wchrtk49 103 +#define FRAME_Wchrtk50 104 +#define FRAME_Wchrtk51 105 +#define FRAME_Wchrtk52 106 +#define FRAME_Wchrtk53 107 +#define FRAME_Wchrtk54 108 +#define FRAME_Wchrtk55 109 +#define FRAME_Wchrtk56 110 +#define FRAME_Wchrtk57 111 +#define FRAME_Wchrtk58 112 +#define FRAME_Wchrtk59 113 +#define FRAME_Wchrtk60 114 +#define FRAME_Wchrtk61 115 +#define FRAME_Wchrtk62 116 +#define FRAME_Wchrtk63 117 +#define FRAME_Wchrtk64 118 +#define FRAME_Wchrtk65 119 +#define FRAME_Wchrtk66 120 +#define FRAME_Wchrtk67 121 +#define FRAME_Wchrtk68 122 +#define FRAME_Wchrtk69 123 +#define FRAME_Wchrtk70 124 +#define FRAME_Wchrtk71 125 +#define FRAME_Wchrtk72 126 +#define FRAME_Wchrtk73 127 +#define FRAME_Wchrtk74 128 +#define FRAME_Wchrtk75 129 +#define FRAME_Wchrtk76 130 +#define FRAME_Wchrtk77 131 +#define FRAME_Wchrtk78 132 +#define FRAME_Wchrtk79 133 +#define FRAME_Wchrtk80 134 +#define FRAME_Wchrtk81 135 +#define FRAME_Wchrtk82 136 +#define FRAME_Wchrtk83 137 +#define FRAME_Wchrtk84 138 +#define FRAME_Wchrtk85 139 +#define FRAME_Wchrtk86 140 +#define FRAME_Wchrtk87 141 +#define FRAME_Wchrtk88 142 +#define FRAME_Wchrtk89 143 +#define FRAME_Wchrtk90 144 +#define FRAME_Wchrtk91 145 +#define FRAME_Wchrtk92 146 +#define FRAME_Wchrtk93 147 +#define FRAME_Wchrtk94 148 +#define FRAME_Wchrtk95 149 +#define FRAME_Wchrtk96 150 +#define FRAME_Wchrtk97 151 +#define FRAME_Wchrtk98 152 +#define FRAME_Wchrtk99 153 +#define FRAME_Wchrtk100 154 +#define FRAME_Wchrtk101 155 +#define FRAME_Wchrtk102 156 +#define FRAME_Wchrtk103 157 +#define FRAME_Wchrtk104 158 +#define FRAME_Wchrtk105 159 +#define FRAME_Wchrtk106 160 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_corvus3.c b/Toolkit/Programming/GameCode/game/c_corvus3.c new file mode 100644 index 0000000..522aa8c --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus3.c @@ -0,0 +1,327 @@ +/*------------------------------------------------------------------- +c_corvus.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "c_corvus3.h" +#include "c_corvus3_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[NUM_ANIMS] = +{ + // Cinematics + &corvus3_move_c_action1, + &corvus3_move_c_action2, + &corvus3_move_c_action3, + &corvus3_move_c_action4, + &corvus3_move_c_action5, + &corvus3_move_c_action6, + &corvus3_move_c_action7, + &corvus3_move_c_action8, + &corvus3_move_c_action9, + &corvus3_move_c_action10, + &corvus3_move_c_action11, + &corvus3_move_c_action12, + &corvus3_move_c_action13, + &corvus3_move_c_action14, + &corvus3_move_c_action15, + &corvus3_move_c_action16, + &corvus3_move_c_action17, + &corvus3_move_c_action18, + &corvus3_move_c_action19, + &corvus3_move_c_action20, + &corvus3_move_c_idle1, + &corvus3_move_c_idle2, + &corvus3_move_c_idle3, + &corvus3_move_c_walkstart, + &corvus3_move_c_walk1, + &corvus3_move_c_walk2, + &corvus3_move_c_walk3, + &corvus3_move_c_walkstop1, + &corvus3_move_c_walkstop2, + &corvus3_move_c_pivotleftgo, + &corvus3_move_c_pivotleft, + &corvus3_move_c_pivotleftstop, + &corvus3_move_c_pivotrightgo, + &corvus3_move_c_pivotright, + &corvus3_move_c_pivotrightstop +}; + +static ClassResourceInfo_t resInfo; + +void corvus3_invisible (edict_t *self) +{ + self->s.modelindex = 0; +} + +void corvus3_visible (edict_t *self) +{ + self->s.modelindex = self->count; +} + +void corvus3_teleportsmalleffect (edict_t *self) +{ + vec3_t holdorigin,forward,right; + int holdfor; + + VectorCopy(self->s.origin,holdorigin); + + AngleVectors(self->s.angles, forward, right, NULL); + + holdfor = irand(5,10); + VectorMA(holdorigin, holdfor, forward, holdorigin); + holdfor = irand(-5,5); + VectorMA(holdorigin, holdfor, right, holdorigin); + holdorigin[2] += flrand(-25,5); + + gi.sound(self, CHAN_WEAPON, gi.soundindex("player/picup.wav"), 1, ATTN_NORM, 0); + gi.CreateEffect(NULL, FX_PICKUP, 0, holdorigin, NULL); +} + +void corvus3_teleporteffect (edict_t *self) +{ + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + gi.CreateEffect(&self->s, FX_PLAYER_TELEPORT_IN, CEF_OWNERS_ORIGIN, self->s.origin, NULL); +} + +/*------------------------------------------------------------------------- + corvus3_c_anims +-------------------------------------------------------------------------*/ +void corvus3_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_ACTION8: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + case MSG_C_ACTION9: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION9; + break; + case MSG_C_ACTION10: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION10; + break; + case MSG_C_ACTION11: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION11; + break; + case MSG_C_ACTION12: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION12; + break; + case MSG_C_ACTION13: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION13; + break; + case MSG_C_ACTION14: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION14; + break; + case MSG_C_ACTION15: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION15; + break; + case MSG_C_ACTION16: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION16; + break; + case MSG_C_ACTION17: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION17; + break; + case MSG_C_ACTION18: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION18; + break; + case MSG_C_ACTION19: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION19; + break; + case MSG_C_ACTION20: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION20; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_PIVOTLEFTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTGO; + break; + case MSG_C_PIVOTLEFT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTLEFT; + break; + case MSG_C_PIVOTLEFTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTSTOP; + break; + case MSG_C_PIVOTRIGHTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTGO; + break; + case MSG_C_PIVOTRIGHT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTRIGHT; + break; + case MSG_C_PIVOTRIGHTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTSTOP; + break; + case MSG_C_WALKSTART: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTART; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + case MSG_C_WALK3: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK3; + break; + case MSG_C_WALKSTOP1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP1; + break; + case MSG_C_WALKSTOP2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP2; + break; + + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + PlagueElfStaticsInit +-------------------------------------------------------------------------*/ +void Corvus3StaticsInit() +{ + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION1] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION2] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION3] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION4] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION5] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION6] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION7] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION8] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION9] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION10] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION11] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION12] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION13] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION14] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION15] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION16] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION17] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION18] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION19] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_ACTION20] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_IDLE1] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_IDLE2] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_IDLE3] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_WALKSTART] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_WALK1] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_WALK2] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_WALK3] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_WALKSTOP1] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_WALKSTOP2] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_PIVOTLEFTGO] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_PIVOTLEFT] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_PIVOTLEFTSTOP] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_PIVOTRIGHTGO] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_PIVOTRIGHT] = corvus3_c_anims; + classStatics[CID_CORVUS3].msgReceivers[MSG_C_PIVOTRIGHTSTOP] = corvus3_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/player/highpriestess_scene/tris.fm"); + + classStatics[CID_CORVUS3].resInfo = &resInfo; + +} + + +/*QUAKED character_corvus3 (1 .5 0) (-17 -25 -32) (22 12 32) INVISIBLE +The cinematic Corvus for the high priestess scene +*/ +void SP_character_corvus3 (edict_t *self) +{ + c_corvus_init(self,CID_CORVUS3); +} diff --git a/Toolkit/Programming/GameCode/game/c_corvus3.h b/Toolkit/Programming/GameCode/game/c_corvus3.h new file mode 100644 index 0000000..d9e0e5b --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus3.h @@ -0,0 +1,79 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_ACTION9, + ANIM_C_ACTION10, + ANIM_C_ACTION11, + ANIM_C_ACTION12, + ANIM_C_ACTION13, + ANIM_C_ACTION14, + ANIM_C_ACTION15, + ANIM_C_ACTION16, + ANIM_C_ACTION17, + ANIM_C_ACTION18, + ANIM_C_ACTION19, + ANIM_C_ACTION20, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_WALKSTART, + ANIM_C_WALK1, + ANIM_C_WALK2, + ANIM_C_WALK3, + ANIM_C_WALKSTOP1, + ANIM_C_WALKSTOP2, + ANIM_C_PIVOTLEFTGO, + ANIM_C_PIVOTLEFT, + ANIM_C_PIVOTLEFTSTOP, + ANIM_C_PIVOTRIGHTGO, + ANIM_C_PIVOTRIGHT, + ANIM_C_PIVOTRIGHTSTOP, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t corvus3_move_c_action1; +extern animmove_t corvus3_move_c_action2; +extern animmove_t corvus3_move_c_action3; +extern animmove_t corvus3_move_c_action4; +extern animmove_t corvus3_move_c_action5; +extern animmove_t corvus3_move_c_action6; +extern animmove_t corvus3_move_c_action7; +extern animmove_t corvus3_move_c_action8; +extern animmove_t corvus3_move_c_action9; +extern animmove_t corvus3_move_c_action10; +extern animmove_t corvus3_move_c_action11; +extern animmove_t corvus3_move_c_action12; +extern animmove_t corvus3_move_c_action13; +extern animmove_t corvus3_move_c_action14; +extern animmove_t corvus3_move_c_action15; +extern animmove_t corvus3_move_c_action16; +extern animmove_t corvus3_move_c_action17; +extern animmove_t corvus3_move_c_action18; +extern animmove_t corvus3_move_c_action19; +extern animmove_t corvus3_move_c_action20; + + +extern animmove_t corvus3_move_c_idle1; +extern animmove_t corvus3_move_c_idle2; +extern animmove_t corvus3_move_c_idle3; +extern animmove_t corvus3_move_c_walkstart; +extern animmove_t corvus3_move_c_walk1; +extern animmove_t corvus3_move_c_walk2; +extern animmove_t corvus3_move_c_walk3; +extern animmove_t corvus3_move_c_walkstop1; +extern animmove_t corvus3_move_c_walkstop2; +extern animmove_t corvus3_move_c_pivotleftgo; +extern animmove_t corvus3_move_c_pivotleft; +extern animmove_t corvus3_move_c_pivotleftstop; +extern animmove_t corvus3_move_c_pivotrightgo; +extern animmove_t corvus3_move_c_pivotright; +extern animmove_t corvus3_move_c_pivotrightstop; diff --git a/Toolkit/Programming/GameCode/game/c_corvus3_anim.c b/Toolkit/Programming/GameCode/game/c_corvus3_anim.c new file mode 100644 index 0000000..fbbf502 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus3_anim.c @@ -0,0 +1,2160 @@ +//============================================================================== +// +// c_corvus3_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_corvus3_anim.h" +#include "c_corvus3.h" + +#include "c_ai.h" + +void corvus3_teleporteffect (edict_t *self); +void corvus3_teleportsmalleffect (edict_t *self); +void corvus3_visible (edict_t *self); +void corvus3_invisible (edict_t *self); + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action1 [] = +{ + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_calie1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus3_move_c_action1 = {30, corvus3_frames_c_action1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action2 [] = +{ + FRAME_calie12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_calie21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie47, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action2 = {35, corvus3_frames_c_action2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action3 [] = +{ + FRAME_calie48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_calie54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +// FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t corvus3_move_c_action3 = {151, corvus3_frames_c_action3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action4 [] = +{ + FRAME_catalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_catalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_catalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_catalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_catalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_caidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_caidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cratran5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cratran4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cratran3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cratran2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cratran1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t corvus3_move_c_action4 = {216, corvus3_frames_c_action4, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action5 [] = +{ + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + + FRAME_cwhat1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t corvus3_move_c_action5 = {196, corvus3_frames_c_action5, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action6 [] = +{ + FRAME_cwhat29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwhat37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t corvus3_move_c_action6 = {12, corvus3_frames_c_action6, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action7 [] = +{ + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action7 = {11, corvus3_frames_c_action7, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action8 [] = +{ + FRAME_crtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_crtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_crtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action8 = {65, corvus3_frames_c_action8, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action9 [] = +{ + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action9 = {102, corvus3_frames_c_action9, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action10 [] = +{ + FRAME_crtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_crtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t corvus3_move_c_action10 = {40, corvus3_frames_c_action10, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action11 [] = +{ + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t corvus3_move_c_action11 = {179, corvus3_frames_c_action11, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action12 [] = +{ + FRAME_crtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_crtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_crtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_crtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t corvus3_move_c_action12 = {53, corvus3_frames_c_action12, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action13 [] = +{ + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action13 = {58, corvus3_frames_c_action13, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action14 [] = +{ + FRAME_cido2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cido3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cido4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cido5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cido7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cido8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cido9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cido10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cido12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cido13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cido14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cido15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cido17, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action14 = {13, corvus3_frames_c_action14, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action15 [] = +{ + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t corvus3_move_c_action15 = {142, corvus3_frames_c_action15, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action16 [] = +{ + FRAME_cstalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cstalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cstalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_cstalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, corvus3_teleportsmalleffect, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, corvus3_teleportsmalleffect, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, corvus3_teleportsmalleffect, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, corvus3_teleportsmalleffect, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle16, ai_c_move, 0, 0, 0, NULL, 0, corvus3_teleportsmalleffect, + FRAME_csidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle20, ai_c_move, 0, 0, 0, NULL, 0, corvus3_teleportsmalleffect, + + + FRAME_csidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle4, ai_c_move, 0, 0, 0, NULL, 0, corvus3_teleportsmalleffect, + FRAME_csidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle8, ai_c_move, 0, 0, 0, NULL, 0, corvus3_teleportsmalleffect, + FRAME_csidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_csidle10, ai_c_move, 0, 0, 0, NULL, 0, corvus3_teleporteffect, + FRAME_csidle11, ai_c_move, 0, 0, 0, NULL, 0, corvus3_invisible, + +}; +animmove_t corvus3_move_c_action16 = {149, corvus3_frames_c_action16, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action17 [] = +{ + FRAME_cpidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cpidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action17 = {20, corvus3_frames_c_action17, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action18 [] = +{ + FRAME_cwish1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cwish11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action18 = {11, corvus3_frames_c_action18, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action19 [] = +{ + FRAME_ciwill1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ciwill64, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action19 = {64, corvus3_frames_c_action19, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_action20 [] = +{ + FRAME_cyour1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cyour48, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_action20 = {48, corvus3_frames_c_action20, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_idle1 [] = +{ + FRAME_Breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL + +}; + +animmove_t corvus3_move_c_idle1 = {23, corvus3_frames_c_idle1, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_idle2 [] = +{ + FRAME_stance1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance16, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance17, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance18, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance19, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance20, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance21, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance22, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance23, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance24, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus3_move_c_idle2 = {24, corvus3_frames_c_idle2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_idle3 [] = +{ + FRAME_stance1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance16, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance17, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance18, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance19, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance20, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance21, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance22, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance23, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance24, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus3_move_c_idle3 = {24, corvus3_frames_c_idle3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the left +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_pivotleftgo [] = +{ + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_pivotleftgo = {2, corvus3_frames_c_pivotleftgo, ai_c_cycleend}; + +animframe_t corvus3_frames_c_pivotleft [] = +{ + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_pivotleft = {2, corvus3_frames_c_pivotleft, ai_c_cycleend}; + + +animframe_t corvus3_frames_c_pivotleftstop [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_pivotleftstop = {1, corvus3_frames_c_pivotleftstop, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the right +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_pivotrightgo [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_pivotrightgo = {2, corvus3_frames_c_pivotrightgo, ai_c_cycleend}; + +animframe_t corvus3_frames_c_pivotright [] = +{ + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_pivotright = {2, corvus3_frames_c_pivotright, ai_c_cycleend}; + + +animframe_t corvus3_frames_c_pivotrightstop [] = +{ + FRAME_Lpivot1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_pivotrightstop = {1, corvus3_frames_c_pivotrightstop, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_walk1 [] = +{ + FRAME_jog1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog3, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog4, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog5, ai_c_move, 17, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog7, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog8, ai_c_move, 16, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_walk1 = {8, corvus3_frames_c_walk1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_walk2 [] = +{ + FRAME_cinewalk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus3_move_c_walk2 = {16, corvus3_frames_c_walk2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_walk3 [] = +{ + FRAME_cinewalk1, ai_c_move, 4, 0, 0, NULL, 0, corvus3_teleporteffect, + FRAME_cinewalk2, ai_c_move, 4, 0, 0, NULL, 0, corvus3_visible, + FRAME_cinewalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus3_move_c_walk3 = {20, corvus3_frames_c_walk3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - starting his walk anims +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_walkstart [] = +{ + FRAME_gorun2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_gorun3, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_walkstart = {2, corvus3_frames_c_walkstart, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with right foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_walkstop1 [] = +{ + FRAME_jog1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_walkstop1 = {2, corvus3_frames_c_walkstop1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with left foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus3_frames_c_walkstop2 [] = +{ + FRAME_jog5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus3_move_c_walkstop2 = {2, corvus3_frames_c_walkstop2, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/c_corvus3_anim.h b/Toolkit/Programming/GameCode/game/c_corvus3_anim.h new file mode 100644 index 0000000..d294036 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus3_anim.h @@ -0,0 +1,481 @@ +// R:\Art\models/player\highpriestess_scene + +// This file generated by qdata - Do NOT Modify + +#define FRAME_Breath1 0 +#define FRAME_Breath2 1 +#define FRAME_Breath3 2 +#define FRAME_Breath4 3 +#define FRAME_Breath5 4 +#define FRAME_Breath6 5 +#define FRAME_Breath7 6 +#define FRAME_Breath8 7 +#define FRAME_Breath9 8 +#define FRAME_Breath10 9 +#define FRAME_Breath11 10 +#define FRAME_Breath12 11 +#define FRAME_Breath13 12 +#define FRAME_Breath14 13 +#define FRAME_Breath15 14 +#define FRAME_Breath16 15 +#define FRAME_Breath17 16 +#define FRAME_Breath18 17 +#define FRAME_Breath19 18 +#define FRAME_Breath20 19 +#define FRAME_Breath21 20 +#define FRAME_Breath22 21 +#define FRAME_Breath23 22 +#define FRAME_caidle1 23 +#define FRAME_caidle2 24 +#define FRAME_caidle3 25 +#define FRAME_caidle4 26 +#define FRAME_caidle5 27 +#define FRAME_caidle6 28 +#define FRAME_caidle7 29 +#define FRAME_caidle8 30 +#define FRAME_caidle9 31 +#define FRAME_caidle10 32 +#define FRAME_caidle11 33 +#define FRAME_caidle12 34 +#define FRAME_caidle13 35 +#define FRAME_caidle14 36 +#define FRAME_caidle15 37 +#define FRAME_caidle16 38 +#define FRAME_caidle17 39 +#define FRAME_caidle18 40 +#define FRAME_caidle19 41 +#define FRAME_caidle20 42 +#define FRAME_calie1 43 +#define FRAME_calie2 44 +#define FRAME_calie3 45 +#define FRAME_calie4 46 +#define FRAME_calie5 47 +#define FRAME_calie6 48 +#define FRAME_calie7 49 +#define FRAME_calie8 50 +#define FRAME_calie9 51 +#define FRAME_calie10 52 +#define FRAME_calie11 53 +#define FRAME_calie12 54 +#define FRAME_calie13 55 +#define FRAME_calie14 56 +#define FRAME_calie15 57 +#define FRAME_calie16 58 +#define FRAME_calie17 59 +#define FRAME_calie18 60 +#define FRAME_calie19 61 +#define FRAME_calie20 62 +#define FRAME_calie21 63 +#define FRAME_calie22 64 +#define FRAME_calie23 65 +#define FRAME_calie24 66 +#define FRAME_calie25 67 +#define FRAME_calie26 68 +#define FRAME_calie27 69 +#define FRAME_calie28 70 +#define FRAME_calie29 71 +#define FRAME_calie30 72 +#define FRAME_calie31 73 +#define FRAME_calie32 74 +#define FRAME_calie33 75 +#define FRAME_calie34 76 +#define FRAME_calie35 77 +#define FRAME_calie36 78 +#define FRAME_calie37 79 +#define FRAME_calie38 80 +#define FRAME_calie39 81 +#define FRAME_calie40 82 +#define FRAME_calie41 83 +#define FRAME_calie42 84 +#define FRAME_calie43 85 +#define FRAME_calie44 86 +#define FRAME_calie45 87 +#define FRAME_calie46 88 +#define FRAME_calie47 89 +#define FRAME_calie48 90 +#define FRAME_calie49 91 +#define FRAME_calie50 92 +#define FRAME_calie51 93 +#define FRAME_calie52 94 +#define FRAME_calie53 95 +#define FRAME_calie54 96 +#define FRAME_catalk1 97 +#define FRAME_catalk2 98 +#define FRAME_catalk3 99 +#define FRAME_catalk4 100 +#define FRAME_catalk5 101 +#define FRAME_catalk6 102 +#define FRAME_catalk7 103 +#define FRAME_catalk8 104 +#define FRAME_catalk9 105 +#define FRAME_catalk10 106 +#define FRAME_catalk11 107 +#define FRAME_catalk12 108 +#define FRAME_cido1 109 +#define FRAME_cido2 110 +#define FRAME_cido3 111 +#define FRAME_cido4 112 +#define FRAME_cido5 113 +#define FRAME_cido6 114 +#define FRAME_cido7 115 +#define FRAME_cido8 116 +#define FRAME_cido9 117 +#define FRAME_cido10 118 +#define FRAME_cido11 119 +#define FRAME_cido12 120 +#define FRAME_cido13 121 +#define FRAME_cido14 122 +#define FRAME_cido15 123 +#define FRAME_cido16 124 +#define FRAME_cido17 125 +#define FRAME_cido18 126 +#define FRAME_cinewalk1 127 +#define FRAME_cinewalk2 128 +#define FRAME_cinewalk3 129 +#define FRAME_cinewalk4 130 +#define FRAME_cinewalk5 131 +#define FRAME_cinewalk6 132 +#define FRAME_cinewalk7 133 +#define FRAME_cinewalk8 134 +#define FRAME_cinewalk9 135 +#define FRAME_cinewalk10 136 +#define FRAME_cinewalk11 137 +#define FRAME_cinewalk12 138 +#define FRAME_cinewalk13 139 +#define FRAME_cinewalk14 140 +#define FRAME_cinewalk15 141 +#define FRAME_cinewalk16 142 +#define FRAME_cluster 143 +#define FRAME_cratran1 144 +#define FRAME_cratran2 145 +#define FRAME_cratran3 146 +#define FRAME_cratran4 147 +#define FRAME_cratran5 148 +#define FRAME_cridle1 149 +#define FRAME_cridle2 150 +#define FRAME_cridle3 151 +#define FRAME_cridle4 152 +#define FRAME_cridle5 153 +#define FRAME_cridle6 154 +#define FRAME_cridle7 155 +#define FRAME_cridle8 156 +#define FRAME_cridle9 157 +#define FRAME_cridle10 158 +#define FRAME_cridle11 159 +#define FRAME_cridle12 160 +#define FRAME_cridle13 161 +#define FRAME_cridle14 162 +#define FRAME_cridle15 163 +#define FRAME_cridle16 164 +#define FRAME_cridle17 165 +#define FRAME_cridle18 166 +#define FRAME_cridle19 167 +#define FRAME_cridle20 168 +#define FRAME_cridle21 169 +#define FRAME_cridle22 170 +#define FRAME_cridle23 171 +#define FRAME_cridle24 172 +#define FRAME_crtalk1 173 +#define FRAME_crtalk2 174 +#define FRAME_crtalk3 175 +#define FRAME_crtalk4 176 +#define FRAME_crtalk5 177 +#define FRAME_crtalk6 178 +#define FRAME_crtalk7 179 +#define FRAME_crtalk8 180 +#define FRAME_crtalk9 181 +#define FRAME_crtalk10 182 +#define FRAME_crtalk11 183 +#define FRAME_crtalk12 184 +#define FRAME_crtalk13 185 +#define FRAME_crtalk14 186 +#define FRAME_crtalk15 187 +#define FRAME_crtalk16 188 +#define FRAME_crtalk17 189 +#define FRAME_crtalk18 190 +#define FRAME_crtalk19 191 +#define FRAME_crtalk20 192 +#define FRAME_crtalk21 193 +#define FRAME_crtalk22 194 +#define FRAME_crtalk23 195 +#define FRAME_crtalk24 196 +#define FRAME_csidle1 197 +#define FRAME_csidle2 198 +#define FRAME_csidle3 199 +#define FRAME_csidle4 200 +#define FRAME_csidle5 201 +#define FRAME_csidle6 202 +#define FRAME_csidle7 203 +#define FRAME_csidle8 204 +#define FRAME_csidle9 205 +#define FRAME_csidle10 206 +#define FRAME_csidle11 207 +#define FRAME_csidle12 208 +#define FRAME_csidle13 209 +#define FRAME_csidle14 210 +#define FRAME_csidle15 211 +#define FRAME_csidle16 212 +#define FRAME_csidle17 213 +#define FRAME_csidle18 214 +#define FRAME_csidle19 215 +#define FRAME_csidle20 216 +#define FRAME_cstalk1 217 +#define FRAME_cstalk2 218 +#define FRAME_cstalk3 219 +#define FRAME_cstalk4 220 +#define FRAME_cstalk5 221 +#define FRAME_cstalk6 222 +#define FRAME_cstalk7 223 +#define FRAME_cstalk8 224 +#define FRAME_cstalk9 225 +#define FRAME_cstalk10 226 +#define FRAME_cstalk11 227 +#define FRAME_cstalk12 228 +#define FRAME_cstalk13 229 +#define FRAME_cstalk14 230 +#define FRAME_cstalk15 231 +#define FRAME_cstalk16 232 +#define FRAME_cstalk17 233 +#define FRAME_cstalk18 234 +#define FRAME_cstalk19 235 +#define FRAME_cstalk20 236 +#define FRAME_cwhat1 237 +#define FRAME_cwhat2 238 +#define FRAME_cwhat3 239 +#define FRAME_cwhat4 240 +#define FRAME_cwhat5 241 +#define FRAME_cwhat6 242 +#define FRAME_cwhat7 243 +#define FRAME_cwhat8 244 +#define FRAME_cwhat9 245 +#define FRAME_cwhat10 246 +#define FRAME_cwhat11 247 +#define FRAME_cwhat12 248 +#define FRAME_cwhat13 249 +#define FRAME_cwhat14 250 +#define FRAME_cwhat15 251 +#define FRAME_cwhat16 252 +#define FRAME_cwhat17 253 +#define FRAME_cwhat18 254 +#define FRAME_cwhat19 255 +#define FRAME_cwhat20 256 +#define FRAME_cwhat21 257 +#define FRAME_cwhat22 258 +#define FRAME_cwhat23 259 +#define FRAME_cwhat24 260 +#define FRAME_cwhat25 261 +#define FRAME_cwhat26 262 +#define FRAME_cwhat27 263 +#define FRAME_cwhat28 264 +#define FRAME_cwhat29 265 +#define FRAME_cwhat30 266 +#define FRAME_cwhat31 267 +#define FRAME_cwhat32 268 +#define FRAME_cwhat33 269 +#define FRAME_cwhat34 270 +#define FRAME_cwhat35 271 +#define FRAME_cwhat36 272 +#define FRAME_cwhat37 273 +#define FRAME_gorun1 274 +#define FRAME_gorun2 275 +#define FRAME_gorun3 276 +#define FRAME_jog1 277 +#define FRAME_jog2 278 +#define FRAME_jog3 279 +#define FRAME_jog4 280 +#define FRAME_jog5 281 +#define FRAME_jog6 282 +#define FRAME_jog7 283 +#define FRAME_jog8 284 +#define FRAME_Lpivot1 285 +#define FRAME_Lpivot2 286 +#define FRAME_Lpivot3 287 +#define FRAME_Lpivot4 288 +#define FRAME_ciwill1 289 +#define FRAME_ciwill2 290 +#define FRAME_ciwill3 291 +#define FRAME_ciwill4 292 +#define FRAME_ciwill5 293 +#define FRAME_ciwill6 294 +#define FRAME_ciwill7 295 +#define FRAME_ciwill8 296 +#define FRAME_ciwill9 297 +#define FRAME_ciwill10 298 +#define FRAME_ciwill11 299 +#define FRAME_ciwill12 300 +#define FRAME_ciwill13 301 +#define FRAME_ciwill14 302 +#define FRAME_ciwill15 303 +#define FRAME_ciwill16 304 +#define FRAME_ciwill17 305 +#define FRAME_ciwill18 306 +#define FRAME_ciwill19 307 +#define FRAME_ciwill20 308 +#define FRAME_ciwill21 309 +#define FRAME_ciwill22 310 +#define FRAME_ciwill23 311 +#define FRAME_ciwill24 312 +#define FRAME_ciwill25 313 +#define FRAME_ciwill26 314 +#define FRAME_ciwill27 315 +#define FRAME_ciwill28 316 +#define FRAME_ciwill29 317 +#define FRAME_ciwill30 318 +#define FRAME_ciwill31 319 +#define FRAME_ciwill32 320 +#define FRAME_ciwill33 321 +#define FRAME_ciwill34 322 +#define FRAME_ciwill35 323 +#define FRAME_ciwill36 324 +#define FRAME_ciwill37 325 +#define FRAME_ciwill38 326 +#define FRAME_ciwill39 327 +#define FRAME_ciwill40 328 +#define FRAME_ciwill41 329 +#define FRAME_ciwill42 330 +#define FRAME_ciwill43 331 +#define FRAME_ciwill44 332 +#define FRAME_ciwill45 333 +#define FRAME_ciwill46 334 +#define FRAME_ciwill47 335 +#define FRAME_ciwill48 336 +#define FRAME_ciwill49 337 +#define FRAME_ciwill50 338 +#define FRAME_ciwill51 339 +#define FRAME_ciwill52 340 +#define FRAME_ciwill53 341 +#define FRAME_ciwill54 342 +#define FRAME_ciwill55 343 +#define FRAME_ciwill56 344 +#define FRAME_ciwill57 345 +#define FRAME_ciwill58 346 +#define FRAME_ciwill59 347 +#define FRAME_ciwill60 348 +#define FRAME_ciwill61 349 +#define FRAME_ciwill62 350 +#define FRAME_ciwill63 351 +#define FRAME_ciwill64 352 +#define FRAME_cpidle1 353 +#define FRAME_cpidle2 354 +#define FRAME_cpidle3 355 +#define FRAME_cpidle4 356 +#define FRAME_cpidle5 357 +#define FRAME_cpidle6 358 +#define FRAME_cpidle7 359 +#define FRAME_cpidle8 360 +#define FRAME_cpidle9 361 +#define FRAME_cpidle10 362 +#define FRAME_cpidle11 363 +#define FRAME_cpidle12 364 +#define FRAME_cpidle13 365 +#define FRAME_cpidle14 366 +#define FRAME_cpidle15 367 +#define FRAME_cpidle16 368 +#define FRAME_cpidle17 369 +#define FRAME_cpidle18 370 +#define FRAME_cpidle19 371 +#define FRAME_cpidle20 372 +#define FRAME_cwish1 373 +#define FRAME_cwish2 374 +#define FRAME_cwish3 375 +#define FRAME_cwish4 376 +#define FRAME_cwish5 377 +#define FRAME_cwish6 378 +#define FRAME_cwish7 379 +#define FRAME_cwish8 380 +#define FRAME_cwish9 381 +#define FRAME_cwish10 382 +#define FRAME_cwish11 383 +#define FRAME_cyour1 384 +#define FRAME_cyour2 385 +#define FRAME_cyour3 386 +#define FRAME_cyour4 387 +#define FRAME_cyour5 388 +#define FRAME_cyour6 389 +#define FRAME_cyour7 390 +#define FRAME_cyour8 391 +#define FRAME_cyour9 392 +#define FRAME_cyour10 393 +#define FRAME_cyour11 394 +#define FRAME_cyour12 395 +#define FRAME_cyour13 396 +#define FRAME_cyour14 397 +#define FRAME_cyour15 398 +#define FRAME_cyour16 399 +#define FRAME_cyour17 400 +#define FRAME_cyour18 401 +#define FRAME_cyour19 402 +#define FRAME_cyour20 403 +#define FRAME_cyour21 404 +#define FRAME_cyour22 405 +#define FRAME_cyour23 406 +#define FRAME_cyour24 407 +#define FRAME_cyour25 408 +#define FRAME_cyour26 409 +#define FRAME_cyour27 410 +#define FRAME_cyour28 411 +#define FRAME_cyour29 412 +#define FRAME_cyour30 413 +#define FRAME_cyour31 414 +#define FRAME_cyour32 415 +#define FRAME_cyour33 416 +#define FRAME_cyour34 417 +#define FRAME_cyour35 418 +#define FRAME_cyour36 419 +#define FRAME_cyour37 420 +#define FRAME_cyour38 421 +#define FRAME_cyour39 422 +#define FRAME_cyour40 423 +#define FRAME_cyour41 424 +#define FRAME_cyour42 425 +#define FRAME_cyour43 426 +#define FRAME_cyour44 427 +#define FRAME_cyour45 428 +#define FRAME_cyour46 429 +#define FRAME_cyour47 430 +#define FRAME_cyour48 431 +#define FRAME_stance1 432 +#define FRAME_stance2 433 +#define FRAME_stance3 434 +#define FRAME_stance4 435 +#define FRAME_stance5 436 +#define FRAME_stance6 437 +#define FRAME_stance7 438 +#define FRAME_stance8 439 +#define FRAME_stance9 440 +#define FRAME_stance10 441 +#define FRAME_stance11 442 +#define FRAME_stance12 443 +#define FRAME_stance13 444 +#define FRAME_stance14 445 +#define FRAME_stance15 446 +#define FRAME_stance16 447 +#define FRAME_stance17 448 +#define FRAME_stance18 449 +#define FRAME_stance19 450 +#define FRAME_stance20 451 +#define FRAME_stance21 452 +#define FRAME_stance22 453 +#define FRAME_stance23 454 +#define FRAME_stance24 455 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_corvus4.c b/Toolkit/Programming/GameCode/game/c_corvus4.c new file mode 100644 index 0000000..2b62859 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus4.c @@ -0,0 +1,190 @@ +/*------------------------------------------------------------------- +c_corvus.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "c_corvus4.h" +#include "c_corvus4_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[NUM_ANIMS] = +{ + // Cinematics + &corvus4_move_c_action1, + &corvus4_move_c_action2, + &corvus4_move_c_action3, + &corvus4_move_c_action4, + &corvus4_move_c_action5, + &corvus4_move_c_idle1, + &corvus4_move_c_idle2, + &corvus4_move_c_walkstart, + &corvus4_move_c_walk1, + &corvus4_move_c_walk2, + &corvus4_move_c_walkstop1, + &corvus4_move_c_walkstop2, + &corvus4_move_c_pivotleftgo, + &corvus4_move_c_pivotleft, + &corvus4_move_c_pivotleftstop, + &corvus4_move_c_pivotrightgo, + &corvus4_move_c_pivotright, + &corvus4_move_c_pivotrightstop +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + corvus4_c_anims +-------------------------------------------------------------------------*/ +void corvus4_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_PIVOTLEFTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTGO; + break; + case MSG_C_PIVOTLEFT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTLEFT; + break; + case MSG_C_PIVOTLEFTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTSTOP; + break; + case MSG_C_PIVOTRIGHTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTGO; + break; + case MSG_C_PIVOTRIGHT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTRIGHT; + break; + case MSG_C_PIVOTRIGHTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTSTOP; + break; + case MSG_C_WALKSTART: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTART; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + case MSG_C_WALKSTOP1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP1; + break; + case MSG_C_WALKSTOP2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP2; + break; + + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + PlagueElfStaticsInit +-------------------------------------------------------------------------*/ +void Corvus4StaticsInit() +{ + classStatics[CID_CORVUS4].msgReceivers[MSG_C_ACTION1] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_ACTION2] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_ACTION3] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_ACTION4] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_ACTION5] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_IDLE1] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_IDLE2] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_WALKSTART] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_WALK1] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_WALK2] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_WALKSTOP1] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_WALKSTOP2] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_PIVOTLEFTGO] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_PIVOTLEFT] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_PIVOTLEFTSTOP] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_PIVOTRIGHTGO] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_PIVOTRIGHT] = corvus4_c_anims; + classStatics[CID_CORVUS4].msgReceivers[MSG_C_PIVOTRIGHTSTOP] = corvus4_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/player/scout_scene/tris.fm"); + + classStatics[CID_CORVUS4].resInfo = &resInfo; + +} + +/*QUAKED character_corvus4 (1 .5 0) (-16 -16 -34) (16 16 25) INVISIBLE +The cinematic Corvus for the Scout scene +*/ +void SP_character_corvus4 (edict_t *self) +{ + c_corvus_init(self,CID_CORVUS4); +} diff --git a/Toolkit/Programming/GameCode/game/c_corvus4.h b/Toolkit/Programming/GameCode/game/c_corvus4.h new file mode 100644 index 0000000..cf25d4f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus4.h @@ -0,0 +1,45 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_WALKSTART, + ANIM_C_WALK1, + ANIM_C_WALK2, + ANIM_C_WALKSTOP1, + ANIM_C_WALKSTOP2, + ANIM_C_PIVOTLEFTGO, + ANIM_C_PIVOTLEFT, + ANIM_C_PIVOTLEFTSTOP, + ANIM_C_PIVOTRIGHTGO, + ANIM_C_PIVOTRIGHT, + ANIM_C_PIVOTRIGHTSTOP, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + + + +extern animmove_t corvus4_move_c_action1; +extern animmove_t corvus4_move_c_action2; +extern animmove_t corvus4_move_c_action3; +extern animmove_t corvus4_move_c_action4; +extern animmove_t corvus4_move_c_action5; +extern animmove_t corvus4_move_c_idle1; +extern animmove_t corvus4_move_c_idle2; +extern animmove_t corvus4_move_c_walkstart; +extern animmove_t corvus4_move_c_walk1; +extern animmove_t corvus4_move_c_walk2; +extern animmove_t corvus4_move_c_walkstop1; +extern animmove_t corvus4_move_c_walkstop2; +extern animmove_t corvus4_move_c_pivotleftgo; +extern animmove_t corvus4_move_c_pivotleft; +extern animmove_t corvus4_move_c_pivotleftstop; +extern animmove_t corvus4_move_c_pivotrightgo; +extern animmove_t corvus4_move_c_pivotright; +extern animmove_t corvus4_move_c_pivotrightstop; diff --git a/Toolkit/Programming/GameCode/game/c_corvus4_anim.c b/Toolkit/Programming/GameCode/game/c_corvus4_anim.c new file mode 100644 index 0000000..3abde00 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus4_anim.c @@ -0,0 +1,400 @@ +//============================================================================== +// +// c_corvus4_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_corvus4_anim.h" +#include "c_corvus4.h" + +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_action1 [] = +{ + FRAME_ss_kneel1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_kneel12, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus4_move_c_action1 = {12, corvus4_frames_c_action1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_action2 [] = +{ + FRAME_ss_youare1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_youare40, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus4_move_c_action2 = {40, corvus4_frames_c_action2, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_action3 [] = +{ + FRAME_ss_arethe1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_arethe16, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus4_move_c_action3 = {16, corvus4_frames_c_action3, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_action4 [] = +{ + FRAME_ss_myjourn1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_myjourn24, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus4_move_c_action4 = {24, corvus4_frames_c_action4, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_action5 [] = +{ + FRAME_ss_getup1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_getup39, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus4_move_c_action5 = {39, corvus4_frames_c_action5, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_idle1 [] = +{ + FRAME_Breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus4_move_c_idle1 = {23, corvus4_frames_c_idle1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_idle2 [] = +{ + FRAME_ss_idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idle20, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus4_move_c_idle2 = {20, corvus4_frames_c_idle2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the left +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_pivotleftgo [] = +{ + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_pivotleftgo = {2, corvus4_frames_c_pivotleftgo, ai_c_cycleend}; + +animframe_t corvus4_frames_c_pivotleft [] = +{ + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_pivotleft = {2, corvus4_frames_c_pivotleft, ai_c_cycleend}; + + +animframe_t corvus4_frames_c_pivotleftstop [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_pivotleftstop = {1, corvus4_frames_c_pivotleftstop, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the right +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_pivotrightgo [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_pivotrightgo = {2, corvus4_frames_c_pivotrightgo, ai_c_cycleend}; + +animframe_t corvus4_frames_c_pivotright [] = +{ + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_pivotright = {2, corvus4_frames_c_pivotright, ai_c_cycleend}; + + +animframe_t corvus4_frames_c_pivotrightstop [] = +{ + FRAME_Lpivot1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_pivotrightstop = {1, corvus4_frames_c_pivotrightstop, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_walk1 [] = +{ + FRAME_jog1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog3, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog4, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog5, ai_c_move, 17, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog7, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog8, ai_c_move, 16, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_walk1 = {8, corvus4_frames_c_walk1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_walk2 [] = +{ + FRAME_cinewalk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus4_move_c_walk2 = {16, corvus4_frames_c_walk2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - starting his walk anims +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_walkstart [] = +{ + FRAME_gorun2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_gorun3, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_walkstart = {2, corvus4_frames_c_walkstart, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with right foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_walkstop1 [] = +{ + FRAME_jog1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_walkstop1 = {2, corvus4_frames_c_walkstop1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with left foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus4_frames_c_walkstop2 [] = +{ + FRAME_jog5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus4_move_c_walkstop2 = {2, corvus4_frames_c_walkstop2, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/c_corvus4_anim.h b/Toolkit/Programming/GameCode/game/c_corvus4_anim.h new file mode 100644 index 0000000..0cfeba0 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus4_anim.h @@ -0,0 +1,231 @@ +// R:\Art\models/player\scout_scene + +// This file generated by qdata - Do NOT Modify + +#define FRAME_Breath1 0 +#define FRAME_Breath2 1 +#define FRAME_Breath3 2 +#define FRAME_Breath4 3 +#define FRAME_Breath5 4 +#define FRAME_Breath6 5 +#define FRAME_Breath7 6 +#define FRAME_Breath8 7 +#define FRAME_Breath9 8 +#define FRAME_Breath10 9 +#define FRAME_Breath11 10 +#define FRAME_Breath12 11 +#define FRAME_Breath13 12 +#define FRAME_Breath14 13 +#define FRAME_Breath15 14 +#define FRAME_Breath16 15 +#define FRAME_Breath17 16 +#define FRAME_Breath18 17 +#define FRAME_Breath19 18 +#define FRAME_Breath20 19 +#define FRAME_Breath21 20 +#define FRAME_Breath22 21 +#define FRAME_Breath23 22 +#define FRAME_cinewalk1 23 +#define FRAME_cinewalk2 24 +#define FRAME_cinewalk3 25 +#define FRAME_cinewalk4 26 +#define FRAME_cinewalk5 27 +#define FRAME_cinewalk6 28 +#define FRAME_cinewalk7 29 +#define FRAME_cinewalk8 30 +#define FRAME_cinewalk9 31 +#define FRAME_cinewalk10 32 +#define FRAME_cinewalk11 33 +#define FRAME_cinewalk12 34 +#define FRAME_cinewalk13 35 +#define FRAME_cinewalk14 36 +#define FRAME_cinewalk15 37 +#define FRAME_cinewalk16 38 +#define FRAME_cluster 39 +#define FRAME_gorun1 40 +#define FRAME_gorun2 41 +#define FRAME_gorun3 42 +#define FRAME_jog1 43 +#define FRAME_jog2 44 +#define FRAME_jog3 45 +#define FRAME_jog4 46 +#define FRAME_jog5 47 +#define FRAME_jog6 48 +#define FRAME_jog7 49 +#define FRAME_jog8 50 +#define FRAME_Lpivot1 51 +#define FRAME_Lpivot2 52 +#define FRAME_Lpivot3 53 +#define FRAME_Lpivot4 54 +#define FRAME_ss_arethe1 55 +#define FRAME_ss_arethe2 56 +#define FRAME_ss_arethe3 57 +#define FRAME_ss_arethe4 58 +#define FRAME_ss_arethe5 59 +#define FRAME_ss_arethe6 60 +#define FRAME_ss_arethe7 61 +#define FRAME_ss_arethe8 62 +#define FRAME_ss_arethe9 63 +#define FRAME_ss_arethe10 64 +#define FRAME_ss_arethe11 65 +#define FRAME_ss_arethe12 66 +#define FRAME_ss_arethe13 67 +#define FRAME_ss_arethe14 68 +#define FRAME_ss_arethe15 69 +#define FRAME_ss_arethe16 70 +#define FRAME_ss_getup1 71 +#define FRAME_ss_getup2 72 +#define FRAME_ss_getup3 73 +#define FRAME_ss_getup4 74 +#define FRAME_ss_getup5 75 +#define FRAME_ss_getup6 76 +#define FRAME_ss_getup7 77 +#define FRAME_ss_getup8 78 +#define FRAME_ss_getup9 79 +#define FRAME_ss_getup10 80 +#define FRAME_ss_getup11 81 +#define FRAME_ss_getup12 82 +#define FRAME_ss_getup13 83 +#define FRAME_ss_getup14 84 +#define FRAME_ss_getup15 85 +#define FRAME_ss_getup16 86 +#define FRAME_ss_getup17 87 +#define FRAME_ss_getup18 88 +#define FRAME_ss_getup19 89 +#define FRAME_ss_getup20 90 +#define FRAME_ss_getup21 91 +#define FRAME_ss_getup22 92 +#define FRAME_ss_getup23 93 +#define FRAME_ss_getup24 94 +#define FRAME_ss_getup25 95 +#define FRAME_ss_getup26 96 +#define FRAME_ss_getup27 97 +#define FRAME_ss_getup28 98 +#define FRAME_ss_getup29 99 +#define FRAME_ss_getup30 100 +#define FRAME_ss_getup31 101 +#define FRAME_ss_getup32 102 +#define FRAME_ss_getup33 103 +#define FRAME_ss_getup34 104 +#define FRAME_ss_getup35 105 +#define FRAME_ss_getup36 106 +#define FRAME_ss_getup37 107 +#define FRAME_ss_getup38 108 +#define FRAME_ss_getup39 109 +#define FRAME_ss_idle1 110 +#define FRAME_ss_idle2 111 +#define FRAME_ss_idle3 112 +#define FRAME_ss_idle4 113 +#define FRAME_ss_idle5 114 +#define FRAME_ss_idle6 115 +#define FRAME_ss_idle7 116 +#define FRAME_ss_idle8 117 +#define FRAME_ss_idle9 118 +#define FRAME_ss_idle10 119 +#define FRAME_ss_idle11 120 +#define FRAME_ss_idle12 121 +#define FRAME_ss_idle13 122 +#define FRAME_ss_idle14 123 +#define FRAME_ss_idle15 124 +#define FRAME_ss_idle16 125 +#define FRAME_ss_idle17 126 +#define FRAME_ss_idle18 127 +#define FRAME_ss_idle19 128 +#define FRAME_ss_idle20 129 +#define FRAME_ss_kneel1 130 +#define FRAME_ss_kneel2 131 +#define FRAME_ss_kneel3 132 +#define FRAME_ss_kneel4 133 +#define FRAME_ss_kneel5 134 +#define FRAME_ss_kneel6 135 +#define FRAME_ss_kneel7 136 +#define FRAME_ss_kneel8 137 +#define FRAME_ss_kneel9 138 +#define FRAME_ss_kneel10 139 +#define FRAME_ss_kneel11 140 +#define FRAME_ss_kneel12 141 +#define FRAME_ss_myjourn1 142 +#define FRAME_ss_myjourn2 143 +#define FRAME_ss_myjourn3 144 +#define FRAME_ss_myjourn4 145 +#define FRAME_ss_myjourn5 146 +#define FRAME_ss_myjourn6 147 +#define FRAME_ss_myjourn7 148 +#define FRAME_ss_myjourn8 149 +#define FRAME_ss_myjourn9 150 +#define FRAME_ss_myjourn10 151 +#define FRAME_ss_myjourn11 152 +#define FRAME_ss_myjourn12 153 +#define FRAME_ss_myjourn13 154 +#define FRAME_ss_myjourn14 155 +#define FRAME_ss_myjourn15 156 +#define FRAME_ss_myjourn16 157 +#define FRAME_ss_myjourn17 158 +#define FRAME_ss_myjourn18 159 +#define FRAME_ss_myjourn19 160 +#define FRAME_ss_myjourn20 161 +#define FRAME_ss_myjourn21 162 +#define FRAME_ss_myjourn22 163 +#define FRAME_ss_myjourn23 164 +#define FRAME_ss_myjourn24 165 +#define FRAME_ss_youare1 166 +#define FRAME_ss_youare2 167 +#define FRAME_ss_youare3 168 +#define FRAME_ss_youare4 169 +#define FRAME_ss_youare5 170 +#define FRAME_ss_youare6 171 +#define FRAME_ss_youare7 172 +#define FRAME_ss_youare8 173 +#define FRAME_ss_youare9 174 +#define FRAME_ss_youare10 175 +#define FRAME_ss_youare11 176 +#define FRAME_ss_youare12 177 +#define FRAME_ss_youare13 178 +#define FRAME_ss_youare14 179 +#define FRAME_ss_youare15 180 +#define FRAME_ss_youare16 181 +#define FRAME_ss_youare17 182 +#define FRAME_ss_youare18 183 +#define FRAME_ss_youare19 184 +#define FRAME_ss_youare20 185 +#define FRAME_ss_youare21 186 +#define FRAME_ss_youare22 187 +#define FRAME_ss_youare23 188 +#define FRAME_ss_youare24 189 +#define FRAME_ss_youare25 190 +#define FRAME_ss_youare26 191 +#define FRAME_ss_youare27 192 +#define FRAME_ss_youare28 193 +#define FRAME_ss_youare29 194 +#define FRAME_ss_youare30 195 +#define FRAME_ss_youare31 196 +#define FRAME_ss_youare32 197 +#define FRAME_ss_youare33 198 +#define FRAME_ss_youare34 199 +#define FRAME_ss_youare35 200 +#define FRAME_ss_youare36 201 +#define FRAME_ss_youare37 202 +#define FRAME_ss_youare38 203 +#define FRAME_ss_youare39 204 +#define FRAME_ss_youare40 205 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_corvus5.c b/Toolkit/Programming/GameCode/game/c_corvus5.c new file mode 100644 index 0000000..d31ea83 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus5.c @@ -0,0 +1,215 @@ +/*------------------------------------------------------------------- +c_corvus.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "c_corvus5.h" +#include "c_corvus5_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[NUM_ANIMS] = +{ + // Cinematics + &corvus5_move_c_action1, + &corvus5_move_c_action2, + &corvus5_move_c_action3, + &corvus5_move_c_action4, + &corvus5_move_c_action5, + &corvus5_move_c_action6, + &corvus5_move_c_action7, + &corvus5_move_c_action8, + &corvus5_move_c_idle1, + &corvus5_move_c_idle2, + &corvus5_move_c_idle3, + &corvus5_move_c_walkstart, + &corvus5_move_c_walk1, + &corvus5_move_c_walk2, + &corvus5_move_c_walkstop1, + &corvus5_move_c_walkstop2, + &corvus5_move_c_pivotleftgo, + &corvus5_move_c_pivotleft, + &corvus5_move_c_pivotleftstop, + &corvus5_move_c_pivotrightgo, + &corvus5_move_c_pivotright, + &corvus5_move_c_pivotrightstop +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + corvus5_c_anims +-------------------------------------------------------------------------*/ +void corvus5_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_ACTION8: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_PIVOTLEFTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTGO; + break; + case MSG_C_PIVOTLEFT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTLEFT; + break; + case MSG_C_PIVOTLEFTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTSTOP; + break; + case MSG_C_PIVOTRIGHTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTGO; + break; + case MSG_C_PIVOTRIGHT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTRIGHT; + break; + case MSG_C_PIVOTRIGHTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTSTOP; + break; + case MSG_C_WALKSTART: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTART; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + case MSG_C_WALKSTOP1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP1; + break; + case MSG_C_WALKSTOP2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP2; + break; + + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + PlagueElfStaticsInit +-------------------------------------------------------------------------*/ +void Corvus5StaticsInit() +{ + classStatics[CID_CORVUS5].msgReceivers[MSG_C_ACTION1] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_ACTION2] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_ACTION3] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_ACTION4] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_ACTION5] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_ACTION6] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_ACTION7] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_ACTION8] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_IDLE1] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_IDLE2] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_IDLE3] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_WALKSTART] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_WALK1] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_WALK2] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_WALKSTOP1] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_WALKSTOP2] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_PIVOTLEFTGO] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_PIVOTLEFT] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_PIVOTLEFTSTOP] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_PIVOTRIGHTGO] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_PIVOTRIGHT] = corvus5_c_anims; + classStatics[CID_CORVUS5].msgReceivers[MSG_C_PIVOTRIGHTSTOP] = corvus5_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/player/dranor_scene/tris.fm"); + + classStatics[CID_CORVUS5].resInfo = &resInfo; + +} + + +/*QUAKED character_corvus5 (1 .5 0) (-16 -16 -34) (16 16 25) INVISIBLE +The cinematic Corvus for the Dranor scene +*/ +void SP_character_corvus5 (edict_t *self) +{ + c_corvus_init(self,CID_CORVUS5); +} diff --git a/Toolkit/Programming/GameCode/game/c_corvus5.h b/Toolkit/Programming/GameCode/game/c_corvus5.h new file mode 100644 index 0000000..fbd4007 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus5.h @@ -0,0 +1,51 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_WALKSTART, + ANIM_C_WALK1, + ANIM_C_WALK2, + ANIM_C_WALKSTOP1, + ANIM_C_WALKSTOP2, + ANIM_C_PIVOTLEFTGO, + ANIM_C_PIVOTLEFT, + ANIM_C_PIVOTLEFTSTOP, + ANIM_C_PIVOTRIGHTGO, + ANIM_C_PIVOTRIGHT, + ANIM_C_PIVOTRIGHTSTOP, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t corvus5_move_c_action1; +extern animmove_t corvus5_move_c_action2; +extern animmove_t corvus5_move_c_action3; +extern animmove_t corvus5_move_c_action4; +extern animmove_t corvus5_move_c_action5; +extern animmove_t corvus5_move_c_action6; +extern animmove_t corvus5_move_c_action7; +extern animmove_t corvus5_move_c_action8; +extern animmove_t corvus5_move_c_idle1; +extern animmove_t corvus5_move_c_idle2; +extern animmove_t corvus5_move_c_idle3; +extern animmove_t corvus5_move_c_walkstart; +extern animmove_t corvus5_move_c_walk1; +extern animmove_t corvus5_move_c_walk2; +extern animmove_t corvus5_move_c_walkstop1; +extern animmove_t corvus5_move_c_walkstop2; +extern animmove_t corvus5_move_c_pivotleftgo; +extern animmove_t corvus5_move_c_pivotleft; +extern animmove_t corvus5_move_c_pivotleftstop; +extern animmove_t corvus5_move_c_pivotrightgo; +extern animmove_t corvus5_move_c_pivotright; +extern animmove_t corvus5_move_c_pivotrightstop; diff --git a/Toolkit/Programming/GameCode/game/c_corvus5_anim.c b/Toolkit/Programming/GameCode/game/c_corvus5_anim.c new file mode 100644 index 0000000..868f34e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus5_anim.c @@ -0,0 +1,466 @@ +//============================================================================== +// +// c_corvus5_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_corvus5_anim.h" +#include "c_corvus5.h" + +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_action1 [] = +{ + FRAME_youknow1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_youknow2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_youknow3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_youknow4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_youknow5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_youknow6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_youknow7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_youknow8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_action1 = {8, corvus5_frames_c_action1, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_action2 [] = +{ + FRAME_who1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_who47, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_action2 = {47, corvus5_frames_c_action2, ai_c_cycleend}; + + + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_action3 [] = +{ + FRAME_spared1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spared2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spared3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spared4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spared5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spared6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spared7, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_action3 = {7, corvus5_frames_c_action3, ai_c_cycleend}; + + + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_action4 [] = +{ + FRAME_itsnot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_itsnot23, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_action4 = {23, corvus5_frames_c_action4, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_action5 [] = +{ + FRAME_iwill1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iwill33, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_action5 = {33, corvus5_frames_c_action5, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_action6[] = +{ + FRAME_ready1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_action6 = {3, corvus5_frames_c_action6, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_action7[] = +{ + FRAME_ready4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready26, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_action7 = {23, corvus5_frames_c_action7, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_action8[] = +{ + FRAME_ready3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_action8 = {3, corvus5_frames_c_action8, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_idle1 [] = +{ + FRAME_Breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus5_move_c_idle1 = {23, corvus5_frames_c_idle1, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_idle2 [] = +{ + FRAME_who1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_idle2 = {1, corvus5_frames_c_idle2, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_idle3 [] = +{ + FRAME_stance1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance16, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance17, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance18, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance19, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance20, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance21, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance22, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance23, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_stance24, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_idle3 = {24, corvus5_frames_c_idle3, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the left +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_pivotleftgo [] = +{ + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_pivotleftgo = {2, corvus5_frames_c_pivotleftgo, ai_c_cycleend}; + +animframe_t corvus5_frames_c_pivotleft [] = +{ + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_pivotleft = {2, corvus5_frames_c_pivotleft, ai_c_cycleend}; + + +animframe_t corvus5_frames_c_pivotleftstop [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_pivotleftstop = {1, corvus5_frames_c_pivotleftstop, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the right +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_pivotrightgo [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_pivotrightgo = {2, corvus5_frames_c_pivotrightgo, ai_c_cycleend}; + +animframe_t corvus5_frames_c_pivotright [] = +{ + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_pivotright = {2, corvus5_frames_c_pivotright, ai_c_cycleend}; + + +animframe_t corvus5_frames_c_pivotrightstop [] = +{ + FRAME_Lpivot1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_pivotrightstop = {1, corvus5_frames_c_pivotrightstop, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_walk1 [] = +{ + FRAME_jog1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog3, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog4, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog5, ai_c_move, 17, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog7, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog8, ai_c_move, 16, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_walk1 = {8, corvus5_frames_c_walk1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_walk2 [] = +{ + FRAME_cinewalk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus5_move_c_walk2 = {16, corvus5_frames_c_walk2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - starting his walk anims +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_walkstart [] = +{ + FRAME_gorun2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_gorun3, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_walkstart = {2, corvus5_frames_c_walkstart, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with right foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_walkstop1 [] = +{ + FRAME_jog1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_walkstop1 = {2, corvus5_frames_c_walkstop1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with left foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus5_frames_c_walkstop2 [] = +{ + FRAME_jog5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus5_move_c_walkstop2 = {2, corvus5_frames_c_walkstop2, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/c_corvus5_anim.h b/Toolkit/Programming/GameCode/game/c_corvus5_anim.h new file mode 100644 index 0000000..5818f55 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus5_anim.h @@ -0,0 +1,248 @@ +// R:\Art\models/player\dranor_scene + +// This file generated by qdata - Do NOT Modify + +#define FRAME_Breath1 0 +#define FRAME_Breath2 1 +#define FRAME_Breath3 2 +#define FRAME_Breath4 3 +#define FRAME_Breath5 4 +#define FRAME_Breath6 5 +#define FRAME_Breath7 6 +#define FRAME_Breath8 7 +#define FRAME_Breath9 8 +#define FRAME_Breath10 9 +#define FRAME_Breath11 10 +#define FRAME_Breath12 11 +#define FRAME_Breath13 12 +#define FRAME_Breath14 13 +#define FRAME_Breath15 14 +#define FRAME_Breath16 15 +#define FRAME_Breath17 16 +#define FRAME_Breath18 17 +#define FRAME_Breath19 18 +#define FRAME_Breath20 19 +#define FRAME_Breath21 20 +#define FRAME_Breath22 21 +#define FRAME_Breath23 22 +#define FRAME_cinewalk1 23 +#define FRAME_cinewalk2 24 +#define FRAME_cinewalk3 25 +#define FRAME_cinewalk4 26 +#define FRAME_cinewalk5 27 +#define FRAME_cinewalk6 28 +#define FRAME_cinewalk7 29 +#define FRAME_cinewalk8 30 +#define FRAME_cinewalk9 31 +#define FRAME_cinewalk10 32 +#define FRAME_cinewalk11 33 +#define FRAME_cinewalk12 34 +#define FRAME_cinewalk13 35 +#define FRAME_cinewalk14 36 +#define FRAME_cinewalk15 37 +#define FRAME_cinewalk16 38 +#define FRAME_cluster 39 +#define FRAME_gorun1 40 +#define FRAME_gorun2 41 +#define FRAME_gorun3 42 +#define FRAME_itsnot1 43 +#define FRAME_itsnot2 44 +#define FRAME_itsnot3 45 +#define FRAME_itsnot4 46 +#define FRAME_itsnot5 47 +#define FRAME_itsnot6 48 +#define FRAME_itsnot7 49 +#define FRAME_itsnot8 50 +#define FRAME_itsnot9 51 +#define FRAME_itsnot10 52 +#define FRAME_itsnot11 53 +#define FRAME_itsnot12 54 +#define FRAME_itsnot13 55 +#define FRAME_itsnot14 56 +#define FRAME_itsnot15 57 +#define FRAME_itsnot16 58 +#define FRAME_itsnot17 59 +#define FRAME_itsnot18 60 +#define FRAME_itsnot19 61 +#define FRAME_itsnot20 62 +#define FRAME_itsnot21 63 +#define FRAME_itsnot22 64 +#define FRAME_itsnot23 65 +#define FRAME_iwill1 66 +#define FRAME_iwill2 67 +#define FRAME_iwill3 68 +#define FRAME_iwill4 69 +#define FRAME_iwill5 70 +#define FRAME_iwill6 71 +#define FRAME_iwill7 72 +#define FRAME_iwill8 73 +#define FRAME_iwill9 74 +#define FRAME_iwill10 75 +#define FRAME_iwill11 76 +#define FRAME_iwill12 77 +#define FRAME_iwill13 78 +#define FRAME_iwill14 79 +#define FRAME_iwill15 80 +#define FRAME_iwill16 81 +#define FRAME_iwill17 82 +#define FRAME_iwill18 83 +#define FRAME_iwill19 84 +#define FRAME_iwill20 85 +#define FRAME_iwill21 86 +#define FRAME_iwill22 87 +#define FRAME_iwill23 88 +#define FRAME_iwill24 89 +#define FRAME_iwill25 90 +#define FRAME_iwill26 91 +#define FRAME_iwill27 92 +#define FRAME_iwill28 93 +#define FRAME_iwill29 94 +#define FRAME_iwill30 95 +#define FRAME_iwill31 96 +#define FRAME_iwill32 97 +#define FRAME_iwill33 98 +#define FRAME_jog1 99 +#define FRAME_jog2 100 +#define FRAME_jog3 101 +#define FRAME_jog4 102 +#define FRAME_jog5 103 +#define FRAME_jog6 104 +#define FRAME_jog7 105 +#define FRAME_jog8 106 +#define FRAME_Lpivot1 107 +#define FRAME_Lpivot2 108 +#define FRAME_Lpivot3 109 +#define FRAME_Lpivot4 110 +#define FRAME_spared1 111 +#define FRAME_spared2 112 +#define FRAME_spared3 113 +#define FRAME_spared4 114 +#define FRAME_spared5 115 +#define FRAME_spared6 116 +#define FRAME_spared7 117 +#define FRAME_who1 118 +#define FRAME_who2 119 +#define FRAME_who3 120 +#define FRAME_who4 121 +#define FRAME_who5 122 +#define FRAME_who6 123 +#define FRAME_who7 124 +#define FRAME_who8 125 +#define FRAME_who9 126 +#define FRAME_who10 127 +#define FRAME_who11 128 +#define FRAME_who12 129 +#define FRAME_who13 130 +#define FRAME_who14 131 +#define FRAME_who15 132 +#define FRAME_who16 133 +#define FRAME_who17 134 +#define FRAME_who18 135 +#define FRAME_who19 136 +#define FRAME_who20 137 +#define FRAME_who21 138 +#define FRAME_who22 139 +#define FRAME_who23 140 +#define FRAME_who24 141 +#define FRAME_who25 142 +#define FRAME_who26 143 +#define FRAME_who27 144 +#define FRAME_who28 145 +#define FRAME_who29 146 +#define FRAME_who30 147 +#define FRAME_who31 148 +#define FRAME_who32 149 +#define FRAME_who33 150 +#define FRAME_who34 151 +#define FRAME_who35 152 +#define FRAME_who36 153 +#define FRAME_who37 154 +#define FRAME_who38 155 +#define FRAME_who39 156 +#define FRAME_who40 157 +#define FRAME_who41 158 +#define FRAME_who42 159 +#define FRAME_who43 160 +#define FRAME_who44 161 +#define FRAME_who45 162 +#define FRAME_who46 163 +#define FRAME_who47 164 +#define FRAME_youknow1 165 +#define FRAME_youknow2 166 +#define FRAME_youknow3 167 +#define FRAME_youknow4 168 +#define FRAME_youknow5 169 +#define FRAME_youknow6 170 +#define FRAME_youknow7 171 +#define FRAME_youknow8 172 +#define FRAME_stance1 173 +#define FRAME_stance2 174 +#define FRAME_stance3 175 +#define FRAME_stance4 176 +#define FRAME_stance5 177 +#define FRAME_stance6 178 +#define FRAME_stance7 179 +#define FRAME_stance8 180 +#define FRAME_stance9 181 +#define FRAME_stance10 182 +#define FRAME_stance11 183 +#define FRAME_stance12 184 +#define FRAME_stance13 185 +#define FRAME_stance14 186 +#define FRAME_stance15 187 +#define FRAME_stance16 188 +#define FRAME_stance17 189 +#define FRAME_stance18 190 +#define FRAME_stance19 191 +#define FRAME_stance20 192 +#define FRAME_stance21 193 +#define FRAME_stance22 194 +#define FRAME_stance23 195 +#define FRAME_stance24 196 +#define FRAME_ready1 197 +#define FRAME_ready2 198 +#define FRAME_ready3 199 +#define FRAME_ready4 200 +#define FRAME_ready5 201 +#define FRAME_ready6 202 +#define FRAME_ready7 203 +#define FRAME_ready8 204 +#define FRAME_ready9 205 +#define FRAME_ready10 206 +#define FRAME_ready11 207 +#define FRAME_ready12 208 +#define FRAME_ready13 209 +#define FRAME_ready14 210 +#define FRAME_ready15 211 +#define FRAME_ready16 212 +#define FRAME_ready17 213 +#define FRAME_ready18 214 +#define FRAME_ready19 215 +#define FRAME_ready20 216 +#define FRAME_ready21 217 +#define FRAME_ready22 218 +#define FRAME_ready23 219 +#define FRAME_ready24 220 +#define FRAME_ready25 221 +#define FRAME_ready26 222 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_corvus6.c b/Toolkit/Programming/GameCode/game/c_corvus6.c new file mode 100644 index 0000000..0d9c983 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus6.c @@ -0,0 +1,191 @@ +/*------------------------------------------------------------------- +c_corvus.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "c_corvus6.h" +#include "c_corvus6_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[NUM_ANIMS] = +{ + // Cinematics + &corvus6_move_c_action1, + &corvus6_move_c_action2, + &corvus6_move_c_action3, + &corvus6_move_c_action4, + &corvus6_move_c_action5, + &corvus6_move_c_action6, + &corvus6_move_c_action7, + &corvus6_move_c_action8, + &corvus6_move_c_action9, + &corvus6_move_c_action10, + &corvus6_move_c_action11, + &corvus6_move_c_idle1, + &corvus6_move_c_idle2, + &corvus6_move_c_idle3, + &corvus6_move_c_idle4, + &corvus6_move_c_idle5, +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + corvus6_c_anims +-------------------------------------------------------------------------*/ +void corvus6_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + + case MSG_C_ACTION2 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + + case MSG_C_ACTION3 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + + case MSG_C_ACTION4 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + + case MSG_C_ACTION5 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + + case MSG_C_ACTION6 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + + case MSG_C_ACTION7 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + + case MSG_C_ACTION8 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + + case MSG_C_ACTION9 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION9; + break; + case MSG_C_ACTION10 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION10; + break; + case MSG_C_ACTION11 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION11; + break; + + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE3; + break; + + case MSG_C_IDLE4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE4; + break; + + case MSG_C_IDLE5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE5; + break; + + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + StaticsInit +-------------------------------------------------------------------------*/ +void Corvus6StaticsInit() +{ + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION1] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION2] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION3] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION4] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION5] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION6] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION7] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION8] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION9] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION10] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_ACTION11] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_IDLE1] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_IDLE2] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_IDLE3] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_IDLE4] = corvus6_c_anims; + classStatics[CID_CORVUS6].msgReceivers[MSG_C_IDLE5] = corvus6_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/player/sewer_scene/tris.fm"); + + classStatics[CID_CORVUS6].resInfo = &resInfo; + +} + +/*QUAKED character_corvus6 (1 .5 0) (-16 -16 -34) (16 16 25) INVISIBLE +The cinematic Corvus for the Dranor scene +*/ +void SP_character_corvus6 (edict_t *self) +{ + c_corvus_init(self,CID_CORVUS6); +} diff --git a/Toolkit/Programming/GameCode/game/c_corvus6.h b/Toolkit/Programming/GameCode/game/c_corvus6.h new file mode 100644 index 0000000..64ee6b2 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus6.h @@ -0,0 +1,40 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_ACTION9, + ANIM_C_ACTION10, + ANIM_C_ACTION11, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_IDLE4, + ANIM_C_IDLE5, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t corvus6_move_c_action1; +extern animmove_t corvus6_move_c_action2; +extern animmove_t corvus6_move_c_action3; +extern animmove_t corvus6_move_c_action4; +extern animmove_t corvus6_move_c_action5; +extern animmove_t corvus6_move_c_action6; +extern animmove_t corvus6_move_c_action7; +extern animmove_t corvus6_move_c_action8; +extern animmove_t corvus6_move_c_action9; +extern animmove_t corvus6_move_c_action10; +extern animmove_t corvus6_move_c_action11; +extern animmove_t corvus6_move_c_idle1; +extern animmove_t corvus6_move_c_idle2; +extern animmove_t corvus6_move_c_idle3; +extern animmove_t corvus6_move_c_idle4; +extern animmove_t corvus6_move_c_idle5; + diff --git a/Toolkit/Programming/GameCode/game/c_corvus6_anim.c b/Toolkit/Programming/GameCode/game/c_corvus6_anim.c new file mode 100644 index 0000000..c0f15fe --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus6_anim.c @@ -0,0 +1,485 @@ +//============================================================================== +// +// c_corvus5_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_corvus6_anim.h" +#include "c_corvus6.h" + +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action1 [] = +{ + FRAME_propup1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action1 = {11, corvus6_frames_c_action1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action2 [] = +{ + FRAME_groan1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_groan20, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action2 = {20, corvus6_frames_c_action2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action3 [] = +{ + FRAME_moan1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_moan12, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action3 = {12, corvus6_frames_c_action3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action4 [] = +{ + FRAME_lookup1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lookup29, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action4 = {29, corvus6_frames_c_action4, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action5 [] = +{ + FRAME_strong1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strong11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action5 = {11, corvus6_frames_c_action5, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action6 [] = +{ + FRAME_notnow1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notnow47, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action6 = {47, corvus6_frames_c_action6, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action7 [] = +{ + FRAME_relax1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax16, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action7 = {16, corvus6_frames_c_action7, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action8 [] = +{ + FRAME_nofear1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_nofear35, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action8 = {35, corvus6_frames_c_action8, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action9 [] = +{ + FRAME_standup1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_standup18, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action9 = {18, corvus6_frames_c_action9, ai_c_cycleend}; + + + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action10 [] = +{ + FRAME_falling1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_falling15, NULL, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action10 = {15, corvus6_frames_c_action10, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_action11 [] = +{ + FRAME_kodown1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown12, NULL, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_action11 = {12, corvus6_frames_c_action11, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_idle1 [] = +{ + FRAME_propup1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_propup1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_idle1 = {3, corvus6_frames_c_idle1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_idle2 [] = +{ + FRAME_1breathing1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing26, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_idle2 = {26, corvus6_frames_c_idle2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_idle3 [] = +{ + FRAME_2breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_idle3 = {21, corvus6_frames_c_idle3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_idle4 [] = +{ + FRAME_1breathing26, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus6_move_c_idle4 = {1, corvus6_frames_c_idle4, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus6_frames_c_idle5 [] = +{ + FRAME_breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus6_move_c_idle5 = {23, corvus6_frames_c_idle5, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/c_corvus6_anim.h b/Toolkit/Programming/GameCode/game/c_corvus6_anim.h new file mode 100644 index 0000000..2496903 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus6_anim.h @@ -0,0 +1,331 @@ +// R:\Art\models/player\sewer_scene + +// This file generated by qdata - Do NOT Modify + +#define FRAME_1breathing1 0 +#define FRAME_1breathing2 1 +#define FRAME_1breathing3 2 +#define FRAME_1breathing4 3 +#define FRAME_1breathing5 4 +#define FRAME_1breathing6 5 +#define FRAME_1breathing7 6 +#define FRAME_1breathing8 7 +#define FRAME_1breathing9 8 +#define FRAME_1breathing10 9 +#define FRAME_1breathing11 10 +#define FRAME_1breathing12 11 +#define FRAME_1breathing13 12 +#define FRAME_1breathing14 13 +#define FRAME_1breathing15 14 +#define FRAME_1breathing16 15 +#define FRAME_1breathing17 16 +#define FRAME_1breathing18 17 +#define FRAME_1breathing19 18 +#define FRAME_1breathing20 19 +#define FRAME_1breathing21 20 +#define FRAME_1breathing22 21 +#define FRAME_1breathing23 22 +#define FRAME_1breathing24 23 +#define FRAME_1breathing25 24 +#define FRAME_1breathing26 25 +#define FRAME_2breath1 26 +#define FRAME_2breath2 27 +#define FRAME_2breath3 28 +#define FRAME_2breath4 29 +#define FRAME_2breath5 30 +#define FRAME_2breath6 31 +#define FRAME_2breath7 32 +#define FRAME_2breath8 33 +#define FRAME_2breath9 34 +#define FRAME_2breath10 35 +#define FRAME_2breath11 36 +#define FRAME_2breath12 37 +#define FRAME_2breath13 38 +#define FRAME_2breath14 39 +#define FRAME_2breath15 40 +#define FRAME_2breath16 41 +#define FRAME_2breath17 42 +#define FRAME_2breath18 43 +#define FRAME_2breath19 44 +#define FRAME_2breath20 45 +#define FRAME_2breath21 46 +#define FRAME_groan1 47 +#define FRAME_groan2 48 +#define FRAME_groan3 49 +#define FRAME_groan4 50 +#define FRAME_groan5 51 +#define FRAME_groan6 52 +#define FRAME_groan7 53 +#define FRAME_groan8 54 +#define FRAME_groan9 55 +#define FRAME_groan10 56 +#define FRAME_groan11 57 +#define FRAME_groan12 58 +#define FRAME_groan13 59 +#define FRAME_groan14 60 +#define FRAME_groan15 61 +#define FRAME_groan16 62 +#define FRAME_groan17 63 +#define FRAME_groan18 64 +#define FRAME_groan19 65 +#define FRAME_groan20 66 +#define FRAME_lookup1 67 +#define FRAME_lookup2 68 +#define FRAME_lookup3 69 +#define FRAME_lookup4 70 +#define FRAME_lookup5 71 +#define FRAME_lookup6 72 +#define FRAME_lookup7 73 +#define FRAME_lookup8 74 +#define FRAME_lookup9 75 +#define FRAME_lookup10 76 +#define FRAME_lookup11 77 +#define FRAME_lookup12 78 +#define FRAME_lookup13 79 +#define FRAME_lookup14 80 +#define FRAME_lookup15 81 +#define FRAME_lookup16 82 +#define FRAME_lookup17 83 +#define FRAME_lookup18 84 +#define FRAME_lookup19 85 +#define FRAME_lookup20 86 +#define FRAME_lookup21 87 +#define FRAME_lookup22 88 +#define FRAME_lookup23 89 +#define FRAME_lookup24 90 +#define FRAME_lookup25 91 +#define FRAME_lookup26 92 +#define FRAME_lookup27 93 +#define FRAME_lookup28 94 +#define FRAME_lookup29 95 +#define FRAME_moan1 96 +#define FRAME_moan2 97 +#define FRAME_moan3 98 +#define FRAME_moan4 99 +#define FRAME_moan5 100 +#define FRAME_moan6 101 +#define FRAME_moan7 102 +#define FRAME_moan8 103 +#define FRAME_moan9 104 +#define FRAME_moan10 105 +#define FRAME_moan11 106 +#define FRAME_moan12 107 +#define FRAME_nofear1 108 +#define FRAME_nofear2 109 +#define FRAME_nofear3 110 +#define FRAME_nofear4 111 +#define FRAME_nofear5 112 +#define FRAME_nofear6 113 +#define FRAME_nofear7 114 +#define FRAME_nofear8 115 +#define FRAME_nofear9 116 +#define FRAME_nofear10 117 +#define FRAME_nofear11 118 +#define FRAME_nofear12 119 +#define FRAME_nofear13 120 +#define FRAME_nofear14 121 +#define FRAME_nofear15 122 +#define FRAME_nofear16 123 +#define FRAME_nofear17 124 +#define FRAME_nofear18 125 +#define FRAME_nofear19 126 +#define FRAME_nofear20 127 +#define FRAME_nofear21 128 +#define FRAME_nofear22 129 +#define FRAME_nofear23 130 +#define FRAME_nofear24 131 +#define FRAME_nofear25 132 +#define FRAME_nofear26 133 +#define FRAME_nofear27 134 +#define FRAME_nofear28 135 +#define FRAME_nofear29 136 +#define FRAME_nofear30 137 +#define FRAME_nofear31 138 +#define FRAME_nofear32 139 +#define FRAME_nofear33 140 +#define FRAME_nofear34 141 +#define FRAME_nofear35 142 +#define FRAME_notnow1 143 +#define FRAME_notnow2 144 +#define FRAME_notnow3 145 +#define FRAME_notnow4 146 +#define FRAME_notnow5 147 +#define FRAME_notnow6 148 +#define FRAME_notnow7 149 +#define FRAME_notnow8 150 +#define FRAME_notnow9 151 +#define FRAME_notnow10 152 +#define FRAME_notnow11 153 +#define FRAME_notnow12 154 +#define FRAME_notnow13 155 +#define FRAME_notnow14 156 +#define FRAME_notnow15 157 +#define FRAME_notnow16 158 +#define FRAME_notnow17 159 +#define FRAME_notnow18 160 +#define FRAME_notnow19 161 +#define FRAME_notnow20 162 +#define FRAME_notnow21 163 +#define FRAME_notnow22 164 +#define FRAME_notnow23 165 +#define FRAME_notnow24 166 +#define FRAME_notnow25 167 +#define FRAME_notnow26 168 +#define FRAME_notnow27 169 +#define FRAME_notnow28 170 +#define FRAME_notnow29 171 +#define FRAME_notnow30 172 +#define FRAME_notnow31 173 +#define FRAME_notnow32 174 +#define FRAME_notnow33 175 +#define FRAME_notnow34 176 +#define FRAME_notnow35 177 +#define FRAME_notnow36 178 +#define FRAME_notnow37 179 +#define FRAME_notnow38 180 +#define FRAME_notnow39 181 +#define FRAME_notnow40 182 +#define FRAME_notnow41 183 +#define FRAME_notnow42 184 +#define FRAME_notnow43 185 +#define FRAME_notnow44 186 +#define FRAME_notnow45 187 +#define FRAME_notnow46 188 +#define FRAME_notnow47 189 +#define FRAME_propup1 190 +#define FRAME_propup2 191 +#define FRAME_propup3 192 +#define FRAME_propup4 193 +#define FRAME_propup5 194 +#define FRAME_propup6 195 +#define FRAME_propup7 196 +#define FRAME_propup8 197 +#define FRAME_propup9 198 +#define FRAME_propup10 199 +#define FRAME_propup11 200 +#define FRAME_relax1 201 +#define FRAME_relax2 202 +#define FRAME_relax3 203 +#define FRAME_relax4 204 +#define FRAME_relax5 205 +#define FRAME_relax6 206 +#define FRAME_relax7 207 +#define FRAME_relax8 208 +#define FRAME_relax9 209 +#define FRAME_relax10 210 +#define FRAME_relax11 211 +#define FRAME_relax12 212 +#define FRAME_relax13 213 +#define FRAME_relax14 214 +#define FRAME_relax15 215 +#define FRAME_relax16 216 +#define FRAME_standup1 217 +#define FRAME_standup2 218 +#define FRAME_standup3 219 +#define FRAME_standup4 220 +#define FRAME_standup5 221 +#define FRAME_standup6 222 +#define FRAME_standup7 223 +#define FRAME_standup8 224 +#define FRAME_standup9 225 +#define FRAME_standup10 226 +#define FRAME_standup11 227 +#define FRAME_standup12 228 +#define FRAME_standup13 229 +#define FRAME_standup14 230 +#define FRAME_standup15 231 +#define FRAME_standup16 232 +#define FRAME_standup17 233 +#define FRAME_standup18 234 +#define FRAME_strong1 235 +#define FRAME_strong2 236 +#define FRAME_strong3 237 +#define FRAME_strong4 238 +#define FRAME_strong5 239 +#define FRAME_strong6 240 +#define FRAME_strong7 241 +#define FRAME_strong8 242 +#define FRAME_strong9 243 +#define FRAME_strong10 244 +#define FRAME_strong11 245 +#define FRAME_breath1 246 +#define FRAME_breath2 247 +#define FRAME_breath3 248 +#define FRAME_breath4 249 +#define FRAME_breath5 250 +#define FRAME_breath6 251 +#define FRAME_breath7 252 +#define FRAME_breath8 253 +#define FRAME_breath9 254 +#define FRAME_breath10 255 +#define FRAME_breath11 256 +#define FRAME_breath12 257 +#define FRAME_breath13 258 +#define FRAME_breath14 259 +#define FRAME_breath15 260 +#define FRAME_breath16 261 +#define FRAME_breath17 262 +#define FRAME_breath18 263 +#define FRAME_breath19 264 +#define FRAME_breath20 265 +#define FRAME_breath21 266 +#define FRAME_breath22 267 +#define FRAME_breath23 268 +#define FRAME_falling1 269 +#define FRAME_falling2 270 +#define FRAME_falling3 271 +#define FRAME_falling4 272 +#define FRAME_falling5 273 +#define FRAME_falling6 274 +#define FRAME_falling7 275 +#define FRAME_falling8 276 +#define FRAME_falling9 277 +#define FRAME_falling10 278 +#define FRAME_falling11 279 +#define FRAME_falling12 280 +#define FRAME_falling13 281 +#define FRAME_falling14 282 +#define FRAME_falling15 283 +#define FRAME_kodown1 284 +#define FRAME_kodown2 285 +#define FRAME_kodown3 286 +#define FRAME_kodown4 287 +#define FRAME_kodown5 288 +#define FRAME_kodown6 289 +#define FRAME_kodown7 290 +#define FRAME_kodown8 291 +#define FRAME_kodown9 292 +#define FRAME_kodown10 293 +#define FRAME_kodown11 294 +#define FRAME_kodown12 295 +#define FRAME_kodown13 296 +#define FRAME_kodown14 297 +#define FRAME_kodown15 298 +#define FRAME_kodown16 299 +#define FRAME_kodown17 300 +#define FRAME_kodown18 301 +#define FRAME_kodown19 302 +#define FRAME_kodown20 303 +#define FRAME_kodown21 304 +#define FRAME_kodown22 305 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_corvus7.c b/Toolkit/Programming/GameCode/game/c_corvus7.c new file mode 100644 index 0000000..7c7adb4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus7.c @@ -0,0 +1,186 @@ +/*------------------------------------------------------------------- +c_corvus7.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "c_corvus7.h" +#include "c_corvus7_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + // Cinematics + &corvus7_move_c_action1, + &corvus7_move_c_action2, + &corvus7_move_c_action3, + &corvus7_move_c_idle1, + &corvus7_move_c_idle2, + &corvus7_move_c_idle3, + &corvus7_move_c_walkstart, + &corvus7_move_c_walk1, + &corvus7_move_c_walk2, + &corvus7_move_c_walkstop1, + &corvus7_move_c_walkstop2, + &corvus7_move_c_pivotleftgo, + &corvus7_move_c_pivotleft, + &corvus7_move_c_pivotleftstop, + &corvus7_move_c_pivotrightgo, + &corvus7_move_c_pivotright, + &corvus7_move_c_pivotrightstop +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + corvus7_c_anims +-------------------------------------------------------------------------*/ +void corvus7_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_PIVOTLEFTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTGO; + break; + case MSG_C_PIVOTLEFT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTLEFT; + break; + case MSG_C_PIVOTLEFTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTSTOP; + break; + case MSG_C_PIVOTRIGHTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTGO; + break; + case MSG_C_PIVOTRIGHT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTRIGHT; + break; + case MSG_C_PIVOTRIGHTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTSTOP; + break; + case MSG_C_WALKSTART: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTART; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + case MSG_C_WALKSTOP1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP1; + break; + case MSG_C_WALKSTOP2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP2; + break; + + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + StaticsInit +-------------------------------------------------------------------------*/ +void Corvus7StaticsInit() +{ + + classStatics[CID_CORVUS7].msgReceivers[MSG_C_ACTION1] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_ACTION2] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_ACTION3] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_IDLE1] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_IDLE2] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_IDLE3] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_WALKSTART] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_WALK1] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_WALK2] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_WALKSTOP1] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_WALKSTOP2] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_PIVOTLEFTGO] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_PIVOTLEFT] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_PIVOTLEFTSTOP] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_PIVOTRIGHTGO] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_PIVOTRIGHT] = corvus7_c_anims; + classStatics[CID_CORVUS7].msgReceivers[MSG_C_PIVOTRIGHTSTOP] = corvus7_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + //note that the name is different in the path + resInfo.modelIndex = gi.modelindex("models/player/morcalavin_scene/tris.fm"); + + classStatics[CID_CORVUS7].resInfo = &resInfo; + +} + +/*QUAKED character_corvus7 (1 .5 0) (-17 -25 -32) (22 12 32) INVISIBLE +The cinematic corvus for the Morcalavin scene +*/ +void SP_character_corvus7 (edict_t *self) +{ + c_corvus_init(self,CID_CORVUS7); +} diff --git a/Toolkit/Programming/GameCode/game/c_corvus7.h b/Toolkit/Programming/GameCode/game/c_corvus7.h new file mode 100644 index 0000000..a248d39 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus7.h @@ -0,0 +1,41 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_WALKSTART, + ANIM_C_WALK1, + ANIM_C_WALK2, + ANIM_C_WALKSTOP1, + ANIM_C_WALKSTOP2, + ANIM_C_PIVOTLEFTGO, + ANIM_C_PIVOTLEFT, + ANIM_C_PIVOTLEFTSTOP, + ANIM_C_PIVOTRIGHTGO, + ANIM_C_PIVOTRIGHT, + ANIM_C_PIVOTRIGHTSTOP, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t corvus7_move_c_action1; +extern animmove_t corvus7_move_c_action2; +extern animmove_t corvus7_move_c_action3; +extern animmove_t corvus7_move_c_idle1; +extern animmove_t corvus7_move_c_idle2; +extern animmove_t corvus7_move_c_idle3; +extern animmove_t corvus7_move_c_walkstart; +extern animmove_t corvus7_move_c_walk1; +extern animmove_t corvus7_move_c_walk2; +extern animmove_t corvus7_move_c_walkstop1; +extern animmove_t corvus7_move_c_walkstop2; +extern animmove_t corvus7_move_c_pivotleftgo; +extern animmove_t corvus7_move_c_pivotleft; +extern animmove_t corvus7_move_c_pivotleftstop; +extern animmove_t corvus7_move_c_pivotrightgo; +extern animmove_t corvus7_move_c_pivotright; +extern animmove_t corvus7_move_c_pivotrightstop; diff --git a/Toolkit/Programming/GameCode/game/c_corvus7_anim.c b/Toolkit/Programming/GameCode/game/c_corvus7_anim.c new file mode 100644 index 0000000..edea80f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus7_anim.c @@ -0,0 +1,330 @@ +//============================================================================== +// +// m_corvus_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_corvus7_anim.h" +#include "c_corvus7.h" + +#include "g_monster.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_action1 [] = +{ + FRAME_MCinaa1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinaa40, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus7_move_c_action1 = {40, corvus7_frames_c_action1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_action2 [] = +{ + FRAME_MCinab1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinab16, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus7_move_c_action2 = {16, corvus7_frames_c_action2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_action3 [] = +{ + FRAME_MCinac1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_MCinac14, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus7_move_c_action3 = {14, corvus7_frames_c_action3, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_idle1 [] = +{ + FRAME_Breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus7_move_c_idle1 = {23, corvus7_frames_c_idle1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_idle2 [] = +{ + FRAME_idleA1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleA12, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus7_move_c_idle2 = {12, corvus7_frames_c_idle2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_idle3 [] = +{ + FRAME_idleB1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleB12, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus7_move_c_idle3 = {12, corvus7_frames_c_idle3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the left +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_pivotleftgo [] = +{ + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_pivotleftgo = {2, corvus7_frames_c_pivotleftgo, ai_c_cycleend}; + +animframe_t corvus7_frames_c_pivotleft [] = +{ + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_pivotleft = {2, corvus7_frames_c_pivotleft, ai_c_cycleend}; + + +animframe_t corvus7_frames_c_pivotleftstop [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_pivotleftstop = {1, corvus7_frames_c_pivotleftstop, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the right +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_pivotrightgo [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_pivotrightgo = {2, corvus7_frames_c_pivotrightgo, ai_c_cycleend}; + +animframe_t corvus7_frames_c_pivotright [] = +{ + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_pivotright = {2, corvus7_frames_c_pivotright, ai_c_cycleend}; + + +animframe_t corvus7_frames_c_pivotrightstop [] = +{ + FRAME_Lpivot1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_pivotrightstop = {1, corvus7_frames_c_pivotrightstop, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_walk1 [] = +{ + FRAME_jog1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog3, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog4, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog5, ai_c_move, 17, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog7, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog8, ai_c_move, 16, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_walk1 = {8, corvus7_frames_c_walk1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_walk2 [] = +{ + FRAME_cinewalk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus7_move_c_walk2 = {16, corvus7_frames_c_walk2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - starting his walk anims +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_walkstart [] = +{ + FRAME_gorun2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_gorun3, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_walkstart = {2, corvus7_frames_c_walkstart, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with right foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_walkstop1 [] = +{ + FRAME_jog1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_walkstop1 = {2, corvus7_frames_c_walkstop1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with left foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus7_frames_c_walkstop2 [] = +{ + FRAME_jog5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus7_move_c_walkstop2 = {2, corvus7_frames_c_walkstop2, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/c_corvus7_anim.h b/Toolkit/Programming/GameCode/game/c_corvus7_anim.h new file mode 100644 index 0000000..8580aa1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus7_anim.h @@ -0,0 +1,174 @@ +// R:\Art\models/player\morcalavin_scene + +// This file generated by qdata - Do NOT Modify + +#define FRAME_Breath1 0 +#define FRAME_Breath2 1 +#define FRAME_Breath3 2 +#define FRAME_Breath4 3 +#define FRAME_Breath5 4 +#define FRAME_Breath6 5 +#define FRAME_Breath7 6 +#define FRAME_Breath8 7 +#define FRAME_Breath9 8 +#define FRAME_Breath10 9 +#define FRAME_Breath11 10 +#define FRAME_Breath12 11 +#define FRAME_Breath13 12 +#define FRAME_Breath14 13 +#define FRAME_Breath15 14 +#define FRAME_Breath16 15 +#define FRAME_Breath17 16 +#define FRAME_Breath18 17 +#define FRAME_Breath19 18 +#define FRAME_Breath20 19 +#define FRAME_Breath21 20 +#define FRAME_Breath22 21 +#define FRAME_Breath23 22 +#define FRAME_cinewalk1 23 +#define FRAME_cinewalk2 24 +#define FRAME_cinewalk3 25 +#define FRAME_cinewalk4 26 +#define FRAME_cinewalk5 27 +#define FRAME_cinewalk6 28 +#define FRAME_cinewalk7 29 +#define FRAME_cinewalk8 30 +#define FRAME_cinewalk9 31 +#define FRAME_cinewalk10 32 +#define FRAME_cinewalk11 33 +#define FRAME_cinewalk12 34 +#define FRAME_cinewalk13 35 +#define FRAME_cinewalk14 36 +#define FRAME_cinewalk15 37 +#define FRAME_cinewalk16 38 +#define FRAME_cluster 39 +#define FRAME_gorun1 40 +#define FRAME_gorun2 41 +#define FRAME_gorun3 42 +#define FRAME_jog1 43 +#define FRAME_jog2 44 +#define FRAME_jog3 45 +#define FRAME_jog4 46 +#define FRAME_jog5 47 +#define FRAME_jog6 48 +#define FRAME_jog7 49 +#define FRAME_jog8 50 +#define FRAME_Lpivot1 51 +#define FRAME_Lpivot2 52 +#define FRAME_Lpivot3 53 +#define FRAME_Lpivot4 54 +#define FRAME_MCinaa1 55 +#define FRAME_MCinaa2 56 +#define FRAME_MCinaa3 57 +#define FRAME_MCinaa4 58 +#define FRAME_MCinaa5 59 +#define FRAME_MCinaa6 60 +#define FRAME_MCinaa7 61 +#define FRAME_MCinaa8 62 +#define FRAME_MCinaa9 63 +#define FRAME_MCinaa10 64 +#define FRAME_MCinaa11 65 +#define FRAME_MCinaa12 66 +#define FRAME_MCinaa13 67 +#define FRAME_MCinaa14 68 +#define FRAME_MCinaa15 69 +#define FRAME_MCinaa16 70 +#define FRAME_MCinaa17 71 +#define FRAME_MCinaa18 72 +#define FRAME_MCinaa19 73 +#define FRAME_MCinaa20 74 +#define FRAME_MCinaa21 75 +#define FRAME_MCinaa22 76 +#define FRAME_MCinaa23 77 +#define FRAME_MCinaa24 78 +#define FRAME_MCinaa25 79 +#define FRAME_MCinaa26 80 +#define FRAME_MCinaa27 81 +#define FRAME_MCinaa28 82 +#define FRAME_MCinaa29 83 +#define FRAME_MCinaa30 84 +#define FRAME_MCinaa31 85 +#define FRAME_MCinaa32 86 +#define FRAME_MCinaa33 87 +#define FRAME_MCinaa34 88 +#define FRAME_MCinaa35 89 +#define FRAME_MCinaa36 90 +#define FRAME_MCinaa37 91 +#define FRAME_MCinaa38 92 +#define FRAME_MCinaa39 93 +#define FRAME_MCinaa40 94 +#define FRAME_MCinab1 95 +#define FRAME_MCinab2 96 +#define FRAME_MCinab3 97 +#define FRAME_MCinab4 98 +#define FRAME_MCinab5 99 +#define FRAME_MCinab6 100 +#define FRAME_MCinab7 101 +#define FRAME_MCinab8 102 +#define FRAME_MCinab9 103 +#define FRAME_MCinab10 104 +#define FRAME_MCinab11 105 +#define FRAME_MCinab12 106 +#define FRAME_MCinab13 107 +#define FRAME_MCinab14 108 +#define FRAME_MCinab15 109 +#define FRAME_MCinab16 110 +#define FRAME_MCinac1 111 +#define FRAME_MCinac2 112 +#define FRAME_MCinac3 113 +#define FRAME_MCinac4 114 +#define FRAME_MCinac5 115 +#define FRAME_MCinac6 116 +#define FRAME_MCinac7 117 +#define FRAME_MCinac8 118 +#define FRAME_MCinac9 119 +#define FRAME_MCinac10 120 +#define FRAME_MCinac11 121 +#define FRAME_MCinac12 122 +#define FRAME_MCinac13 123 +#define FRAME_MCinac14 124 +#define FRAME_idleA1 125 +#define FRAME_idleA2 126 +#define FRAME_idleA3 127 +#define FRAME_idleA4 128 +#define FRAME_idleA5 129 +#define FRAME_idleA6 130 +#define FRAME_idleA7 131 +#define FRAME_idleA8 132 +#define FRAME_idleA9 133 +#define FRAME_idleA10 134 +#define FRAME_idleA11 135 +#define FRAME_idleA12 136 +#define FRAME_idleB1 137 +#define FRAME_idleB2 138 +#define FRAME_idleB3 139 +#define FRAME_idleB4 140 +#define FRAME_idleB5 141 +#define FRAME_idleB6 142 +#define FRAME_idleB7 143 +#define FRAME_idleB8 144 +#define FRAME_idleB9 145 +#define FRAME_idleB10 146 +#define FRAME_idleB11 147 +#define FRAME_idleB12 148 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_corvus8.c b/Toolkit/Programming/GameCode/game/c_corvus8.c new file mode 100644 index 0000000..60f5550 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus8.c @@ -0,0 +1,288 @@ +/*------------------------------------------------------------------- +c_corvus8.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "c_corvus8.h" +#include "c_corvus8_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + // Cinematics + &corvus8_move_c_action1, + &corvus8_move_c_action2, + &corvus8_move_c_action3, + &corvus8_move_c_action4, + &corvus8_move_c_action5, + &corvus8_move_c_action6, + &corvus8_move_c_action7, + &corvus8_move_c_action8, + &corvus8_move_c_action9, + &corvus8_move_c_action10, + &corvus8_move_c_action11, + &corvus8_move_c_action12, + &corvus8_move_c_action13, + &corvus8_move_c_action14, + &corvus8_move_c_action15, + &corvus8_move_c_action16, + &corvus8_move_c_action17, + &corvus8_move_c_action18, + &corvus8_move_c_action19, + &corvus8_move_c_action20, + + &corvus8_move_c_idle1, + &corvus8_move_c_idle2, + &corvus8_move_c_walkstart, + &corvus8_move_c_walk1, + &corvus8_move_c_walk2, + &corvus8_move_c_walk3, + &corvus8_move_c_walkstop1, + &corvus8_move_c_walkstop2, + &corvus8_move_c_pivotleftgo, + &corvus8_move_c_pivotleft, + &corvus8_move_c_pivotleftstop, + &corvus8_move_c_pivotrightgo, + &corvus8_move_c_pivotright, + &corvus8_move_c_pivotrightstop +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + corvus8_c_anims +-------------------------------------------------------------------------*/ +void corvus8_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_ACTION8 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + case MSG_C_ACTION9 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION9; + break; + case MSG_C_ACTION10 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION10; + break; + case MSG_C_ACTION11 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION11; + break; + case MSG_C_ACTION12 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION12; + break; + case MSG_C_ACTION13 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION13; + break; + case MSG_C_ACTION14 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION14; + break; + case MSG_C_ACTION15 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION15; + break; + case MSG_C_ACTION16 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION16; + break; + case MSG_C_ACTION17 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION17; + break; + case MSG_C_ACTION18 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION18; + break; + case MSG_C_ACTION19 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION19; + break; + case MSG_C_ACTION20 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION20; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_PIVOTLEFTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTGO; + break; + case MSG_C_PIVOTLEFT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTLEFT; + break; + case MSG_C_PIVOTLEFTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTLEFTSTOP; + break; + case MSG_C_PIVOTRIGHTGO: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTGO; + break; + case MSG_C_PIVOTRIGHT: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_PIVOTRIGHT; + break; + case MSG_C_PIVOTRIGHTSTOP: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PIVOTRIGHTSTOP; + break; + case MSG_C_WALKSTART: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTART; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + case MSG_C_WALK3: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK3; + break; + case MSG_C_WALKSTOP1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP1; + break; + case MSG_C_WALKSTOP2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP2; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + StaticsInit +-------------------------------------------------------------------------*/ +void Corvus8StaticsInit() +{ + + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION1] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION2] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION3] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION4] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION5] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION6] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION7] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION8] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION9] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION10] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION11] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION12] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION13] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION14] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION15] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION16] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION17] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION18] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION19] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_ACTION20] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_IDLE1] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_IDLE2] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_WALKSTART] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_WALK1] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_WALK2] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_WALK3] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_WALKSTOP1] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_WALKSTOP2] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_PIVOTLEFTGO] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_PIVOTLEFT] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_PIVOTLEFTSTOP] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_PIVOTRIGHTGO] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_PIVOTRIGHT] = corvus8_c_anims; + classStatics[CID_CORVUS8].msgReceivers[MSG_C_PIVOTRIGHTSTOP] = corvus8_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + //note that the name is different in the path + resInfo.modelIndex = gi.modelindex("models/player/siernan_scene/tris.fm"); + + classStatics[CID_CORVUS8].resInfo = &resInfo; + +} + +/*QUAKED character_corvus8 (1 .5 0) (-17 -25 -32) (22 12 32) INVISIBLE +The cinematic corvus for the Siernan scenes +*/ +void SP_character_corvus8 (edict_t *self) +{ + c_corvus_init(self,CID_CORVUS8); +} diff --git a/Toolkit/Programming/GameCode/game/c_corvus8.h b/Toolkit/Programming/GameCode/game/c_corvus8.h new file mode 100644 index 0000000..1cb6b97 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus8.h @@ -0,0 +1,75 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_ACTION9, + ANIM_C_ACTION10, + ANIM_C_ACTION11, + ANIM_C_ACTION12, + ANIM_C_ACTION13, + ANIM_C_ACTION14, + ANIM_C_ACTION15, + ANIM_C_ACTION16, + ANIM_C_ACTION17, + ANIM_C_ACTION18, + ANIM_C_ACTION19, + ANIM_C_ACTION20, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_WALKSTART, + ANIM_C_WALK1, + ANIM_C_WALK2, + ANIM_C_WALK3, + ANIM_C_WALKSTOP1, + ANIM_C_WALKSTOP2, + ANIM_C_PIVOTLEFTGO, + ANIM_C_PIVOTLEFT, + ANIM_C_PIVOTLEFTSTOP, + ANIM_C_PIVOTRIGHTGO, + ANIM_C_PIVOTRIGHT, + ANIM_C_PIVOTRIGHTSTOP, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t corvus8_move_c_action1; +extern animmove_t corvus8_move_c_action2; +extern animmove_t corvus8_move_c_action3; +extern animmove_t corvus8_move_c_action4; +extern animmove_t corvus8_move_c_action5; +extern animmove_t corvus8_move_c_action6; +extern animmove_t corvus8_move_c_action7; +extern animmove_t corvus8_move_c_action8; +extern animmove_t corvus8_move_c_action9; +extern animmove_t corvus8_move_c_action10; +extern animmove_t corvus8_move_c_action11; +extern animmove_t corvus8_move_c_action12; +extern animmove_t corvus8_move_c_action13; +extern animmove_t corvus8_move_c_action14; +extern animmove_t corvus8_move_c_action15; +extern animmove_t corvus8_move_c_action16; +extern animmove_t corvus8_move_c_action17; +extern animmove_t corvus8_move_c_action18; +extern animmove_t corvus8_move_c_action19; +extern animmove_t corvus8_move_c_action20; +extern animmove_t corvus8_move_c_idle1; +extern animmove_t corvus8_move_c_idle2; +extern animmove_t corvus8_move_c_walkstart; +extern animmove_t corvus8_move_c_walk1; +extern animmove_t corvus8_move_c_walk2; +extern animmove_t corvus8_move_c_walk3; +extern animmove_t corvus8_move_c_walkstop1; +extern animmove_t corvus8_move_c_walkstop2; +extern animmove_t corvus8_move_c_pivotleftgo; +extern animmove_t corvus8_move_c_pivotleft; +extern animmove_t corvus8_move_c_pivotleftstop; +extern animmove_t corvus8_move_c_pivotrightgo; +extern animmove_t corvus8_move_c_pivotright; +extern animmove_t corvus8_move_c_pivotrightstop; diff --git a/Toolkit/Programming/GameCode/game/c_corvus8_anim.c b/Toolkit/Programming/GameCode/game/c_corvus8_anim.c new file mode 100644 index 0000000..d789643 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus8_anim.c @@ -0,0 +1,861 @@ +//============================================================================== +// +// m_corvus_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_corvus8_anim.h" +#include "c_corvus8.h" + +#include "g_monster.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action1 [] = +{ + FRAME_kneel1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kneel2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kneel3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kneel4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kneel5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kneel6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kneel7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kneel8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action1 = {8, corvus8_frames_c_action1, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action2 [] = +{ + FRAME_knltrn1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knltrn13, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action2 = {13, corvus8_frames_c_action2, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action3 [] = +{ + FRAME_knlcyc1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_knlcyc12, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action3 = {12, corvus8_frames_c_action3, ai_c_cycleend}; + + + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action4 [] = +{ + FRAME_Ido1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Ido2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Ido3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Ido4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Ido5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Ido6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action4 = {6, corvus8_frames_c_action4, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action5 [] = +{ + FRAME_stand8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stand7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stand6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stand5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stand4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stand3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stand2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stand1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action5 = {8, corvus8_frames_c_action5, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action6 [] = +{ + FRAME_butits1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_butits24, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action6 = {24, corvus8_frames_c_action6, ai_c_cycleend}; + + + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action7 [] = +{ + FRAME_bytome1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome18, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action7 = {18, corvus8_frames_c_action7, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action8 [] = +{ + FRAME_iam1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_iam11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action8 = {11, corvus8_frames_c_action8, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action9 [] = +{ + FRAME_noharm1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noharm31, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action9 = {31, corvus8_frames_c_action9, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action10 [] = +{ + FRAME_willu1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_willu2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_willu3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_willu4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_willu5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_willu6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_willu7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_willu8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_willu9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_willu10, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action10 = {10, corvus8_frames_c_action10, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action11 [] = +{ + FRAME_bytome1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome9, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action11 = {9, corvus8_frames_c_action11, ai_c_cycleend}; + + + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action12 [] = +{ + FRAME_bytome10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bytome18, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action12 = {9, corvus8_frames_c_action12, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action13 [] = +{ + FRAME_arethe1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_arethe21, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action13 = {21, corvus8_frames_c_action13, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action14 [] = +{ + FRAME_canit1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_canit21, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action14 = {21, corvus8_frames_c_action14, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action15 [] = +{ + FRAME_grtful1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_grtful58, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action15 = {58, corvus8_frames_c_action15, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action16 [] = +{ + FRAME_kelmnt1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kelmnt77, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action16 = {77, corvus8_frames_c_action16, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action17 [] = +{ + FRAME_potion1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_potion51, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action17 = {51, corvus8_frames_c_action17, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action18 [] = +{ + FRAME_pstop1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pstop2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pstop3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pstop4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pstop5, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action18 = {5, corvus8_frames_c_action18, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action19 [] = +{ + FRAME_drink1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_drink21, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action19 = {21, corvus8_frames_c_action19, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_action20 [] = +{ + FRAME_pour1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour19, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_action20 = {19, corvus8_frames_c_action20, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_idle1 [] = +{ + FRAME_Breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus8_move_c_idle1 = {23, corvus8_frames_c_idle1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus Standing - +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_idle2 [] = +{ + FRAME_pour19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pour19, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_idle2 = {2, corvus8_frames_c_idle2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the left +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_pivotleftgo [] = +{ + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_pivotleftgo = {2, corvus8_frames_c_pivotleftgo, ai_c_cycleend}; + +animframe_t corvus8_frames_c_pivotleft [] = +{ + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_pivotleft = {2, corvus8_frames_c_pivotleft, ai_c_cycleend}; + + +animframe_t corvus8_frames_c_pivotleftstop [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_pivotleftstop = {1, corvus8_frames_c_pivotleftstop, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus - starting his pivot to the right +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_pivotrightgo [] = +{ + FRAME_Lpivot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_pivotrightgo = {2, corvus8_frames_c_pivotrightgo, ai_c_cycleend}; + +animframe_t corvus8_frames_c_pivotright [] = +{ + FRAME_Lpivot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Lpivot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_pivotright = {2, corvus8_frames_c_pivotright, ai_c_cycleend}; + + +animframe_t corvus8_frames_c_pivotrightstop [] = +{ + FRAME_Lpivot1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_pivotrightstop = {1, corvus8_frames_c_pivotrightstop, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_walk1 [] = +{ + FRAME_jog1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog3, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog4, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog5, ai_c_move, 17, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_jog7, ai_c_move, 15, 0, 0, NULL, 0, NULL, + FRAME_jog8, ai_c_move, 16, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_walk1 = {8, corvus8_frames_c_walk1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_walk2 [] = +{ + FRAME_cinewalk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_walk2 = {16, corvus8_frames_c_walk2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_walk3 [] = +{ + FRAME_pwalk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_pwalk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus8_move_c_walk3 = {16, corvus8_frames_c_walk3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - starting his walk anims +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_walkstart [] = +{ + FRAME_gorun2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_gorun3, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_walkstart = {2, corvus8_frames_c_walkstart, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with right foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_walkstop1 [] = +{ + FRAME_jog1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog2, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_walkstop1 = {2, corvus8_frames_c_walkstop1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus - stopping his walk with left foot in front +-----------------------------------------------------------------------*/ +animframe_t corvus8_frames_c_walkstop2 [] = +{ + FRAME_jog5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_jog6, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t corvus8_move_c_walkstop2 = {2, corvus8_frames_c_walkstop2, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/c_corvus8_anim.h b/Toolkit/Programming/GameCode/game/c_corvus8_anim.h new file mode 100644 index 0000000..9565ffb --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus8_anim.h @@ -0,0 +1,510 @@ +// R:\Art\models/player\siernan_scene + +// This file generated by qdata - Do NOT Modify + +#define FRAME_Breath1 0 +#define FRAME_Breath2 1 +#define FRAME_Breath3 2 +#define FRAME_Breath4 3 +#define FRAME_Breath5 4 +#define FRAME_Breath6 5 +#define FRAME_Breath7 6 +#define FRAME_Breath8 7 +#define FRAME_Breath9 8 +#define FRAME_Breath10 9 +#define FRAME_Breath11 10 +#define FRAME_Breath12 11 +#define FRAME_Breath13 12 +#define FRAME_Breath14 13 +#define FRAME_Breath15 14 +#define FRAME_Breath16 15 +#define FRAME_Breath17 16 +#define FRAME_Breath18 17 +#define FRAME_Breath19 18 +#define FRAME_Breath20 19 +#define FRAME_Breath21 20 +#define FRAME_Breath22 21 +#define FRAME_Breath23 22 +#define FRAME_butits1 23 +#define FRAME_butits2 24 +#define FRAME_butits3 25 +#define FRAME_butits4 26 +#define FRAME_butits5 27 +#define FRAME_butits6 28 +#define FRAME_butits7 29 +#define FRAME_butits8 30 +#define FRAME_butits9 31 +#define FRAME_butits10 32 +#define FRAME_butits11 33 +#define FRAME_butits12 34 +#define FRAME_butits13 35 +#define FRAME_butits14 36 +#define FRAME_butits15 37 +#define FRAME_butits16 38 +#define FRAME_butits17 39 +#define FRAME_butits18 40 +#define FRAME_butits19 41 +#define FRAME_butits20 42 +#define FRAME_butits21 43 +#define FRAME_butits22 44 +#define FRAME_butits23 45 +#define FRAME_butits24 46 +#define FRAME_bytome1 47 +#define FRAME_bytome2 48 +#define FRAME_bytome3 49 +#define FRAME_bytome4 50 +#define FRAME_bytome5 51 +#define FRAME_bytome6 52 +#define FRAME_bytome7 53 +#define FRAME_bytome8 54 +#define FRAME_bytome9 55 +#define FRAME_bytome10 56 +#define FRAME_bytome11 57 +#define FRAME_bytome12 58 +#define FRAME_bytome13 59 +#define FRAME_bytome14 60 +#define FRAME_bytome15 61 +#define FRAME_bytome16 62 +#define FRAME_bytome17 63 +#define FRAME_bytome18 64 +#define FRAME_cinewalk1 65 +#define FRAME_cinewalk2 66 +#define FRAME_cinewalk3 67 +#define FRAME_cinewalk4 68 +#define FRAME_cinewalk5 69 +#define FRAME_cinewalk6 70 +#define FRAME_cinewalk7 71 +#define FRAME_cinewalk8 72 +#define FRAME_cinewalk9 73 +#define FRAME_cinewalk10 74 +#define FRAME_cinewalk11 75 +#define FRAME_cinewalk12 76 +#define FRAME_cinewalk13 77 +#define FRAME_cinewalk14 78 +#define FRAME_cinewalk15 79 +#define FRAME_cinewalk16 80 +#define FRAME_cluster 81 +#define FRAME_gorun1 82 +#define FRAME_gorun2 83 +#define FRAME_gorun3 84 +#define FRAME_iam1 85 +#define FRAME_iam2 86 +#define FRAME_iam3 87 +#define FRAME_iam4 88 +#define FRAME_iam5 89 +#define FRAME_iam6 90 +#define FRAME_iam7 91 +#define FRAME_iam8 92 +#define FRAME_iam9 93 +#define FRAME_iam10 94 +#define FRAME_iam11 95 +#define FRAME_Ido1 96 +#define FRAME_Ido2 97 +#define FRAME_Ido3 98 +#define FRAME_Ido4 99 +#define FRAME_Ido5 100 +#define FRAME_Ido6 101 +#define FRAME_jog1 102 +#define FRAME_jog2 103 +#define FRAME_jog3 104 +#define FRAME_jog4 105 +#define FRAME_jog5 106 +#define FRAME_jog6 107 +#define FRAME_jog7 108 +#define FRAME_jog8 109 +#define FRAME_kneel1 110 +#define FRAME_kneel2 111 +#define FRAME_kneel3 112 +#define FRAME_kneel4 113 +#define FRAME_kneel5 114 +#define FRAME_kneel6 115 +#define FRAME_kneel7 116 +#define FRAME_kneel8 117 +#define FRAME_knlcyc1 118 +#define FRAME_knlcyc2 119 +#define FRAME_knlcyc3 120 +#define FRAME_knlcyc4 121 +#define FRAME_knlcyc5 122 +#define FRAME_knlcyc6 123 +#define FRAME_knlcyc7 124 +#define FRAME_knlcyc8 125 +#define FRAME_knlcyc9 126 +#define FRAME_knlcyc10 127 +#define FRAME_knlcyc11 128 +#define FRAME_knlcyc12 129 +#define FRAME_knltrn1 130 +#define FRAME_knltrn2 131 +#define FRAME_knltrn3 132 +#define FRAME_knltrn4 133 +#define FRAME_knltrn5 134 +#define FRAME_knltrn6 135 +#define FRAME_knltrn7 136 +#define FRAME_knltrn8 137 +#define FRAME_knltrn9 138 +#define FRAME_knltrn10 139 +#define FRAME_knltrn11 140 +#define FRAME_knltrn12 141 +#define FRAME_knltrn13 142 +#define FRAME_Lpivot1 143 +#define FRAME_Lpivot2 144 +#define FRAME_Lpivot3 145 +#define FRAME_Lpivot4 146 +#define FRAME_noharm1 147 +#define FRAME_noharm2 148 +#define FRAME_noharm3 149 +#define FRAME_noharm4 150 +#define FRAME_noharm5 151 +#define FRAME_noharm6 152 +#define FRAME_noharm7 153 +#define FRAME_noharm8 154 +#define FRAME_noharm9 155 +#define FRAME_noharm10 156 +#define FRAME_noharm11 157 +#define FRAME_noharm12 158 +#define FRAME_noharm13 159 +#define FRAME_noharm14 160 +#define FRAME_noharm15 161 +#define FRAME_noharm16 162 +#define FRAME_noharm17 163 +#define FRAME_noharm18 164 +#define FRAME_noharm19 165 +#define FRAME_noharm20 166 +#define FRAME_noharm21 167 +#define FRAME_noharm22 168 +#define FRAME_noharm23 169 +#define FRAME_noharm24 170 +#define FRAME_noharm25 171 +#define FRAME_noharm26 172 +#define FRAME_noharm27 173 +#define FRAME_noharm28 174 +#define FRAME_noharm29 175 +#define FRAME_noharm30 176 +#define FRAME_noharm31 177 +#define FRAME_stand1 178 +#define FRAME_stand2 179 +#define FRAME_stand3 180 +#define FRAME_stand4 181 +#define FRAME_stand5 182 +#define FRAME_stand6 183 +#define FRAME_stand7 184 +#define FRAME_stand8 185 +#define FRAME_willu1 186 +#define FRAME_willu2 187 +#define FRAME_willu3 188 +#define FRAME_willu4 189 +#define FRAME_willu5 190 +#define FRAME_willu6 191 +#define FRAME_willu7 192 +#define FRAME_willu8 193 +#define FRAME_willu9 194 +#define FRAME_willu10 195 +#define FRAME_arethe1 196 +#define FRAME_arethe2 197 +#define FRAME_arethe3 198 +#define FRAME_arethe4 199 +#define FRAME_arethe5 200 +#define FRAME_arethe6 201 +#define FRAME_arethe7 202 +#define FRAME_arethe8 203 +#define FRAME_arethe9 204 +#define FRAME_arethe10 205 +#define FRAME_arethe11 206 +#define FRAME_arethe12 207 +#define FRAME_arethe13 208 +#define FRAME_arethe14 209 +#define FRAME_arethe15 210 +#define FRAME_arethe16 211 +#define FRAME_arethe17 212 +#define FRAME_arethe18 213 +#define FRAME_arethe19 214 +#define FRAME_arethe20 215 +#define FRAME_arethe21 216 +#define FRAME_canit1 217 +#define FRAME_canit2 218 +#define FRAME_canit3 219 +#define FRAME_canit4 220 +#define FRAME_canit5 221 +#define FRAME_canit6 222 +#define FRAME_canit7 223 +#define FRAME_canit8 224 +#define FRAME_canit9 225 +#define FRAME_canit10 226 +#define FRAME_canit11 227 +#define FRAME_canit12 228 +#define FRAME_canit13 229 +#define FRAME_canit14 230 +#define FRAME_canit15 231 +#define FRAME_canit16 232 +#define FRAME_canit17 233 +#define FRAME_canit18 234 +#define FRAME_canit19 235 +#define FRAME_canit20 236 +#define FRAME_canit21 237 +#define FRAME_grtful1 238 +#define FRAME_grtful2 239 +#define FRAME_grtful3 240 +#define FRAME_grtful4 241 +#define FRAME_grtful5 242 +#define FRAME_grtful6 243 +#define FRAME_grtful7 244 +#define FRAME_grtful8 245 +#define FRAME_grtful9 246 +#define FRAME_grtful10 247 +#define FRAME_grtful11 248 +#define FRAME_grtful12 249 +#define FRAME_grtful13 250 +#define FRAME_grtful14 251 +#define FRAME_grtful15 252 +#define FRAME_grtful16 253 +#define FRAME_grtful17 254 +#define FRAME_grtful18 255 +#define FRAME_grtful19 256 +#define FRAME_grtful20 257 +#define FRAME_grtful21 258 +#define FRAME_grtful22 259 +#define FRAME_grtful23 260 +#define FRAME_grtful24 261 +#define FRAME_grtful25 262 +#define FRAME_grtful26 263 +#define FRAME_grtful27 264 +#define FRAME_grtful28 265 +#define FRAME_grtful29 266 +#define FRAME_grtful30 267 +#define FRAME_grtful31 268 +#define FRAME_grtful32 269 +#define FRAME_grtful33 270 +#define FRAME_grtful34 271 +#define FRAME_grtful35 272 +#define FRAME_grtful36 273 +#define FRAME_grtful37 274 +#define FRAME_grtful38 275 +#define FRAME_grtful39 276 +#define FRAME_grtful40 277 +#define FRAME_grtful41 278 +#define FRAME_grtful42 279 +#define FRAME_grtful43 280 +#define FRAME_grtful44 281 +#define FRAME_grtful45 282 +#define FRAME_grtful46 283 +#define FRAME_grtful47 284 +#define FRAME_grtful48 285 +#define FRAME_grtful49 286 +#define FRAME_grtful50 287 +#define FRAME_grtful51 288 +#define FRAME_grtful52 289 +#define FRAME_grtful53 290 +#define FRAME_grtful54 291 +#define FRAME_grtful55 292 +#define FRAME_grtful56 293 +#define FRAME_grtful57 294 +#define FRAME_grtful58 295 +#define FRAME_kelmnt1 296 +#define FRAME_kelmnt2 297 +#define FRAME_kelmnt3 298 +#define FRAME_kelmnt4 299 +#define FRAME_kelmnt5 300 +#define FRAME_kelmnt6 301 +#define FRAME_kelmnt7 302 +#define FRAME_kelmnt8 303 +#define FRAME_kelmnt9 304 +#define FRAME_kelmnt10 305 +#define FRAME_kelmnt11 306 +#define FRAME_kelmnt12 307 +#define FRAME_kelmnt13 308 +#define FRAME_kelmnt14 309 +#define FRAME_kelmnt15 310 +#define FRAME_kelmnt16 311 +#define FRAME_kelmnt17 312 +#define FRAME_kelmnt18 313 +#define FRAME_kelmnt19 314 +#define FRAME_kelmnt20 315 +#define FRAME_kelmnt21 316 +#define FRAME_kelmnt22 317 +#define FRAME_kelmnt23 318 +#define FRAME_kelmnt24 319 +#define FRAME_kelmnt25 320 +#define FRAME_kelmnt26 321 +#define FRAME_kelmnt27 322 +#define FRAME_kelmnt28 323 +#define FRAME_kelmnt29 324 +#define FRAME_kelmnt30 325 +#define FRAME_kelmnt31 326 +#define FRAME_kelmnt32 327 +#define FRAME_kelmnt33 328 +#define FRAME_kelmnt34 329 +#define FRAME_kelmnt35 330 +#define FRAME_kelmnt36 331 +#define FRAME_kelmnt37 332 +#define FRAME_kelmnt38 333 +#define FRAME_kelmnt39 334 +#define FRAME_kelmnt40 335 +#define FRAME_kelmnt41 336 +#define FRAME_kelmnt42 337 +#define FRAME_kelmnt43 338 +#define FRAME_kelmnt44 339 +#define FRAME_kelmnt45 340 +#define FRAME_kelmnt46 341 +#define FRAME_kelmnt47 342 +#define FRAME_kelmnt48 343 +#define FRAME_kelmnt49 344 +#define FRAME_kelmnt50 345 +#define FRAME_kelmnt51 346 +#define FRAME_kelmnt52 347 +#define FRAME_kelmnt53 348 +#define FRAME_kelmnt54 349 +#define FRAME_kelmnt55 350 +#define FRAME_kelmnt56 351 +#define FRAME_kelmnt57 352 +#define FRAME_kelmnt58 353 +#define FRAME_kelmnt59 354 +#define FRAME_kelmnt60 355 +#define FRAME_kelmnt61 356 +#define FRAME_kelmnt62 357 +#define FRAME_kelmnt63 358 +#define FRAME_kelmnt64 359 +#define FRAME_kelmnt65 360 +#define FRAME_kelmnt66 361 +#define FRAME_kelmnt67 362 +#define FRAME_kelmnt68 363 +#define FRAME_kelmnt69 364 +#define FRAME_kelmnt70 365 +#define FRAME_kelmnt71 366 +#define FRAME_kelmnt72 367 +#define FRAME_kelmnt73 368 +#define FRAME_kelmnt74 369 +#define FRAME_kelmnt75 370 +#define FRAME_kelmnt76 371 +#define FRAME_kelmnt77 372 +#define FRAME_potion1 373 +#define FRAME_potion2 374 +#define FRAME_potion3 375 +#define FRAME_potion4 376 +#define FRAME_potion5 377 +#define FRAME_potion6 378 +#define FRAME_potion7 379 +#define FRAME_potion8 380 +#define FRAME_potion9 381 +#define FRAME_potion10 382 +#define FRAME_potion11 383 +#define FRAME_potion12 384 +#define FRAME_potion13 385 +#define FRAME_potion14 386 +#define FRAME_potion15 387 +#define FRAME_potion16 388 +#define FRAME_potion17 389 +#define FRAME_potion18 390 +#define FRAME_potion19 391 +#define FRAME_potion20 392 +#define FRAME_potion21 393 +#define FRAME_potion22 394 +#define FRAME_potion23 395 +#define FRAME_potion24 396 +#define FRAME_potion25 397 +#define FRAME_potion26 398 +#define FRAME_potion27 399 +#define FRAME_potion28 400 +#define FRAME_potion29 401 +#define FRAME_potion30 402 +#define FRAME_potion31 403 +#define FRAME_potion32 404 +#define FRAME_potion33 405 +#define FRAME_potion34 406 +#define FRAME_potion35 407 +#define FRAME_potion36 408 +#define FRAME_potion37 409 +#define FRAME_potion38 410 +#define FRAME_potion39 411 +#define FRAME_potion40 412 +#define FRAME_potion41 413 +#define FRAME_potion42 414 +#define FRAME_potion43 415 +#define FRAME_potion44 416 +#define FRAME_potion45 417 +#define FRAME_potion46 418 +#define FRAME_potion47 419 +#define FRAME_potion48 420 +#define FRAME_potion49 421 +#define FRAME_potion50 422 +#define FRAME_potion51 423 +#define FRAME_pwalk1 424 +#define FRAME_pwalk2 425 +#define FRAME_pwalk3 426 +#define FRAME_pwalk4 427 +#define FRAME_pwalk5 428 +#define FRAME_pwalk6 429 +#define FRAME_pwalk7 430 +#define FRAME_pwalk8 431 +#define FRAME_pwalk9 432 +#define FRAME_pwalk10 433 +#define FRAME_pwalk11 434 +#define FRAME_pwalk12 435 +#define FRAME_pwalk13 436 +#define FRAME_pwalk14 437 +#define FRAME_pwalk15 438 +#define FRAME_pwalk16 439 +#define FRAME_pstop1 440 +#define FRAME_pstop2 441 +#define FRAME_pstop3 442 +#define FRAME_pstop4 443 +#define FRAME_pstop5 444 +#define FRAME_drink1 445 +#define FRAME_drink2 446 +#define FRAME_drink3 447 +#define FRAME_drink4 448 +#define FRAME_drink5 449 +#define FRAME_drink6 450 +#define FRAME_drink7 451 +#define FRAME_drink8 452 +#define FRAME_drink9 453 +#define FRAME_drink10 454 +#define FRAME_drink11 455 +#define FRAME_drink12 456 +#define FRAME_drink13 457 +#define FRAME_drink14 458 +#define FRAME_drink15 459 +#define FRAME_drink16 460 +#define FRAME_drink17 461 +#define FRAME_drink18 462 +#define FRAME_drink19 463 +#define FRAME_drink20 464 +#define FRAME_drink21 465 +#define FRAME_pour1 466 +#define FRAME_pour2 467 +#define FRAME_pour3 468 +#define FRAME_pour4 469 +#define FRAME_pour5 470 +#define FRAME_pour6 471 +#define FRAME_pour7 472 +#define FRAME_pour8 473 +#define FRAME_pour9 474 +#define FRAME_pour10 475 +#define FRAME_pour11 476 +#define FRAME_pour12 477 +#define FRAME_pour13 478 +#define FRAME_pour14 479 +#define FRAME_pour15 480 +#define FRAME_pour16 481 +#define FRAME_pour17 482 +#define FRAME_pour18 483 +#define FRAME_pour19 484 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_corvus9.c b/Toolkit/Programming/GameCode/game/c_corvus9.c new file mode 100644 index 0000000..8bd5c46 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus9.c @@ -0,0 +1,180 @@ +/*------------------------------------------------------------------- +c_corvus9.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "c_corvus9.h" +#include "c_corvus9_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + // Cinematics + &corvus9_move_c_action1, + &corvus9_move_c_action2, + &corvus9_move_c_action3, + &corvus9_move_c_action4, + &corvus9_move_c_action5, + &corvus9_move_c_action6, + &corvus9_move_c_action7, + &corvus9_move_c_action8, + &corvus9_move_c_action9, + &corvus9_move_c_action10, + &corvus9_move_c_action11, + &corvus9_move_c_idle1, + &corvus9_move_c_idle2, + &corvus9_move_c_idle3, + &corvus9_move_c_walk1, + &corvus9_move_c_walk2, +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + corvus9_c_anims +-------------------------------------------------------------------------*/ +void corvus9_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_ACTION8 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + case MSG_C_ACTION9 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION9; + break; + case MSG_C_ACTION10 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION10; + break; + case MSG_C_ACTION11 : + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_ACTION11; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + StaticsInit +-------------------------------------------------------------------------*/ +void Corvus9StaticsInit() +{ + + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION1] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION2] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION3] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION4] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION5] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION6] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION7] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION8] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION9] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION10] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_ACTION11] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_IDLE1] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_IDLE2] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_IDLE3] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_WALK1] = corvus9_c_anims; + classStatics[CID_CORVUS9].msgReceivers[MSG_C_WALK2] = corvus9_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + //note that the name is different in the path + resInfo.modelIndex = gi.modelindex("models/player/t'chekrikscene/tris.fm"); + + classStatics[CID_CORVUS9].resInfo = &resInfo; + +} + +/*QUAKED character_corvus9 (1 .5 0) (-17 -25 -32) (22 12 32) INVISIBLE +The cinematic corvus for the T'chekrik scenes +*/ +void SP_character_corvus9 (edict_t *self) +{ + c_corvus_init(self,CID_CORVUS9); + self->svflags|=SVF_FLOAT; +} diff --git a/Toolkit/Programming/GameCode/game/c_corvus9.h b/Toolkit/Programming/GameCode/game/c_corvus9.h new file mode 100644 index 0000000..4598efa --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus9.h @@ -0,0 +1,40 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_ACTION9, + ANIM_C_ACTION10, + ANIM_C_ACTION11, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_WALK1, + ANIM_C_WALK2, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t corvus9_move_c_action1; +extern animmove_t corvus9_move_c_action2; +extern animmove_t corvus9_move_c_action3; +extern animmove_t corvus9_move_c_action4; +extern animmove_t corvus9_move_c_action5; +extern animmove_t corvus9_move_c_action6; +extern animmove_t corvus9_move_c_action7; +extern animmove_t corvus9_move_c_action8; +extern animmove_t corvus9_move_c_action9; +extern animmove_t corvus9_move_c_action10; +extern animmove_t corvus9_move_c_action11; +extern animmove_t corvus9_move_c_idle1; +extern animmove_t corvus9_move_c_idle2; +extern animmove_t corvus9_move_c_idle3; +extern animmove_t corvus9_move_c_walk1; +extern animmove_t corvus9_move_c_walk2; + diff --git a/Toolkit/Programming/GameCode/game/c_corvus9_anim.c b/Toolkit/Programming/GameCode/game/c_corvus9_anim.c new file mode 100644 index 0000000..8ff74e8 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus9_anim.c @@ -0,0 +1,536 @@ +//============================================================================== +// +// m_corvus_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_corvus9_anim.h" +#include "c_corvus9.h" + +#include "g_monster.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action1[] = +{ + FRAME_cstartled1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cstartled26, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action1 = {26, corvus9_frames_c_action1, ai_c_cycleend}; + + + + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action2[] = +{ + FRAME_ctranslate1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctranslate19, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action2 = {19, corvus9_frames_c_action2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action3[] = +{ + FRAME_ctell1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ctell63, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action3 = {63, corvus9_frames_c_action3, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action4[] = +{ + FRAME_cbecause1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cbecause77, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action4 = {77, corvus9_frames_c_action4, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action5[] = +{ + FRAME_cchallenge1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cchallenge13, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action5 = {13, corvus9_frames_c_action5, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action6[] = +{ + FRAME_cfall1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cfall2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cfall3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cfall4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cfall5, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action6 = {5, corvus9_frames_c_action6, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action7[] = +{ + FRAME_kodown1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_kodown12, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action7 = {12, corvus9_frames_c_action7, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action8[] = +{ + FRAME_ready1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action8 = {3, corvus9_frames_c_action8, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action9[] = +{ + FRAME_ready4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready26, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action9 = {23, corvus9_frames_c_action9, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action10[] = +{ + FRAME_ready3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ready1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action10 = {3, corvus9_frames_c_action10, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_action11[] = +{ + FRAME_rolla1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_rolla15, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_action11 = {15, corvus9_frames_c_action11, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_idle1 [] = +{ + FRAME_breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_idle1 = {23, corvus9_frames_c_idle1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_idle2 [] = +{ + FRAME_1breathing1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1breathing26, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t corvus9_move_c_idle2 = {26, corvus9_frames_c_idle2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_idle3[] = +{ + FRAME_cfinalidle, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cfinalidle, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_idle3 = {2, corvus9_frames_c_idle3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_walk1[] = +{ + FRAME_cinewalk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_walk1 = {16, corvus9_frames_c_walk1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Corvus +-----------------------------------------------------------------------*/ +animframe_t corvus9_frames_c_walk2[] = +{ + FRAME_cinewalk16, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk15, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk14, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk13, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk12, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk11, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk10, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk9, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk8, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk7, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk6, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk5, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk4, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk3, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk2, ai_c_move, -4, 0, 0, NULL, 0, NULL, + FRAME_cinewalk1, ai_c_move, -4, 0, 0, NULL, 0, NULL, +}; + +animmove_t corvus9_move_c_walk2 = {16, corvus9_frames_c_walk2, ai_c_cycleend}; + + + diff --git a/Toolkit/Programming/GameCode/game/c_corvus9_anim.h b/Toolkit/Programming/GameCode/game/c_corvus9_anim.h new file mode 100644 index 0000000..d7adbc8 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_corvus9_anim.h @@ -0,0 +1,347 @@ +// R:\Art\models/player\t'chekrikscene + +// This file generated by qdata - Do NOT Modify + +#define FRAME_1breathing1 0 +#define FRAME_1breathing2 1 +#define FRAME_1breathing3 2 +#define FRAME_1breathing4 3 +#define FRAME_1breathing5 4 +#define FRAME_1breathing6 5 +#define FRAME_1breathing7 6 +#define FRAME_1breathing8 7 +#define FRAME_1breathing9 8 +#define FRAME_1breathing10 9 +#define FRAME_1breathing11 10 +#define FRAME_1breathing12 11 +#define FRAME_1breathing13 12 +#define FRAME_1breathing14 13 +#define FRAME_1breathing15 14 +#define FRAME_1breathing16 15 +#define FRAME_1breathing17 16 +#define FRAME_1breathing18 17 +#define FRAME_1breathing19 18 +#define FRAME_1breathing20 19 +#define FRAME_1breathing21 20 +#define FRAME_1breathing22 21 +#define FRAME_1breathing23 22 +#define FRAME_1breathing24 23 +#define FRAME_1breathing25 24 +#define FRAME_1breathing26 25 +#define FRAME_cbecause1 26 +#define FRAME_cbecause2 27 +#define FRAME_cbecause3 28 +#define FRAME_cbecause4 29 +#define FRAME_cbecause5 30 +#define FRAME_cbecause6 31 +#define FRAME_cbecause7 32 +#define FRAME_cbecause8 33 +#define FRAME_cbecause9 34 +#define FRAME_cbecause10 35 +#define FRAME_cbecause11 36 +#define FRAME_cbecause12 37 +#define FRAME_cbecause13 38 +#define FRAME_cbecause14 39 +#define FRAME_cbecause15 40 +#define FRAME_cbecause16 41 +#define FRAME_cbecause17 42 +#define FRAME_cbecause18 43 +#define FRAME_cbecause19 44 +#define FRAME_cbecause20 45 +#define FRAME_cbecause21 46 +#define FRAME_cbecause22 47 +#define FRAME_cbecause23 48 +#define FRAME_cbecause24 49 +#define FRAME_cbecause25 50 +#define FRAME_cbecause26 51 +#define FRAME_cbecause27 52 +#define FRAME_cbecause28 53 +#define FRAME_cbecause29 54 +#define FRAME_cbecause30 55 +#define FRAME_cbecause31 56 +#define FRAME_cbecause32 57 +#define FRAME_cbecause33 58 +#define FRAME_cbecause34 59 +#define FRAME_cbecause35 60 +#define FRAME_cbecause36 61 +#define FRAME_cbecause37 62 +#define FRAME_cbecause38 63 +#define FRAME_cbecause39 64 +#define FRAME_cbecause40 65 +#define FRAME_cbecause41 66 +#define FRAME_cbecause42 67 +#define FRAME_cbecause43 68 +#define FRAME_cbecause44 69 +#define FRAME_cbecause45 70 +#define FRAME_cbecause46 71 +#define FRAME_cbecause47 72 +#define FRAME_cbecause48 73 +#define FRAME_cbecause49 74 +#define FRAME_cbecause50 75 +#define FRAME_cbecause51 76 +#define FRAME_cbecause52 77 +#define FRAME_cbecause53 78 +#define FRAME_cbecause54 79 +#define FRAME_cbecause55 80 +#define FRAME_cbecause56 81 +#define FRAME_cbecause57 82 +#define FRAME_cbecause58 83 +#define FRAME_cbecause59 84 +#define FRAME_cbecause60 85 +#define FRAME_cbecause61 86 +#define FRAME_cbecause62 87 +#define FRAME_cbecause63 88 +#define FRAME_cbecause64 89 +#define FRAME_cbecause65 90 +#define FRAME_cbecause66 91 +#define FRAME_cbecause67 92 +#define FRAME_cbecause68 93 +#define FRAME_cbecause69 94 +#define FRAME_cbecause70 95 +#define FRAME_cbecause71 96 +#define FRAME_cbecause72 97 +#define FRAME_cbecause73 98 +#define FRAME_cbecause74 99 +#define FRAME_cbecause75 100 +#define FRAME_cbecause76 101 +#define FRAME_cbecause77 102 +#define FRAME_cchallenge1 103 +#define FRAME_cchallenge2 104 +#define FRAME_cchallenge3 105 +#define FRAME_cchallenge4 106 +#define FRAME_cchallenge5 107 +#define FRAME_cchallenge6 108 +#define FRAME_cchallenge7 109 +#define FRAME_cchallenge8 110 +#define FRAME_cchallenge9 111 +#define FRAME_cchallenge10 112 +#define FRAME_cchallenge11 113 +#define FRAME_cchallenge12 114 +#define FRAME_cchallenge13 115 +#define FRAME_cfall1 116 +#define FRAME_cfall2 117 +#define FRAME_cfall3 118 +#define FRAME_cfall4 119 +#define FRAME_cfall5 120 +#define FRAME_cstartled1 121 +#define FRAME_cstartled2 122 +#define FRAME_cstartled3 123 +#define FRAME_cstartled4 124 +#define FRAME_cstartled5 125 +#define FRAME_cstartled6 126 +#define FRAME_cstartled7 127 +#define FRAME_cstartled8 128 +#define FRAME_cstartled9 129 +#define FRAME_cstartled10 130 +#define FRAME_cstartled11 131 +#define FRAME_cstartled12 132 +#define FRAME_cstartled13 133 +#define FRAME_cstartled14 134 +#define FRAME_cstartled15 135 +#define FRAME_cstartled16 136 +#define FRAME_cstartled17 137 +#define FRAME_cstartled18 138 +#define FRAME_cstartled19 139 +#define FRAME_cstartled20 140 +#define FRAME_cstartled21 141 +#define FRAME_cstartled22 142 +#define FRAME_cstartled23 143 +#define FRAME_cstartled24 144 +#define FRAME_cstartled25 145 +#define FRAME_cstartled26 146 +#define FRAME_ctell1 147 +#define FRAME_ctell2 148 +#define FRAME_ctell3 149 +#define FRAME_ctell4 150 +#define FRAME_ctell5 151 +#define FRAME_ctell6 152 +#define FRAME_ctell7 153 +#define FRAME_ctell8 154 +#define FRAME_ctell9 155 +#define FRAME_ctell10 156 +#define FRAME_ctell11 157 +#define FRAME_ctell12 158 +#define FRAME_ctell13 159 +#define FRAME_ctell14 160 +#define FRAME_ctell15 161 +#define FRAME_ctell16 162 +#define FRAME_ctell17 163 +#define FRAME_ctell18 164 +#define FRAME_ctell19 165 +#define FRAME_ctell20 166 +#define FRAME_ctell21 167 +#define FRAME_ctell22 168 +#define FRAME_ctell23 169 +#define FRAME_ctell24 170 +#define FRAME_ctell25 171 +#define FRAME_ctell26 172 +#define FRAME_ctell27 173 +#define FRAME_ctell28 174 +#define FRAME_ctell29 175 +#define FRAME_ctell30 176 +#define FRAME_ctell31 177 +#define FRAME_ctell32 178 +#define FRAME_ctell33 179 +#define FRAME_ctell34 180 +#define FRAME_ctell35 181 +#define FRAME_ctell36 182 +#define FRAME_ctell37 183 +#define FRAME_ctell38 184 +#define FRAME_ctell39 185 +#define FRAME_ctell40 186 +#define FRAME_ctell41 187 +#define FRAME_ctell42 188 +#define FRAME_ctell43 189 +#define FRAME_ctell44 190 +#define FRAME_ctell45 191 +#define FRAME_ctell46 192 +#define FRAME_ctell47 193 +#define FRAME_ctell48 194 +#define FRAME_ctell49 195 +#define FRAME_ctell50 196 +#define FRAME_ctell51 197 +#define FRAME_ctell52 198 +#define FRAME_ctell53 199 +#define FRAME_ctell54 200 +#define FRAME_ctell55 201 +#define FRAME_ctell56 202 +#define FRAME_ctell57 203 +#define FRAME_ctell58 204 +#define FRAME_ctell59 205 +#define FRAME_ctell60 206 +#define FRAME_ctell61 207 +#define FRAME_ctell62 208 +#define FRAME_ctell63 209 +#define FRAME_ctranslate1 210 +#define FRAME_ctranslate2 211 +#define FRAME_ctranslate3 212 +#define FRAME_ctranslate4 213 +#define FRAME_ctranslate5 214 +#define FRAME_ctranslate6 215 +#define FRAME_ctranslate7 216 +#define FRAME_ctranslate8 217 +#define FRAME_ctranslate9 218 +#define FRAME_ctranslate10 219 +#define FRAME_ctranslate11 220 +#define FRAME_ctranslate12 221 +#define FRAME_ctranslate13 222 +#define FRAME_ctranslate14 223 +#define FRAME_ctranslate15 224 +#define FRAME_ctranslate16 225 +#define FRAME_ctranslate17 226 +#define FRAME_ctranslate18 227 +#define FRAME_ctranslate19 228 +#define FRAME_kodown1 229 +#define FRAME_kodown2 230 +#define FRAME_kodown3 231 +#define FRAME_kodown4 232 +#define FRAME_kodown5 233 +#define FRAME_kodown6 234 +#define FRAME_kodown7 235 +#define FRAME_kodown8 236 +#define FRAME_kodown9 237 +#define FRAME_kodown10 238 +#define FRAME_kodown11 239 +#define FRAME_kodown12 240 +#define FRAME_ready1 241 +#define FRAME_ready2 242 +#define FRAME_ready3 243 +#define FRAME_ready4 244 +#define FRAME_ready5 245 +#define FRAME_ready6 246 +#define FRAME_ready7 247 +#define FRAME_ready8 248 +#define FRAME_ready9 249 +#define FRAME_ready10 250 +#define FRAME_ready11 251 +#define FRAME_ready12 252 +#define FRAME_ready13 253 +#define FRAME_ready14 254 +#define FRAME_ready15 255 +#define FRAME_ready16 256 +#define FRAME_ready17 257 +#define FRAME_ready18 258 +#define FRAME_ready19 259 +#define FRAME_ready20 260 +#define FRAME_ready21 261 +#define FRAME_ready22 262 +#define FRAME_ready23 263 +#define FRAME_ready24 264 +#define FRAME_ready25 265 +#define FRAME_ready26 266 +#define FRAME_cinewalk1 267 +#define FRAME_cinewalk2 268 +#define FRAME_cinewalk3 269 +#define FRAME_cinewalk4 270 +#define FRAME_cinewalk5 271 +#define FRAME_cinewalk6 272 +#define FRAME_cinewalk7 273 +#define FRAME_cinewalk8 274 +#define FRAME_cinewalk9 275 +#define FRAME_cinewalk10 276 +#define FRAME_cinewalk11 277 +#define FRAME_cinewalk12 278 +#define FRAME_cinewalk13 279 +#define FRAME_cinewalk14 280 +#define FRAME_cinewalk15 281 +#define FRAME_cinewalk16 282 +#define FRAME_cfinalidle 283 +#define FRAME_breath1 284 +#define FRAME_breath2 285 +#define FRAME_breath3 286 +#define FRAME_breath4 287 +#define FRAME_breath5 288 +#define FRAME_breath6 289 +#define FRAME_breath7 290 +#define FRAME_breath8 291 +#define FRAME_breath9 292 +#define FRAME_breath10 293 +#define FRAME_breath11 294 +#define FRAME_breath12 295 +#define FRAME_breath13 296 +#define FRAME_breath14 297 +#define FRAME_breath15 298 +#define FRAME_breath16 299 +#define FRAME_breath17 300 +#define FRAME_breath18 301 +#define FRAME_breath19 302 +#define FRAME_breath20 303 +#define FRAME_breath21 304 +#define FRAME_breath22 305 +#define FRAME_breath23 306 +#define FRAME_rolla1 307 +#define FRAME_rolla2 308 +#define FRAME_rolla3 309 +#define FRAME_rolla4 310 +#define FRAME_rolla5 311 +#define FRAME_rolla6 312 +#define FRAME_rolla7 313 +#define FRAME_rolla8 314 +#define FRAME_rolla9 315 +#define FRAME_rolla10 316 +#define FRAME_rolla11 317 +#define FRAME_rolla12 318 +#define FRAME_rolla13 319 +#define FRAME_rolla14 320 +#define FRAME_rolla15 321 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_dranor.c b/Toolkit/Programming/GameCode/game/c_dranor.c new file mode 100644 index 0000000..c3e944c --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_dranor.c @@ -0,0 +1,192 @@ +//============================================================================== +// +// m_victimSsithra.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#include "c_dranor_anim.h" +#include "c_dranor.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + victimSsithra Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + &dranor_move_c_action1, + &dranor_move_c_action2, + &dranor_move_c_action3, + &dranor_move_c_action4, + &dranor_move_c_action5, + &dranor_move_c_action6, + &dranor_move_c_action7, + &dranor_move_c_action8, + &dranor_move_c_action9, + &dranor_move_c_action10, + &dranor_move_c_action11, + &dranor_move_c_action12, + &dranor_move_c_death1, + &dranor_move_c_idle1, + &dranor_move_c_idle2, + &dranor_move_c_idle3, +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + victimSsithra_c_anims +-------------------------------------------------------------------------*/ +void Dranor_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_ACTION8: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + case MSG_C_ACTION9: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION9; + break; + case MSG_C_ACTION10: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION10; + break; + case MSG_C_ACTION11: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION11; + break; + case MSG_C_ACTION12: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION12; + break; + case MSG_C_DEATH1: + self->monsterinfo.c_anim_flag |= C_ANIM_DONE; + self->health = 5; + curr_anim = ANIM_C_DEATH1; + self->svflags |= SVF_DEADMONSTER;//doesn't block walking + self->takedamage = DAMAGE_YES; + self->movetype = PHYSICSTYPE_STOP; + self->solid = SOLID_BBOX; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE3; + break; + default: + break; + } + + SetAnim(self, curr_anim); +} + +/*------------------------------------------------------------------------- + DranorStaticsInit +-------------------------------------------------------------------------*/ +void DranorStaticsInit() +{ + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION1] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION2] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION3] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION4] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION5] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION6] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION7] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION8] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION9] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION10] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION11] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_ACTION12] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_DEATH1] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_IDLE1] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_IDLE2] = Dranor_c_anims; + classStatics[CID_DRANOR].msgReceivers[MSG_C_IDLE3] = Dranor_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/monsters/plaguelf/dranor/tris.fm"); + + classStatics[CID_SSITHRA_VICTIM].resInfo = &resInfo; + + sounds[SND_PAIN1] = gi.soundindex("monsters/plagueElf/pain1.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_DRANOR].resInfo = &resInfo; + +} + +/*QUAKED character_dranor (1 .5 0) (-17 -25 -32) (22 12 32) INVISIBLE +The elf who talks like Sean Connery +*/ +void SP_character_dranor (edict_t *self) +{ + VectorSet (self->mins, -16, -16, -32); + VectorSet (self->maxs, 16, 16, 32); + + c_character_init(self,CID_DRANOR); + + self->s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + self->health = 30; + +} + diff --git a/Toolkit/Programming/GameCode/game/c_dranor.h b/Toolkit/Programming/GameCode/game/c_dranor.h new file mode 100644 index 0000000..29e5e0c --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_dranor.h @@ -0,0 +1,48 @@ +//c_Dranor.h + + +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_ACTION9, + ANIM_C_ACTION10, + ANIM_C_ACTION11, + ANIM_C_ACTION12, + ANIM_C_DEATH1, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PAIN1, + NUM_SOUNDS +} SoundID_t; + +#define MODEL_SCALE 1.000000 + +extern animmove_t dranor_move_c_action1; +extern animmove_t dranor_move_c_action2; +extern animmove_t dranor_move_c_action3; +extern animmove_t dranor_move_c_action4; +extern animmove_t dranor_move_c_action5; +extern animmove_t dranor_move_c_action6; +extern animmove_t dranor_move_c_action7; +extern animmove_t dranor_move_c_action8; +extern animmove_t dranor_move_c_action9; +extern animmove_t dranor_move_c_action10; +extern animmove_t dranor_move_c_action11; +extern animmove_t dranor_move_c_action12; +extern animmove_t dranor_move_c_death1; +extern animmove_t dranor_move_c_idle1; +extern animmove_t dranor_move_c_idle2; +extern animmove_t dranor_move_c_idle3; diff --git a/Toolkit/Programming/GameCode/game/c_dranor_anim.c b/Toolkit/Programming/GameCode/game/c_dranor_anim.c new file mode 100644 index 0000000..faa6eef --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_dranor_anim.c @@ -0,0 +1,769 @@ + +//============================================================================== +// +// m_victimSsitra_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_dranor_anim.h" +#include "c_dranor.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_idle1 [] = +{ + FRAME_1idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1idle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1idle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1idle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1idle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1idle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_idle1 = { 10, dranor_frames_c_idle1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_idle2 [] = +{ + FRAME_relax1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_relax11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_idle2 = { 11, dranor_frames_c_idle2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_idle3 [] = +{ + FRAME_2idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2idle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_idle3 = { 20, dranor_frames_c_idle3, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action1 [] = +{ + FRAME_go1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_action1 = { 4, dranor_frames_c_action1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action2 [] = +{ + FRAME_go5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_go111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_go114, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t dranor_move_c_action2 = { 110, dranor_frames_c_action2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action3 [] = +{ + FRAME_slayer1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_slayer11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_slayer21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_slayer31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_slayer41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_slayer51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_slayer52, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_action3 = { 52, dranor_frames_c_action3, ai_c_cycleend}; + + + +animframe_t dranor_frames_c_action4 [] = +{ + FRAME_1iwas1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_action4 = { 8, dranor_frames_c_action4, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action5 [] = +{ + FRAME_2iwas1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t dranor_move_c_action5 = { 74, dranor_frames_c_action5, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action6 [] = +{ + FRAME_1iwas8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_action6 = { 8, dranor_frames_c_action6, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action7 [] = +{ + FRAME_2iwas74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2iwas9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2iwas1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_1iwas8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1iwas1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_action7 = { 74, dranor_frames_c_action7, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action8 [] = +{ + FRAME_1butyou1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_1butyou11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_1butyou21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_1butyou31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_1butyou41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_1butyou51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_1butyou61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1butyou70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_1butyou71, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_action8 = { 71, dranor_frames_c_action8, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action9 [] = +{ + FRAME_2butyou1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2butyou11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2butyou21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2butyou31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2butyou33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t dranor_move_c_action9 = { 33, dranor_frames_c_action9, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action10 [] = +{ + FRAME_2insert1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2insert11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2insert21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_2insert31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_2insert33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t dranor_move_c_action10 = { 33, dranor_frames_c_action10, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action11 [] = +{ + FRAME_1insert1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1insert2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1insert3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1insert4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1insert5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1insert6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1insert7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_1insert8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_action11 = { 8, dranor_frames_c_action11, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_action12 [] = +{ + FRAME_2insert33, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_action12 = { 1, dranor_frames_c_action12, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Dranor - +-----------------------------------------------------------------------*/ +animframe_t dranor_frames_c_death1 [] = +{ + FRAME_death1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death20, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t dranor_move_c_death1 = { 20, dranor_frames_c_death1, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/c_dranor_anim.h b/Toolkit/Programming/GameCode/game/c_dranor_anim.h new file mode 100644 index 0000000..4f3b1e7 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_dranor_anim.h @@ -0,0 +1,474 @@ +// R:\Art\models/monsters\plaguelf\dranor + +// This file generated by qdata - Do NOT Modify + +#define FRAME_1butyou1 0 +#define FRAME_1butyou2 1 +#define FRAME_1butyou3 2 +#define FRAME_1butyou4 3 +#define FRAME_1butyou5 4 +#define FRAME_1butyou6 5 +#define FRAME_1butyou7 6 +#define FRAME_1butyou8 7 +#define FRAME_1butyou9 8 +#define FRAME_1butyou10 9 +#define FRAME_1butyou11 10 +#define FRAME_1butyou12 11 +#define FRAME_1butyou13 12 +#define FRAME_1butyou14 13 +#define FRAME_1butyou15 14 +#define FRAME_1butyou16 15 +#define FRAME_1butyou17 16 +#define FRAME_1butyou18 17 +#define FRAME_1butyou19 18 +#define FRAME_1butyou20 19 +#define FRAME_1butyou21 20 +#define FRAME_1butyou22 21 +#define FRAME_1butyou23 22 +#define FRAME_1butyou24 23 +#define FRAME_1butyou25 24 +#define FRAME_1butyou26 25 +#define FRAME_1butyou27 26 +#define FRAME_1butyou28 27 +#define FRAME_1butyou29 28 +#define FRAME_1butyou30 29 +#define FRAME_1butyou31 30 +#define FRAME_1butyou32 31 +#define FRAME_1butyou33 32 +#define FRAME_1butyou34 33 +#define FRAME_1butyou35 34 +#define FRAME_1butyou36 35 +#define FRAME_1butyou37 36 +#define FRAME_1butyou38 37 +#define FRAME_1butyou39 38 +#define FRAME_1butyou40 39 +#define FRAME_1butyou41 40 +#define FRAME_1butyou42 41 +#define FRAME_1butyou43 42 +#define FRAME_1butyou44 43 +#define FRAME_1butyou45 44 +#define FRAME_1butyou46 45 +#define FRAME_1butyou47 46 +#define FRAME_1butyou48 47 +#define FRAME_1butyou49 48 +#define FRAME_1butyou50 49 +#define FRAME_1butyou51 50 +#define FRAME_1butyou52 51 +#define FRAME_1butyou53 52 +#define FRAME_1butyou54 53 +#define FRAME_1butyou55 54 +#define FRAME_1butyou56 55 +#define FRAME_1butyou57 56 +#define FRAME_1butyou58 57 +#define FRAME_1butyou59 58 +#define FRAME_1butyou60 59 +#define FRAME_1butyou61 60 +#define FRAME_1butyou62 61 +#define FRAME_1butyou63 62 +#define FRAME_1butyou64 63 +#define FRAME_1butyou65 64 +#define FRAME_1butyou66 65 +#define FRAME_1butyou67 66 +#define FRAME_1butyou68 67 +#define FRAME_1butyou69 68 +#define FRAME_1butyou70 69 +#define FRAME_1butyou71 70 +#define FRAME_1idle1 71 +#define FRAME_1idle2 72 +#define FRAME_1idle3 73 +#define FRAME_1idle4 74 +#define FRAME_1idle5 75 +#define FRAME_1idle6 76 +#define FRAME_1idle7 77 +#define FRAME_1idle8 78 +#define FRAME_1idle9 79 +#define FRAME_1idle10 80 +#define FRAME_1insert1 81 +#define FRAME_1insert2 82 +#define FRAME_1insert3 83 +#define FRAME_1insert4 84 +#define FRAME_1insert5 85 +#define FRAME_1insert6 86 +#define FRAME_1insert7 87 +#define FRAME_1insert8 88 +#define FRAME_1iwas1 89 +#define FRAME_1iwas2 90 +#define FRAME_1iwas3 91 +#define FRAME_1iwas4 92 +#define FRAME_1iwas5 93 +#define FRAME_1iwas6 94 +#define FRAME_1iwas7 95 +#define FRAME_1iwas8 96 +#define FRAME_2butyou1 97 +#define FRAME_2butyou2 98 +#define FRAME_2butyou3 99 +#define FRAME_2butyou4 100 +#define FRAME_2butyou5 101 +#define FRAME_2butyou6 102 +#define FRAME_2butyou7 103 +#define FRAME_2butyou8 104 +#define FRAME_2butyou9 105 +#define FRAME_2butyou10 106 +#define FRAME_2butyou11 107 +#define FRAME_2butyou12 108 +#define FRAME_2butyou13 109 +#define FRAME_2butyou14 110 +#define FRAME_2butyou15 111 +#define FRAME_2butyou16 112 +#define FRAME_2butyou17 113 +#define FRAME_2butyou18 114 +#define FRAME_2butyou19 115 +#define FRAME_2butyou20 116 +#define FRAME_2butyou21 117 +#define FRAME_2butyou22 118 +#define FRAME_2butyou23 119 +#define FRAME_2butyou24 120 +#define FRAME_2butyou25 121 +#define FRAME_2butyou26 122 +#define FRAME_2butyou27 123 +#define FRAME_2butyou28 124 +#define FRAME_2butyou29 125 +#define FRAME_2butyou30 126 +#define FRAME_2butyou31 127 +#define FRAME_2butyou32 128 +#define FRAME_2butyou33 129 +#define FRAME_2idle1 130 +#define FRAME_2idle2 131 +#define FRAME_2idle3 132 +#define FRAME_2idle4 133 +#define FRAME_2idle5 134 +#define FRAME_2idle6 135 +#define FRAME_2idle7 136 +#define FRAME_2idle8 137 +#define FRAME_2idle9 138 +#define FRAME_2idle10 139 +#define FRAME_2idle11 140 +#define FRAME_2idle12 141 +#define FRAME_2idle13 142 +#define FRAME_2idle14 143 +#define FRAME_2idle15 144 +#define FRAME_2idle16 145 +#define FRAME_2idle17 146 +#define FRAME_2idle18 147 +#define FRAME_2idle19 148 +#define FRAME_2idle20 149 +#define FRAME_2insert1 150 +#define FRAME_2insert2 151 +#define FRAME_2insert3 152 +#define FRAME_2insert4 153 +#define FRAME_2insert5 154 +#define FRAME_2insert6 155 +#define FRAME_2insert7 156 +#define FRAME_2insert8 157 +#define FRAME_2insert9 158 +#define FRAME_2insert10 159 +#define FRAME_2insert11 160 +#define FRAME_2insert12 161 +#define FRAME_2insert13 162 +#define FRAME_2insert14 163 +#define FRAME_2insert15 164 +#define FRAME_2insert16 165 +#define FRAME_2insert17 166 +#define FRAME_2insert18 167 +#define FRAME_2insert19 168 +#define FRAME_2insert20 169 +#define FRAME_2insert21 170 +#define FRAME_2insert22 171 +#define FRAME_2insert23 172 +#define FRAME_2insert24 173 +#define FRAME_2insert25 174 +#define FRAME_2insert26 175 +#define FRAME_2insert27 176 +#define FRAME_2insert28 177 +#define FRAME_2insert29 178 +#define FRAME_2insert30 179 +#define FRAME_2insert31 180 +#define FRAME_2insert32 181 +#define FRAME_2insert33 182 +#define FRAME_2iwas1 183 +#define FRAME_2iwas2 184 +#define FRAME_2iwas3 185 +#define FRAME_2iwas4 186 +#define FRAME_2iwas5 187 +#define FRAME_2iwas6 188 +#define FRAME_2iwas7 189 +#define FRAME_2iwas8 190 +#define FRAME_2iwas9 191 +#define FRAME_2iwas10 192 +#define FRAME_2iwas11 193 +#define FRAME_2iwas12 194 +#define FRAME_2iwas13 195 +#define FRAME_2iwas14 196 +#define FRAME_2iwas15 197 +#define FRAME_2iwas16 198 +#define FRAME_2iwas17 199 +#define FRAME_2iwas18 200 +#define FRAME_2iwas19 201 +#define FRAME_2iwas20 202 +#define FRAME_2iwas21 203 +#define FRAME_2iwas22 204 +#define FRAME_2iwas23 205 +#define FRAME_2iwas24 206 +#define FRAME_2iwas25 207 +#define FRAME_2iwas26 208 +#define FRAME_2iwas27 209 +#define FRAME_2iwas28 210 +#define FRAME_2iwas29 211 +#define FRAME_2iwas30 212 +#define FRAME_2iwas31 213 +#define FRAME_2iwas32 214 +#define FRAME_2iwas33 215 +#define FRAME_2iwas34 216 +#define FRAME_2iwas35 217 +#define FRAME_2iwas36 218 +#define FRAME_2iwas37 219 +#define FRAME_2iwas38 220 +#define FRAME_2iwas39 221 +#define FRAME_2iwas40 222 +#define FRAME_2iwas41 223 +#define FRAME_2iwas42 224 +#define FRAME_2iwas43 225 +#define FRAME_2iwas44 226 +#define FRAME_2iwas45 227 +#define FRAME_2iwas46 228 +#define FRAME_2iwas47 229 +#define FRAME_2iwas48 230 +#define FRAME_2iwas49 231 +#define FRAME_2iwas50 232 +#define FRAME_2iwas51 233 +#define FRAME_2iwas52 234 +#define FRAME_2iwas53 235 +#define FRAME_2iwas54 236 +#define FRAME_2iwas55 237 +#define FRAME_2iwas56 238 +#define FRAME_2iwas57 239 +#define FRAME_2iwas58 240 +#define FRAME_2iwas59 241 +#define FRAME_2iwas60 242 +#define FRAME_2iwas61 243 +#define FRAME_2iwas62 244 +#define FRAME_2iwas63 245 +#define FRAME_2iwas64 246 +#define FRAME_2iwas65 247 +#define FRAME_2iwas66 248 +#define FRAME_2iwas67 249 +#define FRAME_2iwas68 250 +#define FRAME_2iwas69 251 +#define FRAME_2iwas70 252 +#define FRAME_2iwas71 253 +#define FRAME_2iwas72 254 +#define FRAME_2iwas73 255 +#define FRAME_2iwas74 256 +#define FRAME_death1 257 +#define FRAME_death2 258 +#define FRAME_death3 259 +#define FRAME_death4 260 +#define FRAME_death5 261 +#define FRAME_death6 262 +#define FRAME_death7 263 +#define FRAME_death8 264 +#define FRAME_death9 265 +#define FRAME_death10 266 +#define FRAME_death11 267 +#define FRAME_death12 268 +#define FRAME_death13 269 +#define FRAME_death14 270 +#define FRAME_death15 271 +#define FRAME_death16 272 +#define FRAME_death17 273 +#define FRAME_death18 274 +#define FRAME_death19 275 +#define FRAME_death20 276 +#define FRAME_go1 277 +#define FRAME_go2 278 +#define FRAME_go3 279 +#define FRAME_go4 280 +#define FRAME_go5 281 +#define FRAME_go6 282 +#define FRAME_go7 283 +#define FRAME_go8 284 +#define FRAME_go9 285 +#define FRAME_go10 286 +#define FRAME_go11 287 +#define FRAME_go12 288 +#define FRAME_go13 289 +#define FRAME_go14 290 +#define FRAME_go15 291 +#define FRAME_go16 292 +#define FRAME_go17 293 +#define FRAME_go18 294 +#define FRAME_go19 295 +#define FRAME_go20 296 +#define FRAME_go21 297 +#define FRAME_go22 298 +#define FRAME_go23 299 +#define FRAME_go24 300 +#define FRAME_go25 301 +#define FRAME_go26 302 +#define FRAME_go27 303 +#define FRAME_go28 304 +#define FRAME_go29 305 +#define FRAME_go30 306 +#define FRAME_go31 307 +#define FRAME_go32 308 +#define FRAME_go33 309 +#define FRAME_go34 310 +#define FRAME_go35 311 +#define FRAME_go36 312 +#define FRAME_go37 313 +#define FRAME_go38 314 +#define FRAME_go39 315 +#define FRAME_go40 316 +#define FRAME_go41 317 +#define FRAME_go42 318 +#define FRAME_go43 319 +#define FRAME_go44 320 +#define FRAME_go45 321 +#define FRAME_go46 322 +#define FRAME_go47 323 +#define FRAME_go48 324 +#define FRAME_go49 325 +#define FRAME_go50 326 +#define FRAME_go51 327 +#define FRAME_go52 328 +#define FRAME_go53 329 +#define FRAME_go54 330 +#define FRAME_go55 331 +#define FRAME_go56 332 +#define FRAME_go57 333 +#define FRAME_go58 334 +#define FRAME_go59 335 +#define FRAME_go60 336 +#define FRAME_go61 337 +#define FRAME_go62 338 +#define FRAME_go63 339 +#define FRAME_go64 340 +#define FRAME_go65 341 +#define FRAME_go66 342 +#define FRAME_go67 343 +#define FRAME_go68 344 +#define FRAME_go69 345 +#define FRAME_go70 346 +#define FRAME_go71 347 +#define FRAME_go72 348 +#define FRAME_go73 349 +#define FRAME_go74 350 +#define FRAME_go75 351 +#define FRAME_go76 352 +#define FRAME_go77 353 +#define FRAME_go78 354 +#define FRAME_go79 355 +#define FRAME_go80 356 +#define FRAME_go81 357 +#define FRAME_go82 358 +#define FRAME_go83 359 +#define FRAME_go84 360 +#define FRAME_go85 361 +#define FRAME_go86 362 +#define FRAME_go87 363 +#define FRAME_go88 364 +#define FRAME_go89 365 +#define FRAME_go90 366 +#define FRAME_go91 367 +#define FRAME_go92 368 +#define FRAME_go93 369 +#define FRAME_go94 370 +#define FRAME_go95 371 +#define FRAME_go96 372 +#define FRAME_go97 373 +#define FRAME_go98 374 +#define FRAME_go99 375 +#define FRAME_go100 376 +#define FRAME_go101 377 +#define FRAME_go102 378 +#define FRAME_go103 379 +#define FRAME_go104 380 +#define FRAME_go105 381 +#define FRAME_go106 382 +#define FRAME_go107 383 +#define FRAME_go108 384 +#define FRAME_go109 385 +#define FRAME_go110 386 +#define FRAME_go111 387 +#define FRAME_go112 388 +#define FRAME_go113 389 +#define FRAME_go114 390 +#define FRAME_relax1 391 +#define FRAME_relax2 392 +#define FRAME_relax3 393 +#define FRAME_relax4 394 +#define FRAME_relax5 395 +#define FRAME_relax6 396 +#define FRAME_relax7 397 +#define FRAME_relax8 398 +#define FRAME_relax9 399 +#define FRAME_relax10 400 +#define FRAME_relax11 401 +#define FRAME_slayer1 402 +#define FRAME_slayer2 403 +#define FRAME_slayer3 404 +#define FRAME_slayer4 405 +#define FRAME_slayer5 406 +#define FRAME_slayer6 407 +#define FRAME_slayer7 408 +#define FRAME_slayer8 409 +#define FRAME_slayer9 410 +#define FRAME_slayer10 411 +#define FRAME_slayer11 412 +#define FRAME_slayer12 413 +#define FRAME_slayer13 414 +#define FRAME_slayer14 415 +#define FRAME_slayer15 416 +#define FRAME_slayer16 417 +#define FRAME_slayer17 418 +#define FRAME_slayer18 419 +#define FRAME_slayer19 420 +#define FRAME_slayer20 421 +#define FRAME_slayer21 422 +#define FRAME_slayer22 423 +#define FRAME_slayer23 424 +#define FRAME_slayer24 425 +#define FRAME_slayer25 426 +#define FRAME_slayer26 427 +#define FRAME_slayer27 428 +#define FRAME_slayer28 429 +#define FRAME_slayer29 430 +#define FRAME_slayer30 431 +#define FRAME_slayer31 432 +#define FRAME_slayer32 433 +#define FRAME_slayer33 434 +#define FRAME_slayer34 435 +#define FRAME_slayer35 436 +#define FRAME_slayer36 437 +#define FRAME_slayer37 438 +#define FRAME_slayer38 439 +#define FRAME_slayer39 440 +#define FRAME_slayer40 441 +#define FRAME_slayer41 442 +#define FRAME_slayer42 443 +#define FRAME_slayer43 444 +#define FRAME_slayer44 445 +#define FRAME_slayer45 446 +#define FRAME_slayer46 447 +#define FRAME_slayer47 448 +#define FRAME_slayer48 449 +#define FRAME_slayer49 450 +#define FRAME_slayer50 451 +#define FRAME_slayer51 452 +#define FRAME_slayer52 453 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 11 + +#define MESH_BASE 0 +#define MESH__HANDLE 1 +#define MESH__HOE 2 +#define MESH__GAFF 3 +#define MESH__HAMMER 4 +#define MESH__BODY 5 +#define MESH__L_LEG 6 +#define MESH__R_LEG 7 +#define MESH__R_ARM 8 +#define MESH__L_ARM 9 +#define MESH__HEAD 10 diff --git a/Toolkit/Programming/GameCode/game/c_elflord.c b/Toolkit/Programming/GameCode/game/c_elflord.c new file mode 100644 index 0000000..73c30ce --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_elflord.c @@ -0,0 +1,201 @@ +//============================================================================== +// +// m_elflord.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" +#include "g_misc.h" +#include "matrix.h" + +#include "c_elflord_anim.h" +#include "c_elflord.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + Elf Lord Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + &Elflord_move_c_action1, + &Elflord_move_c_action2, + &Elflord_move_c_death1, + &Elflord_move_c_death2, + &Elflord_move_c_idle1, + &Elflord_move_c_idle2, + NULL +}; + +static ClassResourceInfo_t resInfo; + +float mist_yaw; +#define MIST_ADD 35 + +void Elflord_c_gib(edict_t *self, G_Message_t *msg) +{ + gi.CreateEffect(&self->s, FX_WEAPON_SPHEREEXPLODE, CEF_OWNERS_ORIGIN , NULL, + "db", self->movedir, (byte)(self->s.scale * 7.5)); + + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/SphereImpact.wav"),2,ATTN_NORM,0); + + self->think = BecomeDebris; + self->nextthink = level.time + 0.1; +} + +void Elflord_c_boom(edict_t *self) +{ + gi.CreateEffect(NULL, FX_WEAPON_FLYINGFISTEXPLODE, 0, self->s.origin, "d", self->movedir); +} + +void Elflord_c_throwhead(edict_t *self) +{ + vec3_t gore_spot; + int throw_nodes = 0; + + mist_yaw = 0; + + VectorClear(gore_spot); + ThrowBodyPart(self, &gore_spot, 8, 15, FRAME_idle1); + gi.sound(self,CHAN_BODY,gi.soundindex("monsters/elflord/death1.wav"),2,ATTN_NORM,0); +} + +/*------------------------------------------------------------------------- + elflord_mist +-------------------------------------------------------------------------*/ +void elflord_mist(edict_t *self, float x, float y, float z) +{ + vec3_t offset; + vec3_t rotoffset; + vec3_t normalized; + vec3_t velocity; + float yaw; + matrix3_t mat; + + if(self->monsterinfo.aiflags & AI_NO_MELEE) + return;//fixme: actually prevent these anims + + mist_yaw = mist_yaw + MIST_ADD; + yaw = anglemod(mist_yaw); + + // Converts degrees to radians for use with trig and matrix functions + yaw = yaw * ANGLE_TO_RAD; + + // Sets offset presuming yaw of zero + VectorSet(offset, 0, 0, 0); + + // Creates a rotation matrix to rotate the point about the z axis + CreateYawMatrix(mat, yaw); + + // Rotates point about local z axis + Matrix3MultByVec3(mat, offset, rotoffset); + + // Get normalized offset + VectorCopy(rotoffset, normalized); + normalized[2] = 0.0F; + VectorNormalize(normalized); + + // Add offset to owners origin + Vec3AddAssign(self->s.origin, rotoffset); + + // Get direction vector scaled by speed + VectorSet(velocity, cos(yaw) * 200.0F, sin(yaw) * 200.0F, -100); + + gi.CreateEffect(NULL, FX_PLAGUEMIST, 0, rotoffset, "vb", velocity, 2050 / 35); + +} + + + +/*------------------------------------------------------------------------- + Elflord_c_anims +-------------------------------------------------------------------------*/ +void Elflord_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_DEATH1: + self->s.fmnodeinfo[MESH__LIGHT25].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HEAD25].flags |= FMNI_NO_DRAW; + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_DEATH1; + break; + case MSG_C_DEATH2: + self->s.fmnodeinfo[MESH__LIGHT25].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HEAD25].flags |= FMNI_NO_DRAW; + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_DEATH2; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE2; + break; + default: + break; + } + + SetAnim(self, curr_anim); +} + +/*------------------------------------------------------------------------- + ElfLordStaticsCinInit +-------------------------------------------------------------------------*/ +void ElflordCinStaticsInit() +{ + classStatics[CID_C_ELFLORD].msgReceivers[MSG_C_ACTION1] = Elflord_c_anims; + classStatics[CID_C_ELFLORD].msgReceivers[MSG_C_ACTION2] = Elflord_c_anims; + classStatics[CID_C_ELFLORD].msgReceivers[MSG_C_DEATH1] = Elflord_c_anims; + classStatics[CID_C_ELFLORD].msgReceivers[MSG_C_DEATH2] = Elflord_c_anims; + classStatics[CID_C_ELFLORD].msgReceivers[MSG_C_IDLE1] = Elflord_c_anims; + classStatics[CID_C_ELFLORD].msgReceivers[MSG_C_IDLE2] = Elflord_c_anims; + classStatics[CID_C_ELFLORD].msgReceivers[MSG_C_GIB1] = Elflord_c_gib; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/elflord/cinematic/tris.fm"); + + classStatics[CID_C_ELFLORD].resInfo = &resInfo; + +} + +/*QUAKED character_elflord (1 .5 0) (-24 -24 -78) (24 24 16) INVISIBLE +The Celestial Watcher who whispers when he talks +*/ +void SP_character_elflord (edict_t *self) +{ + VectorSet (self->mins, -24, -24, -78); + VectorSet (self->maxs, 24, 24, 16); + + c_character_init(self,CID_C_ELFLORD); + + self->s.scale = self->monsterinfo.scale = 2.0; + +} + diff --git a/Toolkit/Programming/GameCode/game/c_elflord.h b/Toolkit/Programming/GameCode/game/c_elflord.h new file mode 100644 index 0000000..c915361 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_elflord.h @@ -0,0 +1,24 @@ +//c_elflord.h + + +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_DEATH1, + ANIM_C_DEATH2, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_GIB1, + NUM_ANIMS +} AnimID_t; + +#define MODEL_SCALE 1.000000 + +extern animmove_t Elflord_move_c_action1; +extern animmove_t Elflord_move_c_action2; +extern animmove_t Elflord_move_c_death1; +extern animmove_t Elflord_move_c_death2; +extern animmove_t Elflord_move_c_idle1; +extern animmove_t Elflord_move_c_idle2; +extern void Elflord_c_boom(edict_t *self); diff --git a/Toolkit/Programming/GameCode/game/c_elflord_anim.c b/Toolkit/Programming/GameCode/game/c_elflord_anim.c new file mode 100644 index 0000000..16d8129 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_elflord_anim.c @@ -0,0 +1,604 @@ +//============================================================================== +// +// c_elflord_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_elflord_anim.h" +#include "c_elflord.h" +#include "c_ai.h" + +void Elflord_c_throwhead(edict_t *self); +void elflord_mist(edict_t *self, float x, float y, float z); + +animframe_t Elflord_frames_c_death1 [] = +{ + FRAME_death1, ai_c_move, 0, 0, 0, NULL, 0, Elflord_c_throwhead, + FRAME_death2, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death8, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death14, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death15, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t Elflord_move_c_death1 = { 15, Elflord_frames_c_death1, ai_c_cycleend}; + + +animframe_t Elflord_frames_c_death2 [] = +{ + FRAME_death1, elflord_mist, 0, 0, 0, NULL, 0, Elflord_c_boom, + FRAME_death2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death7, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death8, ai_c_move, 0, 0, 0, NULL, 0, Elflord_c_boom, + FRAME_death9, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, elflord_mist, 0, 0, 0, NULL, 0, NULL, + FRAME_death14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death15, elflord_mist, 0, 0, 0, NULL, 0, NULL +}; +animmove_t Elflord_move_c_death2 = { 15, Elflord_frames_c_death2, ai_c_cycleend}; + +animframe_t Elflord_frames_c_idle1 [] = +{ + FRAME_idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t Elflord_move_c_idle1 = { 24, Elflord_frames_c_idle1, ai_c_cycleend}; + +animframe_t Elflord_frames_c_idle2 [] = +{ + FRAME_cidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t Elflord_move_c_idle2 = { 20, Elflord_frames_c_idle2, ai_c_cycleend}; + + +animframe_t Elflord_frames_c_action1 [] = +{ + FRAME_Dialoguea1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea129, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea130, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea131, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea132, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea133, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea134, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea135, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea136, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea137, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea138, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea139, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea140, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea141, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea142, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea143, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea144, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea145, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea146, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea147, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea148, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea149, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea150, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea151, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea152, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea153, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea154, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea155, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea156, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea157, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea158, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea159, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea160, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea161, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea162, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea163, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea164, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea165, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea166, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea167, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea168, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea169, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea170, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea171, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea172, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea173, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea174, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea175, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea176, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea177, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea178, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea179, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea180, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea181, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea182, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea183, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea184, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea185, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea186, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea187, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea188, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea189, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea190, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea191, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea192, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea193, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea194, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea195, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea196, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea197, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea198, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea199, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea200, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea201, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea202, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea203, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea204, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea205, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea206, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea207, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea208, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea209, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea210, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialoguea211, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea212, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea213, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea214, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea215, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea216, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea217, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea218, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea219, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialoguea220, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t Elflord_move_c_action1 = { 220, Elflord_frames_c_action1, ai_c_cycleend}; + + +animframe_t Elflord_frames_c_action2 [] = +{ + FRAME_Dialogueb1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb129, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb130, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb131, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb132, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb133, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb134, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb135, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb136, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb137, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb138, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb139, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb140, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb141, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb142, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb143, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb144, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb145, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb146, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb147, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb148, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb149, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb150, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb151, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb152, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb153, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb154, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb155, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb156, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb157, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb158, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb159, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb160, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb161, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb162, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb163, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb164, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb165, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb166, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb167, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb168, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb169, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb170, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb171, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb172, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb173, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb174, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb175, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb176, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb177, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb178, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb179, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb180, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb181, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb182, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb183, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb184, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb185, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb186, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb187, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb188, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb189, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb190, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb191, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb192, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb193, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb194, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb195, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb196, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb197, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb198, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb199, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb200, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Dialogueb201, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb202, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb203, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb204, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb205, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Dialogueb206, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t Elflord_move_c_action2 = { 206, Elflord_frames_c_action2, ai_c_cycleend}; + + + + + + + + diff --git a/Toolkit/Programming/GameCode/game/c_elflord_anim.h b/Toolkit/Programming/GameCode/game/c_elflord_anim.h new file mode 100644 index 0000000..04637b8 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_elflord_anim.h @@ -0,0 +1,501 @@ +// R:\Art\models/monsters\elflord\cinematic + +// This file generated by qdata - Do NOT Modify + +#define FRAME_death1 0 +#define FRAME_death2 1 +#define FRAME_death3 2 +#define FRAME_death4 3 +#define FRAME_death5 4 +#define FRAME_death6 5 +#define FRAME_death7 6 +#define FRAME_death8 7 +#define FRAME_death9 8 +#define FRAME_death10 9 +#define FRAME_death11 10 +#define FRAME_death12 11 +#define FRAME_death13 12 +#define FRAME_death14 13 +#define FRAME_death15 14 +#define FRAME_Dialoguea1 15 +#define FRAME_Dialoguea2 16 +#define FRAME_Dialoguea3 17 +#define FRAME_Dialoguea4 18 +#define FRAME_Dialoguea5 19 +#define FRAME_Dialoguea6 20 +#define FRAME_Dialoguea7 21 +#define FRAME_Dialoguea8 22 +#define FRAME_Dialoguea9 23 +#define FRAME_Dialoguea10 24 +#define FRAME_Dialoguea11 25 +#define FRAME_Dialoguea12 26 +#define FRAME_Dialoguea13 27 +#define FRAME_Dialoguea14 28 +#define FRAME_Dialoguea15 29 +#define FRAME_Dialoguea16 30 +#define FRAME_Dialoguea17 31 +#define FRAME_Dialoguea18 32 +#define FRAME_Dialoguea19 33 +#define FRAME_Dialoguea20 34 +#define FRAME_Dialoguea21 35 +#define FRAME_Dialoguea22 36 +#define FRAME_Dialoguea23 37 +#define FRAME_Dialoguea24 38 +#define FRAME_Dialoguea25 39 +#define FRAME_Dialoguea26 40 +#define FRAME_Dialoguea27 41 +#define FRAME_Dialoguea28 42 +#define FRAME_Dialoguea29 43 +#define FRAME_Dialoguea30 44 +#define FRAME_Dialoguea31 45 +#define FRAME_Dialoguea32 46 +#define FRAME_Dialoguea33 47 +#define FRAME_Dialoguea34 48 +#define FRAME_Dialoguea35 49 +#define FRAME_Dialoguea36 50 +#define FRAME_Dialoguea37 51 +#define FRAME_Dialoguea38 52 +#define FRAME_Dialoguea39 53 +#define FRAME_Dialoguea40 54 +#define FRAME_Dialoguea41 55 +#define FRAME_Dialoguea42 56 +#define FRAME_Dialoguea43 57 +#define FRAME_Dialoguea44 58 +#define FRAME_Dialoguea45 59 +#define FRAME_Dialoguea46 60 +#define FRAME_Dialoguea47 61 +#define FRAME_Dialoguea48 62 +#define FRAME_Dialoguea49 63 +#define FRAME_Dialoguea50 64 +#define FRAME_Dialoguea51 65 +#define FRAME_Dialoguea52 66 +#define FRAME_Dialoguea53 67 +#define FRAME_Dialoguea54 68 +#define FRAME_Dialoguea55 69 +#define FRAME_Dialoguea56 70 +#define FRAME_Dialoguea57 71 +#define FRAME_Dialoguea58 72 +#define FRAME_Dialoguea59 73 +#define FRAME_Dialoguea60 74 +#define FRAME_Dialoguea61 75 +#define FRAME_Dialoguea62 76 +#define FRAME_Dialoguea63 77 +#define FRAME_Dialoguea64 78 +#define FRAME_Dialoguea65 79 +#define FRAME_Dialoguea66 80 +#define FRAME_Dialoguea67 81 +#define FRAME_Dialoguea68 82 +#define FRAME_Dialoguea69 83 +#define FRAME_Dialoguea70 84 +#define FRAME_Dialoguea71 85 +#define FRAME_Dialoguea72 86 +#define FRAME_Dialoguea73 87 +#define FRAME_Dialoguea74 88 +#define FRAME_Dialoguea75 89 +#define FRAME_Dialoguea76 90 +#define FRAME_Dialoguea77 91 +#define FRAME_Dialoguea78 92 +#define FRAME_Dialoguea79 93 +#define FRAME_Dialoguea80 94 +#define FRAME_Dialoguea81 95 +#define FRAME_Dialoguea82 96 +#define FRAME_Dialoguea83 97 +#define FRAME_Dialoguea84 98 +#define FRAME_Dialoguea85 99 +#define FRAME_Dialoguea86 100 +#define FRAME_Dialoguea87 101 +#define FRAME_Dialoguea88 102 +#define FRAME_Dialoguea89 103 +#define FRAME_Dialoguea90 104 +#define FRAME_Dialoguea91 105 +#define FRAME_Dialoguea92 106 +#define FRAME_Dialoguea93 107 +#define FRAME_Dialoguea94 108 +#define FRAME_Dialoguea95 109 +#define FRAME_Dialoguea96 110 +#define FRAME_Dialoguea97 111 +#define FRAME_Dialoguea98 112 +#define FRAME_Dialoguea99 113 +#define FRAME_Dialoguea100 114 +#define FRAME_Dialoguea101 115 +#define FRAME_Dialoguea102 116 +#define FRAME_Dialoguea103 117 +#define FRAME_Dialoguea104 118 +#define FRAME_Dialoguea105 119 +#define FRAME_Dialoguea106 120 +#define FRAME_Dialoguea107 121 +#define FRAME_Dialoguea108 122 +#define FRAME_Dialoguea109 123 +#define FRAME_Dialoguea110 124 +#define FRAME_Dialoguea111 125 +#define FRAME_Dialoguea112 126 +#define FRAME_Dialoguea113 127 +#define FRAME_Dialoguea114 128 +#define FRAME_Dialoguea115 129 +#define FRAME_Dialoguea116 130 +#define FRAME_Dialoguea117 131 +#define FRAME_Dialoguea118 132 +#define FRAME_Dialoguea119 133 +#define FRAME_Dialoguea120 134 +#define FRAME_Dialoguea121 135 +#define FRAME_Dialoguea122 136 +#define FRAME_Dialoguea123 137 +#define FRAME_Dialoguea124 138 +#define FRAME_Dialoguea125 139 +#define FRAME_Dialoguea126 140 +#define FRAME_Dialoguea127 141 +#define FRAME_Dialoguea128 142 +#define FRAME_Dialoguea129 143 +#define FRAME_Dialoguea130 144 +#define FRAME_Dialoguea131 145 +#define FRAME_Dialoguea132 146 +#define FRAME_Dialoguea133 147 +#define FRAME_Dialoguea134 148 +#define FRAME_Dialoguea135 149 +#define FRAME_Dialoguea136 150 +#define FRAME_Dialoguea137 151 +#define FRAME_Dialoguea138 152 +#define FRAME_Dialoguea139 153 +#define FRAME_Dialoguea140 154 +#define FRAME_Dialoguea141 155 +#define FRAME_Dialoguea142 156 +#define FRAME_Dialoguea143 157 +#define FRAME_Dialoguea144 158 +#define FRAME_Dialoguea145 159 +#define FRAME_Dialoguea146 160 +#define FRAME_Dialoguea147 161 +#define FRAME_Dialoguea148 162 +#define FRAME_Dialoguea149 163 +#define FRAME_Dialoguea150 164 +#define FRAME_Dialoguea151 165 +#define FRAME_Dialoguea152 166 +#define FRAME_Dialoguea153 167 +#define FRAME_Dialoguea154 168 +#define FRAME_Dialoguea155 169 +#define FRAME_Dialoguea156 170 +#define FRAME_Dialoguea157 171 +#define FRAME_Dialoguea158 172 +#define FRAME_Dialoguea159 173 +#define FRAME_Dialoguea160 174 +#define FRAME_Dialoguea161 175 +#define FRAME_Dialoguea162 176 +#define FRAME_Dialoguea163 177 +#define FRAME_Dialoguea164 178 +#define FRAME_Dialoguea165 179 +#define FRAME_Dialoguea166 180 +#define FRAME_Dialoguea167 181 +#define FRAME_Dialoguea168 182 +#define FRAME_Dialoguea169 183 +#define FRAME_Dialoguea170 184 +#define FRAME_Dialoguea171 185 +#define FRAME_Dialoguea172 186 +#define FRAME_Dialoguea173 187 +#define FRAME_Dialoguea174 188 +#define FRAME_Dialoguea175 189 +#define FRAME_Dialoguea176 190 +#define FRAME_Dialoguea177 191 +#define FRAME_Dialoguea178 192 +#define FRAME_Dialoguea179 193 +#define FRAME_Dialoguea180 194 +#define FRAME_Dialoguea181 195 +#define FRAME_Dialoguea182 196 +#define FRAME_Dialoguea183 197 +#define FRAME_Dialoguea184 198 +#define FRAME_Dialoguea185 199 +#define FRAME_Dialoguea186 200 +#define FRAME_Dialoguea187 201 +#define FRAME_Dialoguea188 202 +#define FRAME_Dialoguea189 203 +#define FRAME_Dialoguea190 204 +#define FRAME_Dialoguea191 205 +#define FRAME_Dialoguea192 206 +#define FRAME_Dialoguea193 207 +#define FRAME_Dialoguea194 208 +#define FRAME_Dialoguea195 209 +#define FRAME_Dialoguea196 210 +#define FRAME_Dialoguea197 211 +#define FRAME_Dialoguea198 212 +#define FRAME_Dialoguea199 213 +#define FRAME_Dialoguea200 214 +#define FRAME_Dialoguea201 215 +#define FRAME_Dialoguea202 216 +#define FRAME_Dialoguea203 217 +#define FRAME_Dialoguea204 218 +#define FRAME_Dialoguea205 219 +#define FRAME_Dialoguea206 220 +#define FRAME_Dialoguea207 221 +#define FRAME_Dialoguea208 222 +#define FRAME_Dialoguea209 223 +#define FRAME_Dialoguea210 224 +#define FRAME_Dialoguea211 225 +#define FRAME_Dialoguea212 226 +#define FRAME_Dialoguea213 227 +#define FRAME_Dialoguea214 228 +#define FRAME_Dialoguea215 229 +#define FRAME_Dialoguea216 230 +#define FRAME_Dialoguea217 231 +#define FRAME_Dialoguea218 232 +#define FRAME_Dialoguea219 233 +#define FRAME_Dialoguea220 234 +#define FRAME_Dialogueb1 235 +#define FRAME_Dialogueb2 236 +#define FRAME_Dialogueb3 237 +#define FRAME_Dialogueb4 238 +#define FRAME_Dialogueb5 239 +#define FRAME_Dialogueb6 240 +#define FRAME_Dialogueb7 241 +#define FRAME_Dialogueb8 242 +#define FRAME_Dialogueb9 243 +#define FRAME_Dialogueb10 244 +#define FRAME_Dialogueb11 245 +#define FRAME_Dialogueb12 246 +#define FRAME_Dialogueb13 247 +#define FRAME_Dialogueb14 248 +#define FRAME_Dialogueb15 249 +#define FRAME_Dialogueb16 250 +#define FRAME_Dialogueb17 251 +#define FRAME_Dialogueb18 252 +#define FRAME_Dialogueb19 253 +#define FRAME_Dialogueb20 254 +#define FRAME_Dialogueb21 255 +#define FRAME_Dialogueb22 256 +#define FRAME_Dialogueb23 257 +#define FRAME_Dialogueb24 258 +#define FRAME_Dialogueb25 259 +#define FRAME_Dialogueb26 260 +#define FRAME_Dialogueb27 261 +#define FRAME_Dialogueb28 262 +#define FRAME_Dialogueb29 263 +#define FRAME_Dialogueb30 264 +#define FRAME_Dialogueb31 265 +#define FRAME_Dialogueb32 266 +#define FRAME_Dialogueb33 267 +#define FRAME_Dialogueb34 268 +#define FRAME_Dialogueb35 269 +#define FRAME_Dialogueb36 270 +#define FRAME_Dialogueb37 271 +#define FRAME_Dialogueb38 272 +#define FRAME_Dialogueb39 273 +#define FRAME_Dialogueb40 274 +#define FRAME_Dialogueb41 275 +#define FRAME_Dialogueb42 276 +#define FRAME_Dialogueb43 277 +#define FRAME_Dialogueb44 278 +#define FRAME_Dialogueb45 279 +#define FRAME_Dialogueb46 280 +#define FRAME_Dialogueb47 281 +#define FRAME_Dialogueb48 282 +#define FRAME_Dialogueb49 283 +#define FRAME_Dialogueb50 284 +#define FRAME_Dialogueb51 285 +#define FRAME_Dialogueb52 286 +#define FRAME_Dialogueb53 287 +#define FRAME_Dialogueb54 288 +#define FRAME_Dialogueb55 289 +#define FRAME_Dialogueb56 290 +#define FRAME_Dialogueb57 291 +#define FRAME_Dialogueb58 292 +#define FRAME_Dialogueb59 293 +#define FRAME_Dialogueb60 294 +#define FRAME_Dialogueb61 295 +#define FRAME_Dialogueb62 296 +#define FRAME_Dialogueb63 297 +#define FRAME_Dialogueb64 298 +#define FRAME_Dialogueb65 299 +#define FRAME_Dialogueb66 300 +#define FRAME_Dialogueb67 301 +#define FRAME_Dialogueb68 302 +#define FRAME_Dialogueb69 303 +#define FRAME_Dialogueb70 304 +#define FRAME_Dialogueb71 305 +#define FRAME_Dialogueb72 306 +#define FRAME_Dialogueb73 307 +#define FRAME_Dialogueb74 308 +#define FRAME_Dialogueb75 309 +#define FRAME_Dialogueb76 310 +#define FRAME_Dialogueb77 311 +#define FRAME_Dialogueb78 312 +#define FRAME_Dialogueb79 313 +#define FRAME_Dialogueb80 314 +#define FRAME_Dialogueb81 315 +#define FRAME_Dialogueb82 316 +#define FRAME_Dialogueb83 317 +#define FRAME_Dialogueb84 318 +#define FRAME_Dialogueb85 319 +#define FRAME_Dialogueb86 320 +#define FRAME_Dialogueb87 321 +#define FRAME_Dialogueb88 322 +#define FRAME_Dialogueb89 323 +#define FRAME_Dialogueb90 324 +#define FRAME_Dialogueb91 325 +#define FRAME_Dialogueb92 326 +#define FRAME_Dialogueb93 327 +#define FRAME_Dialogueb94 328 +#define FRAME_Dialogueb95 329 +#define FRAME_Dialogueb96 330 +#define FRAME_Dialogueb97 331 +#define FRAME_Dialogueb98 332 +#define FRAME_Dialogueb99 333 +#define FRAME_Dialogueb100 334 +#define FRAME_Dialogueb101 335 +#define FRAME_Dialogueb102 336 +#define FRAME_Dialogueb103 337 +#define FRAME_Dialogueb104 338 +#define FRAME_Dialogueb105 339 +#define FRAME_Dialogueb106 340 +#define FRAME_Dialogueb107 341 +#define FRAME_Dialogueb108 342 +#define FRAME_Dialogueb109 343 +#define FRAME_Dialogueb110 344 +#define FRAME_Dialogueb111 345 +#define FRAME_Dialogueb112 346 +#define FRAME_Dialogueb113 347 +#define FRAME_Dialogueb114 348 +#define FRAME_Dialogueb115 349 +#define FRAME_Dialogueb116 350 +#define FRAME_Dialogueb117 351 +#define FRAME_Dialogueb118 352 +#define FRAME_Dialogueb119 353 +#define FRAME_Dialogueb120 354 +#define FRAME_Dialogueb121 355 +#define FRAME_Dialogueb122 356 +#define FRAME_Dialogueb123 357 +#define FRAME_Dialogueb124 358 +#define FRAME_Dialogueb125 359 +#define FRAME_Dialogueb126 360 +#define FRAME_Dialogueb127 361 +#define FRAME_Dialogueb128 362 +#define FRAME_Dialogueb129 363 +#define FRAME_Dialogueb130 364 +#define FRAME_Dialogueb131 365 +#define FRAME_Dialogueb132 366 +#define FRAME_Dialogueb133 367 +#define FRAME_Dialogueb134 368 +#define FRAME_Dialogueb135 369 +#define FRAME_Dialogueb136 370 +#define FRAME_Dialogueb137 371 +#define FRAME_Dialogueb138 372 +#define FRAME_Dialogueb139 373 +#define FRAME_Dialogueb140 374 +#define FRAME_Dialogueb141 375 +#define FRAME_Dialogueb142 376 +#define FRAME_Dialogueb143 377 +#define FRAME_Dialogueb144 378 +#define FRAME_Dialogueb145 379 +#define FRAME_Dialogueb146 380 +#define FRAME_Dialogueb147 381 +#define FRAME_Dialogueb148 382 +#define FRAME_Dialogueb149 383 +#define FRAME_Dialogueb150 384 +#define FRAME_Dialogueb151 385 +#define FRAME_Dialogueb152 386 +#define FRAME_Dialogueb153 387 +#define FRAME_Dialogueb154 388 +#define FRAME_Dialogueb155 389 +#define FRAME_Dialogueb156 390 +#define FRAME_Dialogueb157 391 +#define FRAME_Dialogueb158 392 +#define FRAME_Dialogueb159 393 +#define FRAME_Dialogueb160 394 +#define FRAME_Dialogueb161 395 +#define FRAME_Dialogueb162 396 +#define FRAME_Dialogueb163 397 +#define FRAME_Dialogueb164 398 +#define FRAME_Dialogueb165 399 +#define FRAME_Dialogueb166 400 +#define FRAME_Dialogueb167 401 +#define FRAME_Dialogueb168 402 +#define FRAME_Dialogueb169 403 +#define FRAME_Dialogueb170 404 +#define FRAME_Dialogueb171 405 +#define FRAME_Dialogueb172 406 +#define FRAME_Dialogueb173 407 +#define FRAME_Dialogueb174 408 +#define FRAME_Dialogueb175 409 +#define FRAME_Dialogueb176 410 +#define FRAME_Dialogueb177 411 +#define FRAME_Dialogueb178 412 +#define FRAME_Dialogueb179 413 +#define FRAME_Dialogueb180 414 +#define FRAME_Dialogueb181 415 +#define FRAME_Dialogueb182 416 +#define FRAME_Dialogueb183 417 +#define FRAME_Dialogueb184 418 +#define FRAME_Dialogueb185 419 +#define FRAME_Dialogueb186 420 +#define FRAME_Dialogueb187 421 +#define FRAME_Dialogueb188 422 +#define FRAME_Dialogueb189 423 +#define FRAME_Dialogueb190 424 +#define FRAME_Dialogueb191 425 +#define FRAME_Dialogueb192 426 +#define FRAME_Dialogueb193 427 +#define FRAME_Dialogueb194 428 +#define FRAME_Dialogueb195 429 +#define FRAME_Dialogueb196 430 +#define FRAME_Dialogueb197 431 +#define FRAME_Dialogueb198 432 +#define FRAME_Dialogueb199 433 +#define FRAME_Dialogueb200 434 +#define FRAME_Dialogueb201 435 +#define FRAME_Dialogueb202 436 +#define FRAME_Dialogueb203 437 +#define FRAME_Dialogueb204 438 +#define FRAME_Dialogueb205 439 +#define FRAME_Dialogueb206 440 +#define FRAME_idle1 441 +#define FRAME_idle2 442 +#define FRAME_idle3 443 +#define FRAME_idle4 444 +#define FRAME_idle5 445 +#define FRAME_idle6 446 +#define FRAME_idle7 447 +#define FRAME_idle8 448 +#define FRAME_idle9 449 +#define FRAME_idle10 450 +#define FRAME_idle11 451 +#define FRAME_idle12 452 +#define FRAME_idle13 453 +#define FRAME_idle14 454 +#define FRAME_idle15 455 +#define FRAME_idle16 456 +#define FRAME_idle17 457 +#define FRAME_idle18 458 +#define FRAME_idle19 459 +#define FRAME_idle20 460 +#define FRAME_idle21 461 +#define FRAME_idle22 462 +#define FRAME_idle23 463 +#define FRAME_idle24 464 +#define FRAME_cidle1 465 +#define FRAME_cidle2 466 +#define FRAME_cidle3 467 +#define FRAME_cidle4 468 +#define FRAME_cidle5 469 +#define FRAME_cidle6 470 +#define FRAME_cidle7 471 +#define FRAME_cidle8 472 +#define FRAME_cidle9 473 +#define FRAME_cidle10 474 +#define FRAME_cidle11 475 +#define FRAME_cidle12 476 +#define FRAME_cidle13 477 +#define FRAME_cidle14 478 +#define FRAME_cidle15 479 +#define FRAME_cidle16 480 +#define FRAME_cidle17 481 +#define FRAME_cidle18 482 +#define FRAME_cidle19 483 +#define FRAME_cidle20 484 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 7 + +#define MESH_IDLE1 0 +#define MESH__BODY25 1 +#define MESH__LEFTARM25 2 +#define MESH__RIGHTARM25 3 +#define MESH__HEAD25 4 +#define MESH__THECAPE25 5 +#define MESH__LIGHT25 6 diff --git a/Toolkit/Programming/GameCode/game/c_morcalavin.c b/Toolkit/Programming/GameCode/game/c_morcalavin.c new file mode 100644 index 0000000..cddce1a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_morcalavin.c @@ -0,0 +1,129 @@ +/*------------------------------------------------------------------- +c_morcalavin.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#include "c_morcalavin.h" +#include "c_morcalavin_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + // Cinematics + &morcalavin_move_c_action1, + &morcalavin_move_c_action2, + &morcalavin_move_c_action3, + &morcalavin_move_c_idle1, + &morcalavin_move_c_idle2, + &morcalavin_move_c_idle3, + &morcalavin_move_c_idle4, +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + morcalavin_c_anims +-------------------------------------------------------------------------*/ +void morcalavin_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_IDLE4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE4; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + StaticsInit +-------------------------------------------------------------------------*/ +void MorcalavinCinStaticsInit() +{ + + classStatics[CID_C_MORCALAVIN].msgReceivers[MSG_C_ACTION1] = morcalavin_c_anims; + classStatics[CID_C_MORCALAVIN].msgReceivers[MSG_C_ACTION2] = morcalavin_c_anims; + classStatics[CID_C_MORCALAVIN].msgReceivers[MSG_C_ACTION3] = morcalavin_c_anims; + classStatics[CID_C_MORCALAVIN].msgReceivers[MSG_C_IDLE1] = morcalavin_c_anims; + classStatics[CID_C_MORCALAVIN].msgReceivers[MSG_C_IDLE2] = morcalavin_c_anims; + classStatics[CID_C_MORCALAVIN].msgReceivers[MSG_C_IDLE3] = morcalavin_c_anims; + classStatics[CID_C_MORCALAVIN].msgReceivers[MSG_C_IDLE4] = morcalavin_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + //note that the name is different in the path + resInfo.modelIndex = gi.modelindex("models/monsters/morcalavin/cinematic/tris.fm"); + + classStatics[CID_C_MORCALAVIN].resInfo = &resInfo; + +} + + +/*QUAKED character_morcalavin (1 .5 0) (-24 -24 -50) (24 24 50) INVISIBLE +The cinematic morcalavin +*/ +void SP_character_morcalavin (edict_t *self) +{ + VectorSet(self->mins, -24, -24, -46); + VectorSet(self->maxs, 24, 24, 46); + + c_character_init(self,CID_C_MORCALAVIN); + +} diff --git a/Toolkit/Programming/GameCode/game/c_morcalavin.h b/Toolkit/Programming/GameCode/game/c_morcalavin.h new file mode 100644 index 0000000..6740bc2 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_morcalavin.h @@ -0,0 +1,22 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_IDLE4, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t morcalavin_move_c_action1; +extern animmove_t morcalavin_move_c_action2; +extern animmove_t morcalavin_move_c_action3; +extern animmove_t morcalavin_move_c_idle1; +extern animmove_t morcalavin_move_c_idle2; +extern animmove_t morcalavin_move_c_idle3; +extern animmove_t morcalavin_move_c_idle4; + diff --git a/Toolkit/Programming/GameCode/game/c_morcalavin_anim.c b/Toolkit/Programming/GameCode/game/c_morcalavin_anim.c new file mode 100644 index 0000000..c960c75 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_morcalavin_anim.c @@ -0,0 +1,587 @@ +//============================================================================== +// +// m_corvus_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_morcalavin_anim.h" +#include "c_morcalavin.h" + +#include "g_monster.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ +/*---------------------------------------------------------------------- + morcalavin +-----------------------------------------------------------------------*/ +animframe_t morcalavin_frames_c_idle1 [] = +{ + FRAME_talka1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t morcalavin_move_c_idle1 = {3, morcalavin_frames_c_idle1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + morcalavin +-----------------------------------------------------------------------*/ +animframe_t morcalavin_frames_c_idle2 [] = +{ + FRAME_talkb1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t morcalavin_move_c_idle2 = {1, morcalavin_frames_c_idle2, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + morcalavin +-----------------------------------------------------------------------*/ +animframe_t morcalavin_frames_c_idle3 [] = +{ + FRAME_talkc66, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t morcalavin_move_c_idle3 = {1, morcalavin_frames_c_idle3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + morcalavin +-----------------------------------------------------------------------*/ +animframe_t morcalavin_frames_c_idle4 [] = +{ + FRAME_talkc1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t morcalavin_move_c_idle4 = {1, morcalavin_frames_c_idle4, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + morcalavin +-----------------------------------------------------------------------*/ +animframe_t morcalavin_frames_c_action1 [] = +{ + FRAME_talka1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka129, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka130, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka131, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka132, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka133, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka134, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka135, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka136, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka137, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka138, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka139, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka140, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka141, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka142, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka143, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka144, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka145, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka146, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka147, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka148, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka149, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka150, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka151, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka152, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka153, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka154, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka155, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka156, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka157, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka158, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka159, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka160, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka161, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka162, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka163, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka164, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka165, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka166, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka167, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka168, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka169, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka170, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka171, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka172, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka173, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka174, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka175, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka176, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka177, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka178, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka179, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka180, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka181, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka182, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka183, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka184, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka185, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka186, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka187, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka188, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka189, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka190, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka191, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka192, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka193, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka194, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka195, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka196, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka197, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka198, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka199, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka200, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka201, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka202, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka203, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka204, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka205, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka206, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka207, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka208, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka209, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka210, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka211, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka212, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka213, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka214, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka215, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka216, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka217, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka218, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka219, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka220, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka221, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka222, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka223, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka224, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka225, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka226, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka227, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka228, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka229, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka230, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka231, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka232, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka233, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka234, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka235, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka236, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka237, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka238, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka239, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka240, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka241, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka242, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka243, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka244, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka245, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka246, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka247, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka248, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka249, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka250, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka251, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka252, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka253, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka254, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka255, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka256, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka257, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka258, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka259, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka260, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka261, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka262, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka263, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka264, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka265, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka266, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka267, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka268, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka269, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka270, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka271, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka272, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka273, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka274, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka275, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka276, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka277, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka278, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka279, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka280, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka281, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka282, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka283, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka284, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka285, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka286, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka287, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka288, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka289, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka290, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka291, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka292, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka293, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka294, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka295, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka296, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka297, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka298, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka299, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talka300, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t morcalavin_move_c_action1 = {300, morcalavin_frames_c_action1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + morcalavin +-----------------------------------------------------------------------*/ +animframe_t morcalavin_frames_c_action2 [] = +{ + FRAME_talkb1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkb101, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t morcalavin_move_c_action2 = {101, morcalavin_frames_c_action2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + morcalavin +-----------------------------------------------------------------------*/ +animframe_t morcalavin_frames_c_action3 [] = +{ + FRAME_talkc1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_talkc82, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t morcalavin_move_c_action3 = {82, morcalavin_frames_c_action3, ai_c_cycleend}; diff --git a/Toolkit/Programming/GameCode/game/c_morcalavin_anim.h b/Toolkit/Programming/GameCode/game/c_morcalavin_anim.h new file mode 100644 index 0000000..b633f63 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_morcalavin_anim.h @@ -0,0 +1,505 @@ +// R:\Art\models/monsters\morcalavin\cinematic + +// This file generated by qdata - Do NOT Modify + +#define FRAME_talka1 0 +#define FRAME_talka2 1 +#define FRAME_talka3 2 +#define FRAME_talka4 3 +#define FRAME_talka5 4 +#define FRAME_talka6 5 +#define FRAME_talka7 6 +#define FRAME_talka8 7 +#define FRAME_talka9 8 +#define FRAME_talka10 9 +#define FRAME_talka11 10 +#define FRAME_talka12 11 +#define FRAME_talka13 12 +#define FRAME_talka14 13 +#define FRAME_talka15 14 +#define FRAME_talka16 15 +#define FRAME_talka17 16 +#define FRAME_talka18 17 +#define FRAME_talka19 18 +#define FRAME_talka20 19 +#define FRAME_talka21 20 +#define FRAME_talka22 21 +#define FRAME_talka23 22 +#define FRAME_talka24 23 +#define FRAME_talka25 24 +#define FRAME_talka26 25 +#define FRAME_talka27 26 +#define FRAME_talka28 27 +#define FRAME_talka29 28 +#define FRAME_talka30 29 +#define FRAME_talka31 30 +#define FRAME_talka32 31 +#define FRAME_talka33 32 +#define FRAME_talka34 33 +#define FRAME_talka35 34 +#define FRAME_talka36 35 +#define FRAME_talka37 36 +#define FRAME_talka38 37 +#define FRAME_talka39 38 +#define FRAME_talka40 39 +#define FRAME_talka41 40 +#define FRAME_talka42 41 +#define FRAME_talka43 42 +#define FRAME_talka44 43 +#define FRAME_talka45 44 +#define FRAME_talka46 45 +#define FRAME_talka47 46 +#define FRAME_talka48 47 +#define FRAME_talka49 48 +#define FRAME_talka50 49 +#define FRAME_talka51 50 +#define FRAME_talka52 51 +#define FRAME_talka53 52 +#define FRAME_talka54 53 +#define FRAME_talka55 54 +#define FRAME_talka56 55 +#define FRAME_talka57 56 +#define FRAME_talka58 57 +#define FRAME_talka59 58 +#define FRAME_talka60 59 +#define FRAME_talka61 60 +#define FRAME_talka62 61 +#define FRAME_talka63 62 +#define FRAME_talka64 63 +#define FRAME_talka65 64 +#define FRAME_talka66 65 +#define FRAME_talka67 66 +#define FRAME_talka68 67 +#define FRAME_talka69 68 +#define FRAME_talka70 69 +#define FRAME_talka71 70 +#define FRAME_talka72 71 +#define FRAME_talka73 72 +#define FRAME_talka74 73 +#define FRAME_talka75 74 +#define FRAME_talka76 75 +#define FRAME_talka77 76 +#define FRAME_talka78 77 +#define FRAME_talka79 78 +#define FRAME_talka80 79 +#define FRAME_talka81 80 +#define FRAME_talka82 81 +#define FRAME_talka83 82 +#define FRAME_talka84 83 +#define FRAME_talka85 84 +#define FRAME_talka86 85 +#define FRAME_talka87 86 +#define FRAME_talka88 87 +#define FRAME_talka89 88 +#define FRAME_talka90 89 +#define FRAME_talka91 90 +#define FRAME_talka92 91 +#define FRAME_talka93 92 +#define FRAME_talka94 93 +#define FRAME_talka95 94 +#define FRAME_talka96 95 +#define FRAME_talka97 96 +#define FRAME_talka98 97 +#define FRAME_talka99 98 +#define FRAME_talka100 99 +#define FRAME_talka101 100 +#define FRAME_talka102 101 +#define FRAME_talka103 102 +#define FRAME_talka104 103 +#define FRAME_talka105 104 +#define FRAME_talka106 105 +#define FRAME_talka107 106 +#define FRAME_talka108 107 +#define FRAME_talka109 108 +#define FRAME_talka110 109 +#define FRAME_talka111 110 +#define FRAME_talka112 111 +#define FRAME_talka113 112 +#define FRAME_talka114 113 +#define FRAME_talka115 114 +#define FRAME_talka116 115 +#define FRAME_talka117 116 +#define FRAME_talka118 117 +#define FRAME_talka119 118 +#define FRAME_talka120 119 +#define FRAME_talka121 120 +#define FRAME_talka122 121 +#define FRAME_talka123 122 +#define FRAME_talka124 123 +#define FRAME_talka125 124 +#define FRAME_talka126 125 +#define FRAME_talka127 126 +#define FRAME_talka128 127 +#define FRAME_talka129 128 +#define FRAME_talka130 129 +#define FRAME_talka131 130 +#define FRAME_talka132 131 +#define FRAME_talka133 132 +#define FRAME_talka134 133 +#define FRAME_talka135 134 +#define FRAME_talka136 135 +#define FRAME_talka137 136 +#define FRAME_talka138 137 +#define FRAME_talka139 138 +#define FRAME_talka140 139 +#define FRAME_talka141 140 +#define FRAME_talka142 141 +#define FRAME_talka143 142 +#define FRAME_talka144 143 +#define FRAME_talka145 144 +#define FRAME_talka146 145 +#define FRAME_talka147 146 +#define FRAME_talka148 147 +#define FRAME_talka149 148 +#define FRAME_talka150 149 +#define FRAME_talka151 150 +#define FRAME_talka152 151 +#define FRAME_talka153 152 +#define FRAME_talka154 153 +#define FRAME_talka155 154 +#define FRAME_talka156 155 +#define FRAME_talka157 156 +#define FRAME_talka158 157 +#define FRAME_talka159 158 +#define FRAME_talka160 159 +#define FRAME_talka161 160 +#define FRAME_talka162 161 +#define FRAME_talka163 162 +#define FRAME_talka164 163 +#define FRAME_talka165 164 +#define FRAME_talka166 165 +#define FRAME_talka167 166 +#define FRAME_talka168 167 +#define FRAME_talka169 168 +#define FRAME_talka170 169 +#define FRAME_talka171 170 +#define FRAME_talka172 171 +#define FRAME_talka173 172 +#define FRAME_talka174 173 +#define FRAME_talka175 174 +#define FRAME_talka176 175 +#define FRAME_talka177 176 +#define FRAME_talka178 177 +#define FRAME_talka179 178 +#define FRAME_talka180 179 +#define FRAME_talka181 180 +#define FRAME_talka182 181 +#define FRAME_talka183 182 +#define FRAME_talka184 183 +#define FRAME_talka185 184 +#define FRAME_talka186 185 +#define FRAME_talka187 186 +#define FRAME_talka188 187 +#define FRAME_talka189 188 +#define FRAME_talka190 189 +#define FRAME_talka191 190 +#define FRAME_talka192 191 +#define FRAME_talka193 192 +#define FRAME_talka194 193 +#define FRAME_talka195 194 +#define FRAME_talka196 195 +#define FRAME_talka197 196 +#define FRAME_talka198 197 +#define FRAME_talka199 198 +#define FRAME_talka200 199 +#define FRAME_talka201 200 +#define FRAME_talka202 201 +#define FRAME_talka203 202 +#define FRAME_talka204 203 +#define FRAME_talka205 204 +#define FRAME_talka206 205 +#define FRAME_talka207 206 +#define FRAME_talka208 207 +#define FRAME_talka209 208 +#define FRAME_talka210 209 +#define FRAME_talka211 210 +#define FRAME_talka212 211 +#define FRAME_talka213 212 +#define FRAME_talka214 213 +#define FRAME_talka215 214 +#define FRAME_talka216 215 +#define FRAME_talka217 216 +#define FRAME_talka218 217 +#define FRAME_talka219 218 +#define FRAME_talka220 219 +#define FRAME_talka221 220 +#define FRAME_talka222 221 +#define FRAME_talka223 222 +#define FRAME_talka224 223 +#define FRAME_talka225 224 +#define FRAME_talka226 225 +#define FRAME_talka227 226 +#define FRAME_talka228 227 +#define FRAME_talka229 228 +#define FRAME_talka230 229 +#define FRAME_talka231 230 +#define FRAME_talka232 231 +#define FRAME_talka233 232 +#define FRAME_talka234 233 +#define FRAME_talka235 234 +#define FRAME_talka236 235 +#define FRAME_talka237 236 +#define FRAME_talka238 237 +#define FRAME_talka239 238 +#define FRAME_talka240 239 +#define FRAME_talka241 240 +#define FRAME_talka242 241 +#define FRAME_talka243 242 +#define FRAME_talka244 243 +#define FRAME_talka245 244 +#define FRAME_talka246 245 +#define FRAME_talka247 246 +#define FRAME_talka248 247 +#define FRAME_talka249 248 +#define FRAME_talka250 249 +#define FRAME_talka251 250 +#define FRAME_talka252 251 +#define FRAME_talka253 252 +#define FRAME_talka254 253 +#define FRAME_talka255 254 +#define FRAME_talka256 255 +#define FRAME_talka257 256 +#define FRAME_talka258 257 +#define FRAME_talka259 258 +#define FRAME_talka260 259 +#define FRAME_talka261 260 +#define FRAME_talka262 261 +#define FRAME_talka263 262 +#define FRAME_talka264 263 +#define FRAME_talka265 264 +#define FRAME_talka266 265 +#define FRAME_talka267 266 +#define FRAME_talka268 267 +#define FRAME_talka269 268 +#define FRAME_talka270 269 +#define FRAME_talka271 270 +#define FRAME_talka272 271 +#define FRAME_talka273 272 +#define FRAME_talka274 273 +#define FRAME_talka275 274 +#define FRAME_talka276 275 +#define FRAME_talka277 276 +#define FRAME_talka278 277 +#define FRAME_talka279 278 +#define FRAME_talka280 279 +#define FRAME_talka281 280 +#define FRAME_talka282 281 +#define FRAME_talka283 282 +#define FRAME_talka284 283 +#define FRAME_talka285 284 +#define FRAME_talka286 285 +#define FRAME_talka287 286 +#define FRAME_talka288 287 +#define FRAME_talka289 288 +#define FRAME_talka290 289 +#define FRAME_talka291 290 +#define FRAME_talka292 291 +#define FRAME_talka293 292 +#define FRAME_talka294 293 +#define FRAME_talka295 294 +#define FRAME_talka296 295 +#define FRAME_talka297 296 +#define FRAME_talka298 297 +#define FRAME_talka299 298 +#define FRAME_talka300 299 +#define FRAME_talkb1 300 +#define FRAME_talkb2 301 +#define FRAME_talkb3 302 +#define FRAME_talkb4 303 +#define FRAME_talkb5 304 +#define FRAME_talkb6 305 +#define FRAME_talkb7 306 +#define FRAME_talkb8 307 +#define FRAME_talkb9 308 +#define FRAME_talkb10 309 +#define FRAME_talkb11 310 +#define FRAME_talkb12 311 +#define FRAME_talkb13 312 +#define FRAME_talkb14 313 +#define FRAME_talkb15 314 +#define FRAME_talkb16 315 +#define FRAME_talkb17 316 +#define FRAME_talkb18 317 +#define FRAME_talkb19 318 +#define FRAME_talkb20 319 +#define FRAME_talkb21 320 +#define FRAME_talkb22 321 +#define FRAME_talkb23 322 +#define FRAME_talkb24 323 +#define FRAME_talkb25 324 +#define FRAME_talkb26 325 +#define FRAME_talkb27 326 +#define FRAME_talkb28 327 +#define FRAME_talkb29 328 +#define FRAME_talkb30 329 +#define FRAME_talkb31 330 +#define FRAME_talkb32 331 +#define FRAME_talkb33 332 +#define FRAME_talkb34 333 +#define FRAME_talkb35 334 +#define FRAME_talkb36 335 +#define FRAME_talkb37 336 +#define FRAME_talkb38 337 +#define FRAME_talkb39 338 +#define FRAME_talkb40 339 +#define FRAME_talkb41 340 +#define FRAME_talkb42 341 +#define FRAME_talkb43 342 +#define FRAME_talkb44 343 +#define FRAME_talkb45 344 +#define FRAME_talkb46 345 +#define FRAME_talkb47 346 +#define FRAME_talkb48 347 +#define FRAME_talkb49 348 +#define FRAME_talkb50 349 +#define FRAME_talkb51 350 +#define FRAME_talkb52 351 +#define FRAME_talkb53 352 +#define FRAME_talkb54 353 +#define FRAME_talkb55 354 +#define FRAME_talkb56 355 +#define FRAME_talkb57 356 +#define FRAME_talkb58 357 +#define FRAME_talkb59 358 +#define FRAME_talkb60 359 +#define FRAME_talkb61 360 +#define FRAME_talkb62 361 +#define FRAME_talkb63 362 +#define FRAME_talkb64 363 +#define FRAME_talkb65 364 +#define FRAME_talkb66 365 +#define FRAME_talkb67 366 +#define FRAME_talkb68 367 +#define FRAME_talkb69 368 +#define FRAME_talkb70 369 +#define FRAME_talkb71 370 +#define FRAME_talkb72 371 +#define FRAME_talkb73 372 +#define FRAME_talkb74 373 +#define FRAME_talkb75 374 +#define FRAME_talkb76 375 +#define FRAME_talkb77 376 +#define FRAME_talkb78 377 +#define FRAME_talkb79 378 +#define FRAME_talkb80 379 +#define FRAME_talkb81 380 +#define FRAME_talkb82 381 +#define FRAME_talkb83 382 +#define FRAME_talkb84 383 +#define FRAME_talkb85 384 +#define FRAME_talkb86 385 +#define FRAME_talkb87 386 +#define FRAME_talkb88 387 +#define FRAME_talkb89 388 +#define FRAME_talkb90 389 +#define FRAME_talkb91 390 +#define FRAME_talkb92 391 +#define FRAME_talkb93 392 +#define FRAME_talkb94 393 +#define FRAME_talkb95 394 +#define FRAME_talkb96 395 +#define FRAME_talkb97 396 +#define FRAME_talkb98 397 +#define FRAME_talkb99 398 +#define FRAME_talkb100 399 +#define FRAME_talkb101 400 +#define FRAME_talkc1 401 +#define FRAME_talkc2 402 +#define FRAME_talkc3 403 +#define FRAME_talkc4 404 +#define FRAME_talkc5 405 +#define FRAME_talkc6 406 +#define FRAME_talkc7 407 +#define FRAME_talkc8 408 +#define FRAME_talkc9 409 +#define FRAME_talkc10 410 +#define FRAME_talkc11 411 +#define FRAME_talkc12 412 +#define FRAME_talkc13 413 +#define FRAME_talkc14 414 +#define FRAME_talkc15 415 +#define FRAME_talkc16 416 +#define FRAME_talkc17 417 +#define FRAME_talkc18 418 +#define FRAME_talkc19 419 +#define FRAME_talkc20 420 +#define FRAME_talkc21 421 +#define FRAME_talkc22 422 +#define FRAME_talkc23 423 +#define FRAME_talkc24 424 +#define FRAME_talkc25 425 +#define FRAME_talkc26 426 +#define FRAME_talkc27 427 +#define FRAME_talkc28 428 +#define FRAME_talkc29 429 +#define FRAME_talkc30 430 +#define FRAME_talkc31 431 +#define FRAME_talkc32 432 +#define FRAME_talkc33 433 +#define FRAME_talkc34 434 +#define FRAME_talkc35 435 +#define FRAME_talkc36 436 +#define FRAME_talkc37 437 +#define FRAME_talkc38 438 +#define FRAME_talkc39 439 +#define FRAME_talkc40 440 +#define FRAME_talkc41 441 +#define FRAME_talkc42 442 +#define FRAME_talkc43 443 +#define FRAME_talkc44 444 +#define FRAME_talkc45 445 +#define FRAME_talkc46 446 +#define FRAME_talkc47 447 +#define FRAME_talkc48 448 +#define FRAME_talkc49 449 +#define FRAME_talkc50 450 +#define FRAME_talkc51 451 +#define FRAME_talkc52 452 +#define FRAME_talkc53 453 +#define FRAME_talkc54 454 +#define FRAME_talkc55 455 +#define FRAME_talkc56 456 +#define FRAME_talkc57 457 +#define FRAME_talkc58 458 +#define FRAME_talkc59 459 +#define FRAME_talkc60 460 +#define FRAME_talkc61 461 +#define FRAME_talkc62 462 +#define FRAME_talkc63 463 +#define FRAME_talkc64 464 +#define FRAME_talkc65 465 +#define FRAME_talkc66 466 +#define FRAME_talkc67 467 +#define FRAME_talkc68 468 +#define FRAME_talkc69 469 +#define FRAME_talkc70 470 +#define FRAME_talkc71 471 +#define FRAME_talkc72 472 +#define FRAME_talkc73 473 +#define FRAME_talkc74 474 +#define FRAME_talkc75 475 +#define FRAME_talkc76 476 +#define FRAME_talkc77 477 +#define FRAME_talkc78 478 +#define FRAME_talkc79 479 +#define FRAME_talkc80 480 +#define FRAME_talkc81 481 +#define FRAME_talkc82 482 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 13 + +#define MESH_NULL1 0 +#define MESH__TORSO 1 +#define MESH__CAPE 2 +#define MESH__DRESS 3 +#define MESH__LUPARM 4 +#define MESH__RSHOULDER 5 +#define MESH__L4ARM 6 +#define MESH__HEAD 7 +#define MESH__RUPARM 8 +#define MESH__LHAND 9 +#define MESH__RHAND 10 +#define MESH__LSHOULDER 11 +#define MESH__R4ARM 12 diff --git a/Toolkit/Programming/GameCode/game/c_priestess.c b/Toolkit/Programming/GameCode/game/c_priestess.c new file mode 100644 index 0000000..a6bc8f4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_priestess.c @@ -0,0 +1,206 @@ +/*------------------------------------------------------------------- +c_priestess.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" + +#include "vector.h" +#include "c_priestess.h" +#include "c_priestess_anim.h" +#include "c_ai.h" + + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[NUM_ANIMS] = +{ + // Cinematics + &priestess_move_c_action1, + &priestess_move_c_action2, + &priestess_move_c_action3, + &priestess_move_c_action4, + &priestess_move_c_action5, + &priestess_move_c_action6, + &priestess_move_c_action7, + &priestess_move_c_action8, + &priestess_move_c_action9, + &priestess_move_c_action10, + &priestess_move_c_action11, + &priestess_move_c_action12, + &priestess_move_c_action13, + &priestess_move_c_action14, + &priestess_move_c_action15, + &priestess_move_c_action16, + &priestess_move_c_backpedal1, + &priestess_move_c_idle1, + &priestess_move_c_idle2, + &priestess_move_c_walk1, +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + priestess_c_anims +-------------------------------------------------------------------------*/ +void priestess_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_ACTION8: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + case MSG_C_ACTION9: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION9; + break; + case MSG_C_ACTION10: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION10; + break; + case MSG_C_ACTION11: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION11; + break; + case MSG_C_ACTION12: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION12; + break; + case MSG_C_ACTION13: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION13; + break; + case MSG_C_ACTION14: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION14; + break; + case MSG_C_ACTION15: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION15; + break; + case MSG_C_ACTION16: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION16; + break; + case MSG_C_BACKPEDAL1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_BACKPEDAL1; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + StaticsInit +-------------------------------------------------------------------------*/ +void PriestessCStaticsInit() +{ + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION1] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION2] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION3] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION4] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION5] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION6] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION7] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION8] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION9] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION10] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION11] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION12] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION13] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION14] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION15] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_ACTION16] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_BACKPEDAL1] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_IDLE1] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_IDLE2] = priestess_c_anims; + classStatics[CID_C_HIGHPRIESTESS].msgReceivers[MSG_C_WALK1] = priestess_c_anims; + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/monsters/highpriestess/cinematic/tris.fm"); + + classStatics[CID_C_HIGHPRIESTESS].resInfo = &resInfo; + +} + + +/*QUAKED character_highpriestess(1 .5 0) (-24 -24 -36) (24 24 36) INVISIBLE +The cinematic High Priestess +--------SPAWNFLAG------------- +INVISIBLE - you won't see her +*/ +void SP_character_highpriestess (edict_t *self) +{ + VectorSet (self->mins, -16, -16, -32); + VectorSet (self->maxs, 16, 16, 32); + + c_character_init(self,CID_C_HIGHPRIESTESS); +} diff --git a/Toolkit/Programming/GameCode/game/c_priestess.h b/Toolkit/Programming/GameCode/game/c_priestess.h new file mode 100644 index 0000000..303b22b --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_priestess.h @@ -0,0 +1,50 @@ +//c_priestess.h + + +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_ACTION9, + ANIM_C_ACTION10, + ANIM_C_ACTION11, + ANIM_C_ACTION12, + ANIM_C_ACTION13, + ANIM_C_ACTION14, + ANIM_C_ACTION15, + ANIM_C_ACTION16, + ANIM_C_BACKPEDAL1, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_WALK1, + NUM_ANIMS +} AnimID_t; + +#define MODEL_SCALE 1.000000 + +extern animmove_t priestess_move_c_action1; +extern animmove_t priestess_move_c_action2; +extern animmove_t priestess_move_c_action3; +extern animmove_t priestess_move_c_action4; +extern animmove_t priestess_move_c_action5; +extern animmove_t priestess_move_c_action6; +extern animmove_t priestess_move_c_action7; +extern animmove_t priestess_move_c_action8; +extern animmove_t priestess_move_c_action9; +extern animmove_t priestess_move_c_action10; +extern animmove_t priestess_move_c_action11; +extern animmove_t priestess_move_c_action12; +extern animmove_t priestess_move_c_action13; +extern animmove_t priestess_move_c_action14; +extern animmove_t priestess_move_c_action15; +extern animmove_t priestess_move_c_action16; +extern animmove_t priestess_move_c_backpedal1; +extern animmove_t priestess_move_c_idle1; +extern animmove_t priestess_move_c_idle2; +extern animmove_t priestess_move_c_walk1; diff --git a/Toolkit/Programming/GameCode/game/c_priestess2.c b/Toolkit/Programming/GameCode/game/c_priestess2.c new file mode 100644 index 0000000..b11f6bc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_priestess2.c @@ -0,0 +1,138 @@ +/*------------------------------------------------------------------- +c_priestess2.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#include "c_priestess2.h" +#include "c_priestess2_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[NUM_ANIMS] = +{ + // Cinematics + &priestess2_move_c_action1, + &priestess2_move_c_action2, + &priestess2_move_c_action3, + &priestess2_move_c_action4, + &priestess2_move_c_action5, + &priestess2_move_c_action6, + &priestess2_move_c_action7, + &priestess2_move_c_idle1, +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + priestess2_c_anims +-------------------------------------------------------------------------*/ +void priestess2_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + self->monsterinfo.c_dist = 40; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + self->monsterinfo.c_dist = 16; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + self->monsterinfo.c_dist = 158; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + self->monsterinfo.c_dist = 96; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + self->monsterinfo.c_dist = 158; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + self->monsterinfo.c_dist = 72; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + StaticsInit +-------------------------------------------------------------------------*/ +void Priestess2CStaticsInit() +{ + classStatics[CID_C_HIGHPRIESTESS2].msgReceivers[MSG_C_ACTION1] = priestess2_c_anims; + classStatics[CID_C_HIGHPRIESTESS2].msgReceivers[MSG_C_ACTION2] = priestess2_c_anims; + classStatics[CID_C_HIGHPRIESTESS2].msgReceivers[MSG_C_ACTION3] = priestess2_c_anims; + classStatics[CID_C_HIGHPRIESTESS2].msgReceivers[MSG_C_ACTION4] = priestess2_c_anims; + classStatics[CID_C_HIGHPRIESTESS2].msgReceivers[MSG_C_ACTION5] = priestess2_c_anims; + classStatics[CID_C_HIGHPRIESTESS2].msgReceivers[MSG_C_ACTION6] = priestess2_c_anims; + classStatics[CID_C_HIGHPRIESTESS2].msgReceivers[MSG_C_ACTION7] = priestess2_c_anims; + classStatics[CID_C_HIGHPRIESTESS2].msgReceivers[MSG_C_IDLE1] = priestess2_c_anims; + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/monsters/highpriestess/pod_scene/tris.fm"); + + classStatics[CID_C_HIGHPRIESTESS2].resInfo = &resInfo; + +} + +/*QUAKED character_highpriestess2(1 .5 0) (-24 -24 -36) (24 24 36) INVISIBLE +The cinematic High Priestess for the Pod Scene +--------SPAWNFLAG------------- +INVISIBLE - you won't see her +*/ +void SP_character_highpriestess2 (edict_t *self) +{ + VectorSet (self->mins, -16, -16, -38); + VectorSet (self->maxs, 16, 16, 38); + + c_character_init(self,CID_C_HIGHPRIESTESS2); +} diff --git a/Toolkit/Programming/GameCode/game/c_priestess2.h b/Toolkit/Programming/GameCode/game/c_priestess2.h new file mode 100644 index 0000000..6f4b0dd --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_priestess2.h @@ -0,0 +1,26 @@ +//c_priestess2.h + + +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_IDLE1, + NUM_ANIMS +} AnimID_t; + +#define MODEL_SCALE 1.000000 + +extern animmove_t priestess2_move_c_action1; +extern animmove_t priestess2_move_c_action2; +extern animmove_t priestess2_move_c_action3; +extern animmove_t priestess2_move_c_action4; +extern animmove_t priestess2_move_c_action5; +extern animmove_t priestess2_move_c_action6; +extern animmove_t priestess2_move_c_action7; +extern animmove_t priestess2_move_c_idle1; diff --git a/Toolkit/Programming/GameCode/game/c_priestess2_anim.c b/Toolkit/Programming/GameCode/game/c_priestess2_anim.c new file mode 100644 index 0000000..11ce9d2 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_priestess2_anim.c @@ -0,0 +1,546 @@ +//============================================================================== +// +// m_victimSsitra_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_priestess2_anim.h" +#include "c_priestess2.h" +#include "c_ai.h" + +animframe_t priestess2_frames_c_action1[] = +{ + FRAME_hpod1, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod2, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod3, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod4, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod5, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod6, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod7, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod8, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod9, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod10, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod11, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod12, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod13, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod14, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod15, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod16, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod17, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod18, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod19, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod20, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod21, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod22, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod23, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod24, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod25, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod26, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod27, ai_c_move, 1, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess2_move_c_action1 = {27,priestess2_frames_c_action1, ai_c_cycleend}; + + + +animframe_t priestess2_frames_c_action2[] = +{ + FRAME_hpod28, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod29, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod30, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod31, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod32, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod33, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod34, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod35, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod36, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod37, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod38, ai_c_move, 1, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess2_move_c_action2 = {11,priestess2_frames_c_action2, ai_c_cycleend}; + + + +animframe_t priestess2_frames_c_action3[] = +{ + FRAME_hpod39, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod40, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod41, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod42, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod43, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod44, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod45, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod46, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod47, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod48, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod49, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod50, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod51, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod52, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod53, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod54, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod55, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod56, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod57, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod58, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod59, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod60, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod61, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod62, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod63, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod64, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod65, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod66, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod67, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod68, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod69, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod70, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod71, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod72, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod73, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod74, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod75, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod76, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod77, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod78, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod79, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod80, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod81, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod82, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod83, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod84, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod85, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod86, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod87, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod88, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod89, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod90, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod91, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod92, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod93, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod94, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod95, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod96, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod97, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod98, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod99, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod100, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod101, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod102, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod103, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod104, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod105, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod106, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod107, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod108, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod109, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod110, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod111, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod112, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod113, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod114, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod115, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod116, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod117, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod118, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod119, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod120, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod121, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod122, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod123, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod124, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod125, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod126, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod127, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod128, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod129, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod130, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod131, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod132, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod133, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod134, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod135, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod136, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod137, ai_c_move, 1, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess2_move_c_action3 = {99,priestess2_frames_c_action3, ai_c_cycleend}; + + +animframe_t priestess2_frames_c_action4[] = +{ + FRAME_hpod138, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod139, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod140, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod141, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod142, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod143, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod144, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod145, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod146, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod147, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod148, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod149, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod150, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod151, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod152, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod153, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod154, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod155, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod156, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod157, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod158, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod159, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod160, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod161, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod162, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod163, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod164, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod165, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod166, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod167, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod168, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod169, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod170, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod171, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod172, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod173, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod174, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod175, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod176, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod177, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod178, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod179, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod180, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod181, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod182, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod183, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod184, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod185, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod186, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod187, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod188, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod189, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod190, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod191, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod192, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod193, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod194, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod195, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod196, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod197, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod198, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod199, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod200, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod201, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess2_move_c_action4 = {64,priestess2_frames_c_action4, ai_c_cycleend}; + + +animframe_t priestess2_frames_c_action5[] = +{ + FRAME_hpod202, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod203, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod204, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod205, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod206, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod207, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod208, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod209, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod210, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod211, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod212, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod213, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod214, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod215, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod216, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod217, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod218, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod219, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod220, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod221, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod222, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod223, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod224, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod225, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod226, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod227, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod228, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod229, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod230, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod231, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod232, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod233, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod234, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod235, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod236, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod237, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod238, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod239, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod240, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod241, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod242, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod243, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod244, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod245, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod246, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod247, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod248, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod249, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod250, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod251, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod252, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod253, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod254, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod255, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod256, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod257, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod258, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod259, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod260, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod261, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod262, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod263, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod264, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod265, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod266, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod267, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod268, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod269, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod270, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod271, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod272, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod273, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod274, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod275, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod276, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod277, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod278, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod279, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod280, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod281, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod282, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod283, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod284, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod285, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod286, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod287, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod288, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod289, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod290, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod291, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod292, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod293, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod294, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod295, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod296, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod297, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod298, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod299, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod300, ai_c_move, 1, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess2_move_c_action5 = {99,priestess2_frames_c_action5, ai_c_cycleend}; + + +animframe_t priestess2_frames_c_action6[] = +{ + FRAME_hpod301, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod302, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod303, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod304, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod305, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod306, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod307, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod308, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod309, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod310, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod311, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod312, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod313, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod314, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod315, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod316, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod317, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod318, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod319, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod320, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod321, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod322, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod323, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod324, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod325, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod326, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod327, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod328, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod329, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod330, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod331, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod332, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod333, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod334, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod335, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod336, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod337, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod338, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod339, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod340, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod341, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod342, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod343, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod344, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod345, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod346, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_hpod347, ai_c_move, 1, 0, 0, NULL, 0, NULL, + FRAME_hpod348, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess2_move_c_action6 = {48,priestess2_frames_c_action6, ai_c_cycleend}; + +animframe_t priestess2_frames_c_action7[] = +{ + FRAME_hpod349, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod350, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod351, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod352, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod353, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod354, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod355, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod356, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod357, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod358, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod359, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod360, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod361, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod362, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod363, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod364, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod365, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod366, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod367, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod368, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod369, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod370, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod371, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod372, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod373, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod374, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod375, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod376, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod377, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod378, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod379, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod380, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod381, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod382, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod383, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod384, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod385, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod386, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod387, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod388, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod389, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod390, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod391, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod392, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod393, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod394, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod395, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod396, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod397, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod398, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod399, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod400, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod401, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod402, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod403, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod404, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod405, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod406, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod407, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod408, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod409, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod410, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod411, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod412, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod413, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod414, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod415, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod416, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod417, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod418, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod419, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod420, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod421, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod422, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod423, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod424, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod425, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod426, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod427, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod428, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod429, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod430, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod431, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod432, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod433, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod434, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod435, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod436, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod437, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod438, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod439, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod440, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod441, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod442, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod443, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod444, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod445, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod446, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod447, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod448, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod449, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod450, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod451, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod452, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod453, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod454, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod455, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod456, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod457, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod458, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod459, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod460, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod461, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod462, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod463, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod464, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod465, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod466, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod467, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod468, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod469, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod470, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess2_move_c_action7 = {122,priestess2_frames_c_action7, ai_c_cycleend}; + + +animframe_t priestess2_frames_c_idle1[] = +{ + FRAME_hpod1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hpod1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess2_move_c_idle1 = {3,priestess2_frames_c_idle1, ai_c_cycleend}; + + + + diff --git a/Toolkit/Programming/GameCode/game/c_priestess2_anim.h b/Toolkit/Programming/GameCode/game/c_priestess2_anim.h new file mode 100644 index 0000000..39d99c2 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_priestess2_anim.h @@ -0,0 +1,482 @@ +// r:\art\models/monsters\highpriestess\pod_scene + +// This file generated by qdata - Do NOT Modify + +#define FRAME_hpod1 0 +#define FRAME_hpod2 1 +#define FRAME_hpod3 2 +#define FRAME_hpod4 3 +#define FRAME_hpod5 4 +#define FRAME_hpod6 5 +#define FRAME_hpod7 6 +#define FRAME_hpod8 7 +#define FRAME_hpod9 8 +#define FRAME_hpod10 9 +#define FRAME_hpod11 10 +#define FRAME_hpod12 11 +#define FRAME_hpod13 12 +#define FRAME_hpod14 13 +#define FRAME_hpod15 14 +#define FRAME_hpod16 15 +#define FRAME_hpod17 16 +#define FRAME_hpod18 17 +#define FRAME_hpod19 18 +#define FRAME_hpod20 19 +#define FRAME_hpod21 20 +#define FRAME_hpod22 21 +#define FRAME_hpod23 22 +#define FRAME_hpod24 23 +#define FRAME_hpod25 24 +#define FRAME_hpod26 25 +#define FRAME_hpod27 26 +#define FRAME_hpod28 27 +#define FRAME_hpod29 28 +#define FRAME_hpod30 29 +#define FRAME_hpod31 30 +#define FRAME_hpod32 31 +#define FRAME_hpod33 32 +#define FRAME_hpod34 33 +#define FRAME_hpod35 34 +#define FRAME_hpod36 35 +#define FRAME_hpod37 36 +#define FRAME_hpod38 37 +#define FRAME_hpod39 38 +#define FRAME_hpod40 39 +#define FRAME_hpod41 40 +#define FRAME_hpod42 41 +#define FRAME_hpod43 42 +#define FRAME_hpod44 43 +#define FRAME_hpod45 44 +#define FRAME_hpod46 45 +#define FRAME_hpod47 46 +#define FRAME_hpod48 47 +#define FRAME_hpod49 48 +#define FRAME_hpod50 49 +#define FRAME_hpod51 50 +#define FRAME_hpod52 51 +#define FRAME_hpod53 52 +#define FRAME_hpod54 53 +#define FRAME_hpod55 54 +#define FRAME_hpod56 55 +#define FRAME_hpod57 56 +#define FRAME_hpod58 57 +#define FRAME_hpod59 58 +#define FRAME_hpod60 59 +#define FRAME_hpod61 60 +#define FRAME_hpod62 61 +#define FRAME_hpod63 62 +#define FRAME_hpod64 63 +#define FRAME_hpod65 64 +#define FRAME_hpod66 65 +#define FRAME_hpod67 66 +#define FRAME_hpod68 67 +#define FRAME_hpod69 68 +#define FRAME_hpod70 69 +#define FRAME_hpod71 70 +#define FRAME_hpod72 71 +#define FRAME_hpod73 72 +#define FRAME_hpod74 73 +#define FRAME_hpod75 74 +#define FRAME_hpod76 75 +#define FRAME_hpod77 76 +#define FRAME_hpod78 77 +#define FRAME_hpod79 78 +#define FRAME_hpod80 79 +#define FRAME_hpod81 80 +#define FRAME_hpod82 81 +#define FRAME_hpod83 82 +#define FRAME_hpod84 83 +#define FRAME_hpod85 84 +#define FRAME_hpod86 85 +#define FRAME_hpod87 86 +#define FRAME_hpod88 87 +#define FRAME_hpod89 88 +#define FRAME_hpod90 89 +#define FRAME_hpod91 90 +#define FRAME_hpod92 91 +#define FRAME_hpod93 92 +#define FRAME_hpod94 93 +#define FRAME_hpod95 94 +#define FRAME_hpod96 95 +#define FRAME_hpod97 96 +#define FRAME_hpod98 97 +#define FRAME_hpod99 98 +#define FRAME_hpod100 99 +#define FRAME_hpod101 100 +#define FRAME_hpod102 101 +#define FRAME_hpod103 102 +#define FRAME_hpod104 103 +#define FRAME_hpod105 104 +#define FRAME_hpod106 105 +#define FRAME_hpod107 106 +#define FRAME_hpod108 107 +#define FRAME_hpod109 108 +#define FRAME_hpod110 109 +#define FRAME_hpod111 110 +#define FRAME_hpod112 111 +#define FRAME_hpod113 112 +#define FRAME_hpod114 113 +#define FRAME_hpod115 114 +#define FRAME_hpod116 115 +#define FRAME_hpod117 116 +#define FRAME_hpod118 117 +#define FRAME_hpod119 118 +#define FRAME_hpod120 119 +#define FRAME_hpod121 120 +#define FRAME_hpod122 121 +#define FRAME_hpod123 122 +#define FRAME_hpod124 123 +#define FRAME_hpod125 124 +#define FRAME_hpod126 125 +#define FRAME_hpod127 126 +#define FRAME_hpod128 127 +#define FRAME_hpod129 128 +#define FRAME_hpod130 129 +#define FRAME_hpod131 130 +#define FRAME_hpod132 131 +#define FRAME_hpod133 132 +#define FRAME_hpod134 133 +#define FRAME_hpod135 134 +#define FRAME_hpod136 135 +#define FRAME_hpod137 136 +#define FRAME_hpod138 137 +#define FRAME_hpod139 138 +#define FRAME_hpod140 139 +#define FRAME_hpod141 140 +#define FRAME_hpod142 141 +#define FRAME_hpod143 142 +#define FRAME_hpod144 143 +#define FRAME_hpod145 144 +#define FRAME_hpod146 145 +#define FRAME_hpod147 146 +#define FRAME_hpod148 147 +#define FRAME_hpod149 148 +#define FRAME_hpod150 149 +#define FRAME_hpod151 150 +#define FRAME_hpod152 151 +#define FRAME_hpod153 152 +#define FRAME_hpod154 153 +#define FRAME_hpod155 154 +#define FRAME_hpod156 155 +#define FRAME_hpod157 156 +#define FRAME_hpod158 157 +#define FRAME_hpod159 158 +#define FRAME_hpod160 159 +#define FRAME_hpod161 160 +#define FRAME_hpod162 161 +#define FRAME_hpod163 162 +#define FRAME_hpod164 163 +#define FRAME_hpod165 164 +#define FRAME_hpod166 165 +#define FRAME_hpod167 166 +#define FRAME_hpod168 167 +#define FRAME_hpod169 168 +#define FRAME_hpod170 169 +#define FRAME_hpod171 170 +#define FRAME_hpod172 171 +#define FRAME_hpod173 172 +#define FRAME_hpod174 173 +#define FRAME_hpod175 174 +#define FRAME_hpod176 175 +#define FRAME_hpod177 176 +#define FRAME_hpod178 177 +#define FRAME_hpod179 178 +#define FRAME_hpod180 179 +#define FRAME_hpod181 180 +#define FRAME_hpod182 181 +#define FRAME_hpod183 182 +#define FRAME_hpod184 183 +#define FRAME_hpod185 184 +#define FRAME_hpod186 185 +#define FRAME_hpod187 186 +#define FRAME_hpod188 187 +#define FRAME_hpod189 188 +#define FRAME_hpod190 189 +#define FRAME_hpod191 190 +#define FRAME_hpod192 191 +#define FRAME_hpod193 192 +#define FRAME_hpod194 193 +#define FRAME_hpod195 194 +#define FRAME_hpod196 195 +#define FRAME_hpod197 196 +#define FRAME_hpod198 197 +#define FRAME_hpod199 198 +#define FRAME_hpod200 199 +#define FRAME_hpod201 200 +#define FRAME_hpod202 201 +#define FRAME_hpod203 202 +#define FRAME_hpod204 203 +#define FRAME_hpod205 204 +#define FRAME_hpod206 205 +#define FRAME_hpod207 206 +#define FRAME_hpod208 207 +#define FRAME_hpod209 208 +#define FRAME_hpod210 209 +#define FRAME_hpod211 210 +#define FRAME_hpod212 211 +#define FRAME_hpod213 212 +#define FRAME_hpod214 213 +#define FRAME_hpod215 214 +#define FRAME_hpod216 215 +#define FRAME_hpod217 216 +#define FRAME_hpod218 217 +#define FRAME_hpod219 218 +#define FRAME_hpod220 219 +#define FRAME_hpod221 220 +#define FRAME_hpod222 221 +#define FRAME_hpod223 222 +#define FRAME_hpod224 223 +#define FRAME_hpod225 224 +#define FRAME_hpod226 225 +#define FRAME_hpod227 226 +#define FRAME_hpod228 227 +#define FRAME_hpod229 228 +#define FRAME_hpod230 229 +#define FRAME_hpod231 230 +#define FRAME_hpod232 231 +#define FRAME_hpod233 232 +#define FRAME_hpod234 233 +#define FRAME_hpod235 234 +#define FRAME_hpod236 235 +#define FRAME_hpod237 236 +#define FRAME_hpod238 237 +#define FRAME_hpod239 238 +#define FRAME_hpod240 239 +#define FRAME_hpod241 240 +#define FRAME_hpod242 241 +#define FRAME_hpod243 242 +#define FRAME_hpod244 243 +#define FRAME_hpod245 244 +#define FRAME_hpod246 245 +#define FRAME_hpod247 246 +#define FRAME_hpod248 247 +#define FRAME_hpod249 248 +#define FRAME_hpod250 249 +#define FRAME_hpod251 250 +#define FRAME_hpod252 251 +#define FRAME_hpod253 252 +#define FRAME_hpod254 253 +#define FRAME_hpod255 254 +#define FRAME_hpod256 255 +#define FRAME_hpod257 256 +#define FRAME_hpod258 257 +#define FRAME_hpod259 258 +#define FRAME_hpod260 259 +#define FRAME_hpod261 260 +#define FRAME_hpod262 261 +#define FRAME_hpod263 262 +#define FRAME_hpod264 263 +#define FRAME_hpod265 264 +#define FRAME_hpod266 265 +#define FRAME_hpod267 266 +#define FRAME_hpod268 267 +#define FRAME_hpod269 268 +#define FRAME_hpod270 269 +#define FRAME_hpod271 270 +#define FRAME_hpod272 271 +#define FRAME_hpod273 272 +#define FRAME_hpod274 273 +#define FRAME_hpod275 274 +#define FRAME_hpod276 275 +#define FRAME_hpod277 276 +#define FRAME_hpod278 277 +#define FRAME_hpod279 278 +#define FRAME_hpod280 279 +#define FRAME_hpod281 280 +#define FRAME_hpod282 281 +#define FRAME_hpod283 282 +#define FRAME_hpod284 283 +#define FRAME_hpod285 284 +#define FRAME_hpod286 285 +#define FRAME_hpod287 286 +#define FRAME_hpod288 287 +#define FRAME_hpod289 288 +#define FRAME_hpod290 289 +#define FRAME_hpod291 290 +#define FRAME_hpod292 291 +#define FRAME_hpod293 292 +#define FRAME_hpod294 293 +#define FRAME_hpod295 294 +#define FRAME_hpod296 295 +#define FRAME_hpod297 296 +#define FRAME_hpod298 297 +#define FRAME_hpod299 298 +#define FRAME_hpod300 299 +#define FRAME_hpod301 300 +#define FRAME_hpod302 301 +#define FRAME_hpod303 302 +#define FRAME_hpod304 303 +#define FRAME_hpod305 304 +#define FRAME_hpod306 305 +#define FRAME_hpod307 306 +#define FRAME_hpod308 307 +#define FRAME_hpod309 308 +#define FRAME_hpod310 309 +#define FRAME_hpod311 310 +#define FRAME_hpod312 311 +#define FRAME_hpod313 312 +#define FRAME_hpod314 313 +#define FRAME_hpod315 314 +#define FRAME_hpod316 315 +#define FRAME_hpod317 316 +#define FRAME_hpod318 317 +#define FRAME_hpod319 318 +#define FRAME_hpod320 319 +#define FRAME_hpod321 320 +#define FRAME_hpod322 321 +#define FRAME_hpod323 322 +#define FRAME_hpod324 323 +#define FRAME_hpod325 324 +#define FRAME_hpod326 325 +#define FRAME_hpod327 326 +#define FRAME_hpod328 327 +#define FRAME_hpod329 328 +#define FRAME_hpod330 329 +#define FRAME_hpod331 330 +#define FRAME_hpod332 331 +#define FRAME_hpod333 332 +#define FRAME_hpod334 333 +#define FRAME_hpod335 334 +#define FRAME_hpod336 335 +#define FRAME_hpod337 336 +#define FRAME_hpod338 337 +#define FRAME_hpod339 338 +#define FRAME_hpod340 339 +#define FRAME_hpod341 340 +#define FRAME_hpod342 341 +#define FRAME_hpod343 342 +#define FRAME_hpod344 343 +#define FRAME_hpod345 344 +#define FRAME_hpod346 345 +#define FRAME_hpod347 346 +#define FRAME_hpod348 347 +#define FRAME_hpod349 348 +#define FRAME_hpod350 349 +#define FRAME_hpod351 350 +#define FRAME_hpod352 351 +#define FRAME_hpod353 352 +#define FRAME_hpod354 353 +#define FRAME_hpod355 354 +#define FRAME_hpod356 355 +#define FRAME_hpod357 356 +#define FRAME_hpod358 357 +#define FRAME_hpod359 358 +#define FRAME_hpod360 359 +#define FRAME_hpod361 360 +#define FRAME_hpod362 361 +#define FRAME_hpod363 362 +#define FRAME_hpod364 363 +#define FRAME_hpod365 364 +#define FRAME_hpod366 365 +#define FRAME_hpod367 366 +#define FRAME_hpod368 367 +#define FRAME_hpod369 368 +#define FRAME_hpod370 369 +#define FRAME_hpod371 370 +#define FRAME_hpod372 371 +#define FRAME_hpod373 372 +#define FRAME_hpod374 373 +#define FRAME_hpod375 374 +#define FRAME_hpod376 375 +#define FRAME_hpod377 376 +#define FRAME_hpod378 377 +#define FRAME_hpod379 378 +#define FRAME_hpod380 379 +#define FRAME_hpod381 380 +#define FRAME_hpod382 381 +#define FRAME_hpod383 382 +#define FRAME_hpod384 383 +#define FRAME_hpod385 384 +#define FRAME_hpod386 385 +#define FRAME_hpod387 386 +#define FRAME_hpod388 387 +#define FRAME_hpod389 388 +#define FRAME_hpod390 389 +#define FRAME_hpod391 390 +#define FRAME_hpod392 391 +#define FRAME_hpod393 392 +#define FRAME_hpod394 393 +#define FRAME_hpod395 394 +#define FRAME_hpod396 395 +#define FRAME_hpod397 396 +#define FRAME_hpod398 397 +#define FRAME_hpod399 398 +#define FRAME_hpod400 399 +#define FRAME_hpod401 400 +#define FRAME_hpod402 401 +#define FRAME_hpod403 402 +#define FRAME_hpod404 403 +#define FRAME_hpod405 404 +#define FRAME_hpod406 405 +#define FRAME_hpod407 406 +#define FRAME_hpod408 407 +#define FRAME_hpod409 408 +#define FRAME_hpod410 409 +#define FRAME_hpod411 410 +#define FRAME_hpod412 411 +#define FRAME_hpod413 412 +#define FRAME_hpod414 413 +#define FRAME_hpod415 414 +#define FRAME_hpod416 415 +#define FRAME_hpod417 416 +#define FRAME_hpod418 417 +#define FRAME_hpod419 418 +#define FRAME_hpod420 419 +#define FRAME_hpod421 420 +#define FRAME_hpod422 421 +#define FRAME_hpod423 422 +#define FRAME_hpod424 423 +#define FRAME_hpod425 424 +#define FRAME_hpod426 425 +#define FRAME_hpod427 426 +#define FRAME_hpod428 427 +#define FRAME_hpod429 428 +#define FRAME_hpod430 429 +#define FRAME_hpod431 430 +#define FRAME_hpod432 431 +#define FRAME_hpod433 432 +#define FRAME_hpod434 433 +#define FRAME_hpod435 434 +#define FRAME_hpod436 435 +#define FRAME_hpod437 436 +#define FRAME_hpod438 437 +#define FRAME_hpod439 438 +#define FRAME_hpod440 439 +#define FRAME_hpod441 440 +#define FRAME_hpod442 441 +#define FRAME_hpod443 442 +#define FRAME_hpod444 443 +#define FRAME_hpod445 444 +#define FRAME_hpod446 445 +#define FRAME_hpod447 446 +#define FRAME_hpod448 447 +#define FRAME_hpod449 448 +#define FRAME_hpod450 449 +#define FRAME_hpod451 450 +#define FRAME_hpod452 451 +#define FRAME_hpod453 452 +#define FRAME_hpod454 453 +#define FRAME_hpod455 454 +#define FRAME_hpod456 455 +#define FRAME_hpod457 456 +#define FRAME_hpod458 457 +#define FRAME_hpod459 458 +#define FRAME_hpod460 459 +#define FRAME_hpod461 460 +#define FRAME_hpod462 461 +#define FRAME_hpod463 462 +#define FRAME_hpod464 463 +#define FRAME_hpod465 464 +#define FRAME_hpod466 465 +#define FRAME_hpod467 466 +#define FRAME_hpod468 467 +#define FRAME_hpod469 468 +#define FRAME_hpod470 469 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 3 + +#define MESH_BASEBIN 0 +#define MESH__STAFF 1 +#define MESH__QUEENBODY 2 diff --git a/Toolkit/Programming/GameCode/game/c_priestess_anim.c b/Toolkit/Programming/GameCode/game/c_priestess_anim.c new file mode 100644 index 0000000..e56c7cf --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_priestess_anim.c @@ -0,0 +1,1712 @@ +//============================================================================== +// +// m_victimSsitra_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_priestess_anim.h" +#include "c_priestess.h" +#include "c_ai.h" + + +animframe_t priestess_frames_c_action1[] = +{ + FRAME_hltalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess_move_c_action1 = {30,priestess_frames_c_action1, ai_c_cycleend}; + + + +animframe_t priestess_frames_c_action2[] = +{ + FRAME_hlidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_action2 = {35,priestess_frames_c_action2, ai_c_cycleend}; + + + + + +animframe_t priestess_frames_c_action3[] = +{ + FRAME_hltalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hltalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk71, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk72, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk73, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk74, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk75, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk76, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk77, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk78, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk79, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +// FRAME_hltalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, +// FRAME_hltalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_action3 = {151,priestess_frames_c_action3, ai_c_cycleend}; + + +animframe_t priestess_frames_c_action4[] = +{ + FRAME_hlidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hlidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hltalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hltalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hltalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_action4 = {216,priestess_frames_c_action4, ai_c_cycleend}; + + +animframe_t priestess_frames_c_action5[] = +{ + FRAME_hlrtran1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlrtran15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + + FRAME_hridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hit1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hit72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + + FRAME_hridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess_move_c_action5 = {196,priestess_frames_c_action5, ai_c_cycleend}; + + +animframe_t priestess_frames_c_action6[] = +{ + FRAME_hridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess_move_c_action6 = {11,priestess_frames_c_action6, ai_c_cycleend}; + + + +animframe_t priestess_frames_c_action7[] = +{ + FRAME_hbutyou1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_action7 = {11,priestess_frames_c_action7, ai_c_cycleend}; + + + +animframe_t priestess_frames_c_action8[] = +{ + FRAME_hbutyou12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou76, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_action8 = {65,priestess_frames_c_action8, ai_c_cycleend}; + +animframe_t priestess_frames_c_action9[] = +{ + FRAME_hbutyou77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou129, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou130, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou131, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou132, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou133, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou134, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou135, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou136, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou137, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou138, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou139, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou140, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou141, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou142, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou143, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou144, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou145, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou146, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou147, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou148, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou149, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou150, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou151, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou152, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou153, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou154, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou155, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou156, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou157, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou158, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou159, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou160, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou161, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou162, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou163, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou164, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou165, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou166, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou167, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou168, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou169, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hbutyou170, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hlidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess_move_c_action9 = {102,priestess_frames_c_action9, ai_c_cycleend}; + +animframe_t priestess_frames_c_action10[] = +{ + FRAME_hlidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess_move_c_action10 = {40,priestess_frames_c_action10, ai_c_cycleend}; + +animframe_t priestess_frames_c_action11[] = +{ + FRAME_hnotfully1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hnotfully101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully129, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully130, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully131, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully132, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully133, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully134, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully135, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully136, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully137, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully138, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully139, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully140, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully141, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully142, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully143, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully144, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully145, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully146, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully147, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully148, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully149, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully150, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully151, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully152, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully153, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully154, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully155, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully156, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully157, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully158, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully159, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully160, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully161, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully162, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully163, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully164, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully165, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully166, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully167, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully168, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully169, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully170, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hnotfully171, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hlidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess_move_c_action11 = {179,priestess_frames_c_action11, ai_c_cycleend}; + + +animframe_t priestess_frames_c_action12[] = +{ + FRAME_hlidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hlidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess_move_c_action12 = {53,priestess_frames_c_action12, ai_c_cycleend}; + +animframe_t priestess_frames_c_action13[] = +{ + FRAME_hltalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hltalk58, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_action13 = {58,priestess_frames_c_action13, ai_c_cycleend}; + +animframe_t priestess_frames_c_action14[] = +{ + FRAME_hlidle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hlidle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_action14 = {13,priestess_frames_c_action14, ai_c_cycleend}; + +animframe_t priestess_frames_c_action15[] = +{ + FRAME_hrtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hrtalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtalk62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess_move_c_action15 = {142,priestess_frames_c_action15, ai_c_cycleend}; + +animframe_t priestess_frames_c_action16[] = +{ + FRAME_hridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hridle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hridle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + + FRAME_hcast1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hcast71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + +}; +animmove_t priestess_move_c_action16 = {169,priestess_frames_c_action16, ai_c_cycleend}; + + + + + +animframe_t priestess_frames_c_idle1[] = +{ + FRAME_idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_idle1 = {18,priestess_frames_c_idle1, ai_c_cycleend}; + + + +animframe_t priestess_frames_c_idle2[] = +{ + FRAME_hpstart1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_idle2 = {1,priestess_frames_c_idle2, ai_c_cycleend}; + + + +animframe_t priestess_frames_c_walk1[] = +{ + FRAME_walk1, ai_c_move, 6, 0, 0, NULL, 0, NULL, + FRAME_walk2, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_walk3, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_walk4, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_walk5, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_walk6, ai_c_move, 6, 0, 0, NULL, 0, NULL, + FRAME_walk7, ai_c_move, 6, 0, 0, NULL, 0, NULL, + FRAME_walk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walk9, ai_c_move, 6, 0, 0, NULL, 0, NULL, + FRAME_walk10, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_walk11, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_walk12, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_walk13, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_walk14, ai_c_move, 6, 0, 0, NULL, 0, NULL, + FRAME_walk15, ai_c_move, 6, 0, 0, NULL, 0, NULL, + FRAME_walk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_walk1 = {16,priestess_frames_c_walk1, ai_c_cycleend}; + + + + +animframe_t priestess_frames_c_backpedal1 [] = +{ + FRAME_backup3, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup4, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup5, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup6, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup7, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup8, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup9, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup10, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup11, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup12, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup13, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_backup14, ai_c_move, -8, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_c_backpedal1 = {12,priestess_frames_c_backpedal1, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/c_priestess_anim.h b/Toolkit/Programming/GameCode/game/c_priestess_anim.h new file mode 100644 index 0000000..8dd9a37 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_priestess_anim.h @@ -0,0 +1,857 @@ +// R:\Art\models/monsters\highpriestess\cinematic + +// This file generated by qdata - Do NOT Modify + +#define FRAME_backup1 0 +#define FRAME_backup2 1 +#define FRAME_backup3 2 +#define FRAME_backup4 3 +#define FRAME_backup5 4 +#define FRAME_backup6 5 +#define FRAME_backup7 6 +#define FRAME_backup8 7 +#define FRAME_backup9 8 +#define FRAME_backup10 9 +#define FRAME_backup11 10 +#define FRAME_backup12 11 +#define FRAME_backup13 12 +#define FRAME_backup14 13 +#define FRAME_hbutyou1 14 +#define FRAME_hbutyou2 15 +#define FRAME_hbutyou3 16 +#define FRAME_hbutyou4 17 +#define FRAME_hbutyou5 18 +#define FRAME_hbutyou6 19 +#define FRAME_hbutyou7 20 +#define FRAME_hbutyou8 21 +#define FRAME_hbutyou9 22 +#define FRAME_hbutyou10 23 +#define FRAME_hbutyou11 24 +#define FRAME_hbutyou12 25 +#define FRAME_hbutyou13 26 +#define FRAME_hbutyou14 27 +#define FRAME_hbutyou15 28 +#define FRAME_hbutyou16 29 +#define FRAME_hbutyou17 30 +#define FRAME_hbutyou18 31 +#define FRAME_hbutyou19 32 +#define FRAME_hbutyou20 33 +#define FRAME_hbutyou21 34 +#define FRAME_hbutyou22 35 +#define FRAME_hbutyou23 36 +#define FRAME_hbutyou24 37 +#define FRAME_hbutyou25 38 +#define FRAME_hbutyou26 39 +#define FRAME_hbutyou27 40 +#define FRAME_hbutyou28 41 +#define FRAME_hbutyou29 42 +#define FRAME_hbutyou30 43 +#define FRAME_hbutyou31 44 +#define FRAME_hbutyou32 45 +#define FRAME_hbutyou33 46 +#define FRAME_hbutyou34 47 +#define FRAME_hbutyou35 48 +#define FRAME_hbutyou36 49 +#define FRAME_hbutyou37 50 +#define FRAME_hbutyou38 51 +#define FRAME_hbutyou39 52 +#define FRAME_hbutyou40 53 +#define FRAME_hbutyou41 54 +#define FRAME_hbutyou42 55 +#define FRAME_hbutyou43 56 +#define FRAME_hbutyou44 57 +#define FRAME_hbutyou45 58 +#define FRAME_hbutyou46 59 +#define FRAME_hbutyou47 60 +#define FRAME_hbutyou48 61 +#define FRAME_hbutyou49 62 +#define FRAME_hbutyou50 63 +#define FRAME_hbutyou51 64 +#define FRAME_hbutyou52 65 +#define FRAME_hbutyou53 66 +#define FRAME_hbutyou54 67 +#define FRAME_hbutyou55 68 +#define FRAME_hbutyou56 69 +#define FRAME_hbutyou57 70 +#define FRAME_hbutyou58 71 +#define FRAME_hbutyou59 72 +#define FRAME_hbutyou60 73 +#define FRAME_hbutyou61 74 +#define FRAME_hbutyou62 75 +#define FRAME_hbutyou63 76 +#define FRAME_hbutyou64 77 +#define FRAME_hbutyou65 78 +#define FRAME_hbutyou66 79 +#define FRAME_hbutyou67 80 +#define FRAME_hbutyou68 81 +#define FRAME_hbutyou69 82 +#define FRAME_hbutyou70 83 +#define FRAME_hbutyou71 84 +#define FRAME_hbutyou72 85 +#define FRAME_hbutyou73 86 +#define FRAME_hbutyou74 87 +#define FRAME_hbutyou75 88 +#define FRAME_hbutyou76 89 +#define FRAME_hbutyou77 90 +#define FRAME_hbutyou78 91 +#define FRAME_hbutyou79 92 +#define FRAME_hbutyou80 93 +#define FRAME_hbutyou81 94 +#define FRAME_hbutyou82 95 +#define FRAME_hbutyou83 96 +#define FRAME_hbutyou84 97 +#define FRAME_hbutyou85 98 +#define FRAME_hbutyou86 99 +#define FRAME_hbutyou87 100 +#define FRAME_hbutyou88 101 +#define FRAME_hbutyou89 102 +#define FRAME_hbutyou90 103 +#define FRAME_hbutyou91 104 +#define FRAME_hbutyou92 105 +#define FRAME_hbutyou93 106 +#define FRAME_hbutyou94 107 +#define FRAME_hbutyou95 108 +#define FRAME_hbutyou96 109 +#define FRAME_hbutyou97 110 +#define FRAME_hbutyou98 111 +#define FRAME_hbutyou99 112 +#define FRAME_hbutyou100 113 +#define FRAME_hbutyou101 114 +#define FRAME_hbutyou102 115 +#define FRAME_hbutyou103 116 +#define FRAME_hbutyou104 117 +#define FRAME_hbutyou105 118 +#define FRAME_hbutyou106 119 +#define FRAME_hbutyou107 120 +#define FRAME_hbutyou108 121 +#define FRAME_hbutyou109 122 +#define FRAME_hbutyou110 123 +#define FRAME_hbutyou111 124 +#define FRAME_hbutyou112 125 +#define FRAME_hbutyou113 126 +#define FRAME_hbutyou114 127 +#define FRAME_hbutyou115 128 +#define FRAME_hbutyou116 129 +#define FRAME_hbutyou117 130 +#define FRAME_hbutyou118 131 +#define FRAME_hbutyou119 132 +#define FRAME_hbutyou120 133 +#define FRAME_hbutyou121 134 +#define FRAME_hbutyou122 135 +#define FRAME_hbutyou123 136 +#define FRAME_hbutyou124 137 +#define FRAME_hbutyou125 138 +#define FRAME_hbutyou126 139 +#define FRAME_hbutyou127 140 +#define FRAME_hbutyou128 141 +#define FRAME_hbutyou129 142 +#define FRAME_hbutyou130 143 +#define FRAME_hbutyou131 144 +#define FRAME_hbutyou132 145 +#define FRAME_hbutyou133 146 +#define FRAME_hbutyou134 147 +#define FRAME_hbutyou135 148 +#define FRAME_hbutyou136 149 +#define FRAME_hbutyou137 150 +#define FRAME_hbutyou138 151 +#define FRAME_hbutyou139 152 +#define FRAME_hbutyou140 153 +#define FRAME_hbutyou141 154 +#define FRAME_hbutyou142 155 +#define FRAME_hbutyou143 156 +#define FRAME_hbutyou144 157 +#define FRAME_hbutyou145 158 +#define FRAME_hbutyou146 159 +#define FRAME_hbutyou147 160 +#define FRAME_hbutyou148 161 +#define FRAME_hbutyou149 162 +#define FRAME_hbutyou150 163 +#define FRAME_hbutyou151 164 +#define FRAME_hbutyou152 165 +#define FRAME_hbutyou153 166 +#define FRAME_hbutyou154 167 +#define FRAME_hbutyou155 168 +#define FRAME_hbutyou156 169 +#define FRAME_hbutyou157 170 +#define FRAME_hbutyou158 171 +#define FRAME_hbutyou159 172 +#define FRAME_hbutyou160 173 +#define FRAME_hbutyou161 174 +#define FRAME_hbutyou162 175 +#define FRAME_hbutyou163 176 +#define FRAME_hbutyou164 177 +#define FRAME_hbutyou165 178 +#define FRAME_hbutyou166 179 +#define FRAME_hbutyou167 180 +#define FRAME_hbutyou168 181 +#define FRAME_hbutyou169 182 +#define FRAME_hbutyou170 183 +#define FRAME_hcast1 184 +#define FRAME_hcast2 185 +#define FRAME_hcast3 186 +#define FRAME_hcast4 187 +#define FRAME_hcast5 188 +#define FRAME_hcast6 189 +#define FRAME_hcast7 190 +#define FRAME_hcast8 191 +#define FRAME_hcast9 192 +#define FRAME_hcast10 193 +#define FRAME_hcast11 194 +#define FRAME_hcast12 195 +#define FRAME_hcast13 196 +#define FRAME_hcast14 197 +#define FRAME_hcast15 198 +#define FRAME_hcast16 199 +#define FRAME_hcast17 200 +#define FRAME_hcast18 201 +#define FRAME_hcast19 202 +#define FRAME_hcast20 203 +#define FRAME_hcast21 204 +#define FRAME_hcast22 205 +#define FRAME_hcast23 206 +#define FRAME_hcast24 207 +#define FRAME_hcast25 208 +#define FRAME_hcast26 209 +#define FRAME_hcast27 210 +#define FRAME_hcast28 211 +#define FRAME_hcast29 212 +#define FRAME_hcast30 213 +#define FRAME_hcast31 214 +#define FRAME_hcast32 215 +#define FRAME_hcast33 216 +#define FRAME_hcast34 217 +#define FRAME_hcast35 218 +#define FRAME_hcast36 219 +#define FRAME_hcast37 220 +#define FRAME_hcast38 221 +#define FRAME_hcast39 222 +#define FRAME_hcast40 223 +#define FRAME_hcast41 224 +#define FRAME_hcast42 225 +#define FRAME_hcast43 226 +#define FRAME_hcast44 227 +#define FRAME_hcast45 228 +#define FRAME_hcast46 229 +#define FRAME_hcast47 230 +#define FRAME_hcast48 231 +#define FRAME_hcast49 232 +#define FRAME_hcast50 233 +#define FRAME_hcast51 234 +#define FRAME_hcast52 235 +#define FRAME_hcast53 236 +#define FRAME_hcast54 237 +#define FRAME_hcast55 238 +#define FRAME_hcast56 239 +#define FRAME_hcast57 240 +#define FRAME_hcast58 241 +#define FRAME_hcast59 242 +#define FRAME_hcast60 243 +#define FRAME_hcast61 244 +#define FRAME_hcast62 245 +#define FRAME_hcast63 246 +#define FRAME_hcast64 247 +#define FRAME_hcast65 248 +#define FRAME_hcast66 249 +#define FRAME_hcast67 250 +#define FRAME_hcast68 251 +#define FRAME_hcast69 252 +#define FRAME_hcast70 253 +#define FRAME_hcast71 254 +#define FRAME_hit1 255 +#define FRAME_hit2 256 +#define FRAME_hit3 257 +#define FRAME_hit4 258 +#define FRAME_hit5 259 +#define FRAME_hit6 260 +#define FRAME_hit7 261 +#define FRAME_hit8 262 +#define FRAME_hit9 263 +#define FRAME_hit10 264 +#define FRAME_hit11 265 +#define FRAME_hit12 266 +#define FRAME_hit13 267 +#define FRAME_hit14 268 +#define FRAME_hit15 269 +#define FRAME_hit16 270 +#define FRAME_hit17 271 +#define FRAME_hit18 272 +#define FRAME_hit19 273 +#define FRAME_hit20 274 +#define FRAME_hit21 275 +#define FRAME_hit22 276 +#define FRAME_hit23 277 +#define FRAME_hit24 278 +#define FRAME_hit25 279 +#define FRAME_hit26 280 +#define FRAME_hit27 281 +#define FRAME_hit28 282 +#define FRAME_hit29 283 +#define FRAME_hit30 284 +#define FRAME_hit31 285 +#define FRAME_hit32 286 +#define FRAME_hit33 287 +#define FRAME_hit34 288 +#define FRAME_hit35 289 +#define FRAME_hit36 290 +#define FRAME_hit37 291 +#define FRAME_hit38 292 +#define FRAME_hit39 293 +#define FRAME_hit40 294 +#define FRAME_hit41 295 +#define FRAME_hit42 296 +#define FRAME_hit43 297 +#define FRAME_hit44 298 +#define FRAME_hit45 299 +#define FRAME_hit46 300 +#define FRAME_hit47 301 +#define FRAME_hit48 302 +#define FRAME_hit49 303 +#define FRAME_hit50 304 +#define FRAME_hit51 305 +#define FRAME_hit52 306 +#define FRAME_hit53 307 +#define FRAME_hit54 308 +#define FRAME_hit55 309 +#define FRAME_hit56 310 +#define FRAME_hit57 311 +#define FRAME_hit58 312 +#define FRAME_hit59 313 +#define FRAME_hit60 314 +#define FRAME_hit61 315 +#define FRAME_hit62 316 +#define FRAME_hit63 317 +#define FRAME_hit64 318 +#define FRAME_hit65 319 +#define FRAME_hit66 320 +#define FRAME_hit67 321 +#define FRAME_hit68 322 +#define FRAME_hit69 323 +#define FRAME_hit70 324 +#define FRAME_hit71 325 +#define FRAME_hit72 326 +#define FRAME_hlidle1 327 +#define FRAME_hlidle2 328 +#define FRAME_hlidle3 329 +#define FRAME_hlidle4 330 +#define FRAME_hlidle5 331 +#define FRAME_hlidle6 332 +#define FRAME_hlidle7 333 +#define FRAME_hlidle8 334 +#define FRAME_hlidle9 335 +#define FRAME_hlidle10 336 +#define FRAME_hlidle11 337 +#define FRAME_hlidle12 338 +#define FRAME_hlidle13 339 +#define FRAME_hlidle14 340 +#define FRAME_hlidle15 341 +#define FRAME_hlidle16 342 +#define FRAME_hlidle17 343 +#define FRAME_hlidle18 344 +#define FRAME_hlidle19 345 +#define FRAME_hlidle20 346 +#define FRAME_hlidle21 347 +#define FRAME_hlidle22 348 +#define FRAME_hlidle23 349 +#define FRAME_hlidle24 350 +#define FRAME_hlidle25 351 +#define FRAME_hlidle26 352 +#define FRAME_hlidle27 353 +#define FRAME_hlidle28 354 +#define FRAME_hlidle29 355 +#define FRAME_hlidle30 356 +#define FRAME_hlidle31 357 +#define FRAME_hlidle32 358 +#define FRAME_hlidle33 359 +#define FRAME_hlidle34 360 +#define FRAME_hlidle35 361 +#define FRAME_hlidle36 362 +#define FRAME_hlidle37 363 +#define FRAME_hlidle38 364 +#define FRAME_hlidle39 365 +#define FRAME_hlidle40 366 +#define FRAME_hlrtran1 367 +#define FRAME_hlrtran2 368 +#define FRAME_hlrtran3 369 +#define FRAME_hlrtran4 370 +#define FRAME_hlrtran5 371 +#define FRAME_hlrtran6 372 +#define FRAME_hlrtran7 373 +#define FRAME_hlrtran8 374 +#define FRAME_hlrtran9 375 +#define FRAME_hlrtran10 376 +#define FRAME_hlrtran11 377 +#define FRAME_hlrtran12 378 +#define FRAME_hlrtran13 379 +#define FRAME_hlrtran14 380 +#define FRAME_hlrtran15 381 +#define FRAME_hltalk1 382 +#define FRAME_hltalk2 383 +#define FRAME_hltalk3 384 +#define FRAME_hltalk4 385 +#define FRAME_hltalk5 386 +#define FRAME_hltalk6 387 +#define FRAME_hltalk7 388 +#define FRAME_hltalk8 389 +#define FRAME_hltalk9 390 +#define FRAME_hltalk10 391 +#define FRAME_hltalk11 392 +#define FRAME_hltalk12 393 +#define FRAME_hltalk13 394 +#define FRAME_hltalk14 395 +#define FRAME_hltalk15 396 +#define FRAME_hltalk16 397 +#define FRAME_hltalk17 398 +#define FRAME_hltalk18 399 +#define FRAME_hltalk19 400 +#define FRAME_hltalk20 401 +#define FRAME_hltalk21 402 +#define FRAME_hltalk22 403 +#define FRAME_hltalk23 404 +#define FRAME_hltalk24 405 +#define FRAME_hltalk25 406 +#define FRAME_hltalk26 407 +#define FRAME_hltalk27 408 +#define FRAME_hltalk28 409 +#define FRAME_hltalk29 410 +#define FRAME_hltalk30 411 +#define FRAME_hltalk31 412 +#define FRAME_hltalk32 413 +#define FRAME_hltalk33 414 +#define FRAME_hltalk34 415 +#define FRAME_hltalk35 416 +#define FRAME_hltalk36 417 +#define FRAME_hltalk37 418 +#define FRAME_hltalk38 419 +#define FRAME_hltalk39 420 +#define FRAME_hltalk40 421 +#define FRAME_hltalk41 422 +#define FRAME_hltalk42 423 +#define FRAME_hltalk43 424 +#define FRAME_hltalk44 425 +#define FRAME_hltalk45 426 +#define FRAME_hltalk46 427 +#define FRAME_hltalk47 428 +#define FRAME_hltalk48 429 +#define FRAME_hltalk49 430 +#define FRAME_hltalk50 431 +#define FRAME_hltalk51 432 +#define FRAME_hltalk52 433 +#define FRAME_hltalk53 434 +#define FRAME_hltalk54 435 +#define FRAME_hltalk55 436 +#define FRAME_hltalk56 437 +#define FRAME_hltalk57 438 +#define FRAME_hltalk58 439 +#define FRAME_hltalk59 440 +#define FRAME_hltalk60 441 +#define FRAME_hltalk61 442 +#define FRAME_hltalk62 443 +#define FRAME_hltalk63 444 +#define FRAME_hltalk64 445 +#define FRAME_hltalk65 446 +#define FRAME_hltalk66 447 +#define FRAME_hltalk67 448 +#define FRAME_hltalk68 449 +#define FRAME_hltalk69 450 +#define FRAME_hltalk70 451 +#define FRAME_hltalk71 452 +#define FRAME_hltalk72 453 +#define FRAME_hltalk73 454 +#define FRAME_hltalk74 455 +#define FRAME_hltalk75 456 +#define FRAME_hltalk76 457 +#define FRAME_hltalk77 458 +#define FRAME_hltalk78 459 +#define FRAME_hltalk79 460 +#define FRAME_hltalk80 461 +#define FRAME_hnotfully1 462 +#define FRAME_hnotfully2 463 +#define FRAME_hnotfully3 464 +#define FRAME_hnotfully4 465 +#define FRAME_hnotfully5 466 +#define FRAME_hnotfully6 467 +#define FRAME_hnotfully7 468 +#define FRAME_hnotfully8 469 +#define FRAME_hnotfully9 470 +#define FRAME_hnotfully10 471 +#define FRAME_hnotfully11 472 +#define FRAME_hnotfully12 473 +#define FRAME_hnotfully13 474 +#define FRAME_hnotfully14 475 +#define FRAME_hnotfully15 476 +#define FRAME_hnotfully16 477 +#define FRAME_hnotfully17 478 +#define FRAME_hnotfully18 479 +#define FRAME_hnotfully19 480 +#define FRAME_hnotfully20 481 +#define FRAME_hnotfully21 482 +#define FRAME_hnotfully22 483 +#define FRAME_hnotfully23 484 +#define FRAME_hnotfully24 485 +#define FRAME_hnotfully25 486 +#define FRAME_hnotfully26 487 +#define FRAME_hnotfully27 488 +#define FRAME_hnotfully28 489 +#define FRAME_hnotfully29 490 +#define FRAME_hnotfully30 491 +#define FRAME_hnotfully31 492 +#define FRAME_hnotfully32 493 +#define FRAME_hnotfully33 494 +#define FRAME_hnotfully34 495 +#define FRAME_hnotfully35 496 +#define FRAME_hnotfully36 497 +#define FRAME_hnotfully37 498 +#define FRAME_hnotfully38 499 +#define FRAME_hnotfully39 500 +#define FRAME_hnotfully40 501 +#define FRAME_hnotfully41 502 +#define FRAME_hnotfully42 503 +#define FRAME_hnotfully43 504 +#define FRAME_hnotfully44 505 +#define FRAME_hnotfully45 506 +#define FRAME_hnotfully46 507 +#define FRAME_hnotfully47 508 +#define FRAME_hnotfully48 509 +#define FRAME_hnotfully49 510 +#define FRAME_hnotfully50 511 +#define FRAME_hnotfully51 512 +#define FRAME_hnotfully52 513 +#define FRAME_hnotfully53 514 +#define FRAME_hnotfully54 515 +#define FRAME_hnotfully55 516 +#define FRAME_hnotfully56 517 +#define FRAME_hnotfully57 518 +#define FRAME_hnotfully58 519 +#define FRAME_hnotfully59 520 +#define FRAME_hnotfully60 521 +#define FRAME_hnotfully61 522 +#define FRAME_hnotfully62 523 +#define FRAME_hnotfully63 524 +#define FRAME_hnotfully64 525 +#define FRAME_hnotfully65 526 +#define FRAME_hnotfully66 527 +#define FRAME_hnotfully67 528 +#define FRAME_hnotfully68 529 +#define FRAME_hnotfully69 530 +#define FRAME_hnotfully70 531 +#define FRAME_hnotfully71 532 +#define FRAME_hnotfully72 533 +#define FRAME_hnotfully73 534 +#define FRAME_hnotfully74 535 +#define FRAME_hnotfully75 536 +#define FRAME_hnotfully76 537 +#define FRAME_hnotfully77 538 +#define FRAME_hnotfully78 539 +#define FRAME_hnotfully79 540 +#define FRAME_hnotfully80 541 +#define FRAME_hnotfully81 542 +#define FRAME_hnotfully82 543 +#define FRAME_hnotfully83 544 +#define FRAME_hnotfully84 545 +#define FRAME_hnotfully85 546 +#define FRAME_hnotfully86 547 +#define FRAME_hnotfully87 548 +#define FRAME_hnotfully88 549 +#define FRAME_hnotfully89 550 +#define FRAME_hnotfully90 551 +#define FRAME_hnotfully91 552 +#define FRAME_hnotfully92 553 +#define FRAME_hnotfully93 554 +#define FRAME_hnotfully94 555 +#define FRAME_hnotfully95 556 +#define FRAME_hnotfully96 557 +#define FRAME_hnotfully97 558 +#define FRAME_hnotfully98 559 +#define FRAME_hnotfully99 560 +#define FRAME_hnotfully100 561 +#define FRAME_hnotfully101 562 +#define FRAME_hnotfully102 563 +#define FRAME_hnotfully103 564 +#define FRAME_hnotfully104 565 +#define FRAME_hnotfully105 566 +#define FRAME_hnotfully106 567 +#define FRAME_hnotfully107 568 +#define FRAME_hnotfully108 569 +#define FRAME_hnotfully109 570 +#define FRAME_hnotfully110 571 +#define FRAME_hnotfully111 572 +#define FRAME_hnotfully112 573 +#define FRAME_hnotfully113 574 +#define FRAME_hnotfully114 575 +#define FRAME_hnotfully115 576 +#define FRAME_hnotfully116 577 +#define FRAME_hnotfully117 578 +#define FRAME_hnotfully118 579 +#define FRAME_hnotfully119 580 +#define FRAME_hnotfully120 581 +#define FRAME_hnotfully121 582 +#define FRAME_hnotfully122 583 +#define FRAME_hnotfully123 584 +#define FRAME_hnotfully124 585 +#define FRAME_hnotfully125 586 +#define FRAME_hnotfully126 587 +#define FRAME_hnotfully127 588 +#define FRAME_hnotfully128 589 +#define FRAME_hnotfully129 590 +#define FRAME_hnotfully130 591 +#define FRAME_hnotfully131 592 +#define FRAME_hnotfully132 593 +#define FRAME_hnotfully133 594 +#define FRAME_hnotfully134 595 +#define FRAME_hnotfully135 596 +#define FRAME_hnotfully136 597 +#define FRAME_hnotfully137 598 +#define FRAME_hnotfully138 599 +#define FRAME_hnotfully139 600 +#define FRAME_hnotfully140 601 +#define FRAME_hnotfully141 602 +#define FRAME_hnotfully142 603 +#define FRAME_hnotfully143 604 +#define FRAME_hnotfully144 605 +#define FRAME_hnotfully145 606 +#define FRAME_hnotfully146 607 +#define FRAME_hnotfully147 608 +#define FRAME_hnotfully148 609 +#define FRAME_hnotfully149 610 +#define FRAME_hnotfully150 611 +#define FRAME_hnotfully151 612 +#define FRAME_hnotfully152 613 +#define FRAME_hnotfully153 614 +#define FRAME_hnotfully154 615 +#define FRAME_hnotfully155 616 +#define FRAME_hnotfully156 617 +#define FRAME_hnotfully157 618 +#define FRAME_hnotfully158 619 +#define FRAME_hnotfully159 620 +#define FRAME_hnotfully160 621 +#define FRAME_hnotfully161 622 +#define FRAME_hnotfully162 623 +#define FRAME_hnotfully163 624 +#define FRAME_hnotfully164 625 +#define FRAME_hnotfully165 626 +#define FRAME_hnotfully166 627 +#define FRAME_hnotfully167 628 +#define FRAME_hnotfully168 629 +#define FRAME_hnotfully169 630 +#define FRAME_hnotfully170 631 +#define FRAME_hnotfully171 632 +#define FRAME_hprltran1 633 +#define FRAME_hprltran2 634 +#define FRAME_hprltran3 635 +#define FRAME_hprltran4 636 +#define FRAME_hprltran5 637 +#define FRAME_hprltran6 638 +#define FRAME_hprltran7 639 +#define FRAME_hprltran8 640 +#define FRAME_hprltran9 641 +#define FRAME_hprltran10 642 +#define FRAME_hprltran11 643 +#define FRAME_hprltran12 644 +#define FRAME_hprltran13 645 +#define FRAME_hprltran14 646 +#define FRAME_hprltran15 647 +#define FRAME_hpstart1 648 +#define FRAME_hpstart2 649 +#define FRAME_hpstart3 650 +#define FRAME_hpstart4 651 +#define FRAME_hpstart5 652 +#define FRAME_hpstart6 653 +#define FRAME_hpstart7 654 +#define FRAME_hpstart8 655 +#define FRAME_hpstart9 656 +#define FRAME_hpstart10 657 +#define FRAME_hpstart11 658 +#define FRAME_hpstart12 659 +#define FRAME_hpstart13 660 +#define FRAME_hpstart14 661 +#define FRAME_hpstart15 662 +#define FRAME_hpstart16 663 +#define FRAME_hpstart17 664 +#define FRAME_hpstart18 665 +#define FRAME_hpstart19 666 +#define FRAME_hridle1 667 +#define FRAME_hridle2 668 +#define FRAME_hridle3 669 +#define FRAME_hridle4 670 +#define FRAME_hridle5 671 +#define FRAME_hridle6 672 +#define FRAME_hridle7 673 +#define FRAME_hridle8 674 +#define FRAME_hridle9 675 +#define FRAME_hridle10 676 +#define FRAME_hridle11 677 +#define FRAME_hridle12 678 +#define FRAME_hridle13 679 +#define FRAME_hridle14 680 +#define FRAME_hridle15 681 +#define FRAME_hridle16 682 +#define FRAME_hridle17 683 +#define FRAME_hridle18 684 +#define FRAME_hridle19 685 +#define FRAME_hridle20 686 +#define FRAME_hridle21 687 +#define FRAME_hridle22 688 +#define FRAME_hridle23 689 +#define FRAME_hridle24 690 +#define FRAME_hridle25 691 +#define FRAME_hridle26 692 +#define FRAME_hridle27 693 +#define FRAME_hridle28 694 +#define FRAME_hridle29 695 +#define FRAME_hridle30 696 +#define FRAME_hridle31 697 +#define FRAME_hridle32 698 +#define FRAME_hridle33 699 +#define FRAME_hridle34 700 +#define FRAME_hridle35 701 +#define FRAME_hridle36 702 +#define FRAME_hridle37 703 +#define FRAME_hridle38 704 +#define FRAME_hridle39 705 +#define FRAME_hridle40 706 +#define FRAME_hrtalk1 707 +#define FRAME_hrtalk2 708 +#define FRAME_hrtalk3 709 +#define FRAME_hrtalk4 710 +#define FRAME_hrtalk5 711 +#define FRAME_hrtalk6 712 +#define FRAME_hrtalk7 713 +#define FRAME_hrtalk8 714 +#define FRAME_hrtalk9 715 +#define FRAME_hrtalk10 716 +#define FRAME_hrtalk11 717 +#define FRAME_hrtalk12 718 +#define FRAME_hrtalk13 719 +#define FRAME_hrtalk14 720 +#define FRAME_hrtalk15 721 +#define FRAME_hrtalk16 722 +#define FRAME_hrtalk17 723 +#define FRAME_hrtalk18 724 +#define FRAME_hrtalk19 725 +#define FRAME_hrtalk20 726 +#define FRAME_hrtalk21 727 +#define FRAME_hrtalk22 728 +#define FRAME_hrtalk23 729 +#define FRAME_hrtalk24 730 +#define FRAME_hrtalk25 731 +#define FRAME_hrtalk26 732 +#define FRAME_hrtalk27 733 +#define FRAME_hrtalk28 734 +#define FRAME_hrtalk29 735 +#define FRAME_hrtalk30 736 +#define FRAME_hrtalk31 737 +#define FRAME_hrtalk32 738 +#define FRAME_hrtalk33 739 +#define FRAME_hrtalk34 740 +#define FRAME_hrtalk35 741 +#define FRAME_hrtalk36 742 +#define FRAME_hrtalk37 743 +#define FRAME_hrtalk38 744 +#define FRAME_hrtalk39 745 +#define FRAME_hrtalk40 746 +#define FRAME_hrtalk41 747 +#define FRAME_hrtalk42 748 +#define FRAME_hrtalk43 749 +#define FRAME_hrtalk44 750 +#define FRAME_hrtalk45 751 +#define FRAME_hrtalk46 752 +#define FRAME_hrtalk47 753 +#define FRAME_hrtalk48 754 +#define FRAME_hrtalk49 755 +#define FRAME_hrtalk50 756 +#define FRAME_hrtalk51 757 +#define FRAME_hrtalk52 758 +#define FRAME_hrtalk53 759 +#define FRAME_hrtalk54 760 +#define FRAME_hrtalk55 761 +#define FRAME_hrtalk56 762 +#define FRAME_hrtalk57 763 +#define FRAME_hrtalk58 764 +#define FRAME_hrtalk59 765 +#define FRAME_hrtalk60 766 +#define FRAME_hrtalk61 767 +#define FRAME_hrtalk62 768 +#define FRAME_hrtalk63 769 +#define FRAME_hrtalk64 770 +#define FRAME_hrtalk65 771 +#define FRAME_hrtalk66 772 +#define FRAME_hrtalk67 773 +#define FRAME_hrtalk68 774 +#define FRAME_hrtalk69 775 +#define FRAME_hrtalk70 776 +#define FRAME_hrtalk71 777 +#define FRAME_hrtalk72 778 +#define FRAME_hrtalk73 779 +#define FRAME_hrtalk74 780 +#define FRAME_hrtalk75 781 +#define FRAME_hrtalk76 782 +#define FRAME_hrtalk77 783 +#define FRAME_hrtalk78 784 +#define FRAME_hrtalk79 785 +#define FRAME_hrtalk80 786 +#define FRAME_idle1 787 +#define FRAME_idle2 788 +#define FRAME_idle3 789 +#define FRAME_idle4 790 +#define FRAME_idle5 791 +#define FRAME_idle6 792 +#define FRAME_idle7 793 +#define FRAME_idle8 794 +#define FRAME_idle9 795 +#define FRAME_idle10 796 +#define FRAME_idle11 797 +#define FRAME_idle12 798 +#define FRAME_idle13 799 +#define FRAME_idle14 800 +#define FRAME_idle15 801 +#define FRAME_idle16 802 +#define FRAME_idle17 803 +#define FRAME_idle18 804 +#define FRAME_poseidle1 805 +#define FRAME_poseidle10 806 +#define FRAME_poseidle11 807 +#define FRAME_poseidle12 808 +#define FRAME_poseidle13 809 +#define FRAME_poseidle14 810 +#define FRAME_poseidle15 811 +#define FRAME_poseidle16 812 +#define FRAME_poseidle17 813 +#define FRAME_poseidle18 814 +#define FRAME_poseidle2 815 +#define FRAME_poseidle3 816 +#define FRAME_poseidle4 817 +#define FRAME_poseidle5 818 +#define FRAME_poseidle6 819 +#define FRAME_poseidle7 820 +#define FRAME_poseidle8 821 +#define FRAME_poseidle9 822 +#define FRAME_pose2ready1 823 +#define FRAME_pose2ready2 824 +#define FRAME_pose2ready3 825 +#define FRAME_pose2ready4 826 +#define FRAME_pose2ready5 827 +#define FRAME_pose2ready6 828 +#define FRAME_walk1 829 +#define FRAME_walk2 830 +#define FRAME_walk3 831 +#define FRAME_walk4 832 +#define FRAME_walk5 833 +#define FRAME_walk6 834 +#define FRAME_walk7 835 +#define FRAME_walk8 836 +#define FRAME_walk9 837 +#define FRAME_walk10 838 +#define FRAME_walk11 839 +#define FRAME_walk12 840 +#define FRAME_walk13 841 +#define FRAME_walk14 842 +#define FRAME_walk15 843 +#define FRAME_walk16 844 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 3 + +#define MESH_BASEBIN 0 +#define MESH__STAFF 1 +#define MESH__QUEENBODY 2 diff --git a/Toolkit/Programming/GameCode/game/c_siernan1.c b/Toolkit/Programming/GameCode/game/c_siernan1.c new file mode 100644 index 0000000..5419102 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_siernan1.c @@ -0,0 +1,227 @@ +/*------------------------------------------------------------------- +c_siernan1.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#include "c_siernan1.h" +#include "c_siernan1_anim.h" +#include "c_ai.h" + +#define ENT_INVISIBLE 1 +#define ENT_LEANING 4 + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + // Cinematics + &siernan1_move_c_action1, + &siernan1_move_c_action2, + &siernan1_move_c_action3, + &siernan1_move_c_action4, + &siernan1_move_c_action5, + &siernan1_move_c_action6, + &siernan1_move_c_action7, + &siernan1_move_c_action8, + &siernan1_move_c_action9, + &siernan1_move_c_action10, + &siernan1_move_c_action11, + &siernan1_move_c_action12, + &siernan1_move_c_action13, + &siernan1_move_c_idle1, + &siernan1_move_c_idle2, + &siernan1_move_c_idle3, + &siernan1_move_c_idle4, + &siernan1_move_c_idle5, + &siernan1_move_c_walkstart, + &siernan1_move_c_walk1, + &siernan1_move_c_walkstop1, +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + siernan1_c_anims +-------------------------------------------------------------------------*/ +void siernan1_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_ACTION8 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + case MSG_C_ACTION9 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION9; + break; + case MSG_C_ACTION10 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION10; + break; + case MSG_C_ACTION11 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION11; + break; + case MSG_C_ACTION12 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION12; + break; + case MSG_C_ACTION13 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION13; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + if (self->spawnflags & ENT_LEANING) + curr_anim = ANIM_C_IDLE3; + else + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_IDLE4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE4; + break; + case MSG_C_IDLE5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE5; + break; + case MSG_C_WALKSTART: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTART; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALKSTOP1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_WALKSTOP1; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + StaticsInit +-------------------------------------------------------------------------*/ +void Siernan1CinStaticsInit() +{ + + + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION1] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION2] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION3] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION4] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION5] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION6] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION7] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION8] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION9] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION10] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION11] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION12] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_ACTION13] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_IDLE1] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_IDLE2] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_IDLE3] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_IDLE4] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_IDLE5] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_WALKSTART] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_WALK1] = siernan1_c_anims; + classStatics[CID_C_SIERNAN1].msgReceivers[MSG_C_WALKSTOP1] = siernan1_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + //note that the name is different in the path + resInfo.modelIndex = gi.modelindex("models/monsters/siernan/standing/tris.fm"); + + classStatics[CID_C_SIERNAN1].resInfo = &resInfo; + +} + + +/*QUAKED character_siernan1 (1 .5 0) (-10 -10 -20) (10 10 20) INVISIBLE x LEANING +The cinematic siernan standing +INVISIBLE - can't be seen +LEANING - leaning against a wall, idling +*/ +void SP_character_siernan1 (edict_t *self) +{ + VectorSet (self->mins, -10, -10, -20); + VectorSet (self->maxs, 10, 10, 20); + + self->s.scale = self->monsterinfo.scale = 1.2; + + c_character_init(self,CID_C_SIERNAN1); + + +} + + diff --git a/Toolkit/Programming/GameCode/game/c_siernan1.h b/Toolkit/Programming/GameCode/game/c_siernan1.h new file mode 100644 index 0000000..bb728a1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_siernan1.h @@ -0,0 +1,49 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_ACTION9, + ANIM_C_ACTION10, + ANIM_C_ACTION11, + ANIM_C_ACTION12, + ANIM_C_ACTION13, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_IDLE4, + ANIM_C_IDLE5, + ANIM_C_WALKSTART, + ANIM_C_WALK1, + ANIM_C_WALKSTOP1, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t siernan1_move_c_action1; +extern animmove_t siernan1_move_c_action2; +extern animmove_t siernan1_move_c_action3; +extern animmove_t siernan1_move_c_action4; +extern animmove_t siernan1_move_c_action5; +extern animmove_t siernan1_move_c_action6; +extern animmove_t siernan1_move_c_action7; +extern animmove_t siernan1_move_c_action8; +extern animmove_t siernan1_move_c_action9; +extern animmove_t siernan1_move_c_action10; +extern animmove_t siernan1_move_c_action11; +extern animmove_t siernan1_move_c_action12; +extern animmove_t siernan1_move_c_action13; +extern animmove_t siernan1_move_c_idle1; +extern animmove_t siernan1_move_c_idle2; +extern animmove_t siernan1_move_c_idle3; +extern animmove_t siernan1_move_c_idle4; +extern animmove_t siernan1_move_c_idle5; +extern animmove_t siernan1_move_c_walkstart; +extern animmove_t siernan1_move_c_walk1; +extern animmove_t siernan1_move_c_walkstop1; diff --git a/Toolkit/Programming/GameCode/game/c_siernan1_anim.c b/Toolkit/Programming/GameCode/game/c_siernan1_anim.c new file mode 100644 index 0000000..c996f2f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_siernan1_anim.c @@ -0,0 +1,1065 @@ +//============================================================================== +// +// m_corvus_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_siernan1_anim.h" +#include "c_siernan1.h" + +#include "g_monster.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action1 [] = +{ + FRAME_A1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_A21, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action1 = {21, siernan1_frames_c_action1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action2 [] = +{ + FRAME_B1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_B20, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action2 = {20, siernan1_frames_c_action2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action3 [] = +{ + FRAME_C1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_C16, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action3 = {16, siernan1_frames_c_action3, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action4 [] = +{ + FRAME_D1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_D11, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action4 = {11, siernan1_frames_c_action4, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action5 [] = +{ + FRAME_E1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_E37, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action5 = {37, siernan1_frames_c_action5, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action6 [] = +{ + FRAME_uhave1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_uhave101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave129, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave130, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave131, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave132, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave133, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave134, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave135, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_uhave136, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action6 = {136, siernan1_frames_c_action6, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action7 [] = +{ + FRAME_rember1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rember68, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action7 = {68, siernan1_frames_c_action7, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action8 [] = +{ + FRAME_noknow1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_noknow81, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action8 = {81, siernan1_frames_c_action8, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action9 [] = +{ + FRAME_ifear1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_ifear101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ifear117, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action9 = {117, siernan1_frames_c_action9, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action10 [] = +{ + FRAME_notin1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_notin101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin129, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin130, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin131, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin132, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin133, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin134, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin135, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin136, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin137, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin138, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin139, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin140, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin141, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin142, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_notin143, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action10 = {143, siernan1_frames_c_action10, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action11 [] = +{ + FRAME_yes1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_yes100, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action11 = {100, siernan1_frames_c_action11, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action12 [] = +{ + FRAME_siping1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping22, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action12 = {22, siernan1_frames_c_action12, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_action13 [] = +{ + FRAME_accept1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept9, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_action13 = {9, siernan1_frames_c_action13, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_idle1 [] = +{ + FRAME_Idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_idle1 = {24, siernan1_frames_c_idle1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_idle2 [] = +{ + FRAME_Idle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Idle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_idle2 = {2, siernan1_frames_c_idle2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_idle3 [] = +{ + FRAME_accept1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_idle3 = {2, siernan1_frames_c_idle3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_idle4 [] = +{ + FRAME_accept9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_accept9, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_idle4 = {2, siernan1_frames_c_idle4, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_idle5 [] = +{ + FRAME_siping22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_siping22, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_idle5 = {2, siernan1_frames_c_idle5, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_walk1 [] = +{ + FRAME_walk1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk2, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk3, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk4, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk6, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk7, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk8, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk9, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk10, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk11, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk12, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_walk1 = {12, siernan1_frames_c_walk1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_walkstart [] = +{ + FRAME_strtwalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strtwalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strtwalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strtwalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strtwalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_strtwalk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_walkstart = {6, siernan1_frames_c_walkstart, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan1_frames_c_walkstop1 [] = +{ + FRAME_stpwalk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stpwalk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stpwalk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stpwalk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_stpwalk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan1_move_c_walkstop1 = {5, siernan1_frames_c_walkstop1, ai_c_cycleend}; + + diff --git a/Toolkit/Programming/GameCode/game/c_siernan1_anim.h b/Toolkit/Programming/GameCode/game/c_siernan1_anim.h new file mode 100644 index 0000000..ad9c3cb --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_siernan1_anim.h @@ -0,0 +1,845 @@ +// R:\Art\models/monsters\siernan\standing + +// This file generated by qdata - Do NOT Modify + +#define FRAME_A1 0 +#define FRAME_A2 1 +#define FRAME_A3 2 +#define FRAME_A4 3 +#define FRAME_A5 4 +#define FRAME_A6 5 +#define FRAME_A7 6 +#define FRAME_A8 7 +#define FRAME_A9 8 +#define FRAME_A10 9 +#define FRAME_A11 10 +#define FRAME_A12 11 +#define FRAME_A13 12 +#define FRAME_A14 13 +#define FRAME_A15 14 +#define FRAME_A16 15 +#define FRAME_A17 16 +#define FRAME_A18 17 +#define FRAME_A19 18 +#define FRAME_A20 19 +#define FRAME_A21 20 +#define FRAME_B1 21 +#define FRAME_B2 22 +#define FRAME_B3 23 +#define FRAME_B4 24 +#define FRAME_B5 25 +#define FRAME_B6 26 +#define FRAME_B7 27 +#define FRAME_B8 28 +#define FRAME_B9 29 +#define FRAME_B10 30 +#define FRAME_B11 31 +#define FRAME_B12 32 +#define FRAME_B13 33 +#define FRAME_B14 34 +#define FRAME_B15 35 +#define FRAME_B16 36 +#define FRAME_B17 37 +#define FRAME_B18 38 +#define FRAME_B19 39 +#define FRAME_B20 40 +#define FRAME_C1 41 +#define FRAME_C2 42 +#define FRAME_C3 43 +#define FRAME_C4 44 +#define FRAME_C5 45 +#define FRAME_C6 46 +#define FRAME_C7 47 +#define FRAME_C8 48 +#define FRAME_C9 49 +#define FRAME_C10 50 +#define FRAME_C11 51 +#define FRAME_C12 52 +#define FRAME_C13 53 +#define FRAME_C14 54 +#define FRAME_C15 55 +#define FRAME_C16 56 +#define FRAME_D1 57 +#define FRAME_D2 58 +#define FRAME_D3 59 +#define FRAME_D4 60 +#define FRAME_D5 61 +#define FRAME_D6 62 +#define FRAME_D7 63 +#define FRAME_D8 64 +#define FRAME_D9 65 +#define FRAME_D10 66 +#define FRAME_D11 67 +#define FRAME_E1 68 +#define FRAME_E2 69 +#define FRAME_E3 70 +#define FRAME_E4 71 +#define FRAME_E5 72 +#define FRAME_E6 73 +#define FRAME_E7 74 +#define FRAME_E8 75 +#define FRAME_E9 76 +#define FRAME_E10 77 +#define FRAME_E11 78 +#define FRAME_E12 79 +#define FRAME_E13 80 +#define FRAME_E14 81 +#define FRAME_E15 82 +#define FRAME_E16 83 +#define FRAME_E17 84 +#define FRAME_E18 85 +#define FRAME_E19 86 +#define FRAME_E20 87 +#define FRAME_E21 88 +#define FRAME_E22 89 +#define FRAME_E23 90 +#define FRAME_E24 91 +#define FRAME_E25 92 +#define FRAME_E26 93 +#define FRAME_E27 94 +#define FRAME_E28 95 +#define FRAME_E29 96 +#define FRAME_E30 97 +#define FRAME_E31 98 +#define FRAME_E32 99 +#define FRAME_E33 100 +#define FRAME_E34 101 +#define FRAME_E35 102 +#define FRAME_E36 103 +#define FRAME_E37 104 +#define FRAME_Idle1 105 +#define FRAME_Idle2 106 +#define FRAME_Idle3 107 +#define FRAME_Idle4 108 +#define FRAME_Idle5 109 +#define FRAME_Idle6 110 +#define FRAME_Idle7 111 +#define FRAME_Idle8 112 +#define FRAME_Idle9 113 +#define FRAME_Idle10 114 +#define FRAME_Idle11 115 +#define FRAME_Idle12 116 +#define FRAME_Idle13 117 +#define FRAME_Idle14 118 +#define FRAME_Idle15 119 +#define FRAME_Idle16 120 +#define FRAME_Idle17 121 +#define FRAME_Idle18 122 +#define FRAME_Idle19 123 +#define FRAME_Idle20 124 +#define FRAME_Idle21 125 +#define FRAME_Idle22 126 +#define FRAME_Idle23 127 +#define FRAME_Idle24 128 +#define FRAME_poly 129 +#define FRAME_Siernan 130 +#define FRAME_stpwalk1 131 +#define FRAME_stpwalk2 132 +#define FRAME_stpwalk3 133 +#define FRAME_stpwalk4 134 +#define FRAME_stpwalk5 135 +#define FRAME_strtwalk1 136 +#define FRAME_strtwalk2 137 +#define FRAME_strtwalk3 138 +#define FRAME_strtwalk4 139 +#define FRAME_strtwalk5 140 +#define FRAME_strtwalk6 141 +#define FRAME_walk1 142 +#define FRAME_walk2 143 +#define FRAME_walk3 144 +#define FRAME_walk4 145 +#define FRAME_walk5 146 +#define FRAME_walk6 147 +#define FRAME_walk7 148 +#define FRAME_walk8 149 +#define FRAME_walk9 150 +#define FRAME_walk10 151 +#define FRAME_walk11 152 +#define FRAME_walk12 153 +#define FRAME_uhave1 154 +#define FRAME_uhave2 155 +#define FRAME_uhave3 156 +#define FRAME_uhave4 157 +#define FRAME_uhave5 158 +#define FRAME_uhave6 159 +#define FRAME_uhave7 160 +#define FRAME_uhave8 161 +#define FRAME_uhave9 162 +#define FRAME_uhave10 163 +#define FRAME_uhave11 164 +#define FRAME_uhave12 165 +#define FRAME_uhave13 166 +#define FRAME_uhave14 167 +#define FRAME_uhave15 168 +#define FRAME_uhave16 169 +#define FRAME_uhave17 170 +#define FRAME_uhave18 171 +#define FRAME_uhave19 172 +#define FRAME_uhave20 173 +#define FRAME_uhave21 174 +#define FRAME_uhave22 175 +#define FRAME_uhave23 176 +#define FRAME_uhave24 177 +#define FRAME_uhave25 178 +#define FRAME_uhave26 179 +#define FRAME_uhave27 180 +#define FRAME_uhave28 181 +#define FRAME_uhave29 182 +#define FRAME_uhave30 183 +#define FRAME_uhave31 184 +#define FRAME_uhave32 185 +#define FRAME_uhave33 186 +#define FRAME_uhave34 187 +#define FRAME_uhave35 188 +#define FRAME_uhave36 189 +#define FRAME_uhave37 190 +#define FRAME_uhave38 191 +#define FRAME_uhave39 192 +#define FRAME_uhave40 193 +#define FRAME_uhave41 194 +#define FRAME_uhave42 195 +#define FRAME_uhave43 196 +#define FRAME_uhave44 197 +#define FRAME_uhave45 198 +#define FRAME_uhave46 199 +#define FRAME_uhave47 200 +#define FRAME_uhave48 201 +#define FRAME_uhave49 202 +#define FRAME_uhave50 203 +#define FRAME_uhave51 204 +#define FRAME_uhave52 205 +#define FRAME_uhave53 206 +#define FRAME_uhave54 207 +#define FRAME_uhave55 208 +#define FRAME_uhave56 209 +#define FRAME_uhave57 210 +#define FRAME_uhave58 211 +#define FRAME_uhave59 212 +#define FRAME_uhave60 213 +#define FRAME_uhave61 214 +#define FRAME_uhave62 215 +#define FRAME_uhave63 216 +#define FRAME_uhave64 217 +#define FRAME_uhave65 218 +#define FRAME_uhave66 219 +#define FRAME_uhave67 220 +#define FRAME_uhave68 221 +#define FRAME_uhave69 222 +#define FRAME_uhave70 223 +#define FRAME_uhave71 224 +#define FRAME_uhave72 225 +#define FRAME_uhave73 226 +#define FRAME_uhave74 227 +#define FRAME_uhave75 228 +#define FRAME_uhave76 229 +#define FRAME_uhave77 230 +#define FRAME_uhave78 231 +#define FRAME_uhave79 232 +#define FRAME_uhave80 233 +#define FRAME_uhave81 234 +#define FRAME_uhave82 235 +#define FRAME_uhave83 236 +#define FRAME_uhave84 237 +#define FRAME_uhave85 238 +#define FRAME_uhave86 239 +#define FRAME_uhave87 240 +#define FRAME_uhave88 241 +#define FRAME_uhave89 242 +#define FRAME_uhave90 243 +#define FRAME_uhave91 244 +#define FRAME_uhave92 245 +#define FRAME_uhave93 246 +#define FRAME_uhave94 247 +#define FRAME_uhave95 248 +#define FRAME_uhave96 249 +#define FRAME_uhave97 250 +#define FRAME_uhave98 251 +#define FRAME_uhave99 252 +#define FRAME_uhave100 253 +#define FRAME_uhave101 254 +#define FRAME_uhave102 255 +#define FRAME_uhave103 256 +#define FRAME_uhave104 257 +#define FRAME_uhave105 258 +#define FRAME_uhave106 259 +#define FRAME_uhave107 260 +#define FRAME_uhave108 261 +#define FRAME_uhave109 262 +#define FRAME_uhave110 263 +#define FRAME_uhave111 264 +#define FRAME_uhave112 265 +#define FRAME_uhave113 266 +#define FRAME_uhave114 267 +#define FRAME_uhave115 268 +#define FRAME_uhave116 269 +#define FRAME_uhave117 270 +#define FRAME_uhave118 271 +#define FRAME_uhave119 272 +#define FRAME_uhave120 273 +#define FRAME_uhave121 274 +#define FRAME_uhave122 275 +#define FRAME_uhave123 276 +#define FRAME_uhave124 277 +#define FRAME_uhave125 278 +#define FRAME_uhave126 279 +#define FRAME_uhave127 280 +#define FRAME_uhave128 281 +#define FRAME_uhave129 282 +#define FRAME_uhave130 283 +#define FRAME_uhave131 284 +#define FRAME_uhave132 285 +#define FRAME_uhave133 286 +#define FRAME_uhave134 287 +#define FRAME_uhave135 288 +#define FRAME_uhave136 289 +#define FRAME_rember1 290 +#define FRAME_rember2 291 +#define FRAME_rember3 292 +#define FRAME_rember4 293 +#define FRAME_rember5 294 +#define FRAME_rember6 295 +#define FRAME_rember7 296 +#define FRAME_rember8 297 +#define FRAME_rember9 298 +#define FRAME_rember10 299 +#define FRAME_rember11 300 +#define FRAME_rember12 301 +#define FRAME_rember13 302 +#define FRAME_rember14 303 +#define FRAME_rember15 304 +#define FRAME_rember16 305 +#define FRAME_rember17 306 +#define FRAME_rember18 307 +#define FRAME_rember19 308 +#define FRAME_rember20 309 +#define FRAME_rember21 310 +#define FRAME_rember22 311 +#define FRAME_rember23 312 +#define FRAME_rember24 313 +#define FRAME_rember25 314 +#define FRAME_rember26 315 +#define FRAME_rember27 316 +#define FRAME_rember28 317 +#define FRAME_rember29 318 +#define FRAME_rember30 319 +#define FRAME_rember31 320 +#define FRAME_rember32 321 +#define FRAME_rember33 322 +#define FRAME_rember34 323 +#define FRAME_rember35 324 +#define FRAME_rember36 325 +#define FRAME_rember37 326 +#define FRAME_rember38 327 +#define FRAME_rember39 328 +#define FRAME_rember40 329 +#define FRAME_rember41 330 +#define FRAME_rember42 331 +#define FRAME_rember43 332 +#define FRAME_rember44 333 +#define FRAME_rember45 334 +#define FRAME_rember46 335 +#define FRAME_rember47 336 +#define FRAME_rember48 337 +#define FRAME_rember49 338 +#define FRAME_rember50 339 +#define FRAME_rember51 340 +#define FRAME_rember52 341 +#define FRAME_rember53 342 +#define FRAME_rember54 343 +#define FRAME_rember55 344 +#define FRAME_rember56 345 +#define FRAME_rember57 346 +#define FRAME_rember58 347 +#define FRAME_rember59 348 +#define FRAME_rember60 349 +#define FRAME_rember61 350 +#define FRAME_rember62 351 +#define FRAME_rember63 352 +#define FRAME_rember64 353 +#define FRAME_rember65 354 +#define FRAME_rember66 355 +#define FRAME_rember67 356 +#define FRAME_rember68 357 +#define FRAME_noknow1 358 +#define FRAME_noknow2 359 +#define FRAME_noknow3 360 +#define FRAME_noknow4 361 +#define FRAME_noknow5 362 +#define FRAME_noknow6 363 +#define FRAME_noknow7 364 +#define FRAME_noknow8 365 +#define FRAME_noknow9 366 +#define FRAME_noknow10 367 +#define FRAME_noknow11 368 +#define FRAME_noknow12 369 +#define FRAME_noknow13 370 +#define FRAME_noknow14 371 +#define FRAME_noknow15 372 +#define FRAME_noknow16 373 +#define FRAME_noknow17 374 +#define FRAME_noknow18 375 +#define FRAME_noknow19 376 +#define FRAME_noknow20 377 +#define FRAME_noknow21 378 +#define FRAME_noknow22 379 +#define FRAME_noknow23 380 +#define FRAME_noknow24 381 +#define FRAME_noknow25 382 +#define FRAME_noknow26 383 +#define FRAME_noknow27 384 +#define FRAME_noknow28 385 +#define FRAME_noknow29 386 +#define FRAME_noknow30 387 +#define FRAME_noknow31 388 +#define FRAME_noknow32 389 +#define FRAME_noknow33 390 +#define FRAME_noknow34 391 +#define FRAME_noknow35 392 +#define FRAME_noknow36 393 +#define FRAME_noknow37 394 +#define FRAME_noknow38 395 +#define FRAME_noknow39 396 +#define FRAME_noknow40 397 +#define FRAME_noknow41 398 +#define FRAME_noknow42 399 +#define FRAME_noknow43 400 +#define FRAME_noknow44 401 +#define FRAME_noknow45 402 +#define FRAME_noknow46 403 +#define FRAME_noknow47 404 +#define FRAME_noknow48 405 +#define FRAME_noknow49 406 +#define FRAME_noknow50 407 +#define FRAME_noknow51 408 +#define FRAME_noknow52 409 +#define FRAME_noknow53 410 +#define FRAME_noknow54 411 +#define FRAME_noknow55 412 +#define FRAME_noknow56 413 +#define FRAME_noknow57 414 +#define FRAME_noknow58 415 +#define FRAME_noknow59 416 +#define FRAME_noknow60 417 +#define FRAME_noknow61 418 +#define FRAME_noknow62 419 +#define FRAME_noknow63 420 +#define FRAME_noknow64 421 +#define FRAME_noknow65 422 +#define FRAME_noknow66 423 +#define FRAME_noknow67 424 +#define FRAME_noknow68 425 +#define FRAME_noknow69 426 +#define FRAME_noknow70 427 +#define FRAME_noknow71 428 +#define FRAME_noknow72 429 +#define FRAME_noknow73 430 +#define FRAME_noknow74 431 +#define FRAME_noknow75 432 +#define FRAME_noknow76 433 +#define FRAME_noknow77 434 +#define FRAME_noknow78 435 +#define FRAME_noknow79 436 +#define FRAME_noknow80 437 +#define FRAME_noknow81 438 +#define FRAME_ifear1 439 +#define FRAME_ifear2 440 +#define FRAME_ifear3 441 +#define FRAME_ifear4 442 +#define FRAME_ifear5 443 +#define FRAME_ifear6 444 +#define FRAME_ifear7 445 +#define FRAME_ifear8 446 +#define FRAME_ifear9 447 +#define FRAME_ifear10 448 +#define FRAME_ifear11 449 +#define FRAME_ifear12 450 +#define FRAME_ifear13 451 +#define FRAME_ifear14 452 +#define FRAME_ifear15 453 +#define FRAME_ifear16 454 +#define FRAME_ifear17 455 +#define FRAME_ifear18 456 +#define FRAME_ifear19 457 +#define FRAME_ifear20 458 +#define FRAME_ifear21 459 +#define FRAME_ifear22 460 +#define FRAME_ifear23 461 +#define FRAME_ifear24 462 +#define FRAME_ifear25 463 +#define FRAME_ifear26 464 +#define FRAME_ifear27 465 +#define FRAME_ifear28 466 +#define FRAME_ifear29 467 +#define FRAME_ifear30 468 +#define FRAME_ifear31 469 +#define FRAME_ifear32 470 +#define FRAME_ifear33 471 +#define FRAME_ifear34 472 +#define FRAME_ifear35 473 +#define FRAME_ifear36 474 +#define FRAME_ifear37 475 +#define FRAME_ifear38 476 +#define FRAME_ifear39 477 +#define FRAME_ifear40 478 +#define FRAME_ifear41 479 +#define FRAME_ifear42 480 +#define FRAME_ifear43 481 +#define FRAME_ifear44 482 +#define FRAME_ifear45 483 +#define FRAME_ifear46 484 +#define FRAME_ifear47 485 +#define FRAME_ifear48 486 +#define FRAME_ifear49 487 +#define FRAME_ifear50 488 +#define FRAME_ifear51 489 +#define FRAME_ifear52 490 +#define FRAME_ifear53 491 +#define FRAME_ifear54 492 +#define FRAME_ifear55 493 +#define FRAME_ifear56 494 +#define FRAME_ifear57 495 +#define FRAME_ifear58 496 +#define FRAME_ifear59 497 +#define FRAME_ifear60 498 +#define FRAME_ifear61 499 +#define FRAME_ifear62 500 +#define FRAME_ifear63 501 +#define FRAME_ifear64 502 +#define FRAME_ifear65 503 +#define FRAME_ifear66 504 +#define FRAME_ifear67 505 +#define FRAME_ifear68 506 +#define FRAME_ifear69 507 +#define FRAME_ifear70 508 +#define FRAME_ifear71 509 +#define FRAME_ifear72 510 +#define FRAME_ifear73 511 +#define FRAME_ifear74 512 +#define FRAME_ifear75 513 +#define FRAME_ifear76 514 +#define FRAME_ifear77 515 +#define FRAME_ifear78 516 +#define FRAME_ifear79 517 +#define FRAME_ifear80 518 +#define FRAME_ifear81 519 +#define FRAME_ifear82 520 +#define FRAME_ifear83 521 +#define FRAME_ifear84 522 +#define FRAME_ifear85 523 +#define FRAME_ifear86 524 +#define FRAME_ifear87 525 +#define FRAME_ifear88 526 +#define FRAME_ifear89 527 +#define FRAME_ifear90 528 +#define FRAME_ifear91 529 +#define FRAME_ifear92 530 +#define FRAME_ifear93 531 +#define FRAME_ifear94 532 +#define FRAME_ifear95 533 +#define FRAME_ifear96 534 +#define FRAME_ifear97 535 +#define FRAME_ifear98 536 +#define FRAME_ifear99 537 +#define FRAME_ifear100 538 +#define FRAME_ifear101 539 +#define FRAME_ifear102 540 +#define FRAME_ifear103 541 +#define FRAME_ifear104 542 +#define FRAME_ifear105 543 +#define FRAME_ifear106 544 +#define FRAME_ifear107 545 +#define FRAME_ifear108 546 +#define FRAME_ifear109 547 +#define FRAME_ifear110 548 +#define FRAME_ifear111 549 +#define FRAME_ifear112 550 +#define FRAME_ifear113 551 +#define FRAME_ifear114 552 +#define FRAME_ifear115 553 +#define FRAME_ifear116 554 +#define FRAME_ifear117 555 +#define FRAME_notin1 556 +#define FRAME_notin2 557 +#define FRAME_notin3 558 +#define FRAME_notin4 559 +#define FRAME_notin5 560 +#define FRAME_notin6 561 +#define FRAME_notin7 562 +#define FRAME_notin8 563 +#define FRAME_notin9 564 +#define FRAME_notin10 565 +#define FRAME_notin11 566 +#define FRAME_notin12 567 +#define FRAME_notin13 568 +#define FRAME_notin14 569 +#define FRAME_notin15 570 +#define FRAME_notin16 571 +#define FRAME_notin17 572 +#define FRAME_notin18 573 +#define FRAME_notin19 574 +#define FRAME_notin20 575 +#define FRAME_notin21 576 +#define FRAME_notin22 577 +#define FRAME_notin23 578 +#define FRAME_notin24 579 +#define FRAME_notin25 580 +#define FRAME_notin26 581 +#define FRAME_notin27 582 +#define FRAME_notin28 583 +#define FRAME_notin29 584 +#define FRAME_notin30 585 +#define FRAME_notin31 586 +#define FRAME_notin32 587 +#define FRAME_notin33 588 +#define FRAME_notin34 589 +#define FRAME_notin35 590 +#define FRAME_notin36 591 +#define FRAME_notin37 592 +#define FRAME_notin38 593 +#define FRAME_notin39 594 +#define FRAME_notin40 595 +#define FRAME_notin41 596 +#define FRAME_notin42 597 +#define FRAME_notin43 598 +#define FRAME_notin44 599 +#define FRAME_notin45 600 +#define FRAME_notin46 601 +#define FRAME_notin47 602 +#define FRAME_notin48 603 +#define FRAME_notin49 604 +#define FRAME_notin50 605 +#define FRAME_notin51 606 +#define FRAME_notin52 607 +#define FRAME_notin53 608 +#define FRAME_notin54 609 +#define FRAME_notin55 610 +#define FRAME_notin56 611 +#define FRAME_notin57 612 +#define FRAME_notin58 613 +#define FRAME_notin59 614 +#define FRAME_notin60 615 +#define FRAME_notin61 616 +#define FRAME_notin62 617 +#define FRAME_notin63 618 +#define FRAME_notin64 619 +#define FRAME_notin65 620 +#define FRAME_notin66 621 +#define FRAME_notin67 622 +#define FRAME_notin68 623 +#define FRAME_notin69 624 +#define FRAME_notin70 625 +#define FRAME_notin71 626 +#define FRAME_notin72 627 +#define FRAME_notin73 628 +#define FRAME_notin74 629 +#define FRAME_notin75 630 +#define FRAME_notin76 631 +#define FRAME_notin77 632 +#define FRAME_notin78 633 +#define FRAME_notin79 634 +#define FRAME_notin80 635 +#define FRAME_notin81 636 +#define FRAME_notin82 637 +#define FRAME_notin83 638 +#define FRAME_notin84 639 +#define FRAME_notin85 640 +#define FRAME_notin86 641 +#define FRAME_notin87 642 +#define FRAME_notin88 643 +#define FRAME_notin89 644 +#define FRAME_notin90 645 +#define FRAME_notin91 646 +#define FRAME_notin92 647 +#define FRAME_notin93 648 +#define FRAME_notin94 649 +#define FRAME_notin95 650 +#define FRAME_notin96 651 +#define FRAME_notin97 652 +#define FRAME_notin98 653 +#define FRAME_notin99 654 +#define FRAME_notin100 655 +#define FRAME_notin101 656 +#define FRAME_notin102 657 +#define FRAME_notin103 658 +#define FRAME_notin104 659 +#define FRAME_notin105 660 +#define FRAME_notin106 661 +#define FRAME_notin107 662 +#define FRAME_notin108 663 +#define FRAME_notin109 664 +#define FRAME_notin110 665 +#define FRAME_notin111 666 +#define FRAME_notin112 667 +#define FRAME_notin113 668 +#define FRAME_notin114 669 +#define FRAME_notin115 670 +#define FRAME_notin116 671 +#define FRAME_notin117 672 +#define FRAME_notin118 673 +#define FRAME_notin119 674 +#define FRAME_notin120 675 +#define FRAME_notin121 676 +#define FRAME_notin122 677 +#define FRAME_notin123 678 +#define FRAME_notin124 679 +#define FRAME_notin125 680 +#define FRAME_notin126 681 +#define FRAME_notin127 682 +#define FRAME_notin128 683 +#define FRAME_notin129 684 +#define FRAME_notin130 685 +#define FRAME_notin131 686 +#define FRAME_notin132 687 +#define FRAME_notin133 688 +#define FRAME_notin134 689 +#define FRAME_notin135 690 +#define FRAME_notin136 691 +#define FRAME_notin137 692 +#define FRAME_notin138 693 +#define FRAME_notin139 694 +#define FRAME_notin140 695 +#define FRAME_notin141 696 +#define FRAME_notin142 697 +#define FRAME_notin143 698 +#define FRAME_yes1 699 +#define FRAME_yes2 700 +#define FRAME_yes3 701 +#define FRAME_yes4 702 +#define FRAME_yes5 703 +#define FRAME_yes6 704 +#define FRAME_yes7 705 +#define FRAME_yes8 706 +#define FRAME_yes9 707 +#define FRAME_yes10 708 +#define FRAME_yes11 709 +#define FRAME_yes12 710 +#define FRAME_yes13 711 +#define FRAME_yes14 712 +#define FRAME_yes15 713 +#define FRAME_yes16 714 +#define FRAME_yes17 715 +#define FRAME_yes18 716 +#define FRAME_yes19 717 +#define FRAME_yes20 718 +#define FRAME_yes21 719 +#define FRAME_yes22 720 +#define FRAME_yes23 721 +#define FRAME_yes24 722 +#define FRAME_yes25 723 +#define FRAME_yes26 724 +#define FRAME_yes27 725 +#define FRAME_yes28 726 +#define FRAME_yes29 727 +#define FRAME_yes30 728 +#define FRAME_yes31 729 +#define FRAME_yes32 730 +#define FRAME_yes33 731 +#define FRAME_yes34 732 +#define FRAME_yes35 733 +#define FRAME_yes36 734 +#define FRAME_yes37 735 +#define FRAME_yes38 736 +#define FRAME_yes39 737 +#define FRAME_yes40 738 +#define FRAME_yes41 739 +#define FRAME_yes42 740 +#define FRAME_yes43 741 +#define FRAME_yes44 742 +#define FRAME_yes45 743 +#define FRAME_yes46 744 +#define FRAME_yes47 745 +#define FRAME_yes48 746 +#define FRAME_yes49 747 +#define FRAME_yes50 748 +#define FRAME_yes51 749 +#define FRAME_yes52 750 +#define FRAME_yes53 751 +#define FRAME_yes54 752 +#define FRAME_yes55 753 +#define FRAME_yes56 754 +#define FRAME_yes57 755 +#define FRAME_yes58 756 +#define FRAME_yes59 757 +#define FRAME_yes60 758 +#define FRAME_yes61 759 +#define FRAME_yes62 760 +#define FRAME_yes63 761 +#define FRAME_yes64 762 +#define FRAME_yes65 763 +#define FRAME_yes66 764 +#define FRAME_yes67 765 +#define FRAME_yes68 766 +#define FRAME_yes69 767 +#define FRAME_yes70 768 +#define FRAME_yes71 769 +#define FRAME_yes72 770 +#define FRAME_yes73 771 +#define FRAME_yes74 772 +#define FRAME_yes75 773 +#define FRAME_yes76 774 +#define FRAME_yes77 775 +#define FRAME_yes78 776 +#define FRAME_yes79 777 +#define FRAME_yes80 778 +#define FRAME_yes81 779 +#define FRAME_yes82 780 +#define FRAME_yes83 781 +#define FRAME_yes84 782 +#define FRAME_yes85 783 +#define FRAME_yes86 784 +#define FRAME_yes87 785 +#define FRAME_yes88 786 +#define FRAME_yes89 787 +#define FRAME_yes90 788 +#define FRAME_yes91 789 +#define FRAME_yes92 790 +#define FRAME_yes93 791 +#define FRAME_yes94 792 +#define FRAME_yes95 793 +#define FRAME_yes96 794 +#define FRAME_yes97 795 +#define FRAME_yes98 796 +#define FRAME_yes99 797 +#define FRAME_yes100 798 +#define FRAME_siping1 799 +#define FRAME_siping2 800 +#define FRAME_siping3 801 +#define FRAME_siping4 802 +#define FRAME_siping5 803 +#define FRAME_siping6 804 +#define FRAME_siping7 805 +#define FRAME_siping8 806 +#define FRAME_siping9 807 +#define FRAME_siping10 808 +#define FRAME_siping11 809 +#define FRAME_siping12 810 +#define FRAME_siping13 811 +#define FRAME_siping14 812 +#define FRAME_siping15 813 +#define FRAME_siping16 814 +#define FRAME_siping17 815 +#define FRAME_siping18 816 +#define FRAME_siping19 817 +#define FRAME_siping20 818 +#define FRAME_siping21 819 +#define FRAME_siping22 820 +#define FRAME_accept1 821 +#define FRAME_accept2 822 +#define FRAME_accept3 823 +#define FRAME_accept4 824 +#define FRAME_accept5 825 +#define FRAME_accept6 826 +#define FRAME_accept7 827 +#define FRAME_accept8 828 +#define FRAME_accept9 829 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 6 + +#define MESH_BASEBIN 0 +#define MESH__TORSO 1 +#define MESH__HEAD1 2 +#define MESH__CENTERSPIKE1 3 +#define MESH__LEFTARM 4 +#define MESH__RIGHTARM 5 diff --git a/Toolkit/Programming/GameCode/game/c_siernan2.c b/Toolkit/Programming/GameCode/game/c_siernan2.c new file mode 100644 index 0000000..8e8aa3d --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_siernan2.c @@ -0,0 +1,110 @@ +/*------------------------------------------------------------------- +c_siernan2.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#include "c_siernan2.h" +#include "c_siernan2_anim.h" +#include "c_ai.h" + +#define ENT_INVISIBLE 1 + + +/*-------------------- +-------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + // Cinematics + &siernan2_move_c_action1, + &siernan2_move_c_action2, + &siernan2_move_c_idle1, +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + siernan2_c_anims +-------------------------------------------------------------------------*/ +void siernan2_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2 : + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + StaticsInit +-------------------------------------------------------------------------*/ +void Siernan2CinStaticsInit() +{ + + classStatics[CID_C_SIERNAN2].msgReceivers[MSG_C_ACTION1] = siernan2_c_anims; + classStatics[CID_C_SIERNAN2].msgReceivers[MSG_C_ACTION2] = siernan2_c_anims; + classStatics[CID_C_SIERNAN2].msgReceivers[MSG_C_IDLE1] = siernan2_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/monsters/siernan/laying/tris.fm"); + + classStatics[CID_C_SIERNAN2].resInfo = &resInfo; + +} + + + +/*QUAKED character_siernan2 (1 .5 0) (-17 -25 0) (22 12 16) INVISIBLE +The cinematic siernan laying down +*/ +void SP_character_siernan2 (edict_t *self) +{ + VectorSet (self->mins, -17, -25, 0); + VectorSet (self->maxs, 22, 12, 16); + + self->s.scale = self->monsterinfo.scale = 1; + + c_character_init(self,CID_C_SIERNAN2); +} diff --git a/Toolkit/Programming/GameCode/game/c_siernan2.h b/Toolkit/Programming/GameCode/game/c_siernan2.h new file mode 100644 index 0000000..791d72d --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_siernan2.h @@ -0,0 +1,13 @@ +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_IDLE1, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t siernan2_move_c_action1; +extern animmove_t siernan2_move_c_action2; +extern animmove_t siernan2_move_c_idle1; diff --git a/Toolkit/Programming/GameCode/game/c_siernan2_anim.c b/Toolkit/Programming/GameCode/game/c_siernan2_anim.c new file mode 100644 index 0000000..a5d44dc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_siernan2_anim.c @@ -0,0 +1,318 @@ +//============================================================================== +// +// m_corvus_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_siernan2_anim.h" +#include "c_siernan2.h" + +#include "g_monster.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan2_frames_c_action1 [] = +{ + FRAME_Minions1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Minions101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions129, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions130, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan2_move_c_action1 = {130, siernan2_frames_c_action1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan2_frames_c_action2 [] = +{ + FRAME_Minions1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_Minions101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions120, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan2_move_c_action2 = {120, siernan2_frames_c_action2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Siernan +-----------------------------------------------------------------------*/ +animframe_t siernan2_frames_c_idle1 [] = +{ + FRAME_Minions1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Minions1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t siernan2_move_c_idle1 = {6, siernan2_frames_c_idle1, ai_c_cycleend}; + + + + diff --git a/Toolkit/Programming/GameCode/game/c_siernan2_anim.h b/Toolkit/Programming/GameCode/game/c_siernan2_anim.h new file mode 100644 index 0000000..b6fcc7f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_siernan2_anim.h @@ -0,0 +1,145 @@ +// r:\art\models/monsters\siernan\laying + +// This file generated by qdata - Do NOT Modify + +#define FRAME_Minions1 0 +#define FRAME_Minions2 1 +#define FRAME_Minions3 2 +#define FRAME_Minions4 3 +#define FRAME_Minions5 4 +#define FRAME_Minions6 5 +#define FRAME_Minions7 6 +#define FRAME_Minions8 7 +#define FRAME_Minions9 8 +#define FRAME_Minions10 9 +#define FRAME_Minions11 10 +#define FRAME_Minions12 11 +#define FRAME_Minions13 12 +#define FRAME_Minions14 13 +#define FRAME_Minions15 14 +#define FRAME_Minions16 15 +#define FRAME_Minions17 16 +#define FRAME_Minions18 17 +#define FRAME_Minions19 18 +#define FRAME_Minions20 19 +#define FRAME_Minions21 20 +#define FRAME_Minions22 21 +#define FRAME_Minions23 22 +#define FRAME_Minions24 23 +#define FRAME_Minions25 24 +#define FRAME_Minions26 25 +#define FRAME_Minions27 26 +#define FRAME_Minions28 27 +#define FRAME_Minions29 28 +#define FRAME_Minions30 29 +#define FRAME_Minions31 30 +#define FRAME_Minions32 31 +#define FRAME_Minions33 32 +#define FRAME_Minions34 33 +#define FRAME_Minions35 34 +#define FRAME_Minions36 35 +#define FRAME_Minions37 36 +#define FRAME_Minions38 37 +#define FRAME_Minions39 38 +#define FRAME_Minions40 39 +#define FRAME_Minions41 40 +#define FRAME_Minions42 41 +#define FRAME_Minions43 42 +#define FRAME_Minions44 43 +#define FRAME_Minions45 44 +#define FRAME_Minions46 45 +#define FRAME_Minions47 46 +#define FRAME_Minions48 47 +#define FRAME_Minions49 48 +#define FRAME_Minions50 49 +#define FRAME_Minions51 50 +#define FRAME_Minions52 51 +#define FRAME_Minions53 52 +#define FRAME_Minions54 53 +#define FRAME_Minions55 54 +#define FRAME_Minions56 55 +#define FRAME_Minions57 56 +#define FRAME_Minions58 57 +#define FRAME_Minions59 58 +#define FRAME_Minions60 59 +#define FRAME_Minions61 60 +#define FRAME_Minions62 61 +#define FRAME_Minions63 62 +#define FRAME_Minions64 63 +#define FRAME_Minions65 64 +#define FRAME_Minions66 65 +#define FRAME_Minions67 66 +#define FRAME_Minions68 67 +#define FRAME_Minions69 68 +#define FRAME_Minions70 69 +#define FRAME_Minions71 70 +#define FRAME_Minions72 71 +#define FRAME_Minions73 72 +#define FRAME_Minions74 73 +#define FRAME_Minions75 74 +#define FRAME_Minions76 75 +#define FRAME_Minions77 76 +#define FRAME_Minions78 77 +#define FRAME_Minions79 78 +#define FRAME_Minions80 79 +#define FRAME_Minions81 80 +#define FRAME_Minions82 81 +#define FRAME_Minions83 82 +#define FRAME_Minions84 83 +#define FRAME_Minions85 84 +#define FRAME_Minions86 85 +#define FRAME_Minions87 86 +#define FRAME_Minions88 87 +#define FRAME_Minions89 88 +#define FRAME_Minions90 89 +#define FRAME_Minions91 90 +#define FRAME_Minions92 91 +#define FRAME_Minions93 92 +#define FRAME_Minions94 93 +#define FRAME_Minions95 94 +#define FRAME_Minions96 95 +#define FRAME_Minions97 96 +#define FRAME_Minions98 97 +#define FRAME_Minions99 98 +#define FRAME_Minions100 99 +#define FRAME_Minions101 100 +#define FRAME_Minions102 101 +#define FRAME_Minions103 102 +#define FRAME_Minions104 103 +#define FRAME_Minions105 104 +#define FRAME_Minions106 105 +#define FRAME_Minions107 106 +#define FRAME_Minions108 107 +#define FRAME_Minions109 108 +#define FRAME_Minions110 109 +#define FRAME_Minions111 110 +#define FRAME_Minions112 111 +#define FRAME_Minions113 112 +#define FRAME_Minions114 113 +#define FRAME_Minions115 114 +#define FRAME_Minions116 115 +#define FRAME_Minions117 116 +#define FRAME_Minions118 117 +#define FRAME_Minions119 118 +#define FRAME_Minions120 119 +#define FRAME_Minions121 120 +#define FRAME_Minions122 121 +#define FRAME_Minions123 122 +#define FRAME_Minions124 123 +#define FRAME_Minions125 124 +#define FRAME_Minions126 125 +#define FRAME_Minions127 126 +#define FRAME_Minions128 127 +#define FRAME_Minions129 128 +#define FRAME_Minions130 129 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 6 + +#define MESH_MINIONS99 0 +#define MESH__TORSO99 1 +#define MESH__HEAD100 2 +#define MESH__CENTERSPIKE100 3 +#define MESH__LEFTARM99 4 +#define MESH__RIGHTARM99 5 diff --git a/Toolkit/Programming/GameCode/game/c_ssithrascout.c b/Toolkit/Programming/GameCode/game/c_ssithrascout.c new file mode 100644 index 0000000..9ae249e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_ssithrascout.c @@ -0,0 +1,170 @@ +//============================================================================== +// +// m_ssithrascout.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#include "c_ssithrascout_anim.h" +#include "c_ssithrascout.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + victimSsithra Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + &scout_move_c_action1, + &scout_move_c_action2, + &scout_move_c_action3, + &scout_move_c_action4, + &scout_move_c_action5, + &scout_move_c_action6, + &scout_move_c_action7, + &scout_move_c_action8, + &scout_move_c_action9, + &scout_move_c_action10, + &scout_move_c_death1, + &scout_move_c_idle1, + &scout_move_c_idle2, + &scout_move_c_idle3, +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + scout_c_anims +-------------------------------------------------------------------------*/ +void scout_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_ACTION8: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + case MSG_C_ACTION9: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION9; + break; + case MSG_C_ACTION10: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION10; + break; + case MSG_C_DEATH1: + self->monsterinfo.c_anim_flag |= C_ANIM_DONE; + curr_anim = ANIM_C_DEATH1; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE3; + break; + default: + break; + } + + SetAnim(self, curr_anim); +} + +/*------------------------------------------------------------------------- + SsithrascoutStaticsInit +-------------------------------------------------------------------------*/ +void SsithrascoutStaticsInit() +{ + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION1] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION2] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION3] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION4] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION5] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION6] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION7] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION8] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION9] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_ACTION10] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_DEATH1] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_IDLE1] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_IDLE2] = scout_c_anims; + classStatics[CID_SSITHRA_SCOUT].msgReceivers[MSG_C_IDLE3] = scout_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/monsters/ssithra/scout_scene/tris.fm"); + + classStatics[CID_SSITHRA_SCOUT].resInfo = &resInfo; + + sounds[SND_PAIN1] = gi.soundindex("monsters/plagueElf/pain1.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_SSITHRA_SCOUT].resInfo = &resInfo; + +} + +/*QUAKED character_ssithra_scout (1 .5 0) (-26 -16 -13) (26 16 13) +The scout +*/ +void SP_character_ssithra_scout (edict_t *self) +{ + VectorSet (self->mins, -26, -16, -13); + VectorSet (self->maxs, 26, 16, 13); + + c_character_init(self,CID_SSITHRA_SCOUT); +} + diff --git a/Toolkit/Programming/GameCode/game/c_ssithrascout.h b/Toolkit/Programming/GameCode/game/c_ssithrascout.h new file mode 100644 index 0000000..deb4a36 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_ssithrascout.h @@ -0,0 +1,44 @@ +//c_ssithrascout.h + + +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_ACTION9, + ANIM_C_ACTION10, + ANIM_C_DEATH1, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PAIN1, + NUM_SOUNDS +} SoundID_t; + +#define MODEL_SCALE 1.000000 + +extern animmove_t scout_move_c_action1; +extern animmove_t scout_move_c_action2; +extern animmove_t scout_move_c_action3; +extern animmove_t scout_move_c_action4; +extern animmove_t scout_move_c_action5; +extern animmove_t scout_move_c_action6; +extern animmove_t scout_move_c_action7; +extern animmove_t scout_move_c_action8; +extern animmove_t scout_move_c_action9; +extern animmove_t scout_move_c_action10; +extern animmove_t scout_move_c_death1; +extern animmove_t scout_move_c_idle1; +extern animmove_t scout_move_c_idle2; +extern animmove_t scout_move_c_idle3; diff --git a/Toolkit/Programming/GameCode/game/c_ssithrascout_anim.c b/Toolkit/Programming/GameCode/game/c_ssithrascout_anim.c new file mode 100644 index 0000000..0f83924 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_ssithrascout_anim.c @@ -0,0 +1,757 @@ + +//============================================================================== +// +// m_victimSsitra_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_ssithrascout_anim.h" +#include "c_ssithrascout.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action1[] = +{ + FRAME_ss_recover1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_recover39, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action1 = { 39, scout_frames_c_action1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action2[] = +{ + FRAME_ss_hecured1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_hecured60, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action2 = { 60, scout_frames_c_action2, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action3[] = +{ + FRAME_ss_talk1A1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1A86, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action3 = { 86, scout_frames_c_action3, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action4[] = +{ + FRAME_ss_talk1B1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk1B44, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action4 = { 44, scout_frames_c_action4, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action5[] = +{ + FRAME_ss_coughA1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughA26, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action5 = { 26, scout_frames_c_action5, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action6[] = +{ + FRAME_ss_noshe1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_noshe34, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action6 = { 34, scout_frames_c_action6, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action7[] = +{ + FRAME_ss_talk2A1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2A70, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action7 = { 70, scout_frames_c_action7, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action8[] = +{ + FRAME_ss_talk2B1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2B62, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action8 = { 62, scout_frames_c_action8, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action9[] = +{ + FRAME_ss_talk2C1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_talk2C25, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action9 = { 25, scout_frames_c_action9, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_action10[] = +{ + FRAME_ss_coughB1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_coughB19, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_action10 = { 19, scout_frames_c_action10, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_death1[] = +{ + FRAME_ss_death1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_death54, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_death1 = { 54, scout_frames_c_death1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_idle1 [] = +{ + FRAME_ss_breath1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_breath31, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_idle1 = { 31, scout_frames_c_idle1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_idle2 [] = +{ + FRAME_ss_idleA1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleA16, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_idle2 = { 16, scout_frames_c_idle2, ai_c_cycleend}; + + + +/*---------------------------------------------------------------------- + Ssithra Scout - +-----------------------------------------------------------------------*/ +animframe_t scout_frames_c_idle3 [] = +{ + FRAME_ss_idleB1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ss_idleB25, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t scout_move_c_idle3 = { 25, scout_frames_c_idle3, ai_c_cycleend}; + + + diff --git a/Toolkit/Programming/GameCode/game/c_ssithrascout_anim.h b/Toolkit/Programming/GameCode/game/c_ssithrascout_anim.h new file mode 100644 index 0000000..8f5476b --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_ssithrascout_anim.h @@ -0,0 +1,616 @@ +// R:\Art\models/monsters\plaguessithra\scout_scene + +// This file generated by qdata - Do NOT Modify + +#define FRAME_ss_breath1 0 +#define FRAME_ss_breath2 1 +#define FRAME_ss_breath3 2 +#define FRAME_ss_breath4 3 +#define FRAME_ss_breath5 4 +#define FRAME_ss_breath6 5 +#define FRAME_ss_breath7 6 +#define FRAME_ss_breath8 7 +#define FRAME_ss_breath9 8 +#define FRAME_ss_breath10 9 +#define FRAME_ss_breath11 10 +#define FRAME_ss_breath12 11 +#define FRAME_ss_breath13 12 +#define FRAME_ss_breath14 13 +#define FRAME_ss_breath15 14 +#define FRAME_ss_breath16 15 +#define FRAME_ss_breath17 16 +#define FRAME_ss_breath18 17 +#define FRAME_ss_breath19 18 +#define FRAME_ss_breath20 19 +#define FRAME_ss_breath21 20 +#define FRAME_ss_breath22 21 +#define FRAME_ss_breath23 22 +#define FRAME_ss_breath24 23 +#define FRAME_ss_breath25 24 +#define FRAME_ss_breath26 25 +#define FRAME_ss_breath27 26 +#define FRAME_ss_breath28 27 +#define FRAME_ss_breath29 28 +#define FRAME_ss_breath30 29 +#define FRAME_ss_breath31 30 +#define FRAME_ss_coughA1 31 +#define FRAME_ss_coughA2 32 +#define FRAME_ss_coughA3 33 +#define FRAME_ss_coughA4 34 +#define FRAME_ss_coughA5 35 +#define FRAME_ss_coughA6 36 +#define FRAME_ss_coughA7 37 +#define FRAME_ss_coughA8 38 +#define FRAME_ss_coughA9 39 +#define FRAME_ss_coughA10 40 +#define FRAME_ss_coughA11 41 +#define FRAME_ss_coughA12 42 +#define FRAME_ss_coughA13 43 +#define FRAME_ss_coughA14 44 +#define FRAME_ss_coughA15 45 +#define FRAME_ss_coughA16 46 +#define FRAME_ss_coughA17 47 +#define FRAME_ss_coughA18 48 +#define FRAME_ss_coughA19 49 +#define FRAME_ss_coughA20 50 +#define FRAME_ss_coughA21 51 +#define FRAME_ss_coughA22 52 +#define FRAME_ss_coughA23 53 +#define FRAME_ss_coughA24 54 +#define FRAME_ss_coughA25 55 +#define FRAME_ss_coughA26 56 +#define FRAME_ss_coughB1 57 +#define FRAME_ss_coughB2 58 +#define FRAME_ss_coughB3 59 +#define FRAME_ss_coughB4 60 +#define FRAME_ss_coughB5 61 +#define FRAME_ss_coughB6 62 +#define FRAME_ss_coughB7 63 +#define FRAME_ss_coughB8 64 +#define FRAME_ss_coughB9 65 +#define FRAME_ss_coughB10 66 +#define FRAME_ss_coughB11 67 +#define FRAME_ss_coughB12 68 +#define FRAME_ss_coughB13 69 +#define FRAME_ss_coughB14 70 +#define FRAME_ss_coughB15 71 +#define FRAME_ss_coughB16 72 +#define FRAME_ss_coughB17 73 +#define FRAME_ss_coughB18 74 +#define FRAME_ss_coughB19 75 +#define FRAME_ss_death1 76 +#define FRAME_ss_death2 77 +#define FRAME_ss_death3 78 +#define FRAME_ss_death4 79 +#define FRAME_ss_death5 80 +#define FRAME_ss_death6 81 +#define FRAME_ss_death7 82 +#define FRAME_ss_death8 83 +#define FRAME_ss_death9 84 +#define FRAME_ss_death10 85 +#define FRAME_ss_death11 86 +#define FRAME_ss_death12 87 +#define FRAME_ss_death13 88 +#define FRAME_ss_death14 89 +#define FRAME_ss_death15 90 +#define FRAME_ss_death16 91 +#define FRAME_ss_death17 92 +#define FRAME_ss_death18 93 +#define FRAME_ss_death19 94 +#define FRAME_ss_death20 95 +#define FRAME_ss_death21 96 +#define FRAME_ss_death22 97 +#define FRAME_ss_death23 98 +#define FRAME_ss_death24 99 +#define FRAME_ss_death25 100 +#define FRAME_ss_death26 101 +#define FRAME_ss_death27 102 +#define FRAME_ss_death28 103 +#define FRAME_ss_death29 104 +#define FRAME_ss_death30 105 +#define FRAME_ss_death31 106 +#define FRAME_ss_death32 107 +#define FRAME_ss_death33 108 +#define FRAME_ss_death34 109 +#define FRAME_ss_death35 110 +#define FRAME_ss_death36 111 +#define FRAME_ss_death37 112 +#define FRAME_ss_death38 113 +#define FRAME_ss_death39 114 +#define FRAME_ss_death40 115 +#define FRAME_ss_death41 116 +#define FRAME_ss_death42 117 +#define FRAME_ss_death43 118 +#define FRAME_ss_death44 119 +#define FRAME_ss_death45 120 +#define FRAME_ss_death46 121 +#define FRAME_ss_death47 122 +#define FRAME_ss_death48 123 +#define FRAME_ss_death49 124 +#define FRAME_ss_death50 125 +#define FRAME_ss_death51 126 +#define FRAME_ss_death52 127 +#define FRAME_ss_death53 128 +#define FRAME_ss_death54 129 +#define FRAME_ss_hecured1 130 +#define FRAME_ss_hecured2 131 +#define FRAME_ss_hecured3 132 +#define FRAME_ss_hecured4 133 +#define FRAME_ss_hecured5 134 +#define FRAME_ss_hecured6 135 +#define FRAME_ss_hecured7 136 +#define FRAME_ss_hecured8 137 +#define FRAME_ss_hecured9 138 +#define FRAME_ss_hecured10 139 +#define FRAME_ss_hecured11 140 +#define FRAME_ss_hecured12 141 +#define FRAME_ss_hecured13 142 +#define FRAME_ss_hecured14 143 +#define FRAME_ss_hecured15 144 +#define FRAME_ss_hecured16 145 +#define FRAME_ss_hecured17 146 +#define FRAME_ss_hecured18 147 +#define FRAME_ss_hecured19 148 +#define FRAME_ss_hecured20 149 +#define FRAME_ss_hecured21 150 +#define FRAME_ss_hecured22 151 +#define FRAME_ss_hecured23 152 +#define FRAME_ss_hecured24 153 +#define FRAME_ss_hecured25 154 +#define FRAME_ss_hecured26 155 +#define FRAME_ss_hecured27 156 +#define FRAME_ss_hecured28 157 +#define FRAME_ss_hecured29 158 +#define FRAME_ss_hecured30 159 +#define FRAME_ss_hecured31 160 +#define FRAME_ss_hecured32 161 +#define FRAME_ss_hecured33 162 +#define FRAME_ss_hecured34 163 +#define FRAME_ss_hecured35 164 +#define FRAME_ss_hecured36 165 +#define FRAME_ss_hecured37 166 +#define FRAME_ss_hecured38 167 +#define FRAME_ss_hecured39 168 +#define FRAME_ss_hecured40 169 +#define FRAME_ss_hecured41 170 +#define FRAME_ss_hecured42 171 +#define FRAME_ss_hecured43 172 +#define FRAME_ss_hecured44 173 +#define FRAME_ss_hecured45 174 +#define FRAME_ss_hecured46 175 +#define FRAME_ss_hecured47 176 +#define FRAME_ss_hecured48 177 +#define FRAME_ss_hecured49 178 +#define FRAME_ss_hecured50 179 +#define FRAME_ss_hecured51 180 +#define FRAME_ss_hecured52 181 +#define FRAME_ss_hecured53 182 +#define FRAME_ss_hecured54 183 +#define FRAME_ss_hecured55 184 +#define FRAME_ss_hecured56 185 +#define FRAME_ss_hecured57 186 +#define FRAME_ss_hecured58 187 +#define FRAME_ss_hecured59 188 +#define FRAME_ss_hecured60 189 +#define FRAME_ss_idleA1 190 +#define FRAME_ss_idleA2 191 +#define FRAME_ss_idleA3 192 +#define FRAME_ss_idleA4 193 +#define FRAME_ss_idleA5 194 +#define FRAME_ss_idleA6 195 +#define FRAME_ss_idleA7 196 +#define FRAME_ss_idleA8 197 +#define FRAME_ss_idleA9 198 +#define FRAME_ss_idleA10 199 +#define FRAME_ss_idleA11 200 +#define FRAME_ss_idleA12 201 +#define FRAME_ss_idleA13 202 +#define FRAME_ss_idleA14 203 +#define FRAME_ss_idleA15 204 +#define FRAME_ss_idleA16 205 +#define FRAME_ss_idleB1 206 +#define FRAME_ss_idleB2 207 +#define FRAME_ss_idleB3 208 +#define FRAME_ss_idleB4 209 +#define FRAME_ss_idleB5 210 +#define FRAME_ss_idleB6 211 +#define FRAME_ss_idleB7 212 +#define FRAME_ss_idleB8 213 +#define FRAME_ss_idleB9 214 +#define FRAME_ss_idleB10 215 +#define FRAME_ss_idleB11 216 +#define FRAME_ss_idleB12 217 +#define FRAME_ss_idleB13 218 +#define FRAME_ss_idleB14 219 +#define FRAME_ss_idleB15 220 +#define FRAME_ss_idleB16 221 +#define FRAME_ss_idleB17 222 +#define FRAME_ss_idleB18 223 +#define FRAME_ss_idleB19 224 +#define FRAME_ss_idleB20 225 +#define FRAME_ss_idleB21 226 +#define FRAME_ss_idleB22 227 +#define FRAME_ss_idleB23 228 +#define FRAME_ss_idleB24 229 +#define FRAME_ss_idleB25 230 +#define FRAME_ss_noshe1 231 +#define FRAME_ss_noshe2 232 +#define FRAME_ss_noshe3 233 +#define FRAME_ss_noshe4 234 +#define FRAME_ss_noshe5 235 +#define FRAME_ss_noshe6 236 +#define FRAME_ss_noshe7 237 +#define FRAME_ss_noshe8 238 +#define FRAME_ss_noshe9 239 +#define FRAME_ss_noshe10 240 +#define FRAME_ss_noshe11 241 +#define FRAME_ss_noshe12 242 +#define FRAME_ss_noshe13 243 +#define FRAME_ss_noshe14 244 +#define FRAME_ss_noshe15 245 +#define FRAME_ss_noshe16 246 +#define FRAME_ss_noshe17 247 +#define FRAME_ss_noshe18 248 +#define FRAME_ss_noshe19 249 +#define FRAME_ss_noshe20 250 +#define FRAME_ss_noshe21 251 +#define FRAME_ss_noshe22 252 +#define FRAME_ss_noshe23 253 +#define FRAME_ss_noshe24 254 +#define FRAME_ss_noshe25 255 +#define FRAME_ss_noshe26 256 +#define FRAME_ss_noshe27 257 +#define FRAME_ss_noshe28 258 +#define FRAME_ss_noshe29 259 +#define FRAME_ss_noshe30 260 +#define FRAME_ss_noshe31 261 +#define FRAME_ss_noshe32 262 +#define FRAME_ss_noshe33 263 +#define FRAME_ss_noshe34 264 +#define FRAME_ss_recover1 265 +#define FRAME_ss_recover2 266 +#define FRAME_ss_recover3 267 +#define FRAME_ss_recover4 268 +#define FRAME_ss_recover5 269 +#define FRAME_ss_recover6 270 +#define FRAME_ss_recover7 271 +#define FRAME_ss_recover8 272 +#define FRAME_ss_recover9 273 +#define FRAME_ss_recover10 274 +#define FRAME_ss_recover11 275 +#define FRAME_ss_recover12 276 +#define FRAME_ss_recover13 277 +#define FRAME_ss_recover14 278 +#define FRAME_ss_recover15 279 +#define FRAME_ss_recover16 280 +#define FRAME_ss_recover17 281 +#define FRAME_ss_recover18 282 +#define FRAME_ss_recover19 283 +#define FRAME_ss_recover20 284 +#define FRAME_ss_recover21 285 +#define FRAME_ss_recover22 286 +#define FRAME_ss_recover23 287 +#define FRAME_ss_recover24 288 +#define FRAME_ss_recover25 289 +#define FRAME_ss_recover26 290 +#define FRAME_ss_recover27 291 +#define FRAME_ss_recover28 292 +#define FRAME_ss_recover29 293 +#define FRAME_ss_recover30 294 +#define FRAME_ss_recover31 295 +#define FRAME_ss_recover32 296 +#define FRAME_ss_recover33 297 +#define FRAME_ss_recover34 298 +#define FRAME_ss_recover35 299 +#define FRAME_ss_recover36 300 +#define FRAME_ss_recover37 301 +#define FRAME_ss_recover38 302 +#define FRAME_ss_recover39 303 +#define FRAME_ss_talk1A1 304 +#define FRAME_ss_talk1A2 305 +#define FRAME_ss_talk1A3 306 +#define FRAME_ss_talk1A4 307 +#define FRAME_ss_talk1A5 308 +#define FRAME_ss_talk1A6 309 +#define FRAME_ss_talk1A7 310 +#define FRAME_ss_talk1A8 311 +#define FRAME_ss_talk1A9 312 +#define FRAME_ss_talk1A10 313 +#define FRAME_ss_talk1A11 314 +#define FRAME_ss_talk1A12 315 +#define FRAME_ss_talk1A13 316 +#define FRAME_ss_talk1A14 317 +#define FRAME_ss_talk1A15 318 +#define FRAME_ss_talk1A16 319 +#define FRAME_ss_talk1A17 320 +#define FRAME_ss_talk1A18 321 +#define FRAME_ss_talk1A19 322 +#define FRAME_ss_talk1A20 323 +#define FRAME_ss_talk1A21 324 +#define FRAME_ss_talk1A22 325 +#define FRAME_ss_talk1A23 326 +#define FRAME_ss_talk1A24 327 +#define FRAME_ss_talk1A25 328 +#define FRAME_ss_talk1A26 329 +#define FRAME_ss_talk1A27 330 +#define FRAME_ss_talk1A28 331 +#define FRAME_ss_talk1A29 332 +#define FRAME_ss_talk1A30 333 +#define FRAME_ss_talk1A31 334 +#define FRAME_ss_talk1A32 335 +#define FRAME_ss_talk1A33 336 +#define FRAME_ss_talk1A34 337 +#define FRAME_ss_talk1A35 338 +#define FRAME_ss_talk1A36 339 +#define FRAME_ss_talk1A37 340 +#define FRAME_ss_talk1A38 341 +#define FRAME_ss_talk1A39 342 +#define FRAME_ss_talk1A40 343 +#define FRAME_ss_talk1A41 344 +#define FRAME_ss_talk1A42 345 +#define FRAME_ss_talk1A43 346 +#define FRAME_ss_talk1A44 347 +#define FRAME_ss_talk1A45 348 +#define FRAME_ss_talk1A46 349 +#define FRAME_ss_talk1A47 350 +#define FRAME_ss_talk1A48 351 +#define FRAME_ss_talk1A49 352 +#define FRAME_ss_talk1A50 353 +#define FRAME_ss_talk1A51 354 +#define FRAME_ss_talk1A52 355 +#define FRAME_ss_talk1A53 356 +#define FRAME_ss_talk1A54 357 +#define FRAME_ss_talk1A55 358 +#define FRAME_ss_talk1A56 359 +#define FRAME_ss_talk1A57 360 +#define FRAME_ss_talk1A58 361 +#define FRAME_ss_talk1A59 362 +#define FRAME_ss_talk1A60 363 +#define FRAME_ss_talk1A61 364 +#define FRAME_ss_talk1A62 365 +#define FRAME_ss_talk1A63 366 +#define FRAME_ss_talk1A64 367 +#define FRAME_ss_talk1A65 368 +#define FRAME_ss_talk1A66 369 +#define FRAME_ss_talk1A67 370 +#define FRAME_ss_talk1A68 371 +#define FRAME_ss_talk1A69 372 +#define FRAME_ss_talk1A70 373 +#define FRAME_ss_talk1A71 374 +#define FRAME_ss_talk1A72 375 +#define FRAME_ss_talk1A73 376 +#define FRAME_ss_talk1A74 377 +#define FRAME_ss_talk1A75 378 +#define FRAME_ss_talk1A76 379 +#define FRAME_ss_talk1A77 380 +#define FRAME_ss_talk1A78 381 +#define FRAME_ss_talk1A79 382 +#define FRAME_ss_talk1A80 383 +#define FRAME_ss_talk1A81 384 +#define FRAME_ss_talk1A82 385 +#define FRAME_ss_talk1A83 386 +#define FRAME_ss_talk1A84 387 +#define FRAME_ss_talk1A85 388 +#define FRAME_ss_talk1A86 389 +#define FRAME_ss_talk1B1 390 +#define FRAME_ss_talk1B2 391 +#define FRAME_ss_talk1B3 392 +#define FRAME_ss_talk1B4 393 +#define FRAME_ss_talk1B5 394 +#define FRAME_ss_talk1B6 395 +#define FRAME_ss_talk1B7 396 +#define FRAME_ss_talk1B8 397 +#define FRAME_ss_talk1B9 398 +#define FRAME_ss_talk1B10 399 +#define FRAME_ss_talk1B11 400 +#define FRAME_ss_talk1B12 401 +#define FRAME_ss_talk1B13 402 +#define FRAME_ss_talk1B14 403 +#define FRAME_ss_talk1B15 404 +#define FRAME_ss_talk1B16 405 +#define FRAME_ss_talk1B17 406 +#define FRAME_ss_talk1B18 407 +#define FRAME_ss_talk1B19 408 +#define FRAME_ss_talk1B20 409 +#define FRAME_ss_talk1B21 410 +#define FRAME_ss_talk1B22 411 +#define FRAME_ss_talk1B23 412 +#define FRAME_ss_talk1B24 413 +#define FRAME_ss_talk1B25 414 +#define FRAME_ss_talk1B26 415 +#define FRAME_ss_talk1B27 416 +#define FRAME_ss_talk1B28 417 +#define FRAME_ss_talk1B29 418 +#define FRAME_ss_talk1B30 419 +#define FRAME_ss_talk1B31 420 +#define FRAME_ss_talk1B32 421 +#define FRAME_ss_talk1B33 422 +#define FRAME_ss_talk1B34 423 +#define FRAME_ss_talk1B35 424 +#define FRAME_ss_talk1B36 425 +#define FRAME_ss_talk1B37 426 +#define FRAME_ss_talk1B38 427 +#define FRAME_ss_talk1B39 428 +#define FRAME_ss_talk1B40 429 +#define FRAME_ss_talk1B41 430 +#define FRAME_ss_talk1B42 431 +#define FRAME_ss_talk1B43 432 +#define FRAME_ss_talk1B44 433 +#define FRAME_ss_talk2A1 434 +#define FRAME_ss_talk2A2 435 +#define FRAME_ss_talk2A3 436 +#define FRAME_ss_talk2A4 437 +#define FRAME_ss_talk2A5 438 +#define FRAME_ss_talk2A6 439 +#define FRAME_ss_talk2A7 440 +#define FRAME_ss_talk2A8 441 +#define FRAME_ss_talk2A9 442 +#define FRAME_ss_talk2A10 443 +#define FRAME_ss_talk2A11 444 +#define FRAME_ss_talk2A12 445 +#define FRAME_ss_talk2A13 446 +#define FRAME_ss_talk2A14 447 +#define FRAME_ss_talk2A15 448 +#define FRAME_ss_talk2A16 449 +#define FRAME_ss_talk2A17 450 +#define FRAME_ss_talk2A18 451 +#define FRAME_ss_talk2A19 452 +#define FRAME_ss_talk2A20 453 +#define FRAME_ss_talk2A21 454 +#define FRAME_ss_talk2A22 455 +#define FRAME_ss_talk2A23 456 +#define FRAME_ss_talk2A24 457 +#define FRAME_ss_talk2A25 458 +#define FRAME_ss_talk2A26 459 +#define FRAME_ss_talk2A27 460 +#define FRAME_ss_talk2A28 461 +#define FRAME_ss_talk2A29 462 +#define FRAME_ss_talk2A30 463 +#define FRAME_ss_talk2A31 464 +#define FRAME_ss_talk2A32 465 +#define FRAME_ss_talk2A33 466 +#define FRAME_ss_talk2A34 467 +#define FRAME_ss_talk2A35 468 +#define FRAME_ss_talk2A36 469 +#define FRAME_ss_talk2A37 470 +#define FRAME_ss_talk2A38 471 +#define FRAME_ss_talk2A39 472 +#define FRAME_ss_talk2A40 473 +#define FRAME_ss_talk2A41 474 +#define FRAME_ss_talk2A42 475 +#define FRAME_ss_talk2A43 476 +#define FRAME_ss_talk2A44 477 +#define FRAME_ss_talk2A45 478 +#define FRAME_ss_talk2A46 479 +#define FRAME_ss_talk2A47 480 +#define FRAME_ss_talk2A48 481 +#define FRAME_ss_talk2A49 482 +#define FRAME_ss_talk2A50 483 +#define FRAME_ss_talk2A51 484 +#define FRAME_ss_talk2A52 485 +#define FRAME_ss_talk2A53 486 +#define FRAME_ss_talk2A54 487 +#define FRAME_ss_talk2A55 488 +#define FRAME_ss_talk2A56 489 +#define FRAME_ss_talk2A57 490 +#define FRAME_ss_talk2A58 491 +#define FRAME_ss_talk2A59 492 +#define FRAME_ss_talk2A60 493 +#define FRAME_ss_talk2A61 494 +#define FRAME_ss_talk2A62 495 +#define FRAME_ss_talk2A63 496 +#define FRAME_ss_talk2A64 497 +#define FRAME_ss_talk2A65 498 +#define FRAME_ss_talk2A66 499 +#define FRAME_ss_talk2A67 500 +#define FRAME_ss_talk2A68 501 +#define FRAME_ss_talk2A69 502 +#define FRAME_ss_talk2A70 503 +#define FRAME_ss_talk2B1 504 +#define FRAME_ss_talk2B2 505 +#define FRAME_ss_talk2B3 506 +#define FRAME_ss_talk2B4 507 +#define FRAME_ss_talk2B5 508 +#define FRAME_ss_talk2B6 509 +#define FRAME_ss_talk2B7 510 +#define FRAME_ss_talk2B8 511 +#define FRAME_ss_talk2B9 512 +#define FRAME_ss_talk2B10 513 +#define FRAME_ss_talk2B11 514 +#define FRAME_ss_talk2B12 515 +#define FRAME_ss_talk2B13 516 +#define FRAME_ss_talk2B14 517 +#define FRAME_ss_talk2B15 518 +#define FRAME_ss_talk2B16 519 +#define FRAME_ss_talk2B17 520 +#define FRAME_ss_talk2B18 521 +#define FRAME_ss_talk2B19 522 +#define FRAME_ss_talk2B20 523 +#define FRAME_ss_talk2B21 524 +#define FRAME_ss_talk2B22 525 +#define FRAME_ss_talk2B23 526 +#define FRAME_ss_talk2B24 527 +#define FRAME_ss_talk2B25 528 +#define FRAME_ss_talk2B26 529 +#define FRAME_ss_talk2B27 530 +#define FRAME_ss_talk2B28 531 +#define FRAME_ss_talk2B29 532 +#define FRAME_ss_talk2B30 533 +#define FRAME_ss_talk2B31 534 +#define FRAME_ss_talk2B32 535 +#define FRAME_ss_talk2B33 536 +#define FRAME_ss_talk2B34 537 +#define FRAME_ss_talk2B35 538 +#define FRAME_ss_talk2B36 539 +#define FRAME_ss_talk2B37 540 +#define FRAME_ss_talk2B38 541 +#define FRAME_ss_talk2B39 542 +#define FRAME_ss_talk2B40 543 +#define FRAME_ss_talk2B41 544 +#define FRAME_ss_talk2B42 545 +#define FRAME_ss_talk2B43 546 +#define FRAME_ss_talk2B44 547 +#define FRAME_ss_talk2B45 548 +#define FRAME_ss_talk2B46 549 +#define FRAME_ss_talk2B47 550 +#define FRAME_ss_talk2B48 551 +#define FRAME_ss_talk2B49 552 +#define FRAME_ss_talk2B50 553 +#define FRAME_ss_talk2B51 554 +#define FRAME_ss_talk2B52 555 +#define FRAME_ss_talk2B53 556 +#define FRAME_ss_talk2B54 557 +#define FRAME_ss_talk2B55 558 +#define FRAME_ss_talk2B56 559 +#define FRAME_ss_talk2B57 560 +#define FRAME_ss_talk2B58 561 +#define FRAME_ss_talk2B59 562 +#define FRAME_ss_talk2B60 563 +#define FRAME_ss_talk2B61 564 +#define FRAME_ss_talk2B62 565 +#define FRAME_ss_talk2C1 566 +#define FRAME_ss_talk2C2 567 +#define FRAME_ss_talk2C3 568 +#define FRAME_ss_talk2C4 569 +#define FRAME_ss_talk2C5 570 +#define FRAME_ss_talk2C6 571 +#define FRAME_ss_talk2C7 572 +#define FRAME_ss_talk2C8 573 +#define FRAME_ss_talk2C9 574 +#define FRAME_ss_talk2C10 575 +#define FRAME_ss_talk2C11 576 +#define FRAME_ss_talk2C12 577 +#define FRAME_ss_talk2C13 578 +#define FRAME_ss_talk2C14 579 +#define FRAME_ss_talk2C15 580 +#define FRAME_ss_talk2C16 581 +#define FRAME_ss_talk2C17 582 +#define FRAME_ss_talk2C18 583 +#define FRAME_ss_talk2C19 584 +#define FRAME_ss_talk2C20 585 +#define FRAME_ss_talk2C21 586 +#define FRAME_ss_talk2C22 587 +#define FRAME_ss_talk2C23 588 +#define FRAME_ss_talk2C24 589 +#define FRAME_ss_talk2C25 590 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_POLY 0 +#define MESH__LOWERTORSO 1 +#define MESH__CAPLOWERTORSO 2 +#define MESH__LEFTLEG 3 +#define MESH__RIGHTLEG 4 +#define MESH__UPPERTORSO 5 +#define MESH__CAPTOPUPPERTORSO 6 +#define MESH__CAPBOTTOMUPPERTORSO 7 +#define MESH__LEFTARM 8 +#define MESH__RIGHTARM 9 +#define MESH__HEAD 10 +#define MESH__CENTERSPIKE 11 +#define MESH__LEFT1SPIKE 12 +#define MESH__RIGHT1SPIKE 13 +#define MESH__RIGHT2SPIKE 14 +#define MESH__CAPHEAD 15 diff --git a/Toolkit/Programming/GameCode/game/c_tome.c b/Toolkit/Programming/GameCode/game/c_tome.c new file mode 100644 index 0000000..14e0fc1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_tome.c @@ -0,0 +1,97 @@ +/*------------------------------------------------------------------- +c_tome.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + +-------------------------------------------------------------------*/ +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#include "c_tome.h" +#include "c_tome_anim.h" +#include "c_ai.h" + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + // Cinematics + &tome_move_c_idle1, + &tome_move_c_idle2, +}; + +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + tome_c_anims +-------------------------------------------------------------------------*/ +void tome_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + +/*------------------------------------------------------------------------- + PlagueElfStaticsInit +-------------------------------------------------------------------------*/ +void TomeStaticsInit() +{ + + classStatics[CID_C_TOME].msgReceivers[MSG_C_IDLE1] = tome_c_anims; + classStatics[CID_C_TOME].msgReceivers[MSG_C_IDLE2] = tome_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/spells/book/tris.fm"); + + classStatics[CID_C_TOME].resInfo = &resInfo; + +} + + +/*QUAKED character_tome (1 .5 0) (-4 -8 -12) (4 8 12) INVISIBLE +The talking tome of power (sounds like a hot babe) +*/ +void SP_character_tome (edict_t *self) +{ + VectorSet (self->mins, -4, -8, -12); + VectorSet (self->maxs, 4, 8, 12); + + c_character_init(self,CID_C_TOME); +} diff --git a/Toolkit/Programming/GameCode/game/c_tome.h b/Toolkit/Programming/GameCode/game/c_tome.h new file mode 100644 index 0000000..e0266ac --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_tome.h @@ -0,0 +1,11 @@ +typedef enum AnimID_e +{ + ANIM_C_IDLE1, + ANIM_C_IDLE2, + NUM_ANIMS +} AnimID_t; + +void MG_InitMoods(edict_t *self); + +extern animmove_t tome_move_c_idle1; +extern animmove_t tome_move_c_idle2; diff --git a/Toolkit/Programming/GameCode/game/c_tome_anim.c b/Toolkit/Programming/GameCode/game/c_tome_anim.c new file mode 100644 index 0000000..a8454dd --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_tome_anim.c @@ -0,0 +1,82 @@ +//============================================================================== +// +// c_tome_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_tome_anim.h" +#include "c_tome.h" + +#include "g_monster.h" +#include "c_ai.h" + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +/*---------------------------------------------------------------------- + Tome of Power +-----------------------------------------------------------------------*/ +animframe_t tome_frames_c_idle1 [] = +{ + FRAME_poly000, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly001, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly002, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly003, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly004, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly005, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly006, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly007, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly008, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly009, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly010, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly011, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly012, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly013, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly014, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly015, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly016, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly017, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly018, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly019, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly020, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly021, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly022, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly023, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly024, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly025, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly026, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly027, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly028, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly029, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_poly030, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t tome_move_c_idle1 = {31, tome_frames_c_idle1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Tome of Power +-----------------------------------------------------------------------*/ +animframe_t tome_frames_c_idle2 [] = +{ + FRAME_poly000, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t tome_move_c_idle2 = {1, tome_frames_c_idle2, ai_c_cycleend}; + + diff --git a/Toolkit/Programming/GameCode/game/c_tome_anim.h b/Toolkit/Programming/GameCode/game/c_tome_anim.h new file mode 100644 index 0000000..74028bd --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_tome_anim.h @@ -0,0 +1,42 @@ +// R:\Art\models/spells\book + +// This file generated by qdata - Do NOT Modify + +#define FRAME_poly000 0 +#define FRAME_poly001 1 +#define FRAME_poly002 2 +#define FRAME_poly003 3 +#define FRAME_poly004 4 +#define FRAME_poly005 5 +#define FRAME_poly006 6 +#define FRAME_poly007 7 +#define FRAME_poly008 8 +#define FRAME_poly009 9 +#define FRAME_poly010 10 +#define FRAME_poly011 11 +#define FRAME_poly012 12 +#define FRAME_poly013 13 +#define FRAME_poly014 14 +#define FRAME_poly015 15 +#define FRAME_poly016 16 +#define FRAME_poly017 17 +#define FRAME_poly018 18 +#define FRAME_poly019 19 +#define FRAME_poly020 20 +#define FRAME_poly021 21 +#define FRAME_poly022 22 +#define FRAME_poly023 23 +#define FRAME_poly024 24 +#define FRAME_poly025 25 +#define FRAME_poly026 26 +#define FRAME_poly027 27 +#define FRAME_poly028 28 +#define FRAME_poly029 29 +#define FRAME_poly030 30 +#define FRAME_test 31 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 1 + +#define MESH_DEFAULT 0 diff --git a/Toolkit/Programming/GameCode/game/c_victimssithra.c b/Toolkit/Programming/GameCode/game/c_victimssithra.c new file mode 100644 index 0000000..a39fea8 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_victimssithra.c @@ -0,0 +1,129 @@ +//============================================================================== +// +// m_victimSsithra.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#include "c_victimSsithra.h" +#include "c_ai.h" + + +void BboxYawAndScale(edict_t *self); + +/*---------------------------------------------------------------------- + victimSsithra Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + &victimSsithra_move_c_action1, + &victimSsithra_move_c_action2, + &victimSsithra_move_c_action3, + &victimSsithra_move_c_action4, + &victimSsithra_move_c_action5, + &victimSsithra_move_c_action6 +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + victimSsithra_c_anims +-------------------------------------------------------------------------*/ +void victimSsithra_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6: + self->monsterinfo.c_anim_flag |= C_ANIM_DONE; + curr_anim = ANIM_C_ACTION6; + break; + default: + break; + } + + SetAnim(self, curr_anim); +} + +/*------------------------------------------------------------------------- + PlagueElfStaticsInit +-------------------------------------------------------------------------*/ +void victimSsithraStaticsInit() +{ + + classStatics[CID_SSITHRA_VICTIM].msgReceivers[MSG_C_IDLE1] = victimSsithra_c_anims; + classStatics[CID_SSITHRA_VICTIM].msgReceivers[MSG_C_ACTION1] = victimSsithra_c_anims; + classStatics[CID_SSITHRA_VICTIM].msgReceivers[MSG_C_ACTION2] = victimSsithra_c_anims; + classStatics[CID_SSITHRA_VICTIM].msgReceivers[MSG_C_ACTION3] = victimSsithra_c_anims; + classStatics[CID_SSITHRA_VICTIM].msgReceivers[MSG_C_ACTION4] = victimSsithra_c_anims; + classStatics[CID_SSITHRA_VICTIM].msgReceivers[MSG_C_ACTION5] = victimSsithra_c_anims; + classStatics[CID_SSITHRA_VICTIM].msgReceivers[MSG_C_ACTION6] = victimSsithra_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/monsters/Ssithra/cinematics/tris.fm"); + + classStatics[CID_SSITHRA_VICTIM].resInfo = &resInfo; + + sounds[SND_PAIN1] = gi.soundindex("monsters/plagueElf/pain1.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_SSITHRA_VICTIM].resInfo = &resInfo; + +} + +/*QUAKED character_ssithra_victim (1 .5 0) (-40 -16 -2) (40 16 2) INVISIBLE +The Ssithra Victim for use in the torture scene +*/ +void SP_character_ssithra_victim (edict_t *self) +{ + VectorSet (self->mins, -40, -16, -2); + VectorSet (self->maxs, 40, 16, 2); + + c_character_init(self,CID_SSITHRA_VICTIM); + +} + diff --git a/Toolkit/Programming/GameCode/game/c_victimssithra.h b/Toolkit/Programming/GameCode/game/c_victimssithra.h new file mode 100644 index 0000000..00cb0a1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_victimssithra.h @@ -0,0 +1,28 @@ +//c_victimSsithra.h + + +typedef enum AnimID_e +{ + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PAIN1, + NUM_SOUNDS +} SoundID_t; + +#define MODEL_SCALE 1.000000 + +extern animmove_t victimSsithra_move_c_action1; +extern animmove_t victimSsithra_move_c_action2; +extern animmove_t victimSsithra_move_c_action3; +extern animmove_t victimSsithra_move_c_action4; +extern animmove_t victimSsithra_move_c_action5; +extern animmove_t victimSsithra_move_c_action6; diff --git a/Toolkit/Programming/GameCode/game/c_victimssithra_anim.c b/Toolkit/Programming/GameCode/game/c_victimssithra_anim.c new file mode 100644 index 0000000..a6ab54a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_victimssithra_anim.c @@ -0,0 +1,545 @@ +//============================================================================== +// +// m_victimSsitra_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_victimssithra_anim.h" +#include "c_victimssithra.h" +#include "c_ai.h" + +//============================================================================== +// victimSsitra +//============================================================================== +animframe_t ssithra_frames_c_action1 [] = +{ + FRAME_rackpain1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rackpain20, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t victimSsithra_move_c_action1 = {20, ssithra_frames_c_action1, ai_c_cycleend}; + +//============================================================================== +// victimSsitra +//============================================================================== +animframe_t ssithra_frames_c_action2 [] = +{ + FRAME_release1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_release23, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t victimSsithra_move_c_action2 = {23, ssithra_frames_c_action2, ai_c_cycleend}; + +//============================================================================== +// victimSsitra +//============================================================================== +animframe_t ssithra_frames_c_action3 [] = +{ + FRAME_recover1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_recover33, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t victimSsithra_move_c_action3 = {33, ssithra_frames_c_action3, ai_c_cycleend}; + +//============================================================================== +// victimSsitra +//============================================================================== +animframe_t ssithra_frames_c_action4 [] = +{ + FRAME_tv_toolate1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate100, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate129, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate130, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate131, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate132, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate133, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate134, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate135, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate136, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate137, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate138, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate139, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate140, ai_c_move, 0, 0, 0, NULL, 0, NULL, + + FRAME_tv_toolate141, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_toolate142, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t victimSsithra_move_c_action4 = {142, ssithra_frames_c_action4, ai_c_cycleend}; + + +//============================================================================== +// victimSsitra +//============================================================================== +animframe_t ssithra_frames_c_action5 [110] = +{ + FRAME_tv_itwillA1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA100,ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillA110, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t victimSsithra_move_c_action5 = {110, ssithra_frames_c_action5, ai_c_cycleend}; + +//============================================================================== +// victimSsitra +//============================================================================== +animframe_t ssithra_frames_c_action6 [129] = +{ + FRAME_tv_itwillB1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB60, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB61, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB80, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB81, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB82, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB83, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB84, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB85, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB86, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB87, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB88, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB89, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB90, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB91, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB92, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB93, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB94, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB95, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB96, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB97, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB98, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB99, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB100,ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB101, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB102, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB103, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB104, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB105, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB106, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB107, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB108, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB109, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB110, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB111, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB112, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB113, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB114, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB115, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB116, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB117, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB118, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB119, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB120, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB121, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB122, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB123, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB124, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB125, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB126, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB127, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB128, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_tv_itwillB129, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t victimSsithra_move_c_action6 = {129, ssithra_frames_c_action6, ai_c_cycleend}; diff --git a/Toolkit/Programming/GameCode/game/c_victimssithra_anim.h b/Toolkit/Programming/GameCode/game/c_victimssithra_anim.h new file mode 100644 index 0000000..658ab23 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/c_victimssithra_anim.h @@ -0,0 +1,483 @@ +// R:\Art\models/monsters\plaguessithra\cinematics + +// This file generated by qdata - Do NOT Modify + +#define FRAME_rackpain1 0 +#define FRAME_rackpain2 1 +#define FRAME_rackpain3 2 +#define FRAME_rackpain4 3 +#define FRAME_rackpain5 4 +#define FRAME_rackpain6 5 +#define FRAME_rackpain7 6 +#define FRAME_rackpain8 7 +#define FRAME_rackpain9 8 +#define FRAME_rackpain10 9 +#define FRAME_rackpain11 10 +#define FRAME_rackpain12 11 +#define FRAME_rackpain13 12 +#define FRAME_rackpain14 13 +#define FRAME_rackpain15 14 +#define FRAME_rackpain16 15 +#define FRAME_rackpain17 16 +#define FRAME_rackpain18 17 +#define FRAME_rackpain19 18 +#define FRAME_rackpain20 19 +#define FRAME_recover1 20 +#define FRAME_recover2 21 +#define FRAME_recover3 22 +#define FRAME_recover4 23 +#define FRAME_recover5 24 +#define FRAME_recover6 25 +#define FRAME_recover7 26 +#define FRAME_recover8 27 +#define FRAME_recover9 28 +#define FRAME_recover10 29 +#define FRAME_recover11 30 +#define FRAME_recover12 31 +#define FRAME_recover13 32 +#define FRAME_recover14 33 +#define FRAME_recover15 34 +#define FRAME_recover16 35 +#define FRAME_recover17 36 +#define FRAME_recover18 37 +#define FRAME_recover19 38 +#define FRAME_recover20 39 +#define FRAME_recover21 40 +#define FRAME_recover22 41 +#define FRAME_recover23 42 +#define FRAME_recover24 43 +#define FRAME_recover25 44 +#define FRAME_recover26 45 +#define FRAME_recover27 46 +#define FRAME_recover28 47 +#define FRAME_recover29 48 +#define FRAME_recover30 49 +#define FRAME_recover31 50 +#define FRAME_recover32 51 +#define FRAME_recover33 52 +#define FRAME_recover34 53 +#define FRAME_release1 54 +#define FRAME_release2 55 +#define FRAME_release3 56 +#define FRAME_release4 57 +#define FRAME_release5 58 +#define FRAME_release6 59 +#define FRAME_release7 60 +#define FRAME_release8 61 +#define FRAME_release9 62 +#define FRAME_release10 63 +#define FRAME_release11 64 +#define FRAME_release12 65 +#define FRAME_release13 66 +#define FRAME_release14 67 +#define FRAME_release15 68 +#define FRAME_release16 69 +#define FRAME_release17 70 +#define FRAME_release18 71 +#define FRAME_release19 72 +#define FRAME_release20 73 +#define FRAME_release21 74 +#define FRAME_release22 75 +#define FRAME_release23 76 +#define FRAME_tv_toolate1 77 +#define FRAME_tv_toolate2 78 +#define FRAME_tv_toolate3 79 +#define FRAME_tv_toolate4 80 +#define FRAME_tv_toolate5 81 +#define FRAME_tv_toolate6 82 +#define FRAME_tv_toolate7 83 +#define FRAME_tv_toolate8 84 +#define FRAME_tv_toolate9 85 +#define FRAME_tv_toolate10 86 +#define FRAME_tv_toolate11 87 +#define FRAME_tv_toolate12 88 +#define FRAME_tv_toolate13 89 +#define FRAME_tv_toolate14 90 +#define FRAME_tv_toolate15 91 +#define FRAME_tv_toolate16 92 +#define FRAME_tv_toolate17 93 +#define FRAME_tv_toolate18 94 +#define FRAME_tv_toolate19 95 +#define FRAME_tv_toolate20 96 +#define FRAME_tv_toolate21 97 +#define FRAME_tv_toolate22 98 +#define FRAME_tv_toolate23 99 +#define FRAME_tv_toolate24 100 +#define FRAME_tv_toolate25 101 +#define FRAME_tv_toolate26 102 +#define FRAME_tv_toolate27 103 +#define FRAME_tv_toolate28 104 +#define FRAME_tv_toolate29 105 +#define FRAME_tv_toolate30 106 +#define FRAME_tv_toolate31 107 +#define FRAME_tv_toolate32 108 +#define FRAME_tv_toolate33 109 +#define FRAME_tv_toolate34 110 +#define FRAME_tv_toolate35 111 +#define FRAME_tv_toolate36 112 +#define FRAME_tv_toolate37 113 +#define FRAME_tv_toolate38 114 +#define FRAME_tv_toolate39 115 +#define FRAME_tv_toolate40 116 +#define FRAME_tv_toolate41 117 +#define FRAME_tv_toolate42 118 +#define FRAME_tv_toolate43 119 +#define FRAME_tv_toolate44 120 +#define FRAME_tv_toolate45 121 +#define FRAME_tv_toolate46 122 +#define FRAME_tv_toolate47 123 +#define FRAME_tv_toolate48 124 +#define FRAME_tv_toolate49 125 +#define FRAME_tv_toolate50 126 +#define FRAME_tv_toolate51 127 +#define FRAME_tv_toolate52 128 +#define FRAME_tv_toolate53 129 +#define FRAME_tv_toolate54 130 +#define FRAME_tv_toolate55 131 +#define FRAME_tv_toolate56 132 +#define FRAME_tv_toolate57 133 +#define FRAME_tv_toolate58 134 +#define FRAME_tv_toolate59 135 +#define FRAME_tv_toolate60 136 +#define FRAME_tv_toolate61 137 +#define FRAME_tv_toolate62 138 +#define FRAME_tv_toolate63 139 +#define FRAME_tv_toolate64 140 +#define FRAME_tv_toolate65 141 +#define FRAME_tv_toolate66 142 +#define FRAME_tv_toolate67 143 +#define FRAME_tv_toolate68 144 +#define FRAME_tv_toolate69 145 +#define FRAME_tv_toolate70 146 +#define FRAME_tv_toolate71 147 +#define FRAME_tv_toolate72 148 +#define FRAME_tv_toolate73 149 +#define FRAME_tv_toolate74 150 +#define FRAME_tv_toolate75 151 +#define FRAME_tv_toolate76 152 +#define FRAME_tv_toolate77 153 +#define FRAME_tv_toolate78 154 +#define FRAME_tv_toolate79 155 +#define FRAME_tv_toolate80 156 +#define FRAME_tv_toolate81 157 +#define FRAME_tv_toolate82 158 +#define FRAME_tv_toolate83 159 +#define FRAME_tv_toolate84 160 +#define FRAME_tv_toolate85 161 +#define FRAME_tv_toolate86 162 +#define FRAME_tv_toolate87 163 +#define FRAME_tv_toolate88 164 +#define FRAME_tv_toolate89 165 +#define FRAME_tv_toolate90 166 +#define FRAME_tv_toolate91 167 +#define FRAME_tv_toolate92 168 +#define FRAME_tv_toolate93 169 +#define FRAME_tv_toolate94 170 +#define FRAME_tv_toolate95 171 +#define FRAME_tv_toolate96 172 +#define FRAME_tv_toolate97 173 +#define FRAME_tv_toolate98 174 +#define FRAME_tv_toolate99 175 +#define FRAME_tv_toolate100 176 +#define FRAME_tv_toolate101 177 +#define FRAME_tv_toolate102 178 +#define FRAME_tv_toolate103 179 +#define FRAME_tv_toolate104 180 +#define FRAME_tv_toolate105 181 +#define FRAME_tv_toolate106 182 +#define FRAME_tv_toolate107 183 +#define FRAME_tv_toolate108 184 +#define FRAME_tv_toolate109 185 +#define FRAME_tv_toolate110 186 +#define FRAME_tv_toolate111 187 +#define FRAME_tv_toolate112 188 +#define FRAME_tv_toolate113 189 +#define FRAME_tv_toolate114 190 +#define FRAME_tv_toolate115 191 +#define FRAME_tv_toolate116 192 +#define FRAME_tv_toolate117 193 +#define FRAME_tv_toolate118 194 +#define FRAME_tv_toolate119 195 +#define FRAME_tv_toolate120 196 +#define FRAME_tv_toolate121 197 +#define FRAME_tv_toolate122 198 +#define FRAME_tv_toolate123 199 +#define FRAME_tv_toolate124 200 +#define FRAME_tv_toolate125 201 +#define FRAME_tv_toolate126 202 +#define FRAME_tv_toolate127 203 +#define FRAME_tv_toolate128 204 +#define FRAME_tv_toolate129 205 +#define FRAME_tv_toolate130 206 +#define FRAME_tv_toolate131 207 +#define FRAME_tv_toolate132 208 +#define FRAME_tv_toolate133 209 +#define FRAME_tv_toolate134 210 +#define FRAME_tv_toolate135 211 +#define FRAME_tv_toolate136 212 +#define FRAME_tv_toolate137 213 +#define FRAME_tv_toolate138 214 +#define FRAME_tv_toolate139 215 +#define FRAME_tv_toolate140 216 +#define FRAME_tv_toolate141 217 +#define FRAME_tv_toolate142 218 +#define FRAME_tv_itwillA1 219 +#define FRAME_tv_itwillA2 220 +#define FRAME_tv_itwillA3 221 +#define FRAME_tv_itwillA4 222 +#define FRAME_tv_itwillA5 223 +#define FRAME_tv_itwillA6 224 +#define FRAME_tv_itwillA7 225 +#define FRAME_tv_itwillA8 226 +#define FRAME_tv_itwillA9 227 +#define FRAME_tv_itwillA10 228 +#define FRAME_tv_itwillA11 229 +#define FRAME_tv_itwillA12 230 +#define FRAME_tv_itwillA13 231 +#define FRAME_tv_itwillA14 232 +#define FRAME_tv_itwillA15 233 +#define FRAME_tv_itwillA16 234 +#define FRAME_tv_itwillA17 235 +#define FRAME_tv_itwillA18 236 +#define FRAME_tv_itwillA19 237 +#define FRAME_tv_itwillA20 238 +#define FRAME_tv_itwillA21 239 +#define FRAME_tv_itwillA22 240 +#define FRAME_tv_itwillA23 241 +#define FRAME_tv_itwillA24 242 +#define FRAME_tv_itwillA25 243 +#define FRAME_tv_itwillA26 244 +#define FRAME_tv_itwillA27 245 +#define FRAME_tv_itwillA28 246 +#define FRAME_tv_itwillA29 247 +#define FRAME_tv_itwillA30 248 +#define FRAME_tv_itwillA31 249 +#define FRAME_tv_itwillA32 250 +#define FRAME_tv_itwillA33 251 +#define FRAME_tv_itwillA34 252 +#define FRAME_tv_itwillA35 253 +#define FRAME_tv_itwillA36 254 +#define FRAME_tv_itwillA37 255 +#define FRAME_tv_itwillA38 256 +#define FRAME_tv_itwillA39 257 +#define FRAME_tv_itwillA40 258 +#define FRAME_tv_itwillA41 259 +#define FRAME_tv_itwillA42 260 +#define FRAME_tv_itwillA43 261 +#define FRAME_tv_itwillA44 262 +#define FRAME_tv_itwillA45 263 +#define FRAME_tv_itwillA46 264 +#define FRAME_tv_itwillA47 265 +#define FRAME_tv_itwillA48 266 +#define FRAME_tv_itwillA49 267 +#define FRAME_tv_itwillA50 268 +#define FRAME_tv_itwillA51 269 +#define FRAME_tv_itwillA52 270 +#define FRAME_tv_itwillA53 271 +#define FRAME_tv_itwillA54 272 +#define FRAME_tv_itwillA55 273 +#define FRAME_tv_itwillA56 274 +#define FRAME_tv_itwillA57 275 +#define FRAME_tv_itwillA58 276 +#define FRAME_tv_itwillA59 277 +#define FRAME_tv_itwillA60 278 +#define FRAME_tv_itwillA61 279 +#define FRAME_tv_itwillA62 280 +#define FRAME_tv_itwillA63 281 +#define FRAME_tv_itwillA64 282 +#define FRAME_tv_itwillA65 283 +#define FRAME_tv_itwillA66 284 +#define FRAME_tv_itwillA67 285 +#define FRAME_tv_itwillA68 286 +#define FRAME_tv_itwillA69 287 +#define FRAME_tv_itwillA70 288 +#define FRAME_tv_itwillA71 289 +#define FRAME_tv_itwillA72 290 +#define FRAME_tv_itwillA73 291 +#define FRAME_tv_itwillA74 292 +#define FRAME_tv_itwillA75 293 +#define FRAME_tv_itwillA76 294 +#define FRAME_tv_itwillA77 295 +#define FRAME_tv_itwillA78 296 +#define FRAME_tv_itwillA79 297 +#define FRAME_tv_itwillA80 298 +#define FRAME_tv_itwillA81 299 +#define FRAME_tv_itwillA82 300 +#define FRAME_tv_itwillA83 301 +#define FRAME_tv_itwillA84 302 +#define FRAME_tv_itwillA85 303 +#define FRAME_tv_itwillA86 304 +#define FRAME_tv_itwillA87 305 +#define FRAME_tv_itwillA88 306 +#define FRAME_tv_itwillA89 307 +#define FRAME_tv_itwillA90 308 +#define FRAME_tv_itwillA91 309 +#define FRAME_tv_itwillA92 310 +#define FRAME_tv_itwillA93 311 +#define FRAME_tv_itwillA94 312 +#define FRAME_tv_itwillA95 313 +#define FRAME_tv_itwillA96 314 +#define FRAME_tv_itwillA97 315 +#define FRAME_tv_itwillA98 316 +#define FRAME_tv_itwillA99 317 +#define FRAME_tv_itwillA100 318 +#define FRAME_tv_itwillA101 319 +#define FRAME_tv_itwillA102 320 +#define FRAME_tv_itwillA103 321 +#define FRAME_tv_itwillA104 322 +#define FRAME_tv_itwillA105 323 +#define FRAME_tv_itwillA106 324 +#define FRAME_tv_itwillA107 325 +#define FRAME_tv_itwillA108 326 +#define FRAME_tv_itwillA109 327 +#define FRAME_tv_itwillA110 328 +#define FRAME_tv_itwillB1 329 +#define FRAME_tv_itwillB2 330 +#define FRAME_tv_itwillB3 331 +#define FRAME_tv_itwillB4 332 +#define FRAME_tv_itwillB5 333 +#define FRAME_tv_itwillB6 334 +#define FRAME_tv_itwillB7 335 +#define FRAME_tv_itwillB8 336 +#define FRAME_tv_itwillB9 337 +#define FRAME_tv_itwillB10 338 +#define FRAME_tv_itwillB11 339 +#define FRAME_tv_itwillB12 340 +#define FRAME_tv_itwillB13 341 +#define FRAME_tv_itwillB14 342 +#define FRAME_tv_itwillB15 343 +#define FRAME_tv_itwillB16 344 +#define FRAME_tv_itwillB17 345 +#define FRAME_tv_itwillB18 346 +#define FRAME_tv_itwillB19 347 +#define FRAME_tv_itwillB20 348 +#define FRAME_tv_itwillB21 349 +#define FRAME_tv_itwillB22 350 +#define FRAME_tv_itwillB23 351 +#define FRAME_tv_itwillB24 352 +#define FRAME_tv_itwillB25 353 +#define FRAME_tv_itwillB26 354 +#define FRAME_tv_itwillB27 355 +#define FRAME_tv_itwillB28 356 +#define FRAME_tv_itwillB29 357 +#define FRAME_tv_itwillB30 358 +#define FRAME_tv_itwillB31 359 +#define FRAME_tv_itwillB32 360 +#define FRAME_tv_itwillB33 361 +#define FRAME_tv_itwillB34 362 +#define FRAME_tv_itwillB35 363 +#define FRAME_tv_itwillB36 364 +#define FRAME_tv_itwillB37 365 +#define FRAME_tv_itwillB38 366 +#define FRAME_tv_itwillB39 367 +#define FRAME_tv_itwillB40 368 +#define FRAME_tv_itwillB41 369 +#define FRAME_tv_itwillB42 370 +#define FRAME_tv_itwillB43 371 +#define FRAME_tv_itwillB44 372 +#define FRAME_tv_itwillB45 373 +#define FRAME_tv_itwillB46 374 +#define FRAME_tv_itwillB47 375 +#define FRAME_tv_itwillB48 376 +#define FRAME_tv_itwillB49 377 +#define FRAME_tv_itwillB50 378 +#define FRAME_tv_itwillB51 379 +#define FRAME_tv_itwillB52 380 +#define FRAME_tv_itwillB53 381 +#define FRAME_tv_itwillB54 382 +#define FRAME_tv_itwillB55 383 +#define FRAME_tv_itwillB56 384 +#define FRAME_tv_itwillB57 385 +#define FRAME_tv_itwillB58 386 +#define FRAME_tv_itwillB59 387 +#define FRAME_tv_itwillB60 388 +#define FRAME_tv_itwillB61 389 +#define FRAME_tv_itwillB62 390 +#define FRAME_tv_itwillB63 391 +#define FRAME_tv_itwillB64 392 +#define FRAME_tv_itwillB65 393 +#define FRAME_tv_itwillB66 394 +#define FRAME_tv_itwillB67 395 +#define FRAME_tv_itwillB68 396 +#define FRAME_tv_itwillB69 397 +#define FRAME_tv_itwillB70 398 +#define FRAME_tv_itwillB71 399 +#define FRAME_tv_itwillB72 400 +#define FRAME_tv_itwillB73 401 +#define FRAME_tv_itwillB74 402 +#define FRAME_tv_itwillB75 403 +#define FRAME_tv_itwillB76 404 +#define FRAME_tv_itwillB77 405 +#define FRAME_tv_itwillB78 406 +#define FRAME_tv_itwillB79 407 +#define FRAME_tv_itwillB80 408 +#define FRAME_tv_itwillB81 409 +#define FRAME_tv_itwillB82 410 +#define FRAME_tv_itwillB83 411 +#define FRAME_tv_itwillB84 412 +#define FRAME_tv_itwillB85 413 +#define FRAME_tv_itwillB86 414 +#define FRAME_tv_itwillB87 415 +#define FRAME_tv_itwillB88 416 +#define FRAME_tv_itwillB89 417 +#define FRAME_tv_itwillB90 418 +#define FRAME_tv_itwillB91 419 +#define FRAME_tv_itwillB92 420 +#define FRAME_tv_itwillB93 421 +#define FRAME_tv_itwillB94 422 +#define FRAME_tv_itwillB95 423 +#define FRAME_tv_itwillB96 424 +#define FRAME_tv_itwillB97 425 +#define FRAME_tv_itwillB98 426 +#define FRAME_tv_itwillB99 427 +#define FRAME_tv_itwillB100 428 +#define FRAME_tv_itwillB101 429 +#define FRAME_tv_itwillB102 430 +#define FRAME_tv_itwillB103 431 +#define FRAME_tv_itwillB104 432 +#define FRAME_tv_itwillB105 433 +#define FRAME_tv_itwillB106 434 +#define FRAME_tv_itwillB107 435 +#define FRAME_tv_itwillB108 436 +#define FRAME_tv_itwillB109 437 +#define FRAME_tv_itwillB110 438 +#define FRAME_tv_itwillB111 439 +#define FRAME_tv_itwillB112 440 +#define FRAME_tv_itwillB113 441 +#define FRAME_tv_itwillB114 442 +#define FRAME_tv_itwillB115 443 +#define FRAME_tv_itwillB116 444 +#define FRAME_tv_itwillB117 445 +#define FRAME_tv_itwillB118 446 +#define FRAME_tv_itwillB119 447 +#define FRAME_tv_itwillB120 448 +#define FRAME_tv_itwillB121 449 +#define FRAME_tv_itwillB122 450 +#define FRAME_tv_itwillB123 451 +#define FRAME_tv_itwillB124 452 +#define FRAME_tv_itwillB125 453 +#define FRAME_tv_itwillB126 454 +#define FRAME_tv_itwillB127 455 +#define FRAME_tv_itwillB128 456 +#define FRAME_tv_itwillB129 457 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_POLY 0 +#define MESH__LOWERTORSO 1 +#define MESH__CAPLOWERTORSO 2 +#define MESH__LEFTLEG 3 +#define MESH__RIGHTLEG 4 +#define MESH__UPPERTORSO 5 +#define MESH__CAPTOPUPPERTORSO 6 +#define MESH__CAPBOTTOMUPPERTORSO 7 +#define MESH__LEFTARM 8 +#define MESH__RIGHTARM 9 +#define MESH__HEAD 10 +#define MESH__CENTERSPIKE 11 +#define MESH__LEFT1SPIKE 12 +#define MESH__RIGHT1SPIKE 13 +#define MESH__RIGHT2SPIKE 14 +#define MESH__CAPHEAD 15 diff --git a/Toolkit/Programming/GameCode/game/decals.c b/Toolkit/Programming/GameCode/game/decals.c new file mode 100644 index 0000000..adf2318 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/decals.c @@ -0,0 +1,75 @@ +// +// decals.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "Vector.h" + +// ************************************************************************************************ +// IsDecalApplicable +// ************************************************************************************************ + +// planeDir parameter will become redundant when all scorchmarks are spawned on the client + +qboolean IsDecalApplicable(edict_t *owner, edict_t *target, vec3_t origin, csurface_t *surface,cplane_t *plane, vec3_t planeDir) +{ + int contents; + +#if DEMO_CODE + if(deathmatch->value) + return(false); +#endif + + + if(!plane) + { + return(false); + } + if(!surface) + { + return(false); + } + if(!Vec3NotZero(plane->normal)) + { + return(false); + } + // this is a brush + if (target->s.number) + { + return(false); + } + // target is damageable + if(target->takedamage) + { + return(false); + } + if(surface->flags & SURF_SKY) + { + return(false); + } + if(!target) + { + return(false); + } + contents = gi.pointcontents(origin); + if(contents & MASK_WATER) + { + return(false); + } + if(target->solid == SOLID_BSP) + { + if(contents & CONTENTS_TRANSLUCENT) + { + return(false); + } + } + if(planeDir) + { + VectorCopy(plane->normal, planeDir); + } + return(true); +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/decals.h b/Toolkit/Programming/GameCode/game/decals.h new file mode 100644 index 0000000..a66d23c --- /dev/null +++ b/Toolkit/Programming/GameCode/game/decals.h @@ -0,0 +1,6 @@ +#ifndef DECALS_H +#define DECALS_H + +qboolean IsDecalApplicable(edict_t *owner, edict_t *target, vec3_t origin, csurface_t *surface,cplane_t *plane, vec3_t planeDir); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/ds.cpp b/Toolkit/Programming/GameCode/game/ds.cpp new file mode 100644 index 0000000..53b2bb2 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/ds.cpp @@ -0,0 +1,4368 @@ +#include "g_local.h" +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN +#include +#include "ds.h" + +#define SCRIPT_SAVE_VERSION 2 + +List GlobalVariables; +List Scripts; + +template size_t tWrite(T *ptr,FILE *FH,int n=1) +{ + return fwrite(ptr,n,sizeof(T),FH); +} + +template size_t tRead(T *ptr,FILE *FH,int n=1) +{ + return fread(ptr,n,sizeof(T),FH); +} + + + + + +#ifdef _HERETIC2_ +extern "C" +{ +#endif + extern void Use_Multi(edict_t *self, edict_t *other, edict_t *activator); + extern void c_swapplayer(edict_t *Self,edict_t *Cinematic); + extern void remove_non_cinematic_entites(edict_t *owner); + extern void reinstate_non_cinematic_entites(edict_t *owner); + extern cvar_t *Cvar_Set (char *var_name, char *value); + + +#ifdef _HERETIC2_ +} +#endif + +#ifdef _HERETIC2_ +int msg_animtype [NUM_MESSAGES] = +{ + MSG_C_ACTION1, + MSG_C_ACTION2, + MSG_C_ACTION3, + MSG_C_ACTION4, + MSG_C_ACTION5, + MSG_C_ACTION6, + MSG_C_ACTION7, + MSG_C_ACTION8, + MSG_C_ACTION9, + MSG_C_ACTION10, + MSG_C_ACTION11, + MSG_C_ACTION12, + MSG_C_ACTION13, + MSG_C_ACTION14, + MSG_C_ACTION15, + MSG_C_ACTION16, + MSG_C_ACTION17, + MSG_C_ACTION18, + MSG_C_ACTION19, + MSG_C_ACTION20, + MSG_C_ATTACK1, + MSG_C_ATTACK2, + MSG_C_ATTACK3, + MSG_C_BACKPEDAL1, + MSG_C_DEATH1, + MSG_C_DEATH2, + MSG_C_DEATH3, + MSG_C_DEATH4, + MSG_C_GIB1, + MSG_C_IDLE1, + MSG_C_IDLE2, + MSG_C_IDLE3, + MSG_C_IDLE4, + MSG_C_IDLE5, + MSG_C_IDLE6, + MSG_C_JUMP1, + MSG_C_PAIN1, + MSG_C_PAIN2, + MSG_C_PAIN3, + MSG_C_PIVOTLEFTGO, + MSG_C_PIVOTLEFT, + MSG_C_PIVOTLEFTSTOP, + MSG_C_PIVOTRIGHTGO, + MSG_C_PIVOTRIGHT, + MSG_C_PIVOTRIGHTSTOP, + MSG_C_RUN1, + MSG_C_STEPLEFT, + MSG_C_STEPRIGHT, + MSG_C_THINKAGAIN, + MSG_C_TRANS1, + MSG_C_TRANS2, + MSG_C_TRANS3, + MSG_C_TRANS4, + MSG_C_TRANS5, + MSG_C_TRANS6, + MSG_C_WALKSTART, + MSG_C_WALK1, + MSG_C_WALK2, + MSG_C_WALK3, + MSG_C_WALK4, + MSG_C_WALKSTOP1, + MSG_C_WALKSTOP2, + MSG_C_ATTACK4, + MSG_C_ATTACK5, +}; + +#define MAX_CINESNDS 255 + +typedef struct CinematicSound_s +{ + edict_t *ent; + int channel; +} CinematicSound_t; + +CinematicSound_t CinematicSound[MAX_CINESNDS]; + +int CinematicSound_cnt; // Count of the current # of sounds executed + +#endif + +//========================================================================== + +typedef struct RestoreList_s +{ + int ID; + void *(*alloc_func)(FILE *, void *); +} RestoreList_t; + +void *RF_IntVar(FILE *FH, void *Data) +{ + return new IntVar(FH, (CScript *)Data); +} + +void *RF_FloatVar(FILE *FH, void *Data) +{ + return new FloatVar(FH, (CScript *)Data); +} + +void *RF_VectorVar(FILE *FH, void *Data) +{ + return new VectorVar(FH, (CScript *)Data); +} + +void *RF_EntityVar(FILE *FH, void *Data) +{ + return new EntityVar(FH, (CScript *)Data); +} + +void *RF_StringVar(FILE *FH, void *Data) +{ + return new StringVar(FH, (CScript *)Data); +} + +void *RF_VariableVar(FILE *FH, void *Data) +{ + return new VariableVar(FH, (CScript *)Data); +} + +void *RF_FieldVariableVar(FILE *FH, void *Data) +{ + return new FieldVariableVar(FH, (CScript *)Data); +} + +void *RF_Signaler(FILE *FH, void *Data) +{ + return new Signaler(FH, (CScript *)Data); +} + +void *RF_MoveDoneEvent(FILE *FH, void *Data) +{ + return new MoveDoneEvent(FH, (CScript *)Data); +} + +void *RF_RotateDoneEvent(FILE *FH, void *Data) +{ + return new RotateDoneEvent(FH, (CScript *)Data); +} + +void *RF_ExecuteEvent(FILE *FH, void *Data) +{ + return new ExecuteEvent(FH, (CScript *)Data); +} + +void *RF_WaitEvent(FILE *FH, void *Data) +{ + return new WaitEvent(FH, (CScript *)Data); +} + +void *RF_Script(FILE *FH, void *Data) +{ + return new CScript(FH); +} + +void *RF_FieldDef(FILE *FH, void *Data) +{ + return new FieldDef(FH, (CScript *)Data); +} + +#define RLID_INTVAR 1 +#define RLID_FLOATVAR 2 +#define RLID_VECTORVAR 3 +#define RLID_ENTITYVAR 4 +#define RLID_STRINGVAR 5 +#define RLID_VARIABLEVAR 6 +#define RLID_FIELDVARIABLEVAR 7 +#define RLID_SIGNALER 8 +#define RLID_MOVEDONEEVENT 9 +#define RLID_ROTATEDONEEVENT 10 +#define RLID_EXECUTEEVENT 11 +#define RLID_WAITEVENT 12 +#define RLID_SCRIPT 13 +#define RLID_FIELDDEF 14 + +RestoreList_t ScriptRL[] = +{ + { RLID_INTVAR, RF_IntVar }, + { RLID_FLOATVAR, RF_FloatVar }, + { RLID_VECTORVAR, RF_VectorVar }, + { RLID_ENTITYVAR, RF_EntityVar }, + { RLID_STRINGVAR, RF_StringVar }, + { RLID_VARIABLEVAR, RF_VariableVar }, + { RLID_FIELDVARIABLEVAR, RF_FieldVariableVar }, + { RLID_SIGNALER, RF_Signaler }, + { RLID_MOVEDONEEVENT, RF_MoveDoneEvent }, + { RLID_ROTATEDONEEVENT, RF_RotateDoneEvent }, + { RLID_EXECUTEEVENT, RF_ExecuteEvent }, + { RLID_WAITEVENT, RF_WaitEvent }, + { RLID_SCRIPT, RF_Script }, + { RLID_FIELDDEF, RF_FieldDef }, + + { 0, NULL }, +}; + +void *RestoreObject(FILE *FH, RestoreList_t *RestoreList, void *Data) +{ + int ID; + RestoreList_t *pos; + + fread(&ID, 1, sizeof(ID), FH); + + for(pos = RestoreList; pos->alloc_func; pos++) + { + if (pos->ID == ID) + { + return pos->alloc_func(FH, Data); + } + } + + return NULL; +} + +//========================================================================== + +void ReadEnt(edict_t **to,FILE *FH) +{ + int index; + tRead(&index,FH); + if (index<0||index>=globals.num_edicts) + { + assert(index==-1); //else invalid edict number + *to=0; + } + else + *to=g_edicts+index; +} + +void WriteEnt(edict_t **to,FILE *FH) +{ + int index; + if (*to) + { + index=(*to)-g_edicts; + assert(index>=0&&index::Iter is; + + if (Scripts.Size()) + { + for (is=Scripts.Begin();is != Scripts.End();is++) + { + (*is)->Think(); + } + } +} + +extern "C" void ShutdownScripts(qboolean Complete) +{ + List::Iter is; + List::Iter iv; + int i; + edict_t *ent; + + while(Scripts.Size()) + { + is=Scripts.Begin(); + delete (*is); + + Scripts.Erase(is); + } + + for(i = 0, ent = g_edicts; i < globals.num_edicts; i++, ent++) + { + ent->Script = NULL; + } + + if (Complete) + { + while(GlobalVariables.Size()) + { + iv=GlobalVariables.Begin(); + delete (*iv); + + GlobalVariables.Erase(iv); + } + } +} + +extern "C" void SaveScripts(FILE *FH, qboolean DoGlobals) +{ + int size; + List::Iter is; + List::Iter iv; + + size = SCRIPT_SAVE_VERSION; + fwrite(&size, 1, sizeof(size), FH); + + if (DoGlobals) + { + size = GlobalVariables.Size(); + fwrite(&size, 1, sizeof(size), FH); + + for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++) + { + (*iv)->Write(FH, NULL); + } + } + else + { + size = Scripts.Size(); + fwrite(&size, 1, sizeof(size), FH); + + for (is=Scripts.Begin();is != Scripts.End();is++) + { + (*is)->Write(FH); + } + } +} + +extern "C" void LoadScripts(FILE *FH, qboolean DoGlobals) +{ + int size, i; + edict_t *ent; + + fread(&size, 1, sizeof(size), FH); + if (size != SCRIPT_SAVE_VERSION) + { + gi.error("LoadScripts(): Expecting version %d, found version %d", SCRIPT_SAVE_VERSION, size); + } + + if (DoGlobals) + { + ShutdownScripts(true); + + fread(&size, 1, sizeof(size), FH); + + for(i=0;iScript = NULL; + } + + fread(&size, 1, sizeof(size), FH); + + for(i=0;iScript->AddEvent(new ExecuteEvent(level.time, other, activator) ); +} + +/*QUAKED script_runner (.5 .5 .5) (-8 -8 -8) (8 8 8) +set Script to the name of the script to run when triggered +use parm1 through parm16 to send parameters to the script +*/ +extern "C" void SP_script_runner (edict_t *ent) +{ + char temp[MAX_PATH]; + int i; + + sprintf(temp,"ds/%s.os",st.script); + ent->Script = new CScript(temp, ent); + Scripts.PushBack(ent->Script); + + for(i=0;iScript->SetParameter(st.parms[i]); + } + else + { + break; + } + } + +#ifdef _HERETIC2_ + ent->movetype = PHYSICSTYPE_NONE; +#else + ent->movetype = MOVETYPE_NONE; +#endif + ent->solid = SOLID_NOT; + ent->svflags |= SVF_NOCLIENT; + ent->use = script_use; + +// gi.setmodel (ent, ent->model); +// gi.linkentity (ent); +} + +/*QUAKE script_parms (.5 .5 .5) ? +target the script_runner object +use parm1 through parm16 to send parameters to the script +*/ +extern "C" void SP_parms (edict_t *ent) +{ +} + +//========================================================================== + +Variable *FindGlobal(char *Name) +{ + List::Iter iv; + + if (GlobalVariables.Size()) + { + for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++) + { + if (strcmp(Name, (*iv)->GetName()) == 0) + { + return *iv; + } + } + } + + return NULL; +} + +bool NewGlobal(Variable *Which) +{ + Variable *Check; + + Check = FindGlobal(Which->GetName()); + if (Check) + { // already exists + return false; + } + + GlobalVariables.PushBack(Which); + + return true; +} + +//========================================================================== + +Variable::Variable(char *NewName, VariableT NewType) +{ + strcpy(Name,NewName); + Type = NewType; +} + +Variable::Variable(FILE *FH, CScript *Script) +{ + int index; + + fread(Name, 1, sizeof(Name), FH); + fread(&Type, 1, sizeof(Type), FH); + fread(&index, 1, sizeof(index), FH); + + if (Script && index != -1) + { + Script->SetVarIndex(index, this); + } +} + +void Variable::Write(FILE *FH, CScript *Script, int ID) +{ + int index = -1; + + fwrite(&ID, 1, sizeof(ID), FH); + fwrite(Name, 1, sizeof(Name), FH); + fwrite(&Type, 1, sizeof(Type), FH); + + if (Script) + { + index = Script->LookupVarIndex(this); + } + fwrite(&index, 1, sizeof(index), FH); +} + +void Variable::Debug(CScript *Script) +{ + Script->DebugLine(" Name: %s\n",Name); +} + +//========================================================================== + +IntVar::IntVar(char *Name, int InitValue) +:Variable(Name, TypeINT) +{ + Value = InitValue; +} + +IntVar::IntVar(FILE *FH, CScript *Script) +:Variable(FH, Script) +{ + fread(&Value, 1, sizeof(Value), FH); +} + +void IntVar::Write(FILE *FH, CScript *Script, int ID) +{ + Variable::Write(FH, Script, RLID_INTVAR); + + fwrite(&Value, 1, sizeof(Value), FH); +} + +void IntVar::ReadValue(CScript *Script) +{ + Value = Script->ReadInt(); +} + +void IntVar::Debug(CScript *Script) +{ + Variable::Debug(Script); + + Script->DebugLine(" Integer Value: %d\n",Value); +} + +void IntVar::Signal(edict_t *Which) +{ + Value++; +} + +void IntVar::ClearSignal(void) +{ + Value = 0; +} + +Variable *IntVar::operator +(Variable *VI) +{ + return new IntVar("",Value + VI->GetIntValue()); +} + +Variable *IntVar::operator -(Variable *VI) +{ + return new IntVar("",Value - VI->GetIntValue()); +} + +Variable *IntVar::operator *(Variable *VI) +{ + return new IntVar("",Value * VI->GetIntValue()); +} + +Variable *IntVar::operator /(Variable *VI) +{ + return new IntVar("",Value / VI->GetIntValue()); +} + +void IntVar::operator =(Variable *VI) +{ + Value = VI->GetIntValue(); +} + +//========================================================================== + +FloatVar::FloatVar(char *Name, float InitValue) +:Variable(Name, TypeFLOAT) +{ + Value = InitValue; +} + +FloatVar::FloatVar(FILE *FH, CScript *Script) +:Variable(FH, Script) +{ + fread(&Value, 1, sizeof(Value), FH); +} + +void FloatVar::Write(FILE *FH, CScript *Script, int ID) +{ + Variable::Write(FH, Script, RLID_FLOATVAR); + + fwrite(&Value, 1, sizeof(Value), FH); +} + +void FloatVar::ReadValue(CScript *Script) +{ + Value = Script->ReadFloat(); +} + +void FloatVar::Debug(CScript *Script) +{ + Variable::Debug(Script); + + Script->DebugLine(" Float Value: %0.f\n",Value); +} + +Variable *FloatVar::operator +(Variable *VI) +{ + return new FloatVar("",Value + VI->GetFloatValue()); +} + +Variable *FloatVar::operator -(Variable *VI) +{ + return new FloatVar("",Value - VI->GetFloatValue()); +} + +Variable *FloatVar::operator *(Variable *VI) +{ + return new FloatVar("",Value * VI->GetFloatValue()); +} + +Variable *FloatVar::operator /(Variable *VI) +{ + return new FloatVar("",Value / VI->GetFloatValue()); +} + +void FloatVar::operator =(Variable *VI) +{ + Value = VI->GetFloatValue(); +} + +//========================================================================== + +VectorVar::VectorVar(char *Name, float InitValueX, float InitValueY, float InitValueZ) +:Variable(Name, TypeVECTOR) +{ + Value[0] = InitValueX; + Value[1] = InitValueY; + Value[2] = InitValueZ; +} + +VectorVar::VectorVar(vec3_t NewValue) +:Variable("", TypeVECTOR) +{ + VectorCopy(NewValue, Value); +} + +VectorVar::VectorVar(FILE *FH, CScript *Script) +:Variable(FH, Script) +{ + fread(&Value, 1, sizeof(Value), FH); +} + +void VectorVar::Write(FILE *FH, CScript *Script, int ID) +{ + Variable::Write(FH, Script, RLID_VECTORVAR); + + fwrite(Value, 1, sizeof(Value), FH); +} + +void VectorVar::GetVectorValue(vec3_t &VecValue) +{ + VecValue[0] = Value[0]; + VecValue[1] = Value[1]; + VecValue[2] = Value[2]; +} + +void VectorVar::ReadValue(CScript *Script) +{ + Value[0] = Script->ReadFloat(); + Value[1] = Script->ReadFloat(); + Value[2] = Script->ReadFloat(); +} + +void VectorVar::Debug(CScript *Script) +{ + Variable::Debug(Script); + + Script->DebugLine(" Vector Value: [%0.f, %0.f, %0.f]\n",Value[0],Value[1],Value[2]); +} + +Variable *VectorVar::operator +(Variable *VI) +{ + vec3_t V2, NewV; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + V2[0] = V2[1] = V2[2] = VI->GetFloatValue(); + } + else + { + VI->GetVectorValue(V2); + } + + NewV[0] = Value[0] + V2[0]; + NewV[1] = Value[1] + V2[1]; + NewV[2] = Value[2] + V2[2]; + + return new VectorVar("", NewV[0], NewV[1], NewV[2]); +} + +Variable *VectorVar::operator -(Variable *VI) +{ + vec3_t V2, NewV; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + V2[0] = V2[1] = V2[2] = VI->GetFloatValue(); + } + else + { + VI->GetVectorValue(V2); + } + + NewV[0] = Value[0] - V2[0]; + NewV[1] = Value[1] - V2[1]; + NewV[2] = Value[2] - V2[2]; + + return new VectorVar("", NewV[0], NewV[1], NewV[2]); +} + +Variable *VectorVar::operator *(Variable *VI) +{ + vec3_t V2, NewV; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + V2[0] = V2[1] = V2[2] = VI->GetFloatValue(); + } + else + { + VI->GetVectorValue(V2); + } + + NewV[0] = Value[0] * V2[0]; + NewV[1] = Value[1] * V2[1]; + NewV[2] = Value[2] * V2[2]; + + return new VectorVar("", NewV[0], NewV[1], NewV[2]); +} + +Variable *VectorVar::operator /(Variable *VI) +{ + vec3_t V2, NewV; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + V2[0] = V2[1] = V2[2] = VI->GetFloatValue(); + } + else + { + VI->GetVectorValue(V2); + } + + NewV[0] = Value[0] / V2[0]; + NewV[1] = Value[1] / V2[1]; + NewV[2] = Value[2] / V2[2]; + + return new VectorVar("", NewV[0], NewV[1], NewV[2]); +} + +void VectorVar::operator =(Variable *VI) +{ + VI->GetVectorValue(Value); +} + +bool VectorVar::operator ==(Variable *VI) +{ + vec3_t vec; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + return VectorLength(Value) == VI->GetFloatValue(); + } + else if (VI->GetType() == TypeVECTOR) + { + VI->GetVectorValue(vec); + + return (VectorCompare(Value, vec) == 1); // VC6 gives a warning about converting int to bool + } + + return false; +} + +bool VectorVar::operator !=(Variable *VI) +{ + vec3_t vec; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + return VectorLength(Value) != VI->GetFloatValue(); + } + else if (VI->GetType() == TypeVECTOR) + { + VI->GetVectorValue(vec); + + return !VectorCompare(Value, vec); + } + + return false; +} + +bool VectorVar::operator <(Variable *VI) +{ + vec3_t vec; + float compare; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + compare = VI->GetFloatValue(); + } + else if (VI->GetType() == TypeVECTOR) + { + VI->GetVectorValue(vec); + compare = VectorLength(vec); + } + else + { + return false; + } + + return VectorLength(Value) < compare; +} + +bool VectorVar::operator <=(Variable *VI) +{ + vec3_t vec; + float compare; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + compare = VI->GetFloatValue(); + } + else if (VI->GetType() == TypeVECTOR) + { + VI->GetVectorValue(vec); + compare = VectorLength(vec); + } + else + { + return false; + } + + return VectorLength(Value) <= compare; +} + +bool VectorVar::operator >(Variable *VI) +{ + vec3_t vec; + float compare; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + compare = VI->GetFloatValue(); + } + else if (VI->GetType() == TypeVECTOR) + { + VI->GetVectorValue(vec); + compare = VectorLength(vec); + } + else + { + return false; + } + + return VectorLength(Value) > compare; +} + +bool VectorVar::operator >=(Variable *VI) +{ + vec3_t vec; + float compare; + + if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT) + { + compare = VI->GetFloatValue(); + } + else if (VI->GetType() == TypeVECTOR) + { + VI->GetVectorValue(vec); + compare = VectorLength(vec); + } + else + { + return false; + } + + return VectorLength(Value) >= compare; +} + +//========================================================================== + +EntityVar::EntityVar(char *Name, int InitValue) +:Variable(Name, TypeENTITY) +{ + if (InitValue == -1) + { + Value = NULL; + } + else + { + Value = &g_edicts[InitValue]; + } +} + +EntityVar::EntityVar(edict_t *Which) +:Variable("", TypeENTITY) +{ + Value = Which; +} + +EntityVar::EntityVar(FILE *FH, CScript *Script) +:Variable(FH, Script) +{ + int index; + + fread(&index, 1, sizeof(index), FH); + + if (index == -1) + { + Value = NULL; + } + else + { + Value = &g_edicts[index]; + } +} + +void EntityVar::Write(FILE *FH, CScript *Script, int ID) +{ + int index; + + Variable::Write(FH, Script, RLID_ENTITYVAR); + + index = GetIntValue(); + fwrite(&index, 1, sizeof(index), FH); +} + +void EntityVar::ReadValue(CScript *Script) +{ + int Index; + + Index = Script->ReadInt(); + if (Index == -1) + { + Value = NULL; + } + else + { + Value = &g_edicts[Index]; + } +} + +void EntityVar::Debug(CScript *Script) +{ + Variable::Debug(Script); + + Script->DebugLine(" Entity Value: %d\n",GetIntValue()); +} + +int EntityVar::GetIntValue(void) +{ + if (Value) + { + return Value - g_edicts; + } + + return -1; +} + +void EntityVar::operator =(Variable *VI) +{ + Value = VI->GetEdictValue(); +} + +bool EntityVar::operator ==(Variable *VI) +{ + if (VI->GetType() == TypeINT) + { + return GetIntValue() == VI->GetIntValue(); + } + else if (VI->GetType() == TypeENTITY) + { + return GetEdictValue() == VI->GetEdictValue(); + } + + return false; +} + +bool EntityVar::operator !=(Variable *VI) +{ + if (VI->GetType() == TypeINT) + { + return GetIntValue() != VI->GetIntValue(); + } + else if (VI->GetType() == TypeENTITY) + { + return GetEdictValue() != VI->GetEdictValue(); + } + + return false; +} + +//========================================================================== + +StringVar::StringVar(char *Name, char *InitValue) +:Variable(Name, TypeSTRING) +{ + strcpy(Value, InitValue); +} + +StringVar::StringVar(FILE *FH, CScript *Script) +:Variable(FH, Script) +{ + fread(&Value, 1, sizeof(Value), FH); +} + +void StringVar::Write(FILE *FH, CScript *Script, int ID) +{ + Variable::Write(FH, Script, RLID_STRINGVAR); + + fwrite(&Value, 1, sizeof(Value), FH); +} + +void StringVar::ReadValue(CScript *Script) +{ + strcpy(Value, Script->ReadString()); +} + +//========================================================================== + +VariableVar::VariableVar(char *Name) +:Variable(Name, TypeUNKNOWN) +{ + Value = NULL; +} + +VariableVar::VariableVar(FILE *FH, CScript *Script) +:Variable(FH, Script) +{ + int index; + + fread(&index, 1, sizeof(index), FH); + Value = Script->LookupVar(index); +} + +void VariableVar::Write(FILE *FH, CScript *Script, int ID) +{ + int index; + + Variable::Write(FH, Script, RLID_VARIABLEVAR); + + index = Script->LookupVarIndex(Value); + fwrite(&index, 1, sizeof(index), FH); +} + +void VariableVar::ReadValue(CScript *Script) +{ + int Index; + + Index = Script->ReadInt(); + + Value = Script->LookupVar(Index); + + if (Value) + { + Type = Value->GetType(); + } +} + +void VariableVar::Debug(CScript *Script) +{ + Value->Debug(Script); +} + +//========================================================================== + +FieldVariableVar::FieldVariableVar(char *Name) +:Variable(Name, TypeUNKNOWN) +{ + Value = NULL; + Field = NULL; +} + +FieldVariableVar::FieldVariableVar(FILE *FH, CScript *Script) +:Variable(FH, Script) +{ + int index; + + fread(&index, 1, sizeof(index), FH); + Value = Script->LookupVar(index); + + fread(&index, 1, sizeof(index), FH); + Field = Script->LookupField(index); +} + +void FieldVariableVar::Write(FILE *FH, CScript *Script, int ID) +{ + int index; + + Variable::Write(FH, Script, RLID_FIELDVARIABLEVAR); + + index = Script->LookupVarIndex(Value); + fwrite(&index, 1, sizeof(index), FH); + + index = Script->LookupFieldIndex(Field); + fwrite(&index, 1, sizeof(index), FH); +} + +void FieldVariableVar::ReadValue(CScript *Script) +{ + int Index; + + Index = Script->ReadInt(); + Value = Script->LookupVar(Index); + + Index = Script->ReadInt(); + Field = Script->LookupField(Index); +} + +void FieldVariableVar::Debug(CScript *Script) +{ + Value->Debug(Script); +} + +int FieldVariableVar::GetIntValue(void) +{ + return Field->GetIntValue(Value); +} + +float FieldVariableVar::GetFloatValue(void) +{ + return Field->GetFloatValue(Value); +} + +void FieldVariableVar::GetVectorValue(vec3_t &VecValue) +{ + Field->GetVectorValue(Value, VecValue); +} + +edict_t *FieldVariableVar::GetEdictValue(void) +{ + return Field->GetEdictValue(Value); +} + +char *FieldVariableVar::GetStringValue(void) +{ + return Field->GetStringValue(Value); +} + +Variable *FieldVariableVar::operator +(Variable *VI) +{ + Variable *Result, *Val; + + Val = Field->GetValue(Value); + + Result = (*Val) + VI; + + delete Val; + + return Result; +} + +Variable *FieldVariableVar::operator -(Variable *VI) +{ + Variable *Result, *Val; + + Val = Field->GetValue(Value); + + Result = (*Val) - VI; + + delete Val; + + return Result; +} + +Variable *FieldVariableVar::operator *(Variable *VI) +{ + Variable *Result, *Val; + + Val = Field->GetValue(Value); + + Result = (*Val) * VI; + + delete Val; + + return Result; +} + +Variable *FieldVariableVar::operator /(Variable *VI) +{ + Variable *Result, *Val; + + Val = Field->GetValue(Value); + + Result = (*Val) / VI; + + delete Val; + + return Result; +} + +void FieldVariableVar::operator =(Variable *VI) +{ + Field->SetValue(Value, VI); +} + +bool FieldVariableVar::operator ==(Variable *VI) +{ + return (*Value) == VI; +} + +bool FieldVariableVar::operator !=(Variable *VI) +{ + return (*Value) != VI; +} + +bool FieldVariableVar::operator <(Variable *VI) +{ + return (*Value) < VI; +} + +bool FieldVariableVar::operator <=(Variable *VI) +{ + return (*Value) <= VI; +} + +bool FieldVariableVar::operator >(Variable *VI) +{ + return (*Value) > VI; +} + +bool FieldVariableVar::operator >=(Variable *VI) +{ + return (*Value) >= VI; +} + +//========================================================================== + +Signaler::Signaler(edict_t *NewEdict, Variable *NewVar, SignalT NewSignalType) +{ + Edict = NewEdict; + Var = NewVar; + SignalType = NewSignalType; +} + +Signaler::Signaler(FILE *FH, CScript *Script) +{ + ReadEnt(&Edict,FH); + tRead(&SignalType, FH); + + Var = (Variable *)RestoreObject(FH, ScriptRL, Script); +} + +Signaler::~Signaler(void) +{ + if (Var) + { + delete Var; + } +} + +void Signaler::Write(FILE *FH, CScript *Script) +{ + int index; + + index = RLID_SIGNALER; + fwrite(&index, 1, sizeof(index), FH); + + WriteEnt(&Edict,FH); + tWrite(&SignalType, FH); + + Var->Write(FH, Script); +} + +bool Signaler::Test(edict_t *Which, SignalT WhichType) +{ + if (WhichType != SignalType) + { + return false; + } + + if (Edict != Which) + { + return false; + } + + Var->Signal(Which); + + return true; +} + +bool Signaler::operator ==(Signaler *SI) +{ + if (Var == SI->GetVar()) + { + return true; + } + + return false; +} + +void script_signaler(edict_t *which, SignalT SignalType) +{ + List::Iter is; + + if (Scripts.Size()) + { + for (is=Scripts.Begin();is != Scripts.End();is++) + { + (*is)->CheckSignalers(which, SignalType); + } + } +} + +void move_signaler(edict_t *which) +{ + script_signaler(which, SIGNAL_MOVE); +} + +void rotate_signaler(edict_t *which) +{ + script_signaler(which, SIGNAL_ROTATE); +} + +void animate_signaler(edict_t *which) +{ + script_signaler(which, SIGNAL_ANIMATE); +} + +//========================================================================== + +// Fields are just yucky now - once H2 finals, I'm going to change them completely + +#define SPEC_X -1 +#define SPEC_Y -2 +#define SPEC_Z -3 +#define SPEC_DELTA_ANGLES -4 +#define SPEC_P_ORIGIN -5 + +static field_t script_fields[] = +{ + { "x", SPEC_X, F_FLOAT }, + { "y", SPEC_Y, F_FLOAT }, + { "z", SPEC_Z, F_FLOAT }, + { "origin", FOFS(s.origin), F_VECTOR }, + { "movetype", FOFS(movetype), F_INT }, + { "start_origin", FOFS(moveinfo.start_origin), F_VECTOR }, + { "distance", FOFS(moveinfo.distance), F_FLOAT }, + { "owner", FOFS(owner), F_EDICT }, + { "wait", FOFS(wait), F_FLOAT }, + { "velocity", FOFS(velocity), F_VECTOR }, + { "angle_velocity", FOFS(avelocity), F_VECTOR }, + { "team_chain", FOFS(teamchain), F_EDICT }, + { "yaw_speed", FOFS(yaw_speed), F_FLOAT }, + { "modelindex", FOFS(s.modelindex), F_INT }, + { "count", FOFS(count), F_INT }, + { "solid", FOFS(solid), F_INT }, + { "angles", FOFS(s.angles), F_VECTOR }, + { "start_angles", FOFS(moveinfo.start_angles), F_VECTOR }, + { "state", FOFS(moveinfo.state), F_INT }, +#ifdef _HERETIC2_ + { "c_mode", FOFS(monsterinfo.c_mode), F_INT }, + { "skinnum", FOFS(s.skinnum), F_INT }, + { "ideal_yaw", FOFS(ideal_yaw), F_FLOAT }, + { "delta_angles", SPEC_DELTA_ANGLES, F_VECTOR }, + { "p_origin", SPEC_P_ORIGIN, F_VECTOR }, + { "takedamage", FOFS(takedamage), F_INT }, +#endif + + { NULL, 0, F_INT } +}; + +FieldDef::FieldDef(CScript *Script) +{ + field_t *Field; + bool Found; + + strcpy(Name, Script->ReadString()); + Type = (VariableT)Script->ReadByte(); + + FieldType = F_IGNORE; + Offset = -1; + + Found = false; + for (Field = script_fields; Field->name; Field++) + { + if (strcmp(Name, Field->name) == 0) + { + Offset = Field->ofs; + FieldType = Field->type; + Found = true; + + break; + } + } + + if (!Found) + { +#ifdef _DEVEL + Com_Printf("Unknown field '%s'\n",Name); +#endif //_DEVEL + } +} + +FieldDef::FieldDef(FILE *FH, CScript *Script) +{ + int index; + bool Found; + field_t *Field; + + fread(Name, 1, sizeof(Name), FH); + fread(&Type, 1, sizeof(Type), FH); + + fread(&index, 1, sizeof(index), FH); + if (Script && index != -1) + { + Script->SetFieldIndex(index, this); + } + + FieldType = F_IGNORE; + Offset = -1; + + Found = false; + for (Field = script_fields; Field->name; Field++) + { + if (strcmp(Name, Field->name) == 0) + { + Offset = Field->ofs; + FieldType = Field->type; + Found = true; + + break; + } + } + + if (!Found) + { +#ifdef _DEVEL + Com_Printf("Unknown field '%s'\n",Name); +#endif //_DEVEL + } +} + +void FieldDef::Write(FILE *FH, CScript *Script) +{ + int index; + + index = RLID_FIELDDEF; + fwrite(&index, 1, sizeof(index), FH); + + fwrite(Name, 1, sizeof(Name), FH); + fwrite(&Type, 1, sizeof(Type), FH); + + index = -1; + if (Script) + { + index = Script->LookupFieldIndex(this); + } + fwrite(&index, 1, sizeof(index), FH); +} + +byte *FieldDef::GetOffset(Variable *Var) +{ + edict_t *ent; + byte *b, *Dest; + + Dest = NULL; + + switch(Offset) + { + case SPEC_X: + break; + case SPEC_Y: + break; + case SPEC_Z: + break; + case SPEC_DELTA_ANGLES: + ent = Var->GetEdictValue(); + if (ent && ent->client) + { + Dest = (byte *)&ent->client->ps.pmove.delta_angles; + } + break; +#ifdef _HERETIC2_ + case SPEC_P_ORIGIN: + ent = Var->GetEdictValue(); + if (ent && ent->client) + { + Dest = (byte *)&ent->client->playerinfo.origin; + } + break; +#endif + default: + ent = Var->GetEdictValue(); + if (ent) + { + b = (byte *)ent; + Dest = b+Offset; + } + break; + } + + return Dest; +} + +Variable *FieldDef::GetValue(Variable *Var) +{ + vec3_t vec; + + switch(FieldType) + { + case F_INT: + return new IntVar("", GetIntValue(Var) ); + break; + + case F_FLOAT: + return new FloatVar("", GetFloatValue(Var) ); + break; + + case F_EDICT: + return new EntityVar(GetEdictValue(Var)); + break; + + case F_VECTOR: + GetVectorValue(Var, vec); + return new VectorVar(vec); + break; + } + + return NULL; +} + +int FieldDef::GetIntValue(Variable *Var) +{ + byte *Dest; + vec3_t data; + + Dest = GetOffset(Var); + + if (FieldType != F_INT || !Dest) + { + switch(Offset) + { + case SPEC_X: + Var->GetVectorValue(data); + return (int)data[0]; + break; + case SPEC_Y: + Var->GetVectorValue(data); + return (int)data[1]; + break; + case SPEC_Z: + Var->GetVectorValue(data); + return (int)data[2]; + break; + } + + return 0.0; + } + + return *(int *)(Dest); +} + +float FieldDef::GetFloatValue(Variable *Var) +{ + byte *Dest; + vec3_t data; + + Dest = GetOffset(Var); + + if (FieldType != F_FLOAT || !Dest) + { + switch(Offset) + { + case SPEC_X: + Var->GetVectorValue(data); + return data[0]; + break; + case SPEC_Y: + Var->GetVectorValue(data); + return data[1]; + break; + case SPEC_Z: + Var->GetVectorValue(data); + return data[2]; + break; + } + + return 0.0; + } + + return *(float *)(Dest); +} + +void FieldDef::GetVectorValue(Variable *Var, vec3_t &VecValue) +{ + byte *Dest; + + Dest = GetOffset(Var); + + if (FieldType != F_VECTOR || !Dest) + { + VectorCopy(vec3_origin, VecValue); + return; + } + + VectorCopy(*(vec3_t *)(Dest), VecValue); +} + +edict_t *FieldDef::GetEdictValue(Variable *Var) +{ + byte *Dest; + + Dest = GetOffset(Var); + + if (FieldType != F_EDICT || !Dest) + { + return NULL; + } + + return *(edict_t **)(Dest); +} + +char *FieldDef::GetStringValue(Variable *Var) +{ + return ""; +} + +void FieldDef::SetValue(Variable *Var, Variable *Value) +{ + byte *Dest; + vec3_t data; + VectorVar *new_var; + + Dest = GetOffset(Var); + if (Dest == NULL) + { + switch(Offset) + { + case SPEC_X: + Var->GetVectorValue(data); + data[0] = Value->GetFloatValue(); + new_var = new VectorVar(data); + *Var = new_var; + delete new_var; + break; + case SPEC_Y: + Var->GetVectorValue(data); + data[1] = Value->GetFloatValue(); + new_var = new VectorVar(data); + *Var = new_var; + delete new_var; + break; + case SPEC_Z: + Var->GetVectorValue(data); + data[2] = Value->GetFloatValue(); + new_var = new VectorVar(data); + *Var = new_var; + delete new_var; + break; + } + + return; + } + + switch(FieldType) + { + case F_INT: + *(int *)(Dest) = Value->GetIntValue(); + break; + case F_FLOAT: + *(float *)(Dest) = Value->GetFloatValue(); + break; + case F_EDICT: + *(edict_t **)(Dest) = Value->GetEdictValue(); + break; + case F_VECTOR: + Value->GetVectorValue(*(vec3_t *)(Dest)); + break; + } +} + +//========================================================================== + +Event::Event(float NewTime, EventT NewType) +{ + Time = floor((NewTime + 0.05) * 10) / 10; // avoids stupid math rounding errors + Type = NewType; +} + +Event::Event(FILE *FH, CScript *Script) +{ + tRead(&Time,FH); + tRead(&Type,FH); + tRead(&Priority,FH); +} + +void Event::Write(FILE *FH, CScript *Script, int ID) +{ + fwrite(&ID, 1, sizeof(ID), FH); + tWrite(&Time,FH); + tWrite(&Type,FH); + tWrite(&Priority,FH); +} + +bool Event::Process(CScript *Script) +{ + return FALSE; +} + +//========================================================================== + +MoveDoneEvent::MoveDoneEvent(float NewTime, edict_t *NewEnt) +:Event(NewTime, EVENT_MOVE_DONE) +{ + Ent = NewEnt; + + Priority = 10; +} + +MoveDoneEvent::MoveDoneEvent(FILE *FH, CScript *Script) +:Event(FH, Script) +{ + ReadEnt(&Ent,FH); +} + +void MoveDoneEvent::Write(FILE *FH, CScript *Script, int ID) +{ + Event::Write(FH, Script, RLID_MOVEDONEEVENT); + WriteEnt(&Ent,FH); +} + +bool MoveDoneEvent::Process(CScript *Script) +{ + if (level.time < Time) + { + return FALSE; + } + + Script->Move_Done(Ent); + move_signaler(Ent); + + return TRUE; +} + +//========================================================================== + +RotateDoneEvent::RotateDoneEvent(float NewTime, edict_t *NewEnt) +:Event(NewTime, EVENT_ROTATE_DONE) +{ + Ent = NewEnt; + + Priority = 10; +} + +RotateDoneEvent::RotateDoneEvent(FILE *FH, CScript *Script) +:Event(FH, Script) +{ + ReadEnt(&Ent,FH); +} + +void RotateDoneEvent::Write(FILE *FH, CScript *Script, int ID) +{ + Event::Write(FH, Script, RLID_ROTATEDONEEVENT); + WriteEnt(&Ent,FH); +} + +bool RotateDoneEvent::Process(CScript *Script) +{ + if (level.time < Time) + { + return FALSE; + } + + Script->Rotate_Done(Ent); + rotate_signaler(Ent); + + return TRUE; +} + +//========================================================================== + +ExecuteEvent::ExecuteEvent(float NewTime, edict_t *NewOther, edict_t *NewActivator) +:Event(NewTime, EVENT_SCRIPT_EXECUTE) +{ + Other = NewOther; + Activator = NewActivator; + + Priority = 0; +} + +ExecuteEvent::ExecuteEvent(FILE *FH, CScript *Script) +:Event(FH, Script) +{ + ReadEnt(&Other,FH); + ReadEnt(&Activator,FH); +} + +void ExecuteEvent::Write(FILE *FH, CScript *Script, int ID) +{ + Event::Write(FH, Script, RLID_EXECUTEEVENT); + WriteEnt(&Other,FH); + WriteEnt(&Activator,FH); +} + +bool ExecuteEvent::Process(CScript *Script) +{ + if (level.time < Time) + { + return FALSE; + } + + if (Script->CheckWait()) + { + Script->Execute(Other,Activator); + } + + return TRUE; +} + +//========================================================================== + +WaitEvent::WaitEvent(float NewTime) +:Event(NewTime, EVENT_SCRIPT_WAIT) +{ + Priority = 0; +} + +WaitEvent::WaitEvent(FILE *FH, CScript *Script) +:Event(FH, Script) +{ +} + +void WaitEvent::Write(FILE *FH, CScript *Script, int ID) +{ + Event::Write(FH, Script, RLID_WAITEVENT); +} + +bool WaitEvent::Process(CScript *Script) +{ + if (level.time < Time) + { + return FALSE; + } + + Script->ClearTimeWait(); + + if (Script->CheckWait()) + { + Script->Execute(NULL,NULL); + } + + return TRUE; +} + +//========================================================================== + +CScript::CScript(char *ScriptName, edict_t *new_owner) +{ + Clear(true); + + owner = new_owner; + strcpy(Name, ScriptName); + + LoadFile(); +} + +CScript::CScript(FILE *FH) +{ + int index; + int size; + int i; + char name[VAR_LENGTH]; + + Clear(true); + + fread(Name, 1, sizeof(Name), FH); + LoadFile(); + + fread(&ScriptCondition, 1, sizeof(ScriptCondition), FH); + fread(&ConditionInfo, 1, sizeof(ConditionInfo), FH); + fread(&Length, 1, sizeof(Length), FH); + fread(&Position, 1, sizeof(Position), FH); + fread(&DebugFlags, 1, sizeof(DebugFlags), FH); + + fread(&index, 1, sizeof(index), FH); + if (index != -1) + { + owner = &g_edicts[index]; + owner->Script = this; + } + + fread(&index, 1, sizeof(index), FH); + if (index != -1) + { + other = &g_edicts[index]; + } + + fread(&index, 1, sizeof(index), FH); + if (index != -1) + { + activator = &g_edicts[index]; + } + + fread(&size, 1, sizeof(size), FH); + for(i=0;i::Iter iv; + List::Iter is; + List::Iter isv; + List::Iter iev; + + if (Data && DoData) + { + gi.FS_FreeFile(Data); + Data = NULL; + } + + while(LocalVariables.Size()) + { + iv=LocalVariables.Begin(); + delete (*iv); + + LocalVariables.Erase(iv); + } + + while(ParameterVariables.Size()) + { + iv=ParameterVariables.Begin(); + delete (*iv); + + ParameterVariables.Erase(iv); + } + + while(Stack.Size()) + { + iv=Stack.Begin(); + delete (*iv); + + Stack.Erase(iv); + } + + while(Waiting.Size()) + { + iv=Waiting.Begin(); + delete (*iv); + + Waiting.Erase(iv); + } + + while(Signalers.Size()) + { + is=Signalers.Begin(); + delete (*is); + + Signalers.Erase(is); + } + + while(ParameterValues.Size()) + { + isv=ParameterValues.Begin(); + delete (*isv); + + ParameterValues.Erase(isv); + } + + while(Events.Size()) + { + iev=Events.Begin(); + delete (*iev); + + Events.Erase(iev); + } + + for(i=0;i::Iter iv; + List::Iter is; + List::Iter isv; + List::Iter iev; + int i; + + index = RLID_SCRIPT; + fwrite(&index, 1, sizeof(index), FH); + + fwrite(Name, 1, sizeof(Name), FH); + fwrite(&ScriptCondition, 1, sizeof(ScriptCondition), FH); + fwrite(&ConditionInfo, 1, sizeof(ConditionInfo), FH); + fwrite(&Length, 1, sizeof(Length), FH); + fwrite(&Position, 1, sizeof(Position), FH); + fwrite(&DebugFlags, 1, sizeof(DebugFlags), FH); + + index = -1; + if (owner) + { + index = owner - g_edicts; + } + fwrite(&index, 1, sizeof(index), FH); + + index = -1; + if (other) + { + index = other - g_edicts; + } + fwrite(&index, 1, sizeof(index), FH); + + index = -1; + if (activator) + { + index = activator - g_edicts; + } + fwrite(&index, 1, sizeof(index), FH); + + size = 0; + for(i=0,size=0;iWrite(FH, this); + } + } + + size = 0; + for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++) + { + if (LookupVarIndex(*iv) != -1) + { + size++; + } + } + fwrite(&size, 1, sizeof(size), FH); + for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++) + { + index = LookupVarIndex(*iv); + if (index != -1) + { + fwrite(&index, 1, sizeof(index), FH); + fwrite((*iv)->GetName(), 1, VAR_LENGTH, FH); + } + } + + size = LocalVariables.Size(); + fwrite(&size, 1, sizeof(size), FH); + for (iv=LocalVariables.Begin();iv != LocalVariables.End();iv++) + { + (*iv)->Write(FH, this); + } + + size = ParameterVariables.Size(); + fwrite(&size, 1, sizeof(size), FH); + for (iv=ParameterVariables.Begin();iv != ParameterVariables.End();iv++) + { + (*iv)->Write(FH, this); + } + + size = Stack.Size(); + fwrite(&size, 1, sizeof(size), FH); + for (iv=Stack.Begin();iv != Stack.End();iv++) + { + (*iv)->Write(FH, this); + } + + size = Waiting.Size(); + fwrite(&size, 1, sizeof(size), FH); + for (iv=Waiting.Begin();iv != Waiting.End();iv++) + { + (*iv)->Write(FH, this); + } + + size = Signalers.Size(); + fwrite(&size, 1, sizeof(size), FH); + for (is=Signalers.Begin();is != Signalers.End();is++) + { + (*is)->Write(FH, this); + } + + + size = ParameterValues.Size(); + fwrite(&size, 1, sizeof(size), FH); + for (isv=ParameterValues.Begin();isv != ParameterValues.End();isv++) + { + (*isv)->Write(FH, this); + } + + size = Events.Size(); + fwrite(&size, 1, sizeof(size), FH); + for (iev=Events.Begin();iev != Events.End();iev++) + { + (*iev)->Write(FH, this); + } +} + +int CScript::LookupVarIndex(Variable *Var) +{ + int i; + + for(i=0;i= MAX_INDEX) + { + Error("Index out of range: %d > %d",Index,MAX_INDEX); + } + + VarIndex[Index] = RetVal; + + return RetVal; +} + +void CScript::PushStack(Variable *VI) +{ + if (!VI) + { + Error("Illegal push"); + } + + Stack.PushBack(VI); +} + +Variable *CScript::PopStack(void) +{ + Variable *Value; + List::Iter iv; + + if (Stack.Size()) + { + iv = --Stack.End(); + Value = *iv; + Stack.PopBack(); + + return Value; + } + + return NULL; +} + +void CScript::HandleGlobal(bool Assignment) +{ + Variable *Var; + int Index; + + Var = ReadDeclaration(Index); + + if (Assignment) + { + Var->ReadValue(this); + } + + if (!NewGlobal(Var)) + { + VarIndex[Index] = FindGlobal(Var->GetName()); + + delete Var; + } +} + +void CScript::HandleLocal(bool Assignment) +{ + Variable *Var; + int Index; + + Var = ReadDeclaration(Index); + + if (Assignment) + { + Var->ReadValue(this); + } + + NewLocal(Var); +} + +void CScript::HandleParameter(bool Assignment) +{ + Variable *Var; + int Index; + + Var = ReadDeclaration(Index); + + if (Assignment) + { + Var->ReadValue(this); + } + + NewParameter(Var); +} + +void CScript::HandleField(void) +{ + int Index; + FieldDef *NewField; + + NewField = new FieldDef(this); + + Index = ReadInt(); + if (Index < 0 || Index >= MAX_INDEX) + { + Error("Index for field out of range: %d > %d\n",Index,MAX_INDEX); + } + + Fields[Index] = NewField; +} + +void CScript::HandleGoto(void) +{ + Position = ReadInt(); +} + +Variable *CScript::HandleSpawn(void) +{ + int Count; + edict_t *ent; + Variable *Name; + Variable *Value; + field_t *f; + const char *NameValue; + byte *b; + + ent = G_Spawn(); + + for(Count = ReadByte(); Count; Count--) + { + Name = PopStack(); + Value = PopStack(); + if (!Name || !Value) + { + Error("Invalid stack for HandleSpawn()"); + } + + NameValue = Name->GetStringValue(); + + for (f=fields ; f->name ; f++) + { + if (!Q_stricmp(f->name, (char *)NameValue) ) + { + if (f->flags & FFL_SPAWNTEMP) + { + b = (byte *)&st; + } + else + { + b = (byte *)ent; + } + + switch (f->type) + { + case F_LSTRING: + *(char **)(b+f->ofs) = ED_NewString (Value->GetStringValue()); + break; + case F_VECTOR: + Value->GetVectorValue(*(vec3_t *)(b+f->ofs)); + break; + case F_INT: + *(int *)(b+f->ofs) = Value->GetIntValue(); + break; + case F_FLOAT: + *(float *)(b+f->ofs) = Value->GetFloatValue(); + break; + case F_ANGLEHACK: + ((float *)(b+f->ofs))[0] = 0; + ((float *)(b+f->ofs))[1] = Value->GetFloatValue(); + ((float *)(b+f->ofs))[2] = 0; + break; + case F_IGNORE: + break; +#ifdef _HERETIC2_ + case F_RGBA: + break; + case F_RGB: + break; +#endif + + } + break; + } + } + } + + ED_CallSpawn(ent); + + return new EntityVar(ent); +} + +Variable *CScript::HandleBuiltinFunction(void) +{ + int Index; + edict_t *Search; + Variable *V1; + Variable *Var; + + Index = ReadByte(); + switch(Index) + { + case FUNC_FIND_ENTITY_WITH_TARGET: + V1 = PopStack(); + Search = G_Find(NULL, FOFS(targetname), V1->GetStringValue()); + Var = new EntityVar(Search); + + delete V1; + break; + + case FUNC_SIN: + V1 = PopStack(); + Var = new FloatVar( "", sin( DEG2RAD(V1->GetFloatValue()) )); + + delete V1; + break; + + case FUNC_COS: + V1 = PopStack(); + Var = new FloatVar("", cos( DEG2RAD(V1->GetFloatValue()) )); + + delete V1; + break; + + case FUNC_FIND_ENTITY_WITH_SCRIPT: + V1 = PopStack(); + Search = G_Find(NULL, FOFS(scripttarget), V1->GetStringValue()); + Var = new EntityVar(Search); + + delete V1; + break; + + case FUNC_SPAWN: + Var = HandleSpawn(); + break; + + case FUNC_GET_OTHER: + Var = new EntityVar(other); + break; + + case FUNC_GET_ACTIVATOR: + Var = new EntityVar(activator); + break; + } + + return Var; +} + +void CScript::HandlePush(void) +{ + int Type; + Variable *Var; + + Type = ReadByte(); + switch(Type) + { + case PUSH_CONST_INT: + Var = new IntVar(); + Var->ReadValue(this); + break; + case PUSH_CONST_FLOAT: + Var = new FloatVar(); + Var->ReadValue(this); + break; + case PUSH_CONST_VECTOR: + Var = new VectorVar(); + Var->ReadValue(this); + break; + case PUSH_CONST_ENTITY: + Var = new EntityVar(); + Var->ReadValue(this); + break; + case PUSH_CONST_STRING: + Var = new StringVar(); + Var->ReadValue(this); + break; + case PUSH_VAR: + Var = new VariableVar(); + ((VariableVar *)Var)->ReadValue(this); + break; + case PUSH_VAR_WITH_FIELD: + Var = new FieldVariableVar(); + ((VariableVar *)Var)->ReadValue(this); + break; + case PUSH_FUNCTION: + Var = HandleBuiltinFunction(); + break; + } + + PushStack(Var); +} + +void CScript::HandlePop(void) +{ + Variable *V; + + V = PopStack(); + if (V) + { + delete V; + } +} + +void CScript::HandleAssignment(void) +{ + Variable *Value, *Assignee; + + Assignee = PopStack(); + Value = PopStack(); + if (Value == NULL || Assignee == NULL) + { + Error("Invalid stack for Add"); + } + + (*Assignee) = Value; + + delete Assignee; + delete Value; +} + +void CScript::HandleAdd(void) +{ + Variable *V1, *V2; + + V1 = PopStack(); + V2 = PopStack(); + if (V1 == NULL || V2 == NULL) + { + Error("Invalid stack for Add"); + } + + PushStack((*V1) + V2); + + delete V1; + delete V2; +} + +void CScript::HandleSubtract(void) +{ + Variable *V1, *V2; + + V1 = PopStack(); + V2 = PopStack(); + if (V1 == NULL || V2 == NULL) + { + Error("Invalid stack for Subtract"); + } + + PushStack((*V1) - V2); + + delete V1; + delete V2; +} + +void CScript::HandleMultiply(void) +{ + Variable *V1, *V2; + + V1 = PopStack(); + V2 = PopStack(); + if (V1 == NULL || V2 == NULL) + { + Error("Invalid stack for Multiply"); + } + + PushStack((*V1) * V2); + + delete V1; + delete V2; +} + +void CScript::HandleDivide(void) +{ + Variable *V1, *V2; + + V1 = PopStack(); + V2 = PopStack(); + if (V1 == NULL || V2 == NULL) + { + Error("Invalid stack for Divide"); + } + + PushStack((*V1) / V2); + + delete V1; + delete V2; +} + +void CScript::HandleDebug(void) +{ + List::Iter iv; + int Flags; + + Flags = ReadByte(); + + if (Flags) + { + if (Flags & DEBUG_ENABLE) + { + Flags &= ~DEBUG_ENABLE; + DebugFlags |= Flags; + } + else + { + DebugFlags &= ~Flags; + } + } + else + { + StartDebug(); + + if (ParameterVariables.Size()) + { + DebugLine(" Parameters:\n"); + for (iv=ParameterVariables.Begin();iv != ParameterVariables.End();iv++) + { + (*iv)->Debug(this); + } + } + + if (GlobalVariables.Size()) + { + DebugLine(" Global Variables:\n"); + for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++) + { + (*iv)->Debug(this); + } + } + + if (LocalVariables.Size()) + { + DebugLine(" Local Variables:\n"); + for (iv=LocalVariables.Begin();iv != LocalVariables.End();iv++) + { + (*iv)->Debug(this); + } + } + EndDebug(); + } +} + +void CScript::HandleDebugStatement(void) +{ + DebugLine("%s\n",ReadString()); +} + +void CScript::HandleAddAssignment(void) +{ + Variable *Value, *Assignee; + + Assignee = PopStack(); + Value = PopStack(); + if (Value == NULL || Assignee == NULL) + { + Error("Invalid stack for AddAssignment"); + } + + (*Assignee) = (*Assignee) + Value; + + delete Assignee; + delete Value; +} + +void CScript::HandleSubtractAssignment(void) +{ + Variable *Value, *Assignee; + + Assignee = PopStack(); + Value = PopStack(); + if (Value == NULL || Assignee == NULL) + { + Error("Invalid stack for SubtractAssignment"); + } + + (*Assignee) = (*Assignee) - Value; + + delete Assignee; + delete Value; +} + +void CScript::HandleMultiplyAssignment(void) +{ + Variable *Value, *Assignee; + + Assignee = PopStack(); + Value = PopStack(); + if (Value == NULL || Assignee == NULL) + { + Error("Invalid stack for MultiplyAssignment"); + } + + (*Assignee) = (*Assignee) * Value; + + delete Assignee; + delete Value; +} + +void CScript::HandleDivideAssignment(void) +{ + Variable *Value, *Assignee; + + Assignee = PopStack(); + Value = PopStack(); + if (Value == NULL || Assignee == NULL) + { + Error("Invalid stack for DivideAssignment"); + } + + (*Assignee) = (*Assignee) / Value; + + delete Assignee; + delete Value; +} + +bool CScript::HandleWait(bool ForAll) +{ + int count; + Variable *VI; + + count = ReadByte(); + if (count & WAIT_CLEAR) + { + ConditionInfo = WAIT_CLEAR; + } + else + { + ConditionInfo = 0; + } + + count &= ~WAIT_CLEAR; + + for(;count;count--) + { + VI = PopStack(); + if (!VI) + { + Error("Invalid stack for HandleWait"); + } + + Waiting.PushBack(VI); + } + + if (ForAll) + { + ScriptCondition = COND_WAIT_ALL; + } + else + { + ScriptCondition = COND_WAIT_ANY; + } + + if (CheckWait()) + { + FinishWait(NULL,false); + + return false; + } + + return true; +} + +bool CScript::HandleTimeWait(void) +{ + Variable *V; + float NextTime; + + V = PopStack(); + if (!V) + { + Error("Invalid stack for Time Wait"); + } + + NextTime = level.time + V->GetFloatValue(); + if (NextTime <= level.time) + { + return false; + } + + AddEvent(new WaitEvent(NextTime) ); + + ScriptCondition = COND_WAIT_TIME; + + return true; +} + +void CScript::HandleIf(void) +{ + int Condition; + int Location; + Variable *V1, *V2; + bool Result; + + Condition = ReadByte(); + Location = ReadInt(); + + V2 = PopStack(); + V1 = PopStack(); + + if (V1 == NULL || V2 == NULL) + { + Error("Invalid stack for If"); + } + + Result = false; + + switch(Condition) + { + case COND_EQUAL: + if ((*V1) == V2) + { + Result = true; + } + break; + case COND_LESS_THAN: + if ((*V1) < V2) + { + Result = true; + } + break; + case COND_LESS_THAN_EQUAL: + if ((*V1) <= V2) + { + Result = true; + } + break; + case COND_GREATER_THAN: + if ((*V1) > V2) + { + Result = true; + } + break; + case COND_GREATER_THAN_EQUAL: + if ((*V1) >= V2) + { + Result = true; + } + break; + case COND_NOT_EQUAL: + if ((*V1) != V2) + { + Result = true; + } + break; + } + + if (!Result) + { + Position = Location; + } +} + +void CScript::HandlePrint(void) +{ + int Flags; + Variable *Text, *Entity, *Level; + char *TextValue; + int LevelValue; + edict_t *ent; +#ifdef _HERETIC2_ + int TextIndex; +#endif + + Entity = Level = NULL; + LevelValue = PRINT_HIGH; + ent = NULL; + + Flags = ReadByte(); + + Text = PopStack(); + if (!Text) + { + Error("Invalid stack for Print"); + } + if (Text->GetType() == TypeSTRING) + { + TextValue = Text->GetStringValue(); + } + else + { +#ifdef _HERETIC2_ + TextIndex = Text->GetIntValue(); + TextValue = message_text[TextIndex].string; +#else + TextValue = ""; +#endif + } + + if (Flags & PRINT_LEVEL) + { + Level = PopStack(); + if (!Level) + { + Error("Invalid stack for Print"); + } + LevelValue = Level->GetIntValue(); + } + + if (Flags & PRINT_ENTITY) + { + Entity = PopStack(); + if (!Entity) + { + Error("Invalid stack for Print"); + } + ent = Entity->GetEdictValue(); + } + +#ifdef _HERETIC2_ + if (!sv_jumpcinematic->value || !sv_cinematicfreeze->value) +#endif + { +#ifdef _HERETIC2_ + if (Flags & PRINT_CAPTIONED) + { + if (ent) + { + gi.captionprintf(ent, TextIndex); // Send the ID for the text to the single player + } + else + { + gi.bcaption(PRINT_HIGH, TextIndex); // Send the ID for the text to all players + } + } + else +#endif // _HERETIC2_ + if (Flags & PRINT_CENTERED) + { + if (ent) + { +#ifdef _HERETIC2_ + gi.levelmsg_centerprintf(ent, TextIndex); // Send the ID over the net rather than the string itself... +#else + gi.centerprintf(ent, TextValue); +#endif // _HERETIC2_ + } + } + else + { + if (ent) + { + gi.cprintf(ent, LevelValue, TextValue); + } + else + { + gi.bprintf(LevelValue, TextValue); + } + } + } + + delete Text; + if (Entity) + { + delete Entity; + } + if (Level) + { + delete Level; + } +} + +void CScript::HandlePlaySound(void) +{ + int Flags; + Variable *SoundName, *Entity, *Volume, *Attenuation, *Channel, *TimeDelay; + char *SoundValue; + float VolumeValue, AttenuationValue, TimeDelayValue; + int ChannelValue; + edict_t *ent; + + + Entity = Volume = Attenuation = Channel = TimeDelay = NULL; + ent = NULL; + VolumeValue = 1.0; + AttenuationValue = ATTN_NORM; + +#ifdef _HERETIC2_ + ChannelValue = CHAN_VOICE; +#else + ChannelValue = CHAN_AUTO; +#endif + + TimeDelayValue = 0.0; + + Flags = ReadByte(); + + SoundName = PopStack(); + if (!SoundName) + { + Error("Invalid stack for PlaySound"); + } + SoundValue = SoundName->GetStringValue(); + + if (Flags & PLAY_SOUND_TIMEDELAY) + { + TimeDelay = PopStack(); + if (!TimeDelay) + { + Error("Invalid stack for PlaySound"); + } + TimeDelayValue = TimeDelay->GetFloatValue(); + } + + if (Flags & PLAY_SOUND_CHANNEL) + { + Channel = PopStack(); + if (!Channel) + { + Error("Invalid stack for PlaySound"); + } + ChannelValue = Channel->GetIntValue(); + } + + if (Flags & PLAY_SOUND_ATTENUATION) + { + Attenuation = PopStack(); + if (!Attenuation) + { + Error("Invalid stack for PlaySound"); + } + AttenuationValue = Attenuation->GetFloatValue(); + } + + if (Flags & PLAY_SOUND_VOLUME) + { + Volume = PopStack(); + if (!Volume) + { + Error("Invalid stack for PlaySound"); + } + VolumeValue = Volume->GetFloatValue(); + } + + if (Flags & PLAY_SOUND_ENTITY) + { + Entity = PopStack(); + if (!Entity) + { + Error("Invalid stack for PlaySound"); + } + ent = Entity->GetEdictValue(); + } + +#ifdef _HERETIC2_ + if (sv_cinematicfreeze->value) // In cinematic freezes, all sounds should be full volume. Thus is it written. + { + AttenuationValue = ATTN_NONE; + CinematicSound[CinematicSound_cnt].ent = ent; + CinematicSound[CinematicSound_cnt].channel = ChannelValue; + + if (CinematicSound_cnt < MAX_CINESNDS-1 ) + ++CinematicSound_cnt; + } +#endif + +#ifdef _HERETIC2_ + if (!sv_jumpcinematic->value || !sv_cinematicfreeze->value) +#endif + { + gi.sound(ent, ChannelValue, gi.soundindex(SoundValue), VolumeValue, AttenuationValue, TimeDelayValue); + } + + delete SoundName; + if (Entity) + { + delete Entity; + } + if (Volume) + { + delete Volume; + } + if (Attenuation) + { + delete Attenuation; + } + if (Channel) + { + delete Channel; + } + if (TimeDelay) + { + delete TimeDelay; + } +} + +void CScript::HandleFeature(bool Enable) +{ + int FeatureType; +#ifdef _HERETIC2_ + int i,null_snd; +#endif + + FeatureType = ReadByte(); + + switch(FeatureType) + { + case FEATURE_TRIGGER: + HandleTrigger(Enable); + break; + + case FEATURE_AMBIENT_SOUNDS: + break; + + case FEATURE_CINEMATICS: + #ifdef _HERETIC2_ + if (Enable) + { + CinematicSound_cnt = 0; + Cvar_Set("sv_cinematicfreeze","1"); + remove_non_cinematic_entites(NULL); + } + else + { + if (sv_jumpcinematic->value == 2) // Jump sent from client + { + Cvar_Set("sv_jumpcinematic","0"); + null_snd = gi.soundindex("misc/null.wav"); + gi.bcaption(PRINT_HIGH, 270); // Send the ID for the text to all players + for (i=0;iGetStringValue(); + +#ifdef _HERETIC2_ + if (!sv_jumpcinematic->value || !sv_cinematicfreeze->value) +#endif + { + gi.soundindex(SoundValue); + } + + delete SoundName; +} + +void CScript::HandleMove(void) +{ + int Flags; + Variable *Signaler, *Rate, *Duration, *Amount, *Entity; + edict_t *ent; + vec3_t Vec,Dest,Diff; + vec_t Length; + + Signaler = Rate = Duration = NULL; + + Flags = ReadByte(); + + if (Flags & MOVE_SIGNALER) + { + Signaler = PopStack(); + } + + if (Flags & MOVE_RATE) + { + Rate = PopStack(); + } + + if (Flags & MOVE_DURATION) + { + Duration = PopStack(); + } + + Amount = PopStack(); + Entity = PopStack(); + + Amount->GetVectorValue(Vec); + + ent = Entity->GetEdictValue(); + if (ent) + { + if (!Rate && !Duration) + { + VectorAdd(ent->s.origin, Vec, ent->s.origin); + if (ent->chain) + { + VectorAdd(ent->chain->s.origin, Vec, ent->chain->s.origin); + } + } + else + { + if (!(Flags & MOVE_ABSOLUTE)) + { + VectorAdd(ent->s.origin, Vec, Dest); + } + else + { + VectorCopy(Vec, Dest); + } + + VectorSubtract(ent->s.origin, Dest, Diff); + Length = VectorLength(Diff); + + if (Rate && Duration) + { + ent->moveinfo.decel = ent->moveinfo.accel = ent->moveinfo.speed = Rate->GetFloatValue(); + Length = Rate->GetFloatValue() * Duration->GetFloatValue(); + VectorNormalize(Diff); + VectorMA(ent->s.origin, Length, Diff, Dest); + } + else if (Rate) + { + ent->moveinfo.decel = ent->moveinfo.accel = ent->moveinfo.speed = Rate->GetFloatValue(); + } + else + { + ent->moveinfo.decel = ent->moveinfo.accel = ent->moveinfo.speed = Length / Duration->GetFloatValue(); + } + + if (DebugFlags & DEBUG_MOVE) + { + StartDebug(); + DebugLine(" Moving Entity %d\n",Entity->GetIntValue()); + DebugLine(" From (%7.3f, %7.3f, %7.3f)\n",ent->s.origin[0],ent->s.origin[1],ent->s.origin[2]); + DebugLine(" To (%7.3f, %7.3f, %7.3f)\n",Dest[0], Dest[1], Dest[2]); + EndDebug(); + } + + if (Signaler) + { + AddSignaler(ent, Signaler, SIGNAL_MOVE); + } + + Move(ent, Dest); + } + } + + delete Amount; + delete Entity; +// Signaling routine will handle this +// if (Signaler) +// { +// delete Signaler; +// } + if (Rate) + { + delete Rate; + } + if (Duration) + { + delete Duration; + } +} + +void CScript::HandleRotate(void) +{ + int Flags; + Variable *Signaler, *Rate, *Duration, *Amount, *Entity; + edict_t *ent; + vec3_t Vec,Dest,Diff; + vec_t Length; + + Signaler = Rate = Duration = NULL; + + Flags = ReadByte(); + + if (Flags & ROTATE_SIGNALER) + { + Signaler = PopStack(); + } + + if (Flags & ROTATE_RATE) + { + Rate = PopStack(); + } + + if (Flags & ROTATE_DURATION) + { + Duration = PopStack(); + } + + Amount = PopStack(); + Entity = PopStack(); + + Amount->GetVectorValue(Vec); + + ent = Entity->GetEdictValue(); + if (ent) + { + if (!Rate && !Duration) + { + VectorAdd(ent->s.angles, Vec, ent->s.angles); + if (ent->chain) + { + VectorAdd(ent->chain->s.angles, Vec, ent->chain->s.angles); + } + } + else + { + if (!(Flags & MOVE_ABSOLUTE)) + { + VectorAdd(ent->s.angles, Vec, Dest); + } + else + { + VectorCopy(Vec, Dest); + } + + VectorSubtract(ent->s.angles, Dest, Diff); + Length = VectorLength(Diff); + + if (Rate && Duration) + { + ent->moveinfo.speed = Rate->GetFloatValue(); + Length = Rate->GetFloatValue() * Duration->GetFloatValue(); + VectorNormalize(Diff); + VectorMA(ent->s.angles, Length, Diff, Dest); + } + else if (Rate) + { + ent->moveinfo.speed = Rate->GetFloatValue(); + } + else + { + ent->moveinfo.speed = Length / Duration->GetFloatValue(); + } + + VectorCopy(Dest, ent->moveinfo.start_angles); + VectorCopy(Dest, ent->moveinfo.end_angles); + + if (DebugFlags & DEBUG_ROTATE) + { + StartDebug(); + DebugLine(" Rotating Entity %d\n",Entity->GetIntValue()); + DebugLine(" From (%7.3f, %7.3f, %7.3f)\n",ent->s.angles[0],ent->s.angles[1],ent->s.angles[2]); + DebugLine(" To (%7.3f, %7.3f, %7.3f)\n",ent->moveinfo.end_angles[0], ent->moveinfo.end_angles[1], ent->moveinfo.end_angles[2]); + EndDebug(); + } + + if (Signaler) + { + AddSignaler(ent, Signaler, SIGNAL_ROTATE); + } + Rotate(ent); + } + } + + delete Amount; + delete Entity; +// Signaling routine will handle this +// if (Signaler) +// { +// delete Signaler; +// } + if (Rate) + { + delete Rate; + } + if (Duration) + { + delete Duration; + } +} + +void CScript::HandleUse(void) +{ + Variable *Entity; + edict_t *use_ent; + + Entity = PopStack(); + + use_ent = Entity->GetEdictValue(); + if (use_ent && use_ent->use) + { + use_ent->use(use_ent,other,activator); + } + + delete Entity; +} + +void CScript::HandleTrigger(bool Enable) +{ + Variable *Entity; + edict_t *trigger_ent; + + Entity = PopStack(); + + trigger_ent = Entity->GetEdictValue(); + if (trigger_ent) + { + if (Enable) + { + trigger_ent->solid = SOLID_TRIGGER; + trigger_ent->use = Use_Multi; + gi.linkentity (trigger_ent); + } + else + { + trigger_ent->solid = SOLID_NOT; + trigger_ent->use = NULL; + } + } +} + +void CScript::HandleAnimate(void) +{ + int Flags; + Variable *Signaler, *Moving, *Turning, *Repeat, *Action, *Entity, *Source; + edict_t *ent, *SourceEnt; + vec3_t MovingVal; + vec3_t TurningVal; + int RepeatVal, ActionVal; + + void (*SignalerRoutine)(edict_t*); + + SignalerRoutine = NULL; + Signaler = Moving = Turning = Repeat = Action = Entity = Source = NULL; + SourceEnt = NULL; + VectorCopy(vec3_origin, MovingVal); + VectorCopy(vec3_origin, TurningVal); + RepeatVal = 0; + + Flags = ReadByte(); + + if (Flags & ANIMATE_SOURCE) + { + Source = PopStack(); + SourceEnt = Source->GetEdictValue(); + } + + if (Flags & ANIMATE_SIGNALER) + { + Signaler = PopStack(); + } + + if (Flags & ANIMATE_MOVING) + { + Moving = PopStack(); + Moving->GetVectorValue(MovingVal); + } + + if (Flags & ANIMATE_TURNING) + { + Turning = PopStack(); + Turning->GetVectorValue(TurningVal); + } + + if (Flags & ANIMATE_REPEAT) + { + Repeat = PopStack(); + RepeatVal = Repeat->GetIntValue(); + } + + + Action = PopStack(); + ActionVal = Action->GetIntValue(); + + Entity = PopStack(); + ent = Entity->GetEdictValue(); + + if (ent) + { + if (Signaler) + { + AddSignaler(ent, Signaler, SIGNAL_ANIMATE); + SignalerRoutine = animate_signaler; + } + +#ifdef _HERETIC2_ + /* + switch(Action->GetIntValue()) + { // Hardcoded yuckiness + case 0: + PostGameMessage(ent, MSG_C_WALK, PRI_DIRECTIVE, "iig",(int)MovingVal[0],(int)TurningVal[0],SignalerRoutine); + break; + case 1: + PostGameMessage(ent, MSG_C_RUN, PRI_DIRECTIVE, "iig",(int)MovingVal[0],(int)TurningVal[0],SignalerRoutine); + break; + case 2: + PostGameMessage(ent, MSG_C_IDLE, PRI_DIRECTIVE, "ig",(int)TurningVal[0],SignalerRoutine); + break; + case 3: + PostGameMessage(ent, MSG_C_ATTACK1, PRI_DIRECTIVE, "g",SignalerRoutine); + break; + case 4: + PostGameMessage(ent, MSG_C_ATTACK2, PRI_DIRECTIVE, "g",SignalerRoutine); + break; + case 5: + PostGameMessage(ent, MSG_C_ATTACK3, PRI_DIRECTIVE, "g",SignalerRoutine); + break; + case 6: + PostGameMessage(ent, MSG_C_BACKPEDAL, PRI_DIRECTIVE, "iig",(int)MovingVal[0],(int)TurningVal[0],SignalerRoutine); + break; + case 7: + PostGameMessage(ent, MSG_C_DEATH1, PRI_DIRECTIVE,"ig",(int)TurningVal[0],SignalerRoutine); + break; + case 8: + PostGameMessage(ent, MSG_C_PAIN1, PRI_DIRECTIVE,"ig",RepeatVal,SignalerRoutine); + break; + case 9: + PostGameMessage(ent, MSG_C_PAIN2, PRI_DIRECTIVE,"g",SignalerRoutine); + break; + default: + break; + } */ + + PostGameMessage(ent,(enum G_MsgID_e) msg_animtype[ActionVal], PRI_DIRECTIVE, "iiige",(int)MovingVal[0],(int)TurningVal[0],(int)RepeatVal,SignalerRoutine,activator); +#endif + } + + delete Action; + delete Entity; + if (Source) + { + delete Source; + } +// Signaling routine will handle this +// if (Signaler) +// { +// delete Signaler; +// } + if (Repeat) + { + delete Repeat; + } + if (Turning) + { + delete Turning; + } + if (Moving) + { + delete Moving; + } +} + + +void CScript::HandleCopyPlayerAttributes(void) +{ + Variable *Player, *Destination; + edict_t *PlayerEnt, *DestinationEnt; + + Destination = PopStack(); + if (!Destination) + { + Error("Invalid stack for HandleCopyPlayerAttributes()"); + } + DestinationEnt = Destination->GetEdictValue(); + + Player = PopStack(); + if (!Player) + { + Error("Invalid stack for HandleCopyPlayerAttributes()"); + } + PlayerEnt = Player->GetEdictValue(); + +#ifdef _HERETIC2_ + c_swapplayer (PlayerEnt,DestinationEnt); +#endif +} + +void CScript::HandleSetViewAngles(void) +{ + Variable *Player, *Angles; + edict_t *PlayerEnt; + vec3_t vec; +#ifdef _HERETIC2_ + vec3_t HoldAngles; +#endif + + Angles = PopStack(); + if (!Angles) + { + Error("Invalid stack for HandleSetViewAngles()"); + } + Angles->GetVectorValue(vec); + + Player = PopStack(); + if (!Player) + { + Error("Invalid stack for HandleSetViewAngles()"); + } + PlayerEnt = Player->GetEdictValue(); + +#ifdef _HERETIC2_ + // use PlayerEnt and vec + // set angles + Angles->GetVectorValue(HoldAngles); + + PlayerEnt->client->ps.pmove.delta_angles[PITCH]=0; + PlayerEnt->client->ps.pmove.delta_angles[YAW]=ANGLE2SHORT(HoldAngles[YAW]-PlayerEnt->client->resp.cmd_angles[YAW]); + PlayerEnt->client->ps.pmove.delta_angles[ROLL]=0; + + PlayerEnt->s.angles[PITCH]=0; + PlayerEnt->s.angles[YAW]=HoldAngles[YAW]; + PlayerEnt->s.angles[ROLL]=0; + +#endif +} + +void CScript::HandleSetCacheSize(void) +{ + Variable *CacheSize; + + CacheSize = PopStack(); + if (!CacheSize) + { + Error("Invalid stack for HandleSetCacheSize()"); + } + +#ifdef _HERETIC2_ + // jscott int size; size = CacheSize->GetIntValue(); +#endif +} + +void CScript::Move_Done(edict_t *ent) +{ + VectorClear (ent->velocity); + + VectorCopy(ent->moveinfo.end_origin, ent->s.origin); +} + +void CScript::Move(edict_t *ent, vec3_t Dest) +{ + float frames; + + VectorCopy(Dest, ent->moveinfo.end_origin); + + VectorSubtract (ent->moveinfo.end_origin, ent->s.origin, ent->moveinfo.dir); + ent->moveinfo.remaining_distance = VectorNormalize (ent->moveinfo.dir); + if (ent->moveinfo.remaining_distance <= 0) + { + frames = 0; + } + else + { + frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME) + 1; + } + + VectorScale (ent->moveinfo.dir, ent->moveinfo.remaining_distance/frames/FRAMETIME, ent->velocity); + + AddEvent(new MoveDoneEvent(level.time + (frames * FRAMETIME), ent)); +} + +void CScript::Rotate_Done (edict_t *ent) +{ + VectorClear (ent->avelocity); +} + +void CScript::Rotate(edict_t *ent) +{ + float distance; + vec3_t destdelta; + float frames; + + VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, destdelta); + + distance = VectorNormalize (destdelta); + if (ent->moveinfo.speed <= 0) + { + frames = 0; + VectorClear (ent->avelocity); + } + else + { + frames = floor((distance / ent->moveinfo.speed) / FRAMETIME) + 1; + VectorScale (destdelta, distance/frames/FRAMETIME, ent->avelocity); + } + + AddEvent(new RotateDoneEvent(level.time + (frames * FRAMETIME), ent)); +} + +void CScript::AddEvent(Event *Which) +{ + List::Iter ie; + float time; + + if (Events.Size()) + { + time = Which->GetTime(); + for (ie=Events.Begin();ie != Events.End();ie++) + { + if ( (*ie)->GetTime() > time) + { + break; + } + } + Events.Insert(ie, Which); + } + else + { + Events.PushBack(Which); + } + +#ifdef _DEBUG + float testtime; + + time = 0; + for (ie=Events.Begin();ie != Events.End();ie++) + { + testtime = (*ie)->GetTime(); + if (testtime < time) + { + DebugBreak(); + } + } +#endif +} + +void CScript::ProcessEvents(void) +{ + List::Iter ie, next; + + while(Events.Size()) + { + ie = Events.Begin(); + + if ((*ie)->Process(this)) + { + delete (*ie); + Events.Erase(ie); + } + else + { + break; + } + } +} + +void CScript::ClearTimeWait(void) +{ + if (ScriptCondition == COND_WAIT_TIME) + { + ScriptCondition = COND_READY; + } +} + +void CScript::AddSignaler(edict_t *Edict, Variable *Var, SignalT SignalType) +{ + List::Iter is; + Signaler *NewSig; + + NewSig = new Signaler(Edict, Var, SignalType); + + // Note that this check does not need to be in there - signalers are very flexible, but if used + // incorrectly, they can result in weird behavior - this check prevents more than one command using + // the same signal varaible prior to a wait command + for (is=Signalers.Begin();is != Signalers.End();is++) + { + if (*(*is) == NewSig) + { + Error("Renner Error #1: Variable '%s' is being used for multiple signals", Var->GetName() ); + } + } + + Signalers.PushBack(NewSig); +} + +void CScript::CheckSignalers(edict_t *Which, SignalT SignalType) +{ + List::Iter is, next; + bool DoCheckWait = false; + + if (Signalers.Size()) + { + for (is=Signalers.Begin();is != Signalers.End();is = next) + { + next = is; + next++; + if ((*is)->Test(Which, SignalType)) + { + delete (*is); + Signalers.Erase(is); + + DoCheckWait = true; + } + } + } + + if (DoCheckWait && (ScriptCondition == COND_WAIT_ANY || ScriptCondition == COND_WAIT_ALL)) + { + if (CheckWait()) + { + FinishWait(Which, true); + } + } +} + +bool CScript::CheckWait(void) +{ + List::Iter iv; + int count, needed; + + if (ScriptCondition == COND_WAIT_ALL) + { + needed = Waiting.Size(); + } + else if (ScriptCondition == COND_WAIT_ANY) + { + needed = 1; + } + else if (ScriptCondition == COND_WAIT_TIME) + { + return false; + } + else if (ScriptCondition == COND_READY) + { + return true; + } + else + { + return false; + } + + count = 0; + if (Waiting.Size()) + { + for (iv=Waiting.Begin();iv != Waiting.End();iv++) + { + if ( (*iv)->GetIntValue()) + { + count++; + } + } + } + + if (count == needed) + { + ScriptCondition = COND_READY; + + return true; + } + + return false; +} + +void CScript::FinishWait(edict_t *Which, bool NoExecute) +{ + List::Iter iv; + + if (Waiting.Size()) + { + for (iv=Waiting.Begin();iv != Waiting.End();iv++) + { + if (ConditionInfo == WAIT_CLEAR) + { + (*iv)->ClearSignal(); + } + + delete *iv; + } + } + Waiting.Erase(Waiting.Begin(), Waiting.End() ); + + if (NoExecute) + { + Execute(Which, NULL); + } +} + +void CScript::Error (char *error, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + gi.error(text); +} + +void CScript::StartDebug(void) +{ + DebugLine("-------------------------------\n"); + DebugLine("Script: %s\n",Name); + DebugLine(" DEBUG at %d\n",Position); +} + +void CScript::EndDebug(void) +{ + DebugLine("-------------------------------\n"); +} + +void CScript::DebugLine (char *debugtext, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, debugtext); + vsprintf (text, debugtext, argptr); + va_end (argptr); + + Com_Printf("%s",text); + +#ifdef _DEBUG + OutputDebugString(text); +#endif +} + +void CScript::Think(void) +{ + ProcessEvents(); +} + +ScriptConditionT CScript::Execute(edict_t *new_other, edict_t *new_activator) +{ + bool Done; + int InstructionCount; + + if (ScriptCondition != COND_READY) + { + return ScriptCondition; + } + + if (DebugFlags & DEBUG_TIME) + { + StartDebug(); + DebugLine(" Current Time: %10.1f\n",level.time); + EndDebug(); + } + + if (new_other) + { + other = new_other; + } + if (new_activator) + { + activator = new_activator; + } + + InstructionCount = 0; + Done = false; + while (!Done) + { + InstructionCount++; + if (InstructionCount > INSTRUCTION_MAX) + { + Error("Runaway loop for script"); + } + + switch(ReadByte()) + { + case CODE_NEW_GLOBAL: + HandleGlobal(false); + break; + case CODE_NEW_GLOBAL_PLUS_ASSIGNMENT: + HandleGlobal(true); + break; + case CODE_NEW_LOCAL: + HandleLocal(false); + break; + case CODE_NEW_LOCAL_PLUS_ASSIGNMENT: + HandleLocal(true); + break; + case CODE_NEW_PARAMETER: + HandleParameter(false); + break; + case CODE_NEW_PARAMETER_PLUS_DEFAULT: + HandleParameter(true); + break; + case CODE_FIELD: + HandleField(); + break; + case CODE_ASSIGNMENT: + HandleAssignment(); + break; + case CODE_ADD: + HandleAdd(); + break; + case CODE_SUBTRACT: + HandleSubtract(); + break; + case CODE_MULTIPLY: + HandleMultiply(); + break; + case CODE_DIVIDE: + HandleDivide(); + break; + case CODE_ADD_ASSIGNMENT: + HandleAddAssignment(); + break; + case CODE_SUBTRACT_ASSIGNMENT: + HandleSubtractAssignment(); + break; + case CODE_MULTIPLY_ASSIGNMENT: + HandleMultiplyAssignment(); + break; + case CODE_DIVIDE_ASSIGNMENT: + HandleDivideAssignment(); + break; + case CODE_GOTO: + HandleGoto(); + break; + case CODE_PUSH: + HandlePush(); + break; + case CODE_POP: + HandlePop(); + break; + case CODE_IF: + HandleIf(); + break; + case CODE_EXIT: + ScriptCondition = COND_COMPLETED; + Done = true; + break; + case CODE_SUSPEND: + //ScriptCondition = COND_SUSPENDED; + Done = true; + break; + case CODE_DEBUG: + HandleDebug(); + break; + case CODE_WAIT_SECONDS: + Done = HandleTimeWait(); + break; + case CODE_WAIT_ALL: + Done = HandleWait(true); + break; + case CODE_WAIT_ANY: + Done = HandleWait(false); + break; + case CODE_MOVE: + HandleMove(); + break; + case CODE_ROTATE: + HandleRotate(); + break; + case CODE_USE: + HandleUse(); + break; + case CODE_COPY_PLAYER_ATTRIBUTES: + HandleCopyPlayerAttributes(); + break; + case CODE_SET_VIEW_ANGLES: + HandleSetViewAngles(); + break; + case CODE_SET_CACHE_SIZE: + HandleSetCacheSize(); + break; + case CODE_ANIMATE: + HandleAnimate(); + break; + case CODE_PRINT: + HandlePrint(); + break; + case CODE_PLAY_SOUND: + HandlePlaySound(); + break; + case CODE_ENABLE: + HandleFeature(true); + break; + case CODE_DISABLE: + HandleFeature(false); + break; + case CODE_DEBUG_STATEMENT: + HandleDebugStatement(); + break; + case CODE_CACHE_SOUND: + HandleCacheSound(); + break; + default: + Done = true; + break; + } + + if (Position >= Length) + { + Done = true; + ScriptCondition = COND_COMPLETED; + } + } + + return ScriptCondition; +} + +Variable *CScript::FindLocal(char *Name) +{ + List::Iter iv; + + if (LocalVariables.Size()) + { + for (iv=LocalVariables.Begin();iv != LocalVariables.End();iv++) + { + if (strcmp(Name, (*iv)->GetName()) == 0) + { + return *iv; + } + } + } + + return NULL; +} + +bool CScript::NewLocal(Variable *Which) +{ + Variable *Check; + + Check = FindLocal(Which->GetName()); + if (Check) + { // already exists + return false; + } + + LocalVariables.PushBack(Which); + + return true; +} + +Variable *CScript::FindParameter(char *Name) +{ + List::Iter iv; + + if (ParameterVariables.Size()) + { + for (iv=ParameterVariables.Begin();iv != ParameterVariables.End();iv++) + { + if (strcmp(Name, (*iv)->GetName()) == 0) + { + return *iv; + } + } + } + + return NULL; +} + +bool CScript::NewParameter(Variable *Which) +{ + Variable *Check; + StringVar *ParmValue; + edict_t *Search; + Variable *temp; + vec3_t vec; + + Check = FindParameter(Which->GetName()); + if (Check) + { // already exists + return false; + } + + ParameterVariables.PushBack(Which); + + if (!ParameterValues.Size()) + { + Error("Missing Parameter"); + } + + ParmValue = *ParameterValues.Begin(); + ParameterValues.Erase(ParameterValues.Begin()); + + switch(Which->GetType()) + { + case TypeENTITY: + Search = G_Find(NULL, FOFS(targetname), ParmValue->GetStringValue()); + temp = new EntityVar(Search); + break; + + case TypeINT: + temp = new IntVar("parm",atol(ParmValue->GetStringValue())); + break; + + case TypeFLOAT: + temp = new FloatVar("parm",atof(ParmValue->GetStringValue())); + break; + + case TypeVECTOR: + sscanf (ParmValue->GetStringValue(), "%f %f %f", &vec[0], &vec[1], &vec[2]); + temp = new VectorVar("parm",vec[0],vec[1],vec[2]); + break; + + default: + delete ParmValue; + return false; + break; + } + + (*Which) = temp; + + delete temp; + delete ParmValue; + + return true; +} + +//========================================================================== + diff --git a/Toolkit/Programming/GameCode/game/ds.h b/Toolkit/Programming/GameCode/game/ds.h new file mode 100644 index 0000000..a2fd0f7 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/ds.h @@ -0,0 +1,513 @@ +#ifndef __DS +#define __DS + +#include "pcode.h" +#include "list.h" + +class CScript; + +enum ScriptConditionT +{ + COND_READY, + COND_COMPLETED, + COND_SUSPENDED, + COND_WAIT_ALL, + COND_WAIT_ANY, + COND_WAIT_TIME, +}; + +#define MAX_INDEX 100 + +#define INSTRUCTION_MAX 500 + +//========================================================================== + +class Variable +{ +protected: + char Name[VAR_LENGTH]; + VariableT Type; + +public: + Variable(char *NewName = "", VariableT NewType = TypeUNKNOWN); + Variable(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + char *GetName(void) { return Name; } + VariableT GetType(void) { return Type; } + virtual int GetIntValue(void) { return 0; } + virtual float GetFloatValue(void) { return 0.0; } + virtual void GetVectorValue(vec3_t &VecValue) { VecValue[0] = VecValue[1] = VecValue[2] = 0.0; } + virtual edict_t *GetEdictValue(void) { return NULL; } + virtual char *GetStringValue(void) { return ""; } + virtual void ReadValue(CScript *Script) {} + virtual void Debug(CScript *Script); + virtual void Signal(edict_t *Which) { } + virtual void ClearSignal(void) { } + + virtual Variable *operator +(Variable *VI) { return NULL; } + virtual Variable *operator -(Variable *VI) { return NULL; } + virtual Variable *operator *(Variable *VI) { return NULL; } + virtual Variable *operator /(Variable *VI) { return NULL; } + virtual void operator =(Variable *VI) { } + virtual bool operator ==(Variable *VI) { return false; } + virtual bool operator !=(Variable *VI) { return false; } + virtual bool operator <(Variable *VI) { return false; } + virtual bool operator <=(Variable *VI) { return false; } + virtual bool operator >(Variable *VI) { return false; } + virtual bool operator >=(Variable *VI) { return false; } +}; + +//========================================================================== + +class IntVar : public Variable +{ +protected: + int Value; + +public: + IntVar(char *Name = "", int InitValue = 0); + IntVar(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual int GetIntValue(void) { return Value; } + virtual float GetFloatValue(void) { return (float)Value; } + virtual void ReadValue(CScript *Script); + virtual void Debug(CScript *Script); + virtual void Signal(edict_t *Which); + virtual void ClearSignal(void); + + virtual Variable *operator +(Variable *VI); + virtual Variable *operator -(Variable *VI); + virtual Variable *operator *(Variable *VI); + virtual Variable *operator /(Variable *VI); + virtual void operator =(Variable *VI); + + virtual bool operator ==(Variable *VI) { return Value == VI->GetIntValue(); } + virtual bool operator !=(Variable *VI) { return Value != VI->GetIntValue(); } + virtual bool operator <(Variable *VI) { return Value < VI->GetIntValue(); } + virtual bool operator <=(Variable *VI) { return Value <= VI->GetIntValue(); } + virtual bool operator >(Variable *VI) { return Value > VI->GetIntValue(); } + virtual bool operator >=(Variable *VI) { return Value >= VI->GetIntValue(); } +}; + +//========================================================================== + +class FloatVar : public Variable +{ +protected: + float Value; + +public: + FloatVar(char *Name = "", float InitValue = 0.0); + FloatVar(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual int GetIntValue(void) { return (int)Value; } + virtual float GetFloatValue(void) { return Value; } + virtual void ReadValue(CScript *Script); + virtual void Debug(CScript *Script); + + virtual Variable *operator +(Variable *VI); + virtual Variable *operator -(Variable *VI); + virtual Variable *operator *(Variable *VI); + virtual Variable *operator /(Variable *VI); + virtual void operator =(Variable *VI); + + virtual bool operator ==(Variable *VI) { return Value == VI->GetFloatValue(); } + virtual bool operator !=(Variable *VI) { return Value != VI->GetFloatValue(); } + virtual bool operator <(Variable *VI) { return Value < VI->GetFloatValue(); } + virtual bool operator <=(Variable *VI) { return Value <= VI->GetFloatValue(); } + virtual bool operator >(Variable *VI) { return Value > VI->GetFloatValue(); } + virtual bool operator >=(Variable *VI) { return Value >= VI->GetFloatValue(); } +}; + +//========================================================================== + +class VectorVar : public Variable +{ +protected: + vec3_t Value; + +public: + VectorVar(char *Name = "", float InitValueX = 0.0, float InitValueY = 0.0, float InitValueZ = 0.0); + VectorVar(vec3_t NewValue); + VectorVar(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual void GetVectorValue(vec3_t &VecValue); + virtual void ReadValue(CScript *Script); + virtual void Debug(CScript *Script); + + virtual Variable *operator +(Variable *VI); + virtual Variable *operator -(Variable *VI); + virtual Variable *operator *(Variable *VI); + virtual Variable *operator /(Variable *VI); + virtual void operator =(Variable *VI); + virtual bool operator ==(Variable *VI); + virtual bool operator !=(Variable *VI); + virtual bool operator <(Variable *VI); + virtual bool operator <=(Variable *VI); + virtual bool operator >(Variable *VI); + virtual bool operator >=(Variable *VI); +}; + +//========================================================================== + +class EntityVar : public Variable +{ +protected: + edict_t *Value; + +public: + EntityVar(char *Name = "", int InitValue = 0); + EntityVar(edict_t *Which); + EntityVar(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual int GetIntValue(void); + virtual edict_t *GetEdictValue(void) { return Value; } + virtual void ReadValue(CScript *Script); + virtual void Debug(CScript *Script); + + virtual void operator =(Variable *VI); + virtual bool operator ==(Variable *VI); + virtual bool operator !=(Variable *VI); +}; + +//========================================================================== + +class StringVar : public Variable +{ +protected: + char Value[VAR_LENGTH]; + +public: + StringVar(char *Name = "", char *InitValue = ""); + StringVar(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual char *GetStringValue(void) { return Value; } + virtual void ReadValue(CScript *Script); +}; + +//========================================================================== + +class VariableVar : public Variable +{ +protected: + Variable *Value; + +public: + VariableVar(char *Name = ""); + VariableVar(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual int GetIntValue(void) { return Value->GetIntValue(); } + virtual float GetFloatValue(void) { return Value->GetFloatValue(); } + virtual void GetVectorValue(vec3_t &VecValue) { Value->GetVectorValue(VecValue); } + virtual edict_t *GetEdictValue(void) { return Value->GetEdictValue(); } + virtual char *GetStringValue(void) { return Value->GetStringValue(); } + virtual void ReadValue(CScript *Script); + virtual void Debug(CScript *Script); + virtual void Signal(edict_t *Which) { Value->Signal(Which); } + virtual void ClearSignal(void) { Value->ClearSignal(); } + + virtual Variable *operator +(Variable *VI) { return (*Value) + VI; } + virtual Variable *operator -(Variable *VI) { return (*Value) - VI; } + virtual Variable *operator *(Variable *VI) { return (*Value) * VI; } + virtual Variable *operator /(Variable *VI) { return (*Value) / VI; } + virtual void operator =(Variable *VI) { (*Value) = VI; } + + virtual bool operator ==(Variable *VI) { return (*Value) == VI; } + virtual bool operator !=(Variable *VI) { return (*Value) != VI; } + virtual bool operator <(Variable *VI) { return (*Value) < VI; } + virtual bool operator <=(Variable *VI) { return (*Value) <= VI; } + virtual bool operator >(Variable *VI) { return (*Value) > VI; } + virtual bool operator >=(Variable *VI) { return (*Value) >= VI; } +}; + +//========================================================================== + +class FieldDef; + +class FieldVariableVar : public Variable +{ +protected: + Variable *Value; + FieldDef *Field; + +public: + FieldVariableVar(char *Name = ""); + FieldVariableVar(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual int GetIntValue(void); + virtual float GetFloatValue(void); + virtual void GetVectorValue(vec3_t &VecValue); + virtual edict_t *GetEdictValue(void); + virtual char *GetStringValue(void); + virtual void ReadValue(CScript *Script); + virtual void Debug(CScript *Script); + virtual void Signal(edict_t *Which) { Value->Signal(Which); } + virtual void ClearSignal(void) { Value->ClearSignal(); } + + virtual Variable *operator +(Variable *VI); + virtual Variable *operator -(Variable *VI); + virtual Variable *operator *(Variable *VI); + virtual Variable *operator /(Variable *VI); + virtual void operator =(Variable *VI); + + virtual bool operator ==(Variable *VI); + virtual bool operator !=(Variable *VI); + virtual bool operator <(Variable *VI); + virtual bool operator <=(Variable *VI); + virtual bool operator >(Variable *VI); + virtual bool operator >=(Variable *VI); +}; + +//========================================================================== + +enum SignalT +{ + SIGNAL_MOVE, + SIGNAL_ROTATE, + SIGNAL_ANIMATE, +}; + +class Signaler +{ +private: + edict_t *Edict; + Variable *Var; + SignalT SignalType; + +public: + Signaler(edict_t *NewEdict, Variable *NewVar, SignalT NewSignalType); + Signaler(FILE *FH, CScript *Script); + ~Signaler(void); + virtual void Write(FILE *FH, CScript *Script); + bool Test(edict_t *Which, SignalT WhichType); + edict_t *GetEdict(void) { return Edict; } + Variable *GetVar(void) { return Var; } + SignalT GetType(void) { return SignalType; } + bool operator ==(Signaler *SI); +}; + +//========================================================================== + +class FieldDef +{ +private: + char Name[VAR_LENGTH]; + VariableT Type; + int Offset; + fieldtype_t FieldType; + +public: + FieldDef(CScript *Script); + FieldDef(FILE *FH, CScript *Script); + void Write(FILE *FH, CScript *Script); + byte *GetOffset(Variable *Var); + Variable *GetValue(Variable *Var); + int GetIntValue(Variable *Var); + float GetFloatValue(Variable *Var); + void GetVectorValue(Variable *Var, vec3_t &VecValue); + edict_t *GetEdictValue(Variable *Var); + char *GetStringValue(Variable *Var); + void SetValue(Variable *Var, Variable *Value); +}; + +//========================================================================== + +enum EventT +{ + EVENT_MOVE_DONE, + EVENT_ROTATE_DONE, + EVENT_SCRIPT_WAIT, + EVENT_SCRIPT_EXECUTE, +}; + +class Event +{ +protected: + float Time; + EventT Type; + int Priority; + +public: + Event(float NewTime, EventT NewType); + Event(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + float GetTime(void) { return Time; } + EventT GetType(void) { return Type; } + int GetPriority(void) { return Priority; } + virtual bool Process(CScript *Script); +}; + +//========================================================================== + +class MoveDoneEvent : public Event +{ +private: + edict_t *Ent; + +public: + MoveDoneEvent(float NewTime, edict_t *NewEnt); + MoveDoneEvent(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual bool Process(CScript *Script); +}; + +//========================================================================== + +class RotateDoneEvent : public Event +{ +private: + edict_t *Ent; + +public: + RotateDoneEvent(float NewTime, edict_t *NewEnt); + RotateDoneEvent(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual bool Process(CScript *Script); +}; + +//========================================================================== + +class ExecuteEvent : public Event +{ +private: + edict_t *Other; + edict_t *Activator; + +public: + ExecuteEvent(float NewTime, edict_t *NewOther = NULL, edict_t *NewActivator = NULL); + ExecuteEvent(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual bool Process(CScript *Script); +}; + +//========================================================================== + +class WaitEvent : public Event +{ +public: + WaitEvent(float NewTime); + WaitEvent(FILE *FH, CScript *Script); + virtual void Write(FILE *FH, CScript *Script, int ID = -1); + virtual bool Process(CScript *Script); +}; + +//========================================================================== + +class CScript +{ +private: + char Name[MAX_PATH]; + unsigned char *Data; + ScriptConditionT ScriptCondition; + int ConditionInfo; + int Length; + int Position; + List LocalVariables; + List ParameterVariables; + List Stack; + List Signalers; + List Waiting; + List ParameterValues; + List Events; + Variable *VarIndex[MAX_INDEX]; + FieldDef *Fields[MAX_INDEX]; + edict_t *owner, *other, *activator; + int DebugFlags; + +public: + CScript(char *ScriptName, edict_t *new_owner); + CScript(FILE *FH); + ~CScript(void); + + void LoadFile(void); + void Free(bool DoData); + void Clear(bool DoData); + void Write(FILE *FH); + + Variable *LookupVar(int Index) { return VarIndex[Index]; } + int LookupVarIndex(Variable *Var); + void SetVarIndex(int Index, Variable *Var) { VarIndex[Index] = Var; } + FieldDef *LookupField(int Index) { return Fields[Index]; } + int LookupFieldIndex(FieldDef *Field); + void SetFieldIndex(int Index, FieldDef *Field) { Fields[Index] = Field; } + void SetParameter(char *Value); + + unsigned char ReadByte(void); + int ReadInt(void); + float ReadFloat(void); + char *ReadString(void); + Variable *ReadDeclaration(int &Index); + + void PushStack(Variable *VI); + Variable *PopStack(void); + + void HandleGlobal(bool Assignment); + void HandleLocal(bool Assignment); + void HandleParameter(bool Assignment); + void HandleField(void); + void HandleGoto(void); + Variable *HandleSpawn(void); + Variable *HandleBuiltinFunction(void); + void HandlePush(void); + void HandlePop(void); + void HandleAssignment(void); + void HandleAdd(void); + void HandleSubtract(void); + void HandleMultiply(void); + void HandleDivide(void); + void HandleDebug(void); + void HandleDebugStatement(void); + void HandleAddAssignment(void); + void HandleSubtractAssignment(void); + void HandleMultiplyAssignment(void); + void HandleDivideAssignment(void); + bool HandleWait(bool ForAll); + bool HandleTimeWait(void); + void HandleIf(void); + + void HandlePrint(void); + void HandlePlaySound(void); + void HandleFeature(bool Enable); + void HandleCacheSound(void); + + void HandleMove(void); + void HandleRotate(void); + void HandleUse(void); + void HandleTrigger(bool Enable); + void HandleAnimate(void); + void HandleCopyPlayerAttributes(void); + void HandleSetViewAngles(void); + void HandleSetCacheSize(void); + + void Move_Done(edict_t *ent); + void Move(edict_t *ent, vec3_t Dest); + void Rotate_Done(edict_t *ent); + void Rotate(edict_t *ent); + + void AddEvent(Event *Which); + void ProcessEvents(void); + void ClearTimeWait(void); + + void AddSignaler(edict_t *Edict, Variable *Var, SignalT SignalType); + void CheckSignalers(edict_t *Which, SignalT SignalType); + bool CheckWait(void); + void FinishWait(edict_t *Which, bool NoExecute); + void Error (char *error, ...); + void StartDebug(void); + void EndDebug(void); + void DebugLine (char *debugtext, ...); + + void Think(void); + ScriptConditionT Execute(edict_t *new_other, edict_t *new_activator); + + Variable *FindLocal(char *Name); + bool NewLocal(Variable *Which); + Variable *FindParameter(char *Name); + bool NewParameter(Variable *Which); +}; + +//========================================================================== + +extern List GlobalVariables; + +#endif diff --git a/Toolkit/Programming/GameCode/game/g_ClassStatics.c b/Toolkit/Programming/GameCode/game/g_ClassStatics.c new file mode 100644 index 0000000..6f2ec45 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_ClassStatics.c @@ -0,0 +1,121 @@ +#include "g_ClassStatics.h" + +G_ClassStatics_t classStatics[NUM_CLASSIDS]; +int Cid_init[NUM_CLASSIDS]; + +void RatStaticsInit(); +void GorgonStaticsInit(); +void PlagueElfStaticsInit(); +void GkrokonStaticsInit(); +void FishStaticsInit(); +void ObjectStaticsInit(); +void LightStaticsInit(); +void TriggerStaticsInit(); +void HarpyStaticsInit(); +void SpreaderStaticsInit(); +void ElflordStaticsInit(); +void BBrushStaticsInit(); +void FuncRotateStaticsInit(); +void FuncDoorStaticsInit(); +void ChickenStaticsInit(); +void SsithraStaticsInit(); +void SpellStaticsInit(); +void MssithraStaticsInit(); +void OgleStaticsInit(); +void SeraphOverlordStaticsInit(); +void SeraphGuardStaticsInit(); +void AssassinStaticsInit(); +void TeleporterStaticsInit(); +void HighPriestessStaticsInit(); +void TcheckrikStaticsInit(); +void ButtonStaticsInit(); +void BeeStaticsInit(); +void LeverStaticsInit(); +void FlameThrowerStaticsInit(); +void CorvusStaticsInit(); +void morcalavinStaticsInit(); +void TBeastStaticsInit(); +void ImpStaticsInit(); +void MotherStaticsInit(); +void victimSsithraStaticsInit(); +void SsithrascoutStaticsInit(); +void DranorStaticsInit(); +void TrigDamageStaticsInit(); +void TrigPushStaticsInit(); +void ElflordCinStaticsInit(); +void PriestessCStaticsInit(); +void Priestess2CStaticsInit(); +void Siernan1CinStaticsInit(); +void Siernan2CinStaticsInit(); +void TomeStaticsInit(); +void MorcalavinCinStaticsInit(); +void Corvus2StaticsInit(); +void Corvus3StaticsInit(); +void Corvus4StaticsInit(); +void Corvus5StaticsInit(); +void Corvus6StaticsInit(); +void Corvus7StaticsInit(); +void Corvus8StaticsInit(); +void Corvus9StaticsInit(); + +void (*classStaticsInits[NUM_CLASSIDS])() = +{ + NULL, + RatStaticsInit, + GorgonStaticsInit, + PlagueElfStaticsInit, + GkrokonStaticsInit, + FishStaticsInit, + ObjectStaticsInit, + LightStaticsInit, + TriggerStaticsInit, + HarpyStaticsInit, + SpreaderStaticsInit, + ElflordStaticsInit, + BBrushStaticsInit, + FuncRotateStaticsInit, + FuncDoorStaticsInit, + ChickenStaticsInit, + SsithraStaticsInit, + NULL, + MssithraStaticsInit, + OgleStaticsInit, + SeraphOverlordStaticsInit, + SeraphGuardStaticsInit, + AssassinStaticsInit, + TeleporterStaticsInit, + HighPriestessStaticsInit, + TcheckrikStaticsInit, + ButtonStaticsInit, + BeeStaticsInit, + CorvusStaticsInit, + morcalavinStaticsInit, + TBeastStaticsInit, + ImpStaticsInit, + LeverStaticsInit, + FlameThrowerStaticsInit, + + MotherStaticsInit, + victimSsithraStaticsInit, + SsithrascoutStaticsInit, + DranorStaticsInit, + TrigDamageStaticsInit, + TrigPushStaticsInit, + ElflordCinStaticsInit, + Siernan1CinStaticsInit, + Siernan2CinStaticsInit, + PriestessCStaticsInit, + Priestess2CStaticsInit, + TomeStaticsInit, + MorcalavinCinStaticsInit, + Corvus2StaticsInit, + Corvus3StaticsInit, + Corvus4StaticsInit, + Corvus5StaticsInit, + Corvus6StaticsInit, + Corvus7StaticsInit, + Corvus8StaticsInit, + Corvus9StaticsInit, +}; + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_ClassStatics.h b/Toolkit/Programming/GameCode/game/g_ClassStatics.h new file mode 100644 index 0000000..6561e51 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_ClassStatics.h @@ -0,0 +1,149 @@ +#ifndef G_CLASSSTATICS_H +#define G_CLASSSTATICS_H + +#include "g_Message.h" +#include "g_local.h" + +// ************************************************************************************************ +// ClassID_t +// ************************************************************************************************ + +/*========================================================================== + + IMPORTANT!!! + + If you add or remove classID's here, you MUST adjust the tables in + m_stats.c accordingly, as well as the StaticsInit and Precache stuff. + Search for "NUM_CLASSIDS" if you're not certain what's effected by this... + + ==========================================================================*/ +typedef enum ClassID_e +{ + CID_NONE = 0, //changed this so that CID_NONE is default + CID_RAT, //1 + CID_GORGON, //2 + CID_PLAGUEELF, //3 + CID_GKROKON, //4 + CID_FISH, //5 + CID_OBJECT, //6 + CID_LIGHT, //7 + CID_TRIGGER, //8 + CID_HARPY, //9 + CID_SPREADER, //10 + CID_ELFLORD, //11 + CID_BBRUSH, //12 + CID_FUNC_ROTATE, //13 + CID_FUNC_DOOR, //14 + CID_CHICKEN, //15 + CID_SSITHRA, //16 + CID_SPELL, //17 + CID_MSSITHRA, //18 + CID_OGLE, //19 + CID_SERAPH_OVERLORD,//20 + CID_SERAPH_GUARD, //21 + CID_ASSASSIN, //22 + CID_TELEPORTER, //23 + CID_HIGHPRIESTESS, //24 + CID_TCHECKRIK, //25 + CID_BUTTON, //26 + CID_BEE, //27 + CID_CORVUS, //28 + CID_MORK, //29 + CID_TBEAST, //30 + CID_IMP, //31 + CID_LEVER, //32 + CID_FLAMETHROWER, //33 +//Monsters ^ + +//Cinematics/other... + CID_MOTHER, //34 + CID_SSITHRA_VICTIM, //35 + CID_SSITHRA_SCOUT, //36 + CID_DRANOR, //37 + CID_TRIG_DAMAGE, //38 + CID_TRIG_PUSH, //39 + CID_C_ELFLORD, //40 + CID_C_SIERNAN1, //41 + CID_C_SIERNAN2, //42 + CID_C_HIGHPRIESTESS,//43 + CID_C_HIGHPRIESTESS2,//44 + CID_C_TOME, //45 + CID_C_MORCALAVIN, //46 + CID_CORVUS2, //47 + CID_CORVUS3, //48 + CID_CORVUS4, //49 + CID_CORVUS5, //50 + CID_CORVUS6, //51 + CID_CORVUS7, //52 + CID_CORVUS8, //53 + CID_CORVUS9, //54 + NUM_CLASSIDS //55 +} ClassID_t; + +#define NUM_ATTACKRANGES NUM_CLASSIDS *4 +// ************************************************************************************************ +// ClassResourceInfo_s +// ************************************************************************************************ + +typedef struct ClassResourceInfo_s +{ + int numAnims; + animmove_t **animations; + int modelIndex; + int numSounds; + int *sounds; + int (*NextAnimForStep)(edict_t *self, float dir, int step); + float (*DistMovedForAnim)(int animID); + float (*SpeedForAnim)(int animID); + int (*NextAnimForPivot)(edict_t *self, float facingDelta); + float (*AnglePivotedForAnim)(int animID); // passing in -1 will return the smallest angle pivoted +} ClassResourceInfo_t; + +#define MINIMUM_PIVOT_ANIM -1 + +// ************************************************************************************************ +// ClassMoveInfo_s +// ************************************************************************************************ + +typedef struct ClassMoveInfo_s +{ + float stepHeight; // max dist something step up or down in a frame + float dropHeight; // max dist something will drop off a ledge + void (*SetForStep)(edict_t *self, float stepDir, int step); + void (*SetForPivot)(edict_t *self, float facingDelta); + void (*SetForStop)(edict_t *self); +} ClassMoveInfo_t; + +// ************************************************************************************************ +// ClassMoveInfo_s +// ************************************************************************************************ + +typedef struct ClassActionInfo_s +{ + void (*SetForStrike)(edict_t *self, int weaponID); + void (*SetForShoot)(edict_t *self, int weaponID); +} ClassActionInfo_t; + +// ************************************************************************************************ +// G_ClassStatics_t +// ************************************************************************************************ + +typedef struct G_ClassStatics_s +{ + G_MsgReceiver_t msgReceivers[NUM_MESSAGES]; + void (*update)(edict_t *self); + ClassResourceInfo_t *resInfo; + ClassMoveInfo_t *moveInfo; + ClassActionInfo_t *actionInfo; + void (*SetForDamage)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, int hitLocation, int flags); + void (*SetForDeath)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, int hitLocation, int flags); + void (*SetForKnockback)(edict_t *self, vec3_t kvel, int flags); + void (*EndKnockback)(edict_t *self); + void (*DieAI)(edict_t *self); +} G_ClassStatics_t; + +extern G_ClassStatics_t classStatics[NUM_CLASSIDS]; +extern int Cid_init[NUM_CLASSIDS]; +extern void (*classStaticsInits[NUM_CLASSIDS])(); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_DefaultMessageHandler.c b/Toolkit/Programming/GameCode/game/g_DefaultMessageHandler.c new file mode 100644 index 0000000..57639ed --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_DefaultMessageHandler.c @@ -0,0 +1,130 @@ +#include "g_DefaultMessageHandler.h" +#include "g_Physics.h" +#include "g_local.h" +#include "Vector.h" +#include "Utilities.h" +#include "g_HitLocation.h" + +G_MsgReceiver_t DefaultMessageReceivers[NUM_MESSAGES] = +{ + NULL, // MSG_STAND + NULL, // MSG_CROUCH + NULL, // MSG_DUCKDOWN, + NULL, // MSG_DUCKHOLD, + NULL, // MSG_DUCKUP, + NULL, // MSG_WALK + NULL, // MSG_RUN + NULL, // MSG_JUMP + NULL, // MSG_MELEE + NULL, // MSG_MISSILE + NULL, // MSG_WATCH + NULL, // MSG_EAT + NULL, // MSG_PAIN + NULL, // MSG_DEATH + NULL, // MSG_FLY + NULL, // MSG_FLYBACK + NULL, // MSG_HOVER + NULL, // MSG_FLEE + NULL, // MSG_FLYATTACK + DefaultReceiver_Repulse, // MSG_REPULSE + NULL, // MSG_IDLE, + NULL, // MSG_TOUCH, + NULL, // MSG_FALLBACK, + NULL, // MSG_SEARCH, + NULL, // MSG_DODGE, + NULL, // MSG_ATTACK, + NULL, // MSG_SIGHT, + NULL, // MSG_TURN, + NULL, // MSG_TURNLEFT, + NULL, // MSG_TURNRIGHT, + NULL, // MSG_BLOCKED, + NULL, // G_MSG_KNOCKEDBACK, + NULL, // G_MSG_RESTSTATE, + DefaultReceiver_SetAnim, // G_MSG_SET_ANIM, + DefaultReceiver_RemoveSelf, // G_MSG_REMOVESELF, + DefaultReceiver_Suspend, // G_MSG_SUSPEND, + DefaultReceiver_Unsuspend, // G_MSG_UNSUSPEND, + + NULL, // MSG_VOICE_SIGHT, + NULL, // MSG_VOICE_POLL, + NULL, // MSG_VOICE_PUPPET, + NULL, // MSG_CHECK_MOOD, +}; + +void DefaultMsgHandler(edict_t *self, G_Message_t *msg) +{ + G_MsgReceiver_t receiver; + char *o_target; + + if(msg->ID == MSG_PAIN) + { + edict_t *targ, *activator; + + ParseMsgParms(msg, "ee", &targ, &activator); + + if(targ->pain_target) + { + o_target = targ->target; + targ->target = targ->pain_target; + G_UseTargets(targ, activator); + targ->target = o_target; + targ->pain_target = NULL; + } + } + + receiver = classStatics[self->classID].msgReceivers[msg->ID]; + + if(receiver) + { + receiver(self, msg); + } + else + { + // if and when there are a good number of defaults, change the NULL to be an Empty + // function, overall that should be faster to just always call the function then + // do the check + receiver = DefaultMessageReceivers[msg->ID]; + + if(receiver) + { + DefaultMessageReceivers[msg->ID](self, msg); + } + } +} + +void DefaultReceiver_Repulse(edict_t *self, G_Message_t *msg) +{ + vec3_t vel; + + ParseMsgParms(msg, "fff", &vel[0], &vel[1], &vel[2]); +// VectorAdd(self->velocity, vel, self->velocity); +} + +void DefaultReceiver_SetAnim(edict_t *self, G_Message_t *msg) +{ + int ID; + + if(msg->priority >= PRI_DIRECTIVE) + { + ParseMsgParms(msg, "i", &ID); + + SetAnim(self, ID); + } +} + +void DefaultReceiver_RemoveSelf(edict_t *self, G_Message_t *msg) +{ + self->think = G_FreeEdict; + + self->nextthink = 0; +} + +void DefaultReceiver_Suspend(edict_t *self, G_Message_t *msg) +{ + self->flags |= FL_SUSPENDED; +} + +void DefaultReceiver_Unsuspend(edict_t *self, G_Message_t *msg) +{ + self->flags &= ~FL_SUSPENDED; +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_DefaultMessageHandler.h b/Toolkit/Programming/GameCode/game/g_DefaultMessageHandler.h new file mode 100644 index 0000000..5628f5f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_DefaultMessageHandler.h @@ -0,0 +1,17 @@ +#ifndef G_DEFAULTMESSAGEHANDLER_H +#define G_DEFAULTMESSAGEHANDLER_H + +#include "g_Message.h" + +extern G_MsgReceiver_t DefaultMessageReceivers[NUM_MESSAGES]; +extern void DefaultMsgHandler(struct edict_s *self, G_Message_t *msg); +extern void DyingMsgHandler(struct edict_s *self, G_Message_t *msg); + + +void DefaultReceiver_Repulse(struct edict_s *self, G_Message_t *msg); +void DefaultReceiver_SetAnim(struct edict_s *self, G_Message_t *msg); +void DefaultReceiver_RemoveSelf(struct edict_s *self, G_Message_t *msg); +void DefaultReceiver_Suspend(struct edict_s *self, G_Message_t *msg); +void DefaultReceiver_Unsuspend(struct edict_s *self, G_Message_t *msg); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_Edict.h b/Toolkit/Programming/GameCode/game/g_Edict.h new file mode 100644 index 0000000..33b60ee --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_Edict.h @@ -0,0 +1,436 @@ +#ifndef G_EDICT_H +#define G_EDICT_H + +#include "g_Message.h" +#include "Message.h" +#include "g_ClassStatics.h" +#include "g_NewSystem.h" + +#define MAX_BUOY_BRANCHES 3 + +// ************************************************************************************************ +// edict_s +// ------- +// ************************************************************************************************ +#ifndef __cplusplus +#else + class CScript; +#endif + +struct edict_s +{ + // This is sent to the server as part of each client frame. + + entity_state_t s; + + // NULL if not a player. The server expects the first part of a 'gclient_s' to be a + // 'player_state_t' but the rest of it is opaque. + + struct gclient_s *client; + + // House keeping information not used by the game logic. + + qboolean inuse; + int ready_cull; // used to delete stuff entities properly on the client + int linkcount; + + // FIXME: move these fields to a server private sv_entity_t + + link_t area; // Linked to a division node or leaf. + int num_clusters; // If -1, use headnode instead. + int clusternums[MAX_ENT_CLUSTERS]; + int headnode; // Unused if num_clusters is -1. + int areanum,areanum2; + + int svflags; + + edict_t *groundentity; // entity serving as ground + int groundentity_linkcount; // if self and groundentity's don't match, groundentity should be cleared + vec3_t groundNormal; // normal of the ground + + vec3_t intentMins, intentMaxs; // if PF_RESIZE is set, then physics will attempt to change + // the ents bounding form to the new one indicated + // If it was succesfully resized, the PF_RESIZE is turned off + // otherwise it will remain on. + + solid_t solid; + int clipmask; + + edict_t *owner; + + vec3_t mins, maxs; + vec3_t absmin,absmax,size; + + // called when self is the collidee in a collision, resulting in the impediment or bouncing of trace->ent + void (*isBlocking)(edict_t *self, struct trace_s *trace); + + // DO NOT MODIFY ANYTHING ABOVE THIS! THE SERVER EXPECTS THE FIELDS IN THAT ORDER! All the + // fields below this are are used by the game only and can be re-aranged, modified etc. + + // ============================================================================================ + + MsgQueue_t msgQ; + G_MessageHandler_t msgHandler; + int classID; + + void (*think)(edict_t *self); + void (*ai)(edict_t *self); + int flags; + float freetime; // Server time when the object was freed. + char *classname; + int spawnflags; + + // Used by the game physics. + + int movetype; + + int physicsFlags; + + edict_t *blockingEntity; // entity serving as ground + int blockingEntity_linkcount; // if self and blockingEntity's don't match, blockingEntity should be + // cleared + vec3_t blockingNormal; // normal of the blocking surface + + // called when self bounces off of something and continues to move unimpeded + void (*bounced)(edict_t *self, struct trace_s *trace); + + // called when self is the collider in a collision, resulting in the impediment of self's movement + void (*isBlocked)(edict_t *self, struct trace_s *trace); + + float friction; // friction multiplier; defaults to 1.0 + // Used to determine whether something will stop, slide, or bounce on impact + float elasticity; + + // Used by anything that can collide (physics). + + void (*touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); + + // Used to indicate teams, (a way to group things). + + char *team; // Team name. + + union { + edict_t *teamchain; + edict_t *targetEnt; + edict_t *slavechain; + edict_t *rope_grab; //Used to by the rope to hold the part of the rope which the player is holding + }; + + union { + edict_t *guidemaster; + edict_t *teammaster; + }; + + float nextthink; + + // Fields used by only one class of game entity (monster, player, poly, trigger, etc). + + char *model; // Model name, which could instead be stored in + + char *message; // index to message_text for printing and wave files + + char *text_msg; // Text printed to con for door, polys, triggers, etc. + + // These really all could be changed to ints or hashed or something (currently, we do a search + // on all the active edicts using strcmps). We should be able to assign indexes in the BSP, by + // doing the string strcmps at BSP time. The player seem to use any of the target stuff. + + char *target; // Name of the entity's target. + char *targetname; // What other entities use to target-lock this entity. + char *scripttarget; + char *killtarget; // Used only in G_UseTargets, which fires all + // of its targets. + char *pathtarget; // Used by trains, also used by monsters in some + // way as well. + union { + char *deathtarget; // Target to be triggered on my death. + char *pathtargetname; // Used to target buoys to doors or plats or etc + }; + + union { + char *combattarget; // Monsters are the primary user of this. + char *jumptarget; // for buoys only + }; + + union { + edict_t *target_ent; // Used by player, trains, and turrets. Monsters + // should be able to use this for current target as well. + edict_t *slave; + edict_t *rope_end; //Used by the rope to store the rope end entity + }; + + vec3_t movedir; // Used by just about everything that moves, but not used in + // physics. + + float air_finished; // Used by things that can breath (monsters and player). + + edict_t *goalentity; // Used primarily by monsters. + edict_t *movetarget; // Used primarily by monsters, also a little use + // by poly/trigger + float yaw_speed; // Used by monsters and player. + float ideal_yaw; // Used by monsters and player. + float ideal_pitch; // Used by monsters and player. + float yawOffset; // Used in CreateMove_Step + + float accel; // Used mostly in g_func.c. + float decel; // Used mostly in g_func.c. + + float timestamp; // Used by a couple of ojects. + + // Used by just about every type of entity. + + void (*use)(edict_t *self, edict_t *other, edict_t *activator); + + int health; // Used by anything that can be destroyed. + int max_health; // Used by anything that can be destroyed. + int bloodType; // type of stuff to spawn off when hit + + union { + int deadflag; // More like a dead state, used by things that can die. + // Would probably be better off with a more general state + // (or two or three). + int deadState; + }; + + union { + qboolean show_hostile; // Only used by monsters (or g_ai.c at least)- not really + // sure what for. + void (*TriggerActivated)(edict_t *self, edict_t *activator); + }; + + char *map; // target_changelevel (used only by). + + int viewheight; // height above origin where eyesight is determined + // used by anything which can "see", player and monsters + float reflected_time; // used by objects to tell if they've been repulsed by something.. + + // Except for a DAMAGE_AIM value in the turret and one commented out in the player this looks + // like a flag indicating if it takes damage anyone ever heard of using a bit for a flag, or + // even better a whole bunch of flags in an 'int'. + + int takedamage; + + // Unless something will do both normal and radius damage, we only need one field. In fact we + // may want to move this into class statics or something. + + int dmg; // the damage something does. + float dmg_radius; // the radius of damage. + + int sounds; // used by a trigger and a splash, could be a class static + + union { + int count; // used by polys, triggers, and items. + int curr_model; // used by player during cinematics + }; + + int targeted; // used by Ogle to denote a targeted action queued up + int lastbuoy; // used to save a buoy in checking + + edict_t *chain; // used by items and player in the body queue. + edict_t *enemy; // used by monsters, player, and a poly or two. + edict_t *oldenemy; // used by monsters. + edict_t *activator; // this that used something, used by monsters, items, and + // polys. + // Used by player only. + + edict_t *mynoise; // Can go in client only. + edict_t *mynoise2; + + edict_t *last_buoyed_enemy; // used by monsters. + + int noise_index; // Used only by targets + + float volume; // used only by target_speaker + + union { + float attenuation; // used only by target_speaker + float maxrange; // used for ai + }; + + // Timing variables. + + float wait; // Used by polys, triggers, and targets. + float delay; // Delay before firing targets. Used by a few polys and targets. + float random; // Used by func_timer and spl_meteorbarrier. + + // Used to delay monster 5 before going after a player sound. Only set on player. + + union + { + float teleport_time; + float time; // misc. time for whatever + }; + + // Move these to clientinfo? + + int light_level; // set on player, checked by monsters + + int style; // also used as areaportal number used by items. + + gitem_t *item; // For bonus items. Used by player, triggers, and monsters. + + // What it's made of, i.e. MAT_XXX. Used to determine gibs to throw. Curently used only by the + // barrel, but applicable to anything generically gibbable. + + int materialtype; + int PersistantCFX; // index to client effect linked to edict + int Leader_PersistantCFX; // non of this should really go in here.. really it should be in the client, but its 2 in the morning, so fuck it + + vec3_t velocity; // linear velocity + vec3_t avelocity; // angular velocity + vec3_t knockbackvel; + + // Used for determining effects of liquids in the environment. + + float speed; + int watertype; // Used to indicate current liquid actor is in. + int waterlevel; // Used by monsters and players and grenades. + + int mass; + float gravity; // Per entity gravity multiplier (1.0 is normal) Used for + // lowgrav artifact, flares. + + // Not currently used by anyone, but it's a part of physics. Probably should remove it. + void (*prethink) (edict_t *ent); + + // Move into the moveinfo structure? Used by polys and turret and in physics. + void (*blocked)(edict_t *self, edict_t *other); + + // Used by animating entities. + + int curAnimID; + int lastAnimID; + + // Used by monsters and player. + + int (*pain)(edict_t *self, edict_t *other, float kick, int damage); + + // Used by monsters, player, and some polys. + + int (*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); + + // used by the Morph Ovum + + void (*oldthink)(edict_t *self); + + // Used by polys and triggers. + + float touch_debounce_time; + + // Used by monsters and player. + + float pain_debounce_time; + + // Used by monsters and player. + + float damage_debounce_time; + float attack_debounce_time; + + //used by reflecting projectiles + int reflect_debounce_time; + + float impact_debounce_time; // impact damage debounce time + + float fire_damage_time; // fire damage length + float fire_timestamp; // timestamp weapons and damaged entities, + // so that the same weapon can't hurt an entity twice + + // Used by shrines + + void (*oldtouch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); + union { + int shrine_type; + int morph_timer; + int buoy_index; + }; + + // Only set in trigger_push_touch and probably only on players. + + union { + float last_buoy_time; + float fly_sound_debounce_time; + }; + + union { + float last_move_time; // Only used by target_earthquake (poly/trigger) + float old_yaw; // Used by the Seraph to return to his exact position and angles + }; + + vec3_t pos1,pos2; // Used by polys and turrets. + + // Common data blocks + + moveinfo_t moveinfo; // 120 bytes + monsterinfo_t monsterinfo; // 156 bytes + + vec3_t v_angle_ofs; //View Angle ofset- for when monsters look around, for line of sight checks + + int ai_mood; // Used by high level ai to relay simple moods to lower level functions (INTEGRAL FOR SWITCH) + int ai_mood_flags; // Used in conjunction with ai_mood to provide more information to the lower functions + byte mintel; //number of buoys allowed to follow + + char *target2; + + vec3_t last_org; + + //next 4 in a table in m_stats + float min_melee_range;// Min distance at which it is ok for this monster to use it's melee attack + float melee_range; //Max distance to do a melee attack, if negative, closest monster should get to enemy + float missile_range; //Max distance to do a missile attack + float min_missile_range; //Least distance to do a missile attack + int bypass_missile_chance;//chance to not use missile attack even if you can (0-100) + void (*cant_attack_think)(edict_t *self, float enemydist, qboolean enemyvis, qboolean enemyinfront);//called only when monster cannot attack player + + int jump_chance;//chance to jump when have opportunity + + float wakeup_distance;//how far the player can be when I see him to wake me up + + float evade_debounce_time;//How long to evade for + float oldenemy_debounce_time;//How long to hunt enemy before looking for oldenemy again + + float best_move_yaw; +// int jump_chance; //0 - 100 chance that monster will try to jump to get around when possible/neccessary - in a table in m_stats + + float mood_nextthink; //not used anymore? + void (*mood_think)(edict_t *self);//you mood setting function + + float next_pre_think;//any prethinking you want a monster to do + void (*pre_think)(edict_t *self);//nextthink time for prethinks + + float next_post_think;//any prethinking you want a monster to do + void (*post_think)(edict_t *self);//nextthink time for prethinks + + int forced_buoy; //monster is forced to go to this buoy + buoy_t *enemy_buoy; //monster's enemy's closest buoy + float pathfind_nextthink; //not used anymore? + edict_t *nextbuoy[MAX_BUOY_BRANCHES]; + + float dead_size; //for dead thinking + struct volume_effect_s *volfx; + + //New monster stuff + char *wakeup_target; //target to fire when find an enemy + char *pain_target; //target to fire when take pain (only once) + char *homebuoy; //yeah, buoyyyyyyy! + + float alert_time; //time when a monster is no longer startled + alertent_t *last_alert; //last alert_ent to startle me, if it's the same one, skip it when going through the list + + edict_t *placeholder; //used by assassin to hold his teleport destination + + float jump_time; //time that a monster's protection from falling damage runs out after a jump + + int red_rain_count; //number of red rains you can have at once + + int deathtype; //how you died + + edict_t *fire_damage_enemy; //who burnt you to death- for proper burning death credit + +#ifndef __cplusplus + void *Script; +#else + CScript *Script; +#endif +}; + +#endif // G_EDICT_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_HitLocation.c b/Toolkit/Programming/GameCode/game/g_HitLocation.c new file mode 100644 index 0000000..36598bc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_HitLocation.c @@ -0,0 +1,379 @@ +#include "q_shared.h" +#include "g_local.h" +#include "matrix.h" +#include "vector.h" +#include "g_HitLocation.h" +#include "random.h" + +// Returns hit location (as defined in h file) assuming upright bipedal humanoid creature. +// This will return incorrect results if called on a non humanoid (eg beetle) or a non +// upright creature (eg a tumbling creature) +#define LT_BIPED 0 +#define LT_WINGED 1 +#define LT_MAX 2 + +// Percentage offsets for a bipedal creature + +static vec3_t LocationsBiped[hl_BipedPoints] = +{ + 0.00F, 0.00F, 0.24F, // head + 0.16F, 0.00F, 0.10F, // hl_TorsoFront + -0.16F, 0.00F, 0.10F, // hl_TorsoBack + 0.00F, 0.35F, 0.08F, // hl_ArmUpperLeft + 0.00F, 0.35F, -0.04F, // hl_ArmLowerLeft + 0.00F, -0.35F, 0.08F, // hl_ArmUpperRight + 0.00F, -0.35F, -0.04F, // hl_ArmLowerRight + 0.00F, 0.20F, -0.10F, // hl_LegUpperLeft + 0.00F, 0.20F, -0.20F, // hl_LegLowerLeft + 0.00F, -0.20F, -0.10F, // hl_LegUpperRight + 0.00F, -0.20F, -0.20F, // hl_LegLowerRight +}; + +// Percentage offsets for a winged creature + +static vec3_t LocationsWinged[hl_WingedPoints] = +{// for+ left+ up+ + 0.60F, 0.00F, 0.10F, // head (horns and neckspikes) + 0.00F, 0.00F, 0.20F, // hl_backspikes + 0.00F, 0.20F, -0.20F, // hl_leftupperleg + 0.00F, 0.20F, -0.40F, // hl_leftlowerleg + 0.10F, 0.20F, -0.60F, // hl_lefthand + 0.00F, -0.20F, -0.20F, // hl_rightupperleg + 0.00F, -0.20F, -0.40F, // hl_rightlowerleg + 0.10F, -0.20F, -0.60F, // hl_righthand + -0.30F, 0.00F, 0.00F, // hl_tailspikes + 0.25F, -1.00F, 0.00F, // hl_rwing + 0.25F, 1.00F, 0.00F, // hl_lwing + -0.50F, 0.00F, -0.60F, // hl_stinger +}; + +// Basic hit location types + +static HlDef_t HitLocTypes[LT_MAX] = +{ + { LocationsBiped, hl_BipedPoints }, + { LocationsWinged, hl_WingedPoints } +}; + +void GetWorkLocations(vec3_t *work, vec3_t scale, vec3_t origin, vec_t angle, int LocType) +{ + int i; + vec3_t *loc; + vec3_t temp; + matrix3_t mat; + + // Create a yaw matrix dependent on targets yaw + CreateYawMatrix(mat, angle); + + // Grab base of hit location table + loc = HitLocTypes[LocType].LocTable; + + // Rotate each point by targets yaw and scale by targets size + for(i = 0; i < HitLocTypes[LocType].NumLocs; i++, loc++, work++) + { + VectorScaleByVector(*loc, scale, temp); + Matrix3MultByVec3(mat, temp, *work); + VectorAdd(*work, origin, *work); + } +} + +// Find the nearest point to point in the created table + +HitLocation_t GetNearestPoint(vec3_t *work, vec3_t point, int LocType) +{ + int i; + vec_t dist; + vec_t mindist = 1024.0F; + int minidx = -1; + + for(i = 0; i < HitLocTypes[LocType].NumLocs; i++, work++) + { + dist = VectorSeparation(*work, point); + if(dist < mindist) + { + mindist = dist; + minidx = i; + } + } + return(minidx); +} + +HitLocation_t MG_GetHitLocation(edict_t *target, edict_t *inflictor, vec3_t ppoint, vec3_t pdir); +HitLocation_t T_GetHitLocation(edict_t *target, edict_t *inflictor, vec3_t ppoint) +{ + HitLocation_t result; + int LocType; + vec3_t center; + vec3_t WorkLocations[hl_Max]; + vec3_t point; + + // Work out which type of location table to use +/* if(target->movetype == PHYSICSTYPE_FLY) + { + LocType = LT_WINGED; + } + else + {*/ + return MG_GetHitLocation(target, inflictor, ppoint, vec3_origin); +// LocType = LT_BIPED; +// } + + // If incoming point is zero, use inflictors origin + if(Vec3IsZero(ppoint)) + VectorCopy(inflictor->s.origin, point); + else + VectorCopy(ppoint, point); + + // Use absmin and absmax to get center of object + VectorAdd(target->absmin, target->absmax, center); + Vec3ScaleAssign(0.5, center); + + // Create a table of rotated offsets + GetWorkLocations(WorkLocations, target->size, center, target->s.angles[YAW], LocType); + + // Find nearest point in table of rotated offsets to collision point + result = GetNearestPoint(WorkLocations, point, LocType); + return(result); +} + +HitLocation_t HitLocationForVFLZone [TOTAL_ZONES] = +{//Lateral: +// 0-20(left), 20-40(lmid), 40-60(mid), 60-80(rmid), 80-100(right) +//Vertical: Between 0% and 20% of height (Lower Leg/Feet) + //Forward: Between 0% and 20% from back to front (Back) + hl_LegLowerLeft,hl_LegLowerLeft,hl_Half_LLL_LRL,hl_LegLowerRight,hl_LegLowerRight, + //Forward: Between 20% and 40% from back to front (BackMid) + hl_LegLowerLeft,hl_LegLowerLeft,hl_Half_LLL_LRL,hl_LegLowerRight,hl_LegLowerRight, + //Forward: Between 40% and 60% from back to front (Middle) + hl_LegLowerLeft,hl_LegLowerLeft,hl_Half_LLL_LRL,hl_LegLowerRight,hl_LegLowerRight, + //Forward: Between 60% and 80% from back to front (Fwd Middle) + hl_LegLowerLeft,hl_LegLowerLeft,hl_Half_LLL_LRL,hl_LegLowerRight,hl_LegLowerRight, + //Forward: Between 80% and 100% from back to front (Forward) + hl_LegLowerLeft,hl_LegLowerLeft,hl_Half_LLL_LRL,hl_LegLowerRight,hl_LegLowerRight, + +//Vertical: Between 20% and 40% of height (Upper Leg/Pelvis) + //Forward: Between 0% and 20% from back to front (Back) + hl_LegUpperLeft,hl_LegUpperLeft,hl_Half_ULL_URL,hl_LegUpperRight,hl_LegUpperRight, + //Forward: Between 20% and 40% from back to front (BackMid) + hl_LegUpperLeft,hl_LegUpperLeft,hl_Half_ULL_URL,hl_LegUpperRight,hl_LegUpperRight, + //Forward: Between 40% and 60% from back to front (Middle) + hl_LegUpperLeft,hl_LegUpperLeft,hl_Half_FT_BT, hl_LegUpperRight,hl_LegUpperRight, + //Forward: Between 60% and 80% from back to front (Fwd Middle) + hl_LegUpperLeft,hl_LegUpperLeft,hl_Half_ULL_URL,hl_LegUpperRight,hl_LegUpperRight, + //Forward: Between 80% and 100% from back to front (Forward) + hl_LegUpperLeft,hl_LegUpperLeft,hl_Half_ULL_URL,hl_LegUpperRight,hl_LegUpperRight, + +//Vertical: Between 40% and 60% of height (Lower Torso/Arm) + //Forward: Between 0% and 20% from back to front (Back) + hl_Half_BT_LLA, hl_TorsoBack, hl_TorsoBack, hl_TorsoBack, hl_Half_BT_LRA, + //Forward: Between 20% and 40% from back to front (BackMid) + hl_ArmLowerLeft,hl_TorsoBack, hl_TorsoBack, hl_TorsoBack, hl_ArmLowerRight, + //Forward: Between 40% and 60% from back to front (Middle) + hl_ArmLowerLeft,hl_Half_FT_BT, hl_Half_FT_BT, hl_Half_FT_BT, hl_ArmLowerRight, + //Forward: Between 60% and 80% from back to front (Fwd Middle) + hl_ArmLowerLeft,hl_TorsoFront, hl_TorsoFront, hl_TorsoFront, hl_ArmLowerRight, + //Forward: Between 80% and 100% from back to front (Forward) + hl_Half_FT_LLA, hl_TorsoFront, hl_TorsoFront, hl_TorsoFront, hl_Half_FT_LRA, + +//Vertical: Between 60% and 80% of height (Upper Torso/Arm) + //Forward: Between 0% and 20% from back to front (Back) + hl_Half_BT_ULA, hl_TorsoBack, hl_TorsoBack, hl_TorsoBack, hl_Half_BT_URA, + //Forward: Between 20% and 40% from back to front (BackMid) + hl_ArmUpperLeft,hl_TorsoBack, hl_TorsoBack, hl_TorsoBack, hl_ArmUpperRight, + //Forward: Between 40% and 60% from back to front (Middle) + hl_ArmUpperLeft,hl_Half_FT_BT, hl_Half_FT_BT, hl_Half_FT_BT, hl_ArmUpperRight, + //Forward: Between 60% and 80% from back to front (Fwd Middle) + hl_ArmUpperLeft,hl_TorsoFront, hl_TorsoFront, hl_TorsoFront, hl_ArmUpperRight, + //Forward: Between 80% and 100% from back to front (Forward) + hl_Half_FT_ULA, hl_TorsoFront, hl_TorsoFront, hl_TorsoFront, hl_Half_FT_URA, + +//Vertical: Between 80% and 100% of height (Head) + //Forward: Between 0% and 20% from back to front (Back) + hl_Half_BT_ULA, hl_TorsoBack, hl_TorsoBack, hl_TorsoBack, hl_Half_BT_URA, + //Forward: Between 20% and 40% from back to front (BackMid) + hl_ArmUpperLeft,hl_Head, hl_Head, hl_Head, hl_ArmUpperRight, + //Forward: Between 40% and 60% from back to front (Middle) + hl_ArmUpperLeft,hl_Head, hl_Head, hl_Head, hl_ArmUpperRight, + //Forward: Between 60% and 80% from back to front (Fwd Middle) + hl_ArmUpperLeft,hl_Head, hl_Head, hl_Head, hl_ArmUpperRight, + //Forward: Between 80% and 100% from back to front (Forward) + hl_Half_FT_ULA, hl_TorsoFront, hl_TorsoFront, hl_TorsoFront, hl_Half_FT_URA, +//Lateral: +// 0-20(left), 20-40(lmid), 40-60(mid), 60-80(rmid), 80-100(right) +}; + +HitLocation_t MG_GetHitLocation(edict_t *target, edict_t *inflictor, vec3_t ppoint, vec3_t pdir) +{ + vec3_t dir, point, point_dir; + vec3_t forward, right, up; + vec3_t tangles, tcenter; + float tradius, hdist; + float udot, fdot, rdot; + int Vertical, Forward, Lateral; + HitLocation_t HitLoc; + +//get target forward, right and up + if(target->client) + {//ignore player's pitch and roll + VectorSet(tangles, 0, target->s.angles[YAW], 0); + } + else + VectorCopy(target->s.angles, tangles); + + AngleVectors(tangles, forward, right, up); + +//get center of target + VectorAdd(target->absmin, target->absmax, tcenter); + Vec3ScaleAssign(0.5, tcenter); + +//get radius width of target + tradius = (fabs(target->maxs[0]) + fabs(target->maxs[1]) + fabs(target->mins[0]) + fabs(target->mins[1]))/4; + +//get impact point + if(ppoint && Vec3NotZero(ppoint)) + VectorCopy(ppoint, point); + else + VectorCopy(inflictor->s.origin, point);//this is bad! + +//get impact dir + if(pdir && Vec3NotZero(pdir)) + VectorCopy(pdir, dir); + else + {//take the inflictor's last origin to current to get dir + VectorSubtract(inflictor->s.origin, inflictor->s.old_origin, dir); + if(Vec3IsZero(dir)) + {//ok, that didn't work, make dir to target center, ignoring z + VectorSubtract(target->s.origin, inflictor->s.origin, dir); + dir[2] = 0; + } + VectorNormalize(dir); + } + +//put point at controlled distance from center + hdist = vhlen(point, tcenter); + + VectorMA(point, hdist - tradius, dir, point); + //now a point on the surface of a cylinder with a radius of tradius + + VectorSubtract(point, tcenter, point_dir); + VectorNormalize(point_dir); + + //Get bottom to top (Vertical) position index + udot = DotProduct(up, point_dir); + if(udot>.666) + Vertical = 4; + else if(udot>.333) + Vertical = 3; + else if(udot>-.333) + Vertical = 2; + else if(udot>-.666) + Vertical = 1; + else + Vertical = 0; + + //Get back to front (Forward) position index + fdot = DotProduct(forward, point_dir); + if(fdot>.666) + Forward = 4; + else if(fdot>.333) + Forward = 3; + else if(fdot>-.333) + Forward = 2; + else if(fdot>-.666) + Forward = 1; + else + Forward = 0; + + //Get left to right (Lateral) position index + rdot = DotProduct(right, point_dir); + if(rdot>.666) + Lateral = 4; + else if(rdot>.333) + Lateral = 3; + else if(rdot>-.333) + Lateral = 2; + else if(rdot>-.666) + Lateral = 1; + else + Lateral = 0; + +//FIXME: make one for horizonal bodies (harpies, corpses) + HitLoc = HitLocationForVFLZone[Vertical * 25 + Forward * 5 + Lateral]; + + switch(HitLoc) + { + case hl_Half_LLL_LRL://left lower leg and right lower leg: + if(!irand(0,1)) + return hl_LegLowerLeft; + else + return hl_LegUpperRight; + break; + case hl_Half_ULL_URL://left upper leg and right upper leg: + if(!irand(0,1)) + return hl_LegUpperLeft; + else + return hl_LegLowerRight; + break; + case hl_Half_FT_BT://front and back torso: + if(!irand(0,1)) + return hl_TorsoFront; + else + return hl_TorsoBack; + break; + case hl_Half_FT_URA://front torso and upper right arm: + if(!irand(0,1)) + return hl_TorsoFront; + else + return hl_ArmUpperRight; + break; + case hl_Half_FT_ULA://front torso and upper left arm: + if(!irand(0,1)) + return hl_TorsoFront; + else + return hl_ArmUpperLeft; + break; + case hl_Half_FT_LRA://front torso and lower right arm: + if(!irand(0,1)) + return hl_TorsoFront; + else + return hl_ArmLowerRight; + break; + case hl_Half_FT_LLA://front torso and lower left arm: + if(!irand(0,1)) + return hl_TorsoFront; + else + return hl_ArmLowerLeft; + break; + case hl_Half_BT_URA://back torso and upper right arm: + if(!irand(0,1)) + return hl_TorsoBack; + else + return hl_ArmUpperRight; + break; + case hl_Half_BT_ULA://back torso and upper left arm: + if(!irand(0,1)) + return hl_TorsoBack; + else + return hl_ArmUpperLeft; + break; + case hl_Half_BT_LRA://back torso and lower right arm: + if(!irand(0,1)) + return hl_TorsoBack; + else + return hl_ArmLowerRight; + break; + case hl_Half_BT_LLA://back torso and lower left arm: + if(!irand(0,1)) + return hl_TorsoBack; + else + return hl_ArmLowerLeft; + break; + default: + return HitLoc; + break; + } + //never happens: + return hl_NoneSpecific; +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_HitLocation.h b/Toolkit/Programming/GameCode/game/g_HitLocation.h new file mode 100644 index 0000000..77295fd --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_HitLocation.h @@ -0,0 +1,61 @@ +#ifndef G_HITLOCATION_H +#define G_HITLOCATION_H +// Enumerated hit locations + +typedef enum HitLocation_e +{ + hl_Null = -1, + hl_NoneSpecific = 0, + hl_Head, + hl_TorsoFront, + hl_TorsoBack, + hl_ArmUpperLeft, + hl_ArmLowerLeft, + hl_ArmUpperRight, + hl_ArmLowerRight, + hl_LegUpperLeft, + hl_LegLowerLeft, + hl_LegUpperRight, + hl_LegLowerRight, + hl_BipedPoints, + hl_WingedPoints, + hl_extra14, + hl_extra15, + hl_MeleeHit,//16 + hl_Max, + //50/50 HITLOCS + hl_Half_LLL_LRL,//left lower leg and right lower leg + hl_Half_ULL_URL,//left upper leg and right upper leg + hl_Half_FT_BT,//front and back torso + hl_Half_FT_URA,//front torso and upper right arm + hl_Half_FT_ULA,//front torso and upper left arm + hl_Half_FT_LRA,//front torso and lower right arm + hl_Half_FT_LLA,//front torso and lower left arm + hl_Half_BT_URA,//back torso and upper right arm + hl_Half_BT_ULA,//back torso and upper left arm + hl_Half_BT_LRA,//back torso and lower right arm + hl_Half_BT_LLA,//back torso and lower left arm +} HitLocation_t; + +typedef enum BloodType_e +{ + BLOODTYPE_NONE, + BLOODTYPE_RED, + BLOODTYPE_GREEN, + BLOODTYPE_STONE_CHIPS, + BLOODTYPE_WOOD_CHIPS, + NUM_BLOOTYPES +} BloodType_t; + +typedef struct HlDef_t +{ + vec3_t *LocTable; + int NumLocs; +} HlDef_t; + +HitLocation_t T_GetHitLocation(struct edict_s *target, struct edict_s *inflictor, vec3_t point); +HitLocation_t MG_GetHitLocation(edict_t *target, edict_t *inflictor, vec3_t ppoint, vec3_t pdir); + +#define TOTAL_ZONES 125//5 upper, 5 forward, 5 lateral + +#endif diff --git a/Toolkit/Programming/GameCode/game/g_Message.c b/Toolkit/Programming/GameCode/game/g_Message.c new file mode 100644 index 0000000..d6649b1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_Message.c @@ -0,0 +1,230 @@ +// +// g_Message.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#include "g_Message.h" +#include "Message.h" + +#include "g_local.h" +#include "ResourceManager.h" +#include "SinglyLinkedList.h" + +static ResourceManager_t MsgMngr; + +void InitMsgMngr() +{ +#define MESSAGE_BLOCK_SIZE 256 + + ResMngr_Con(&MsgMngr, sizeof(G_Message_t), MESSAGE_BLOCK_SIZE); +} + +void ReleaseMsgMngr() +{ + ResMngr_Des(&MsgMngr); +} + +void G_Message_DefaultCon(G_Message_t *this) +{ + SinglyLinkedList_t *parms; + + parms = &this->parms; + + // Fix Me !!! + SLList_DefaultCon(parms); // whoops, need to port object manager to C + SLList_PushEmpty(parms); // should make a constructor fo G_Message_t too +} + +G_Message_t *G_Message_new(G_MsgID_t ID, G_MsgPriority_t priority) +{ + G_Message_t *newMsg; + + newMsg = ResMngr_AllocateResource(&MsgMngr, sizeof(G_Message_t)); + + G_Message_DefaultCon(newMsg); + + newMsg->ID = ID; + newMsg->priority = priority; + + return newMsg; +} + +void G_Message_Des(G_Message_t *this) +{ + SLList_Des(&this->parms); +} + +void G_Message_delete(G_Message_t *this) +{ + G_Message_Des(this); + + ResMngr_DeallocateResource(&MsgMngr, this, sizeof(G_Message_t)); +} + +void QPostMessage(edict_t *to, G_MsgID_t ID, G_MsgPriority_t priority, char *format, ...) +{ + G_Message_t *newMsg; + qboolean append = false; + SinglyLinkedList_t *parms; + va_list marker; + + if(!to->msgHandler) // everything should really have one, but at this point everything + // doesn't so, the messages will never get popped of the queue + // so don't push them on in the first place + { + return; + } + + newMsg = ResMngr_AllocateResource(&MsgMngr, sizeof(G_Message_t)); + + // Fix Me !!! + G_Message_DefaultCon(newMsg); // whoops, need to port object manager to C + + parms = &newMsg->parms; + + newMsg->ID = ID; + newMsg->priority = priority; + + if(format) + { + va_start(marker, format); + + SetParms(parms, format, marker, false); + + va_end(marker); + } + + QueueMessage(&to->msgQ, newMsg); +} + +void PostGameMessage(edict_t *to, G_MsgID_t ID, G_MsgPriority_t priority, char *format, ...) +{ + G_Message_t *newMsg; + qboolean append = false; + SinglyLinkedList_t *parms; + va_list marker; + + if(!to->msgHandler) // everything should really have one, but at this point everything + // doesn't so, the messages will never get popped of the queue + // so don't push them on in the first place + { + return; + } + + newMsg = ResMngr_AllocateResource(&MsgMngr, sizeof(G_Message_t)); + + // Fix Me !!! + G_Message_DefaultCon(newMsg); // whoops, need to port object manager to C + + parms = &newMsg->parms; + + newMsg->ID = ID; + newMsg->priority = priority; + + if(format) + { + va_start(marker, format); + + SetParms(parms, format, marker, false); + + va_end(marker); + } + + QueueMessage(&to->msgQ, newMsg); +} + +int ParseMsgParms(G_Message_t *this, char *format, ...) +{ + SinglyLinkedList_t *parms; + va_list marker; + int args_filled; + + assert(this); + + parms = &this->parms; + + SLList_Front(parms); + + va_start(marker, format); + + args_filled = GetParms(parms, format, marker); + + va_end(marker); + + return args_filled; +} + +void ProcessMessages(edict_t *self) +{ + SinglyLinkedList_t *msgs; + SinglyLinkedList_t *parms; + G_Message_t *msg; + + assert(self->msgHandler); + + msgs = &self->msgQ.msgs; + + if(!SLList_IsEmpty(msgs)) + { + self->flags &= ~FL_SUSPENDED; + } + + while(!SLList_IsEmpty(msgs)) + { + msg = SLList_Pop(msgs).t_void_p; + + parms = &msg->parms; + + if(!SLList_AtLast(parms) && !SLList_AtEnd(parms)) + { + SLList_Chop(parms); + } + + self->msgHandler(self, msg); + + // Fix Me !!! + G_Message_Des(msg); // whoops, need to port object manager to C + + ResMngr_DeallocateResource(&MsgMngr, msg, sizeof(G_Message_t)); + } +} + +void ClearMessageQueue(edict_t *self) +{ + SinglyLinkedList_t *msgs; + SinglyLinkedList_t *parms; + G_Message_t *msg; + + msgs = &self->msgQ.msgs; + + // If either of these fire - do a rebuild all + // otherwise it will try to free random memory and lead to an unstable system + assert(msgs->front); + assert(msgs->rearSentinel); + + while(!SLList_IsEmpty(msgs)) + { + msg = SLList_Pop(msgs).t_void_p; + + parms = &msg->parms; + + // Fix Me !!! + SLList_Des(parms); // whoops, need to port object manager to C + + ResMngr_DeallocateResource(&MsgMngr, msg, sizeof(G_Message_t)); + } +} + +void ClearMessageQueues() +{ + edict_t *ent; + int i; + + for (i=0, ent = &g_edicts[0]; ithink to G_FreeEdict and nextthink to 0 + G_MSG_SUSPEND,//35 + // float time ( <= 0 indicates indefinite suspend ) + G_MSG_UNSUSPEND, + + +//-------------------------------------------- +// Voice messages +//-------------------------------------------- + + MSG_VOICE_SIGHT, //Sight sounds + MSG_VOICE_POLL, //Polled for a reply sound + MSG_VOICE_PUPPET, //Forced sound by a trigger + + MSG_CHECK_MOOD, //forced to check it's mood + + //end + + MSG_DISMEMBER, + + MSG_EVADE, //if set, new ai_run will check and see if going to get hit and send evasion message with hitloc + MSG_DEATH_PAIN, //taking pain after death- for dismemberment or twitch + +//-------------------------------------------- +// Cinematic messages +//-------------------------------------------- + + MSG_C_ACTION1, // Differs between monsters + MSG_C_ACTION2, // + MSG_C_ACTION3, // + MSG_C_ACTION4, // + MSG_C_ACTION5, // + MSG_C_ACTION6, // + MSG_C_ACTION7, // + MSG_C_ACTION8, // + MSG_C_ACTION9, // + MSG_C_ACTION10, // + MSG_C_ACTION11, // + MSG_C_ACTION12, // + MSG_C_ACTION13, // + MSG_C_ACTION14, // + MSG_C_ACTION15, // + MSG_C_ACTION16, // + MSG_C_ACTION17, // + MSG_C_ACTION18, // + MSG_C_ACTION19, // + MSG_C_ACTION20, // + MSG_C_ATTACK1, + MSG_C_ATTACK2, + MSG_C_ATTACK3, + MSG_C_BACKPEDAL1, + MSG_C_DEATH1, + MSG_C_DEATH2, + MSG_C_DEATH3, + MSG_C_DEATH4, + MSG_C_GIB1, + MSG_C_IDLE1, + MSG_C_IDLE2, + MSG_C_IDLE3, + MSG_C_IDLE4, + MSG_C_IDLE5, + MSG_C_IDLE6, + MSG_C_JUMP1, + MSG_C_PAIN1, + MSG_C_PAIN2, + MSG_C_PAIN3, + MSG_C_PIVOTLEFTGO, + MSG_C_PIVOTLEFT, + MSG_C_PIVOTLEFTSTOP, + MSG_C_PIVOTRIGHTGO, + MSG_C_PIVOTRIGHT, + MSG_C_PIVOTRIGHTSTOP, + MSG_C_RUN1, + MSG_C_STEPLEFT, + MSG_C_STEPRIGHT, + MSG_C_THINKAGAIN, // Turns off Cinematic AI and puts monster into idle state + MSG_C_TRANS1, + MSG_C_TRANS2, + MSG_C_TRANS3, + MSG_C_TRANS4, + MSG_C_TRANS5, + MSG_C_TRANS6, + MSG_C_WALKSTART, + MSG_C_WALK1, + MSG_C_WALK2, + MSG_C_WALK3, + MSG_C_WALK4, + MSG_C_WALKSTOP1, + MSG_C_WALKSTOP2, + MSG_C_ATTACK4, + MSG_C_ATTACK5, + + + NUM_MESSAGES +} G_MsgID_t; + +typedef enum G_MsgPriority_e +{ + PRI_SUGGESTION, // message from high level ai that dosn't need to be accepted unless convienent + PRI_ORDER, // message from high level ai that should be accepted if possible + PRI_DIRECTIVE, // message from self that must be accepted unless it conflicts with a + // higher priority message + PRI_PHYSICS, // message that has physical meaning such as knockback or damage + PRI_SYSTEM, // message from the system that must be accepted + NUM_MSG_PRIORITIES +} G_MsgPriority_t; + +typedef struct G_Message_s +{ + G_MsgID_t ID; + G_MsgPriority_t priority; + SinglyLinkedList_t parms; +} G_Message_t; + +typedef void (*G_MessageHandler_t)(struct edict_s *self, G_Message_t *msg); +typedef void (*G_MsgReceiver_t)(struct edict_s *self, G_Message_t *msg); + +void G_Message_DefaultCon(G_Message_t *this_ptr); +G_Message_t *G_Message_new(G_MsgID_t ID, G_MsgPriority_t priority); +void G_Message_delete(G_Message_t *this_ptr); + +void QPostMessage(struct edict_s *to, G_MsgID_t ID, G_MsgPriority_t priority, char *format, ...); + +#ifdef __cplusplus + +extern "C" +{ + void PostGameMessage(struct edict_s *to, G_MsgID_t ID, G_MsgPriority_t priority, char *format, ...); +} + +#endif + +int ParseMsgParms(G_Message_t *this_ptr, char *format, ...); +void ProcessMessages(struct edict_s *this_ptr); +void ClearMessageQueue(struct edict_s *this_ptr); + +#endif diff --git a/Toolkit/Programming/GameCode/game/g_Monster_State.h b/Toolkit/Programming/GameCode/game/g_Monster_State.h new file mode 100644 index 0000000..01a0131 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_Monster_State.h @@ -0,0 +1,65 @@ +//---------------------------------------------------- +// Movement State types +//---------------------------------------------------- + +enum Move_Type_e // this seems to be redundant with physicInfo->type, except for hover +{ + MOVE_TYPE_STATIC, // can't move at all + MOVE_TYPE_TURN, // change orientation, but not position + MOVE_TYPE_STEP, // stuff with legs + MOVE_TYPE_SWIM, // anything submereged + MOVE_TYPE_FLY, // flying creatures, and any others when falling or being knocked back through the air + MOVE_TYPE_AIRBORNE, // nonflying creatures when falling or being knocked back + MOVE_TYPE_HOVER, +}; + +// Step State types + +enum Step_DOF_e +{ + STEP_DOF_1, // forward and back only + STEP_DOF_2_4, // cardinal directions only + STEP_DOF_2_8, // cardinal directions plus, halves in between + STEP_DOF_2, // true 2DOF +}; + +enum Step_State_e +{ + STEP_STATE_STILL, // not stepping + STEP_STATE_PIVOTING, // turning left or right + STEP_STATE_MOVING, // stepping in some form or another + // valid only if STEP_READINESS_STANDING || STEP_READINESS_CROUCHING is set + STEP_STATE_JUMPING, // some kind of jump + // valid only if STEP_READINESS_STANDING is set +}; + +enum Step_Readiness_e +{ + STEP_READINESS_STANDING, + STEP_READINESS_CROUCHING, + STEP_READINESS_SITTING, + STEP_READINESS_LYING, +}; + +//---------------------------------------------------- +// Action State types +//---------------------------------------------------- + +enum Action_State_e +{ + ACTION_STATE_IDLE, // no action, but could be moving + ACTION_STATE_MISC, // getting or using an item + ACTION_STATE_ACTIVATING, // activating something + ACTION_STATE_STRIKING, // making a melee attack + ACTION_STATE_SHOOTING, // making a missile attack + ACTION_STATE_CASTING, // casting a spell +}; + +enum Action_Readiness_e +{ + ACTION_READINESS_NORMAL, + ACTION_READINESS_PAIN, + ACTION_READINESS_KNOCKBACK, + ACTION_READINESS_DEAD, +}; + diff --git a/Toolkit/Programming/GameCode/game/g_MoveInfo.c b/Toolkit/Programming/GameCode/game/g_MoveInfo.c new file mode 100644 index 0000000..06a089d --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_MoveInfo.c @@ -0,0 +1,35 @@ +#include "g_MoveInfo.h" +#include "ResourceManager.h" +#include "g_local.h" + +static ResourceManager_t MoveInfoMngr; + +void InitMoveInfoMngr() +{ +#define MOVEINFO_BLOCK_SIZE 32 + + ResMngr_Con(&MoveInfoMngr, sizeof(MoveInfo_t), MOVEINFO_BLOCK_SIZE); +} + +void ReleaseMoveInfoMngr() +{ + ResMngr_Des(&MoveInfoMngr); +} + +MoveInfo_t *MoveInfo_new() +{ + MoveInfo_t *newInfo; + + newInfo = ResMngr_AllocateResource(&MoveInfoMngr, sizeof(*newInfo)); + + memset(newInfo, 0, sizeof(*newInfo)); + + newInfo->pivotDirection = 1.0; + + return newInfo; +} + +void MoveInfo_delete(MoveInfo_t *toDelete) +{ + ResMngr_DeallocateResource(&MoveInfoMngr, toDelete, sizeof(*toDelete)); +} diff --git a/Toolkit/Programming/GameCode/game/g_MoveInfo.h b/Toolkit/Programming/GameCode/game/g_MoveInfo.h new file mode 100644 index 0000000..dbe0b0b --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_MoveInfo.h @@ -0,0 +1,24 @@ +#ifndef G_MOVEINFO_H +#define G_MOVEINFO_H + +typedef struct MoveInfo_s +{ + int type; + + int stepDOF; + int state; + int readiness; + + float yawOffset; // offset from facing used to determine actual angle moving toward (radians) + float pivotDirection; // 1 is left, -1 is right + float destYaw; // facing the ent is turning towards (radians) + + int blockCount; + float yawAtLastCollision; + +} MoveInfo_t; + +extern MoveInfo_t *MoveInfo_new(); +extern void MoveInfo_delete(MoveInfo_t *toDelete); + +#endif // G_MOVEINFO_H diff --git a/Toolkit/Programming/GameCode/game/g_Physics.c b/Toolkit/Programming/GameCode/game/g_Physics.c new file mode 100644 index 0000000..ab845cc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_Physics.c @@ -0,0 +1,2448 @@ +#include "g_Physics.h" +#include "g_local.h" + +#include "Vector.h" +#include "Angles.h" +#include "PrimitiveDisplayHack.h" +#include "SinglyLinkedList.h" +#include "q_Physics.h" +#include "g_BoundingForm.h" +#include "Utilities.h" +#include "p_main2.h" +#include "random.h" +#include "p_anim_branch2.h" +#include "p_anims2.h" +#include "fx.h" +#include "g_playstats.h" + +static void Physics_None(edict_t *self); +static void Physics_Static(edict_t *self); +static void Physics_NoclipMove(edict_t *self); +static void Physics_FlyMove(edict_t *self); +static void Physics_StepMove(edict_t *self); +static void Physics_Push(edict_t *self); +static void Physics_ScriptAngular(edict_t *self); + +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); + +void (*physicsFuncs[NUM_PHYSICSTYPES])(edict_t *self) = +{ + Physics_None, // PHYSICSTYPE_NONE + Physics_Static, // PHYSICSTYPE_STATIC + Physics_NoclipMove, // PHYSICSTYPE_NOCLIP + Physics_FlyMove, // PHYSICSTYPE_FLY + Physics_StepMove, // PHYSICSTYPE_STEP + Physics_Push, // PHYSICSTYPE_PUSH + Physics_Push, // PHYSICSTYPE_STOP + Physics_FlyMove, // MOVETYPE_FLYMISSILE + Physics_ScriptAngular, // PHYSICSTYPE_SCRIPT_ANGULAR +}; + +void PhysicsCheckWaterTransition(edict_t *self) +{//fixme: a high detail option? Or just not in netplay?- maybe a flag for client to take care of + //disabling for now since it might cause too much net traffic + qboolean wasinwater, isinwater; + trace_t trace; + int size; + + if(deathmatch->value || coop->value) + return; + + // check for water transition + wasinwater = (self->watertype & MASK_WATER); + self->watertype = gi.pointcontents (self->s.origin); + isinwater = self->watertype & MASK_WATER; + + if (!wasinwater && isinwater) + { + gi.trace(self->s.old_origin, vec3_origin, vec3_origin, self->s.origin, self, MASK_WATER,&trace); + } + else if (wasinwater && !isinwater) + { + gi.trace(self->s.origin, vec3_origin, vec3_origin, self->s.old_origin, self, MASK_WATER,&trace); + } + else + return; + + if(trace.fraction==1.0) + return; + +//fixme: just put a flag on them and do the effect on the other side? + size = ceil(VectorLength(self->size) + VectorLength(self->velocity)/10); + if(size<10) + size = 10; + else if(size>255) + size = 255; + + gi.CreateEffect(NULL, + FX_WATER_ENTRYSPLASH, + CEF_FLAG6, + trace.endpos, + "bd", + size, + trace.plane.normal); +} + +//--------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------- +static void Physics_None(edict_t *self) +{ +} + +//--------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------- +static void Physics_Static(edict_t *self) +{ +} + +//--------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------- +static void Physics_NoclipMove(edict_t *self) +{ + VectorMA(self->s.angles, FRAMETIME, self->avelocity, self->s.angles); + VectorMA(self->s.origin, FRAMETIME, self->velocity, self->s.origin); + + gi.linkentity(self); +} + +//--------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------- +static void Physics_FlyMove(edict_t *self) +{ + FormMove_t formMove; + + if(self->physicsFlags & PF_RESIZE) + { + if(gi.ResizeBoundingForm(self, &formMove)) + { + self->physicsFlags &= ~PF_RESIZE; + } + else + { + return; // if an ent can't be resized, then it probably can't be moved either + } + } + + // update angles + VectorMA(self->s.angles, FRAMETIME, self->avelocity, self->s.angles); + + if(!BoundVelocity(self->velocity) && self->gravity <= 0.0f) + { + return; + } + + if(self->velocity[2] > 0.0f) + { + self->groundentity = NULL; + } + else + { + if(self->groundentity) + { // onground, return without moving + return; + } + } + + VectorCopy(self->mins, formMove.mins); + VectorCopy(self->maxs, formMove.maxs); + + formMove.passEntity = self; + formMove.clipMask = self->clipmask; + + MoveEntity_Bounce(self, &formMove); + + PhysicsCheckWaterTransition(self); + + gi.linkentity(self); + + ActivateTriggers(self); +} + +//--------------------------------------------------------------------------------- +//Monsters freefall when they don't have a ground entity, otherwise +//all movement is done with discrete steps. + +//This is also used for objects that have become still on the ground, but +//will fall if the floor is pulled out from under them. +//--------------------------------------------------------------------------------- +static void Physics_StepMove(edict_t *self) +{ + qboolean hasVel; + FormMove_t formMove; + float gravity; + float friction; + + assert(self->gravity >= 0.0f); + + hasVel = Vec3NotZero(self->velocity); + +// gi.dprintf("hasVel %i\n", hasVel); + +// gi.dprintf("vel in Physics_StepMove %f, %f, %f\n", self->velocity[0], +// self->velocity[1], self->velocity[2]); + + // Apply rotation friction if desired + if(self->physicsFlags & PF_ROTATIONAL_FRICTION) + { + if(!Vec3IsZero(self->avelocity)) + { + ApplyRotationalFriction(self); + } + } + else + { + VectorMA(self->s.angles, FRAMETIME, self->avelocity, self->s.angles); + } + + if(self->physicsFlags & PF_RESIZE) + { + if(gi.ResizeBoundingForm(self, &formMove)) + { + self->physicsFlags &= ~PF_RESIZE; + } + } + + gravity = self->gravity * sv_gravity->value; + + // check for submersion or nograv + if(self->waterlevel <= 1 && gravity > 0.0f) + { + if(self->groundentity) + { + friction = self->friction * sv_friction->value; + + if(!hasVel) + { + if(self->groundNormal[2] >= GROUND_NORMAL && self->groundNormal[2] >= (gravity / (friction + gravity))) + { // not going anywhere without velocity on ground whose slope this ent won't slide on + return; + } + } + } + + MoveEntity_Slide(self); + } + else + { + if(!hasVel) + { // not going anywhere without vel + return; + } + + VectorCopy(self->mins, formMove.mins); + VectorCopy(self->maxs, formMove.maxs); + + formMove.passEntity = self; + formMove.clipMask = self->clipmask; + + MoveEntity_Bounce(self, &formMove); + } + + if(!BoundVelocity(self->velocity)) + { +// gi.dprintf("Doesn't have vel\n"); + + if(hasVel) + { // stopped + QPostMessage(self, G_MSG_RESTSTATE, PRI_PHYSICS, "i", hasVel); + } + } + else if(!hasVel) + { // started + QPostMessage(self, G_MSG_RESTSTATE, PRI_PHYSICS, "i", hasVel); + } + + PhysicsCheckWaterTransition(self); + + gi.linkentity(self); + + ActivateTriggers(self); +} + +//--------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------- +void EntityPhysics(edict_t *self) +{ + assert(self->inuse); + + if(self->movetype < 0 || self->movetype >= NUM_PHYSICSTYPES) + { + assert(0); + gi.error ("SV_Physics: bad movetype %i", self->movetype); + return; + } + + physicsFuncs[self->movetype](self); +} + +//--------------------------------------------------------------------------------- +// Determines which entity if any the self is on +// Also zeros z vel and moves onto ground if it was in the air +//--------------------------------------------------------------------------------- +void CheckEntityOn(edict_t *self) +{ + vec3_t point; + FormMove_t formMove; + + assert(self); + + if(self->velocity[2] > Z_VEL_NOT_ONGROUND) + { + self->groundentity = NULL; + return; + } + + // if the hull point one-quarter unit down is solid the entity is on ground + point[0] = self->s.origin[0]; + point[1] = self->s.origin[1]; + point[2] = self->s.origin[2] - (PHYSICS_Z_FUDGE + CHECK_BELOW_DIST); + + VectorCopy(self->mins, formMove.mins); + VectorCopy(self->maxs, formMove.maxs); + + formMove.start = self->s.origin; + formMove.end = point; + formMove.passEntity = self; + formMove.clipMask = MASK_MONSTERSOLID; + + gi.TraceBoundingForm(&formMove); + + // check steepness + if(!formMove.trace.ent || (formMove.trace.plane.normal[2] < GROUND_NORMAL && !formMove.trace.startsolid)) + { + self->groundentity = NULL; + return; + } + + if(!formMove.trace.startsolid && !formMove.trace.allsolid) + { + VectorCopy(formMove.trace.endpos, self->s.origin); + + SetGroundEntFromTrace(self, &formMove.trace); + +// self->velocity[2] = 0; + } +} + +//--------------------------------------------------------------------------------- +// set move to be based on gravity and velocity, and adjust velocity for gravity +//--------------------------------------------------------------------------------- +void ApplyGravity(edict_t *self, vec3_t move) +{ + assert(self); + + if(move) + { + move[2] -= self->gravity * sv_gravity->value * (FRAMETIME * FRAMETIME * 0.5); + } + + self->velocity[2] -= self->gravity * sv_gravity->value * FRAMETIME; +} + +//Make things that hit each other do some damage +void DoImpactDamage(edict_t *self, trace_t *trace) +{ + vec3_t normal, movedir; + float impact_dmg, total_health, tr_health, self_health, speed; + int tr_dmg, self_dmg; + + if(self->impact_debounce_time>level.time) + return; + + if(self->svflags&SVF_DO_NO_IMPACT_DMG) + return; + + if(self->client) + { + if(self->client->playerinfo.edictflags & FL_CHICKEN) + { + return; + } + } + + if(self->svflags&SVF_MONSTER||self->mass||self->client) + { + speed = VectorLength(self->velocity); + + if(speed<50) + return; + + if(speed < 500 && self->watertype) + return; + + impact_dmg = sqrt(speed/10); + + //monsters dont do impact damage to their own type + if(self->classID && trace->ent->classID && self->classID == trace->ent->classID) + return; + + if(impact_dmg>0) + { + VectorSet(normal, 0, 0, 1); + if(&trace->plane) + { + if(trace->plane.normal) + { + VectorCopy(trace->plane.normal, normal); + } + } + + VectorSet(movedir, 0, 0, 1); + if(!Vec3IsZero(self->velocity)) + { + VectorCopy(self->velocity, movedir); + VectorNormalize(movedir); + } + + if(trace->ent->solid==SOLID_BSP) + { + if(self->health>0) + impact_dmg = impact_dmg * self->health / 100; + else if(speed<300) + return; + + if((!trace->ent->takedamage && self->health*10 > 1000) || self->health<=0) + tr_health = self->health * 10; + else + tr_health = 1000; + } + else if(trace->ent->health>0) + tr_health = trace->ent->health * 0.5; + else + tr_health = 1; + + if(self->health>0) + self_health = self->health * 2; + else + self_health = 2; + + total_health = self_health + tr_health; + + if(trace->ent->solid==SOLID_BSP&&!trace->ent->takedamage) + tr_dmg = 0; + else + tr_dmg = floor(impact_dmg * self_health/total_health); + + self_dmg = floor(impact_dmg - tr_dmg); + + if(tr_dmg>=1 && trace->ent->takedamage && !(trace->ent->svflags&SVF_TAKE_NO_IMPACT_DMG)&&!(trace->ent->svflags&SVF_BOSS)) + { + if(skill->value < 2 && self->svflags & SVF_MONSTER && trace->ent->client) + tr_dmg = ceil(tr_dmg * 0.5);//monsters do a bit less damage to player on normal and easy skill + if(tr_dmg >= 1) + { + T_Damage(trace->ent, self, self, movedir, trace->endpos, normal, tr_dmg, tr_dmg, 0,MOD_CRUSH); + if(trace->ent->health>0) + { + if(trace->ent->client) + { + if(tr_dmg > irand(25, 40) - (5 * (skill->value))) + { + if(trace->ent->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + KnockDownPlayer(&trace->ent->client->playerinfo); + } + } + } + } + } + + if(self_dmg>=1 && self->takedamage && (speed > 600 || self->health <= 0) && !(self->svflags&SVF_TAKE_NO_IMPACT_DMG) && !(self->svflags&SVF_BOSS) && self->jump_time < level.time) + { + if(skill->value && self->client && trace->ent->solid == SOLID_BSP) + self_dmg = floor(self->dmg * 1.5);//more damage to player from falls + + if(self_dmg >= 3 && (self->classID != CID_ASSASSIN && self->classID != CID_SSITHRA) || self->health<=0)//but what about ring of repulsion? + { + if(self_dmg < 5) + T_Damage(self, self, self, movedir, trace->endpos, normal, self_dmg, 0, DAMAGE_NO_BLOOD|DAMAGE_AVOID_ARMOR,MOD_FALLING); + else + T_Damage(self, self, self, movedir, trace->endpos, normal, self_dmg, 0, DAMAGE_AVOID_ARMOR,MOD_FALLING); + self->impact_debounce_time = level.time + 0.3;//don't collide again too soon + } + } + } + } +} + +//--------------------------------------------------------------------------------- +// Calls correct collision handling functions for ents involved +//--------------------------------------------------------------------------------- +void HandleCollision(edict_t *self, trace_t *trace, vec3_t move, int forceful, int flags) +{ + edict_t *other = trace->ent; + +// assert(self->solid != SOLID_NOT); +// assert(other->solid != SOLID_NOT); + + if(IMPACT_DAMAGE) + { + if(flags&CH_ISBLOCKED || flags&CH_BOUNCED) + { + DoImpactDamage(self, trace); + } + } + + if(forceful) + { + HandleForcefulCollision(self, other, move, forceful); + } + + if(flags&CH_ISBLOCKED && self->isBlocked) + { + self->isBlocked(self, trace); + } + + if(flags&CH_BOUNCED && self->bounced) + { + self->bounced(self, trace); + } + + if(flags&CH_ISBLOCKING && other->isBlocking) + { + trace_t temp = *trace; + + temp.ent = self; + VectorInverse(temp.plane.normal); + + other->isBlocking(other, &temp); + } +} + +//--------------------------------------------------------------------------------------- +// forceful < 0 indicates that the forcer shouldn't be knocked back +//--------------------------------------------------------------------------------------- +void HandleForcefulCollision(edict_t *forcer, edict_t *forcee, vec3_t move, int forceful) +{ + vec3_t dir, vel; + float knockback; + qboolean hitWorld = false; + + assert(forcee); + + if(forcee == g_edicts) + { + hitWorld = true; + VectorScale(move, -FRAMES_PER_SECOND*0.8, vel); + } + else + { + hitWorld = false; + VectorScale(move, FRAMES_PER_SECOND*0.5, vel); + } + + knockback = VectorNormalize2(vel, dir); + + knockback *= forcer->mass; + knockback /= KNOCK_BACK_MULTIPLIER; + + // knock other entity back + if(!hitWorld) + { + PostKnockBack(forcee, dir, knockback, 0); + Vec3ScaleAssign(-1.0, dir); + } + + if(forceful > 0) + { + // knock back running ent + PostKnockBack(forcer, dir, knockback, 0); + } +} + +//--------------------------------------------------------------------------------- +// takes into account gravity, and bounces an ent away from impacts based on elasticity +// fiction is ignored +//--------------------------------------------------------------------------------- +void MoveEntity_Bounce(edict_t *self, FormMove_t *formMove) +{ + vec3_t move, end; + + VectorScale(self->velocity, FRAMETIME, move); + + // create the delta move + if(self->gravity > 0.0f) + { + ApplyGravity(self, move); + } + + VectorAdd(self->s.origin, move, end); + + formMove->start = self->s.origin; + formMove->end = end; + + gi.TraceBoundingForm(formMove); + + VectorCopy(formMove->trace.endpos, self->s.origin); + + // handle bouncing and sliding + if(formMove->trace.fraction < 1.0) + { + BounceVelocity(self->velocity, formMove->trace.plane.normal, self->velocity, self->elasticity); + + if(self->elasticity > ELASTICITY_SLIDE) + { + if((self->velocity[2] < 60.0) && (formMove->trace.plane.normal[2] > GROUND_NORMAL)) + { + SetGroundEntFromTrace(self, &formMove->trace); + + VectorClear(self->velocity); + VectorClear(self->avelocity); + } + } + + HandleCollision(self, &formMove->trace, move, (self->physicsFlags & PF_FORCEFUL_COLLISIONS), CH_STANDARD); + } +} + +//--------------------------------------------------------------------------------- +// Moves an entity sliding or bouncing of off any planes collided with +//--------------------------------------------------------------------------------- +void MoveEntity_Slide(edict_t *self) +{ +#define MAX_CLIP_PLANES 5 +#define MAX_BUMPS 4 +#define STEEP_SLOPE_FRICTION_MODIFIER 0.1 + + edict_t *hit; + int bumpcount; + vec3_t dir, gdir; + int numplanes = 0; + vec3_t primal_velocity, original_velocity, new_velocity; + int i, j; + vec3_t end, delta; + float timeRemaining = FRAMETIME, timeRemaining2, timeMoved; + static vec3_t planes[MAX_CLIP_PLANES]; + FormMove_t formMove; + float base_friction, friction, gravity; + float dist, dot, accel, speed, faccel, gaccel; + qboolean slide; + float *groundNormal; + int fudgeIndex = -1; + + assert(self->clipmask); + assert(self); + + gravity = self->gravity * sv_gravity->value; + base_friction = self->friction * sv_friction->value; +// gi.dprintf("Gravity %f, Friction %f, to be applied\n", gravity, friction); + +// gi.dprintf("Velocity %f, %f, %f\n", self->velocity[0], self->velocity[1], self->velocity[2]); +// gi.dprintf("speed in %f\n", VectorLength(self->velocity)); + + VectorCopy(self->velocity, original_velocity); + VectorCopy(self->velocity, primal_velocity); + +// self->groundentity = NULL; + + groundNormal = self->groundNormal; + + if(!self->groundentity) + { + groundNormal[2] = 0.0; + } + + VectorCopy(self->mins, formMove.mins); + VectorCopy(self->maxs, formMove.maxs); + + formMove.start = self->s.origin; + formMove.passEntity = self; + formMove.clipMask = self->clipmask; + + for(bumpcount = 0; bumpcount < MAX_BUMPS; ++bumpcount) + { + friction = base_friction; + + VectorScale(self->velocity, timeRemaining, delta); + + timeRemaining2 = timeRemaining * timeRemaining; + + slide = false; + + if(groundNormal[2]) + { // on some type of upward facing slope + assert(groundNormal[2] > 0.0); + + if(Vec3IsZero(self->velocity)) + { // no velocity +// gi.dprintf("no vel on slope\n"); + + if(groundNormal[2] >= GROUND_NORMAL) + { + if(groundNormal[2] >= (gravity / (friction + gravity))) + { // can't slide + if(bumpcount) + { // not going anywhere + // gi.dprintf("no vel on no slide slope\n"); +#if 0 + formMove.trace.fraction = 0.0; + break; +#else + return; +#endif + } + else + { // check in calling func + assert(0); + } + } + } + + // ( |gravity| X groundNormal ) X groundNormal yeilds the vector in the + //direction of gravity applied to the the slope of groundNormal + gdir[0] = groundNormal[0]*groundNormal[2]; + gdir[1] = groundNormal[1]*groundNormal[2]; + gdir[2] = -groundNormal[0]*groundNormal[0] - groundNormal[1]*groundNormal[1]; + + VectorNormalize(gdir); + + dot = DotProduct(gdir, groundNormal); + + if(dot < -FLOAT_ZERO_EPSILON) + { // floating point error, shit, fudge it away from the plane a bit +// gi.dprintf("Dot %f, Fudge for bump %i and plane %i\n", dot, bumpcount, i); + fudgeIndex = i; + VectorMA(self->s.origin, PHYSICS_Z_FUDGE, planes[i], self->s.origin); + } + +// dir[2] += 0.0001; // fudge it away from the slope just a little + + dist = 0; + + dot = 0; + + slide = true; + } + else + { + dist = VectorNormalize2(delta, dir); + dot = DotProduct(dir, groundNormal); + + if(dot < -0.05) + { // the trace will fail, try to restructure inorder to skip it + } + else if(dot < 0.05) // parallel to ground + { + slide = true; + } + else + { // pulling away from ground + } + } + + } + else + { // easy case, fall straight down, no surface friction needed + } + + if(slide) + { // moving along ground, apply gravity and friction appropriatly + gdir[0] = groundNormal[0]*groundNormal[2]; + gdir[1] = groundNormal[1]*groundNormal[2]; + gdir[2] = -groundNormal[0]*groundNormal[0] - groundNormal[1]*groundNormal[1]; + + VectorNormalize(gdir); + + dot = DotProduct(gdir, dir); + + if(groundNormal[2] < GROUND_NORMAL) + { // turn down friction on a steep slope, the theory being that something wouldn't be able to maintain + // good surface contact on such a slope +// friction *= STEEP_SLOPE_FRICTION_MODIFIER; + faccel = -friction * groundNormal[2] * STEEP_SLOPE_FRICTION_MODIFIER; + } + else + { + faccel = -friction * groundNormal[2]; + } + +#if 0 + if(accel < 0) + { + gi.dprintf("Accel less than zero\n"); + } +#endif + + dist += 0.5 * faccel * timeRemaining2; + + if(dist < 0) + { + dist = 0; + faccel = 0; + } + + VectorScale(dir, dist, delta); +// gi.dprintf("Move slid, accel %f\n", faccel); + dot = DotProduct(gdir, groundNormal); + + if(dot < -FLOAT_ZERO_EPSILON) + { // floating point error, shit, fudge it away from the plane a bit +// gi.dprintf("Dot %f, Fudge for bump %i and plane %i\n", dot, bumpcount, i); + fudgeIndex = i; + VectorMA(self->s.origin, PHYSICS_Z_FUDGE, planes[i], self->s.origin); + } + + if(groundNormal[2] < GROUND_NORMAL) + { // turn down friction on a steep slope, the theory being that something wouldn't be able to maintain + // good surface contact on such a slope +// friction *= STEEP_SLOPE_FRICTION_MODIFIER; + gaccel = gravity * (1 - groundNormal[2]) - friction * groundNormal[2] * STEEP_SLOPE_FRICTION_MODIFIER; + } + else + { + gaccel = gravity * (1 - groundNormal[2]) - friction * groundNormal[2]; + } + + if(gaccel < 0) + { + gaccel = 0; + } + + VectorMA(delta, gaccel * 0.5 * timeRemaining2, gdir, delta); + + if(dist + faccel + gaccel == 0.0) + { + VectorClear(self->velocity); +#if 0 + break; +#else + return; +#endif + } + } + else + { // else apply gravity straight down, no friction + delta[2] -= 0.5 * gravity * timeRemaining2; +// gi.dprintf("Move dropped, accel\n"); + } + + VectorCopy(self->s.origin, end); + Vec3AddAssign(delta, end); + + formMove.end = end; + + gi.TraceBoundingForm(&formMove); + + if(formMove.trace.startsolid) + { + if(fudgeIndex != -1) + { // undo fudge and let it try that again +// gi.dprintf("Fudge undone\n"); + VectorMA(self->s.origin, -PHYSICS_Z_FUDGE, planes[fudgeIndex], self->s.origin); + continue; + } + else + { + VectorClear(self->velocity); + +// gi.dprintf("self %i, trace startsolid on bump %i\n", self->s.number, bumpcount); + return; + } + } + + if(formMove.trace.allsolid) + { // entity is trapped in another solid + VectorClear(self->velocity); + + self->s.origin[2] += 20; + +// gi.dprintf("self %d, trace allsolid\n", self->s.number); + return; + } + + timeMoved = timeRemaining * formMove.trace.fraction; + + if(formMove.trace.fraction > 0) + { // actually covered some distance + VectorCopy(formMove.trace.endpos, self->s.origin); + + if(slide) + { + speed = VectorNormalize2(self->velocity, dir); + + dot = DotProduct(dir, groundNormal); + +// assert(Q_fabs(dot) <= 0.05); + + speed += faccel * timeMoved; + +#if 0 + if(Q_fabs(speed) < friction * 0.05) + { + speed = 0; + } +#endif + + VectorScale(dir, speed, self->velocity); +// gi.dprintf("Full move, slid, speed %f\n", speed); + + VectorMA(self->velocity, gaccel * timeMoved, gdir, self->velocity); + } + else + { +// gi.dprintf("Full move, dropped\n"); + self->velocity[2] -= gravity * timeMoved; + } + + if(formMove.trace.fraction == 1) + { + break; // moved the entire distance + } + + VectorCopy(self->velocity, original_velocity); + + numplanes = 0; + fudgeIndex = -1; + } + else + { +#if 0 + dist = VectorNormalize2(delta, dir); + + if(Q_fabs(DotProduct(dir, formMove.trace.plane.normal)) < 0.01) + { + + } +#endif + if(Vec3IsZero(self->velocity) && self->groundNormal[2] >= (gravity / (friction + gravity))) + { // no velocity, and the trace failed, not going anywhere on ground the ent can't slide on + break; + } +// gi.dprintf("0 trace with %i bumps and %i planes\n", bumpcount, numplanes); + } + + hit = formMove.trace.ent; + + if(bumpcount == MAX_BUMPS - 1) + { // results in isBlocked being called on the last bounced + HandleCollision(self, &formMove.trace, delta, -1, CH_BOUNCED|CH_STANDARD); + } + else + { + HandleCollision(self, &formMove.trace, delta, -1, CH_BOUNCED|CH_ISBLOCKING); + } + + VectorCopy(formMove.trace.plane.normal, groundNormal); + + if(groundNormal[2] > 0 && hit->solid == SOLID_BSP) // hit the floor + { + self->groundentity = formMove.trace.ent; + } + else + { + if(groundNormal[2] < 0.0) + { + groundNormal[2] = 0.0; + } + + self->groundentity = NULL; + } + + timeRemaining -= timeMoved; + + // clipped to another plane + assert(numplanes < MAX_CLIP_PLANES); + + if(!numplanes || !VectorCompare(formMove.trace.plane.normal, planes[numplanes-1])) + { + VectorCopy(formMove.trace.plane.normal, planes[numplanes]); + numplanes++; + } + else + { +// gi.dprintf("Attemping to add identical plane for bump %i\n", bumpcount); +// gi.dprintf("Identical Plane Fudge for bump %i and plane %i\n", bumpcount, numplanes); + fudgeIndex = numplanes-1; + VectorMA(self->s.origin, PHYSICS_Z_FUDGE, planes[fudgeIndex], self->s.origin); + } + + // modify original_velocity so it parallels all of the clip planes + for(i = 0; i < numplanes; ++i) + { + float dirMag; + + assert(Vec3NotZero(planes[i])); + +#if 0 +#define ACCEL_A // velocity is maintained throughout, otherwise, elasticity is accounted for +#endif + +#ifdef ACCEL_A // top version is better for testing sliding with sv_friction at 0 + speed = VectorNormalize2(original_velocity, dir); + +// gi.dprintf("Speed %f\n", speed); + + BounceVelocity(dir, planes[i], dir, 1.0001f); // only works with an elasticity a bit greater than 1.0 + // going to need a different func + // for bouncing stuff + + dirMag = VectorNormalize(dir); + +#else + BounceVelocity(original_velocity, planes[i], new_velocity, self->elasticity); + + dirMag = speed = VectorNormalize2(new_velocity, dir); + +#endif // ACCEL_A + + if(FloatIsZeroEpsilon(dirMag)) + { // smacked into something exactly head on + if(planes[i][2] > 0.0) + { // slide down slope + dir[0] = -planes[i][0]*planes[i][2]; + dir[1] = -planes[i][1]*planes[i][2]; + dir[2] = planes[i][0]*planes[i][0] + planes[i][1]*planes[i][1]; + + VectorNormalize(dir); + } + else + { // drop straight down + dir[2] = -1.0; + } + + } + + dot = DotProduct(dir, planes[i]); + + if(dot < -FLOAT_ZERO_EPSILON) + { // floating point error, shit, fudge it away from the plane a bit +// gi.dprintf("Dot %f, Fudge for bump %i and plane %i\n", dot, bumpcount, i); + fudgeIndex = i; + VectorMA(self->s.origin, PHYSICS_Z_FUDGE, planes[i], self->s.origin); + } + + slide = false; + + if(planes[i][2] > 0.0) + { + if(dot < -0.01) + { // the trace will fail, try to restructure inorder to skip it +#ifdef ACCEL_A + assert(0); // shouldn't happen +#endif // ACCEL_A + } + else if(Q_fabs(dot) < 0.01) // parallel to surface + { + slide = true; + } + else + { // pulling away from surface + } + } + else + { // easy case, fall straight down, no surface friction needed + } + +#ifdef ACCEL_A + if(slide) + { // moving along ground, apply gravity and friction appropriatly + assert(Q_fabs(DotProduct(dir, planes[i])) < 0.1); + + accel = -friction * planes[i][2] - gravity * dir[2]; + speed += accel * timeRemaining; + VectorScale(dir, speed, new_velocity); +// gi.dprintf("Velocity slid, accel %f, speed %f\n", accel, speed); + } + else + { // else apply gravity straight down, no friction + VectorScale(dir, speed, new_velocity); + new_velocity[2] -= gravity * timeRemaining; +// gi.dprintf("Velocity dropped 1, bump %i, plane %i\n", bumpcount, i); +// gi.dprintf("dir %f, %f, %f\n", dir[0], dir[1], dir[2]); + } + +#endif // ACCEL_A + +// gi.dprintf("dirMag %f\n", dirMag); +// gi.dprintf("Speed %f\n", VectorLength(new_velocity)); + +// gi.dprintf("Bounce dot %f\n", dot); + + for(j = 0; j < numplanes; ++j) + { + if(j != i) + { + if(DotProduct(new_velocity, planes[j]) <= 0) + { + break; // unacceptable slide + } + } + } + + if(j == numplanes) + { + break; // acceptable slide + } + } + + if (i != numplanes) + { // good slide + VectorCopy (new_velocity, self->velocity); + +// gi.dprintf("Acceptable slide for bump %i\n", bumpcount); + + } + else + { // go along the crease + assert(numplanes); + + if (numplanes != 2) + { +// gi.dprintf ("slide, numplanes == %i\n",numplanes); + VectorClear(self->velocity); + return; + } + +// gi.dprintf("Unacceptable slide for bump %i\n", bumpcount); + + CrossProduct (planes[0], planes[1], dir); + + speed = VectorLength(self->velocity); + + if(dir[2] <= 0) + { +#ifdef ACCEL_A + accel = -friction * (1 - dir[2]) - gravity * dir[2]; + speed += accel * timeRemaining; +#else + slide = true; +#endif // ACCEL_A + } + + VectorScale(dir, speed, self->velocity); + } + +#ifndef ACCEL_A + speed = VectorNormalize2(self->velocity, dir); + + if(slide) + { // moving along ground, apply gravity and friction appropriatly + accel = -friction * (1 - dir[2]) - gravity * dir[2]; + speed += accel * timeRemaining; + VectorScale(dir, speed, new_velocity); +// gi.dprintf("Velocity slid, accel %f, speed %f\n", accel, speed); + } + else + { // else apply gravity straight down, no friction + VectorScale(dir, speed, new_velocity); + new_velocity[2] -= gravity * timeRemaining; +// gi.dprintf("Velocity dropped 2, bump %i, plane %i\n", bumpcount, i); +// gi.dprintf("dir %f, %f, %f\n", dir[0], dir[1], dir[2]); + } + +#endif // ACCEL_A + + // if velocity is against the original velocity, stop dead + // to avoid tiny occilations in sloping corners +#if 0 // haven't seen a problem with it yet. . . + if(DotProduct(self->velocity, primal_velocity) <= 0) + { + gi.dprintf("Velocity was cleared at bump %i\n", bumpcount); + + VectorClear(self->velocity); + break; + } +#endif + } + + if(formMove.trace.fraction < 1) + { + HandleCollision(self, &formMove.trace, delta, -1, CH_STANDARD); + + if(Vec3NotZero(self->velocity)) + { + VectorClear(self->velocity); +// gi.dprintf("Unsuccesful move with %i bumps and %i planes\n", bumpcount, numplanes); + } + + if(formMove.trace.plane.normal[2] > GROUND_NORMAL) // hit the floor + { + SetGroundEntFromTrace(self, &formMove.trace); + return; + } + } + CheckEntityOn(self); +} + +//--------------------------------------------------------------------------------- +// Searches for any triggers in the entities bounding box and their touch function +//--------------------------------------------------------------------------------- +void ActivateTriggers(edict_t *self) +{ + int num; + edict_t *hit; + GenericUnion4_t found; + SinglyLinkedList_t list; + + // dead things don't activate triggers + if(self->deadState != DEAD_NO) + { + return; + } + + SLList_DefaultCon(&list); // this should be global, initialized at startup + + num = gi.FindEntitiesInBounds(self->mins, self->maxs, &list, AREA_TRIGGERS); + + while(!SLList_IsEmpty(&list)) + { + found = SLList_Pop(&list); + + hit = found.t_edict_p; + + if(!hit->inuse || !hit->touch) + { + continue; + } + + hit->touch(hit, self, NULL, NULL); + } + + SLList_Des(&list); // kill on shut down +} + +//--------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------- +void ApplyRotationalFriction(edict_t *self) +{ + int i; + float adjustment; + + VectorMA(self->s.angles, FRAMETIME, self->avelocity, self->s.angles); + + adjustment = FRAMETIME * FRICTION_STOPSPEED * FRICTION_SURFACE; + + for(i = 0; i < 3; ++i) + { + if(self->avelocity[i] > 0.0) + { + self->avelocity[i] -= adjustment; + + if(self->avelocity[i] < 0.0) + { + self->avelocity[i] = 0.0; + } + } + else + { + self->avelocity[i] += adjustment; + + if(self->avelocity[i] > 0.0) + { + self->avelocity[i] = 0.0; + } + } + } +} + +//--------------------------------------------------------------------------------- +// Sets the groundentity info contained in self based on trace +//--------------------------------------------------------------------------------- +void SetGroundEntFromTrace(edict_t *self, trace_t *trace) +{ + assert(self); + + assert(trace->plane.normal[2] > GROUND_NORMAL); + + self->groundentity = trace->ent; + + self->groundentity_linkcount = trace->ent->linkcount; + + VectorCopy(trace->plane.normal, self->groundNormal); +} + +//--------------------------------------------------------------------------------- +// Sets the blockingEntity info contained in self based on trace +//--------------------------------------------------------------------------------- +void SetBlockingEntFromTrace(edict_t *self, trace_t *trace) +{ + assert(self); + + self->blockingEntity = trace->ent; + + self->blockingEntity_linkcount = trace->ent->linkcount; + + VectorCopy(trace->plane.normal, self->blockingNormal); +} + +//--------------------------------------------------------------------------------- +// Determines if the self is in the water; if so, how submereged the self is +//--------------------------------------------------------------------------------- +void CheckInWater(FormMove_t *formMove) +{ + int contents; + float halfHeight; + + assert(formMove); + + contents = gi.GetContentsAtPoint(formMove->start); + + if(!(contents & MASK_WATER)) + { + formMove->waterLevel = 0; + formMove->waterType = 0; + return; + } + + formMove->waterType = contents; + formMove->waterLevel = 1; + + halfHeight = (formMove->maxs[2] - (formMove->mins[2] + 1.0)) * 0.5; + + formMove->start[2] += halfHeight; + + contents = gi.GetContentsAtPoint(formMove->start); + + if(!(contents & MASK_WATER)) + { + return; + } + + formMove->waterLevel = 2; + + formMove->start[2] += halfHeight; + + contents = gi.GetContentsAtPoint(formMove->start); + + if(contents & MASK_WATER) + { + formMove->waterLevel = 3; + } +} + +//--------------------------------------------------------------------------------- +// Returns false if any part of the bottom of the entity is off an edge that +// is not a staircase. +//--------------------------------------------------------------------------------- +qboolean CheckFooting(edict_t *self, vec3_t origin) +{ + vec3_t mins, maxs, start, stop; + int x, y; + float mid, bottom; + qboolean solid; + float stepHeight = classStatics[self->classID].moveInfo->stepHeight; + FormMove_t formMove; + + VectorAdd(origin, self->mins, mins); + VectorAdd(origin, self->maxs, maxs); + + // if all of the points under the corners are solid world, don't bother + // with the tougher checks + start[2] = mins[2] - 1; + + for(x = 0; x <= 1; ++x) + { + for(y = 0; y <= 1; ++y) + { + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + + if(gi.GetContentsAtPoint(start) != CONTENTS_SOLID) + { + solid = false; + } + } + } + + if(solid) + { + return true; + } + + start[0] = stop[0] = (mins[0] + maxs[0])*0.5; + start[1] = stop[1] = (mins[1] + maxs[1])*0.5; + start[2] = mins[2]; + + stop[2] = start[2] - 2*stepHeight; + + VectorClear(formMove.mins); + VectorClear(formMove.maxs); + + formMove.start = start; + formMove.end = stop; + formMove.passEntity = self; + formMove.clipMask = MASK_MONSTERSOLID; + + gi.TraceBoundingForm(&formMove); + + if(formMove.trace.fraction == 1.0) + { + return false; + } + + mid = bottom = formMove.trace.endpos[2]; + + for(x = 0; x <= 1; ++x) + { + for(y = 0; y <= 1; ++y) + { + start[0] = stop[0] = x ? maxs[0] : mins[0]; + start[1] = stop[1] = y ? maxs[1] : mins[1]; + + formMove.start = start; + formMove.end = stop; + + gi.TraceBoundingForm(&formMove); + + if(formMove.trace.fraction != 1.0 && formMove.trace.endpos[2] > bottom) + { + bottom = formMove.trace.endpos[2]; + } + + if(formMove.trace.fraction == 1.0 || mid - formMove.trace.endpos[2] > stepHeight) + { + return false; + } + } + } + + return true; +} + +static void DiscreteMove_Step_FailedDueToCollision(edict_t *self, vec3_t move, FormMove_t *formMove, qboolean forceful) +{ + if(!(formMove->processFlags & PPF_INFO_GRAB)) + { + SetBlockingEntFromTrace(self, &formMove->trace); + HandleCollision(self, &formMove->trace, move, (self->physicsFlags & PF_FORCEFUL_COLLISIONS) & forceful, CH_STANDARD); + } +} + +//--------------------------------------------------------------------------------- +// Attempts to move self as specified by move. Allows walking on slopes up to +// GROUND_NORMAL, steps up or down to classStatics[self->classID].self->stepHeight, +// will drio off edges up to classStatics[self->classID].self->dropHeight, +// won't enter water higher than level 2 +// +// Supports PPF_INFO_GRAB for checking a step without actually moving +//--------------------------------------------------------------------------------- +qboolean DiscreteMove_Step(edict_t *self, vec3_t move, FormMove_t *formMove) +{ + vec3_t neworg, start, end; + float traceLength; + vec3_t test; + qboolean stepUp = false, setGroundEnt = false; + + assert(self); + assert(formMove); + + if(self->physicsFlags & PF_RESIZE) + { + if(gi.ResizeBoundingForm(self, formMove)) + { + self->physicsFlags &= ~PF_RESIZE; + } + else + { + return false; + } + } + + VectorAdd(self->s.origin, move, neworg); + +#ifdef NONCLIENT_PRIMITIVE_DISPLAY_HACK + { + paletteRGBA_t color; + vec3_t origin; + + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + + VectorCopy(self->s.origin, origin); + origin[2] += 100.0; + AddServerParticle(origin, color, 2, 5); + + VectorCopy(neworg, origin); + origin[2] += 100.0; + AddServerParticle(origin, color, 2, 5); + } +#endif + + start[0] = end[0] = neworg[0]; + start[1] = end[1] = neworg[1]; + start[2] = neworg[2] + formMove->stepHeight; + + if(neworg[2] > self->s.origin[2]) + { + end[2] = self->s.origin[2] - formMove->dropHeight; + stepUp = true; + } + else + { + end[2] = neworg[2] - formMove->dropHeight; + } + + traceLength = start[2] - end[2]; + + VectorCopy(self->mins, formMove->mins); + VectorCopy(self->maxs, formMove->maxs); + + formMove->start = start; + formMove->end = end; + formMove->passEntity = self; + formMove->clipMask = self->clipmask; + + gi.TraceBoundingForm(formMove); + + if(formMove->trace.allsolid) + { + end[2] = neworg[2] + 0.25f; + + // find out what's blocking it + formMove->start = self->s.origin; + + gi.TraceBoundingForm(formMove); + + DiscreteMove_Step_FailedDueToCollision(self, move, formMove, true); + return false; + } + + if(formMove->trace.startsolid) + { + start[2] = neworg[2] + 0.25f; + + traceLength = start[2] - end[2]; + + formMove->start = start; + + gi.TraceBoundingForm(formMove); + + if(formMove->trace.allsolid) + { + // find out what's blocking it + formMove->start = self->s.origin; + formMove->end = neworg; + + gi.TraceBoundingForm(formMove); + + DiscreteMove_Step_FailedDueToCollision(self, move, formMove, true); + return false; + } + + if(formMove->trace.startsolid) + { + // find out what's blocking it + formMove->start = self->s.origin; + formMove->end = neworg; + + gi.TraceBoundingForm(formMove); + + DiscreteMove_Step_FailedDueToCollision(self, move, formMove, true); + return false; + } + } + + test[0] = formMove->trace.endpos[0]; + test[1] = formMove->trace.endpos[1]; + test[2] = formMove->trace.endpos[2] + self->mins[2] + 1; + + formMove->start = test; + + CheckInWater(formMove); + + // don't go into deep water + if(formMove->waterLevel > 2) + { + return false; + } + + // don't walk off edges + if(formMove->trace.fraction == 1) + { + return false; + } + +#if 0 + // check point traces down for dangling corners + if(!CheckFooting(self, formMove->trace.endpos)) + { + return false; + } +#endif + + if(stepUp || formMove->trace.endpos[2] >= neworg[2] - formMove->dropHeight) + { + // make sure its still on the ground + if(formMove->trace.plane.normal[2] > GROUND_NORMAL) + { + setGroundEnt = true; + } + else + { + DiscreteMove_Step_FailedDueToCollision(self, move, formMove, !stepUp); + return false; + } + } + + if(!(formMove->processFlags & PPF_INFO_GRAB)) + { // finalize new position + self->waterlevel = formMove->waterLevel; + self->watertype = formMove->waterType; + + self->flags &= ~FL_INWATER; + + if(formMove->waterLevel) + { + self->flags |= FL_INWATER; + } + + if(setGroundEnt) + { // step up or down maintaing contact with the ground + SetGroundEntFromTrace(self, &formMove->trace); + VectorCopy(formMove->trace.endpos, self->s.origin); + } + else + { // drop off and edge + self->groundentity = NULL; + VectorCopy(neworg, self->s.origin); + + // should probably set a velocity here also + } + + gi.linkentity(self); + ActivateTriggers(self); + } + + return true; +} + +void CreateMove_Step(edict_t *self, vec3_t move, float dist) +{ + float yaw, pitch; + float cosYaw; + float sinYaw; + + assert(self->groundentity); // need a groundentity if groundNormal is to be used + +// assert(self->groundNormal[2] > GROUND_NORMAL); + + yaw = self->s.angles[YAW]*ANGLE_TO_RAD + self->yawOffset; + + cosYaw = cos(yaw); + sinYaw = sin(yaw); + + move[0] = cosYaw; + move[1] = sinYaw; + move[2] = 0; + + pitch = acos(DotProduct(self->groundNormal, move)) - ANGLE_90; + + // adjust for sloped ground + if(pitch) + { + float cosPitch; + + cosPitch = cos(pitch); + + move[0] = cosYaw*cosPitch; + move[1] = sinYaw*cosPitch; + move[2] = sin(pitch); + } + + Vec3ScaleAssign(dist, move); +} + +//--------------------------------------------------------------------------------- +//The move will be adjusted for slopes and stairs, but if the move isn't +//possible, no move is done, false is returned +// +// FINISH ME!!! These need a lot more work. +// +//--------------------------------------------------------------------------------- + +void AttemptAdjustOriginToValidPosition(vec3_t adjustFrom, edict_t *self, vec3_t origin) +{ + FormMove_t formMove; + + VectorCopy(self->mins, formMove.mins); + VectorCopy(self->maxs, formMove.maxs); + + formMove.start = adjustFrom; + formMove.end = origin; + formMove.passEntity = self; + formMove.clipMask = self->clipmask; + + gi.TraceBoundingForm(&formMove); + + if(!(formMove.trace.allsolid || formMove.trace.startsolid)) + { + VectorCopy(formMove.trace.endpos, origin); + } + else + { + VectorCopy(adjustFrom, origin); + } +} + +qboolean CheckAnimMove(edict_t *self, vec3_t origin, vec3_t move, float *dist, float attemptDist, int recursionLevel) +{ + vec3_t desiredOrigin, end, temp; + float stepHeight, tempDist; + FormMove_t formMove, stepFormMove; + vec3_t test; + vec3_t adjustFrom, fudgeOrigin; + + if(!checkanim->value) + { // globally disablled, allow full move + *dist = attemptDist; + return true; + } + +#if 1 + if(recursionLevel > 10) + { +// gi.dprintf("trace startsolid in CheckAnimMove, recursion > 10, failing\n"); + return false; + } +#endif + + stepHeight = classStatics[self->classID].moveInfo->stepHeight; + + VectorCopy(origin, fudgeOrigin); + fudgeOrigin[2] += 1.0; + + VectorAdd(fudgeOrigin, move, desiredOrigin); + + VectorCopy(self->mins, formMove.mins); + VectorCopy(self->maxs, formMove.maxs); + + formMove.start = origin; + formMove.end = desiredOrigin; + formMove.passEntity = self; + formMove.clipMask = self->clipmask; + + gi.TraceBoundingForm(&formMove); + + if(formMove.trace.startsolid) + { + if(!Vec3IsZero(formMove.trace.plane.normal)) + { + if(formMove.trace.plane.normal[2] > 0) + { +// gi.dprintf("trace startsolid in CheckAnimMove, attempting to adjust with normal\n"); + + VectorMA(origin, 20.0, formMove.trace.plane.normal, adjustFrom); + + AttemptAdjustOriginToValidPosition(adjustFrom, self, origin); + + return CheckAnimMove(self, origin, move, dist, attemptDist, recursionLevel + 1); + } + else + { +// gi.dprintf("trace startsolid in CheckAnimMove, bad normal\n"); + } + } + else + { +// gi.dprintf("trace startsolid in CheckAnimMove, attempting to adjust without normal\n"); + + VectorCopy(origin, adjustFrom); + + adjustFrom[2] += 20.0; + + AttemptAdjustOriginToValidPosition(adjustFrom, self, origin); + + return CheckAnimMove(self, origin, move, dist, attemptDist, recursionLevel + 1); + } + } + + if(formMove.trace.allsolid) + { +// gi.dprintf("trace allsolid in CheckAnimMove, attempting to adjust without normal\n"); + + VectorCopy(origin, adjustFrom); + + adjustFrom[2] += 20.0; + + AttemptAdjustOriginToValidPosition(adjustFrom, self, origin); + + return CheckAnimMove(self, origin, move, dist, attemptDist, recursionLevel + 1); + } + + VectorScale(move, formMove.trace.fraction, temp); + + tempDist = VectorLength(temp); + +// gi.dprintf("tempDist %f\n", tempDist); + + if(tempDist + *dist < TRACE_FRACTION_FAIL_FOR_WHOLE_MOVE_CHECK*attemptDist) + { + if(recursionLevel) + { + // don't try to step on recursive calls if the surface isn't ground, or + // it was only able to move a little forward + if(formMove.trace.plane.normal[2] <= GROUND_NORMAL || + tempDist < stepHeight) + { + return false; + } + } + + *dist += tempDist; + +// gi.dprintf("Recursion with fraction %f dist %f\n", formMove.trace.fraction, *dist); + + VectorAdd(origin, temp, adjustFrom); + + adjustFrom[2] += stepHeight; + + Vec3ScaleAssign(1.0 - formMove.trace.fraction, move); + + return CheckAnimMove(self, adjustFrom, move, dist, attemptDist, recursionLevel + 1); + } + + VectorMA(fudgeOrigin, formMove.trace.fraction, move, desiredOrigin); + + // Check for going off an edge + end[0] = desiredOrigin[0]; + end[1] = desiredOrigin[1]; + + if(desiredOrigin[2] > origin[2]) + { + end[2] = origin[2] - stepHeight; + } + else + { + end[2] = desiredOrigin[2] - stepHeight; + } + + VectorCopy(formMove.mins, stepFormMove.mins); + VectorCopy(formMove.maxs, stepFormMove.maxs); + + stepFormMove.start = desiredOrigin; + stepFormMove.end = end; + stepFormMove.passEntity = self; + stepFormMove.clipMask = self->clipmask; + + gi.TraceBoundingForm(&stepFormMove); + + if(stepFormMove.trace.startsolid) + { +// gi.dprintf("stepTrace startsolid CheckAnimMove\n"); + return false; +// stepFormMove.trace.fraction = 0.0; + } + + if(stepFormMove.trace.allsolid) + { +// gi.dprintf("stepTrace allsolid CheckAnimMove\n"); + return false; +// stepFormMove.trace.fraction = 0.0; + } + + // may have walked off an edge + if(stepFormMove.trace.fraction == 1.0) + { + VectorCopy(origin, adjustFrom); + + adjustFrom[2] = stepFormMove.trace.endpos[2]; + + stepFormMove.start = stepFormMove.trace.endpos; + stepFormMove.end = adjustFrom; + + gi.TraceBoundingForm(&stepFormMove); + + VectorCopy(temp, move); + + Vec3ScaleAssign(1.0 - stepFormMove.trace.fraction, temp); + + tempDist = VectorLength(temp); + + if(recursionLevel) + { + // don't try to step on recursive calls if the surface isn't ground, or + // it was only able to move a little forward + if(stepFormMove.trace.plane.normal[2] <= GROUND_NORMAL || + tempDist < stepHeight) + { + return false; + } + } + + *dist += tempDist; + + Vec3AddAssign(temp, adjustFrom); + +// gi.dprintf("Step off recursion with fraction %f dist %f\n", stepFormMove.trace.fraction, *dist); + + Vec3ScaleAssign(formMove.trace.fraction, move); + + return CheckAnimMove(self, adjustFrom, move, dist, attemptDist, recursionLevel + 1); + } + + // stepped up onto something it can't stand on + if(stepFormMove.trace.plane.normal[2] <= GROUND_NORMAL) + { + return false; + } + + // don't go into water + if(self->waterlevel == 0.0) + { + test[0] = stepFormMove.trace.endpos[0]; + test[1] = stepFormMove.trace.endpos[1]; + test[2] = stepFormMove.trace.endpos[2] + self->mins[2] + 1; + + stepFormMove.start = test; + + CheckInWater(&stepFormMove); + + // probably want to actually let monsters wade + if(self->flags & FL_INWATER) + { + self->waterlevel = 0; + self->watertype = 0; + + self->flags &= ~FL_INWATER; + return false; + } + } + + VectorScale(move, formMove.trace.fraction, temp); + + *dist += VectorLength(temp); + + return true; +} + +edict_t *TestEntityPosition(edict_t *self) +{ + FormMove_t formMove; + + VectorCopy(self->mins, formMove.mins); + VectorCopy(self->maxs, formMove.maxs); + + formMove.start = self->s.origin; + formMove.end = self->s.origin; + formMove.passEntity = self; + formMove.clipMask = self->clipmask; + + gi.TraceBoundingForm(&formMove); + + if(formMove.trace.startsolid) + { + return g_edicts; + } + + return NULL; +} + +typedef struct +{ + edict_t *ent; + vec3_t origin; + vec3_t angles; + float deltayaw; +} pushed_t; +pushed_t pushed[MAX_EDICTS], *pushed_p; + +edict_t *obstacle; + +#define MAX_MATRIX (3) + +static void BackSub(float a[][MAX_MATRIX],int *indx,float *b,int sz) +{ + int i,j,ii=-1,ip; + float sum; + for (i=0;i=0) + { + for (j=ii;j=0;i--) + { + sum=b[i]; + for (j=i+1;jbig) + big=temp; + if (big=big) + { + big=dum; + imax=i; + } + } + if (j!=imax) + { + for (k=0;kabsmin[0]+move[0]; + maxs[0]=pusher->absmax[0]; + } + else + { + mins[0]=pusher->absmin[0]; + maxs[0]=pusher->absmax[0]+move[0]; + } + if (move[1]<0) + { + mins[1]=pusher->absmin[1]+move[1]; + maxs[1]=pusher->absmax[1]; + } + else + { + mins[1]=pusher->absmin[1]; + maxs[1]=pusher->absmax[1]+move[1]; + } + if (move[2]<0) + { + mins[2]=pusher->absmin[2]+move[2]; + maxs[2]=pusher->absmax[2]; + } + else + { + mins[2]=pusher->absmin[2]; + maxs[2]=pusher->absmax[2]+move[2]; + } + +// we need this for pushing things later +#if GIL_PUSH + VectorCopy(pusher->s.angles, org); + Vec3AddAssign(amove, org); + AngleVectors(org, forward, right, up); +/* + a[0][0]=forward[0]; + a[0][1]=forward[1]; + a[0][2]=forward[2]; + a[1][0]=-right[0]; + a[1][1]=-right[1]; + a[1][2]=-right[2]; + a[2][0]=up[0]; + a[2][1]=up[1]; + a[2][2]=up[2]; +*/ + a[0][0]=forward[0]; + a[1][0]=forward[1]; + a[2][0]=forward[2]; + a[0][1]=-right[0]; + a[1][1]=-right[1]; + a[2][1]=-right[2]; + a[0][2]=up[0]; + a[1][2]=up[1]; + a[2][2]=up[2]; + if (LUDecomposition(a,indx,3,&d)) + { + VectorSet(forwardInv, 1.0, 0.0, 0.0); + BackSub(a,indx,forwardInv,3); + VectorSet(rightInv, 0.0, 1.0, 0.0); + BackSub(a,indx,rightInv,3); + VectorSet(upInv, 0.0, 0.0, 1.0); + BackSub(a,indx,upInv,3); + } + else + { + VectorClear(forwardInv); + VectorClear(rightInv); + VectorClear(upInv); + } + AngleVectors(pusher->s.angles, forward, right, up); +#else + VectorNegate(amove, org); + AngleVectors(org, forward, right, up); +#endif + +// save the pusher's original position + pushed_p->ent = pusher; + + VectorCopy(pusher->s.origin, pushed_p->origin); + VectorCopy(pusher->s.angles, pushed_p->angles); + + if(pusher->client) + { + pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW]; + } + + pushed_p++; + +// move the pusher to it's final position +#if GIL_PUSH + VectorCopy(pusher->s.origin,OrgOrg); +#endif + Vec3AddAssign(move, pusher->s.origin); + Vec3AddAssign(amove, pusher->s.angles); + + gi.linkentity(pusher); + +// see if any solid entities are inside the final position + check = g_edicts+1; + + for(e = 1; e < globals.num_edicts; ++e, ++check) + { + if(!check->inuse) + { + continue; + } + + switch(check->movetype) + { + case PHYSICSTYPE_PUSH: + case PHYSICSTYPE_STOP: + case PHYSICSTYPE_NONE: + case PHYSICSTYPE_NOCLIP: + continue; + } + + // if the entity is standing on the pusher, it will definitely be moved + if(check->groundentity != pusher) + { + // see if the self needs to be tested + if(check->absmin[0] >= maxs[0] + || check->absmin[1] >= maxs[1] + || check->absmin[2] >= maxs[2] + || check->absmax[0] <= mins[0] + || check->absmax[1] <= mins[1] + || check->absmax[2] <= mins[2]) + continue; + + // see if the self's bbox is inside the pusher's final position + if(!TestEntityPosition(check)) + { + continue; + } + } + + if((pusher->movetype == PHYSICSTYPE_PUSH) || (check->groundentity == pusher)) + { + // move this entity + pushed_p->ent = check; + + VectorCopy(check->s.origin, pushed_p->origin); + VectorCopy(check->s.angles, pushed_p->angles); + VectorCopy(check->s.origin, holdOrg); + + ++pushed_p; + + // try moving the contacted entity + + if(check->client) + { // FIXME: doesn't rotate monsters? + check->client->ps.pmove.delta_angles[YAW] += amove[YAW]; + } + // figure movement due to the pusher's amove +#if GIL_PUSH + { + int test; + vec3_t testpnt; + for (test=0;test<4;test++) + { + VectorCopy(holdOrg,testpnt); + VectorCopy(holdOrg,check->s.origin); + testpnt[2]+=check->mins[2]; + if (test&1) + testpnt[0]+=check->mins[0]; + else + testpnt[0]+=check->maxs[0]; + if (test&2) + testpnt[1]+=check->mins[1]; + else + testpnt[1]+=check->maxs[1]; + + VectorSubtract(testpnt, OrgOrg, org); + Vec3AddAssign(move, check->s.origin); + org2[0] = DotProduct(org, forward); + org2[1] = -DotProduct(org, right); + org2[2] = DotProduct(org, up); + move2[0]=DotProduct(org2,forwardInv)-org[0]; + move2[1]=DotProduct(org2,rightInv)-org[1]; + move2[2]=DotProduct(org2,upInv)-org[2]; + Vec3AddAssign(move2, check->s.origin); + + // may have pushed them off an edge + if(check->groundentity != pusher) + { + check->groundentity = NULL; + } + + block = TestEntityPosition(check); + if(!block) + break; + } + } +#else + Vec3AddAssign(move, check->s.origin); + VectorSubtract(check->s.origin, pusher->s.origin, org); + org2[0] = DotProduct(org, forward); + org2[1] = -DotProduct(org, right); + org2[2] = DotProduct(org, up); + VectorSubtract(org2, org, move2); + Vec3AddAssign(move2, check->s.origin); + + // may have pushed them off an edge + if(check->groundentity != pusher) + { + check->groundentity = NULL; + } + + block = TestEntityPosition(check); +#endif + + if(!block) + { // pushed ok + gi.linkentity (check); + + if(check->client) + { + check->client->playerinfo.flags|=PLAYER_FLAG_USE_ENT_POS; + } + + // impact? + continue; + } + // if it is ok to leave in the old position, do it + // this is only relevent for riding entities, not pushed + + // No good, (A+B)-B!=A + //Vec3SubtractAssign(move, check->s.origin); + //Vec3SubtractAssign(move2, check->s.origin); + + VectorCopy(holdOrg,check->s.origin); + block = TestEntityPosition(check); + + if(!block) + { + --pushed_p; + continue; + } + } + + // save off the obstacle so we can call the block function + obstacle = check; + + // move back any entities we already moved + // go backwards, so if the same entity was pushed + // twice, it goes back to the original position + for(p = pushed_p - 1; p >= pushed; --p) + { + VectorCopy(p->origin, p->ent->s.origin); + VectorCopy(p->angles, p->ent->s.angles); + + if(p->ent->client) + { + p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw; + } + + gi.linkentity(p->ent); + } + + return false; + } + + //FIXME: is there a better way to handle this? + // see if anything we moved has touched a trigger + for(p = pushed_p - 1; p >= pushed; --p) + { + ActivateTriggers (p->ent); + } + + return true; +} + +/* +================ +Physics_Push + +Bmodel objects don't interact with each other, but +push all box objects +================ +*/ +void Physics_Push(edict_t *self) +{ + vec3_t move, amove; + edict_t *part, *mv; + + // Not a team captain, so movement will be handled elsewhere + if(self->flags & FL_TEAMSLAVE) + { + return; + } + + // make sure all team slaves can move before commiting + // any moves or calling any think functions + // if the move is blocked, all moved objects will be backed out + pushed_p = pushed; + + for(part = self; part; part = part->teamchain) + { + if(Vec3NotZero(part->velocity) || Vec3NotZero(part->avelocity)) + { // object is moving + VectorScale (part->velocity, FRAMETIME, move); + VectorScale (part->avelocity, FRAMETIME, amove); + + if(!PushEntities(part, move, amove)) + { + break; // move was blocked + } + } + } + + if(pushed_p > &pushed[MAX_EDICTS]) + { + gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted"); + } + + if(part) + { + // the move failed, bump all nextthink times and back out moves + for(mv = self; mv; mv = mv->teamchain) + { + if(mv->nextthink > 0) + { + mv->nextthink += FRAMETIME; + } + } + + // if the pusher has a "blocked" function, call it + // otherwise, just stay in place until the obstacle is gone + if(part->blocked) + { + part->blocked(part, obstacle); + } + } + else + { + // the move succeeded, so call all think functions + for(part = self; part; part = part->teamchain) + { + if(ThinkTime(part)) + { + part->think(part); + } + } + } +} + +static void Physics_ScriptAngular(edict_t *self) +{ + vec3_t forward, dest, angle; + + if (self->owner) + { + VectorAdd(self->owner->s.angles, self->moveinfo.start_angles, angle); + if (self->moveinfo.state & 1) + { + AngleVectors(angle, NULL, forward, NULL); + } + else + { + AngleVectors(angle, NULL, NULL, forward); + } + VectorInverse(forward); + VectorMA(self->moveinfo.start_origin, self->moveinfo.distance, forward, dest); + // Distance moved this frame + Vec3SubtractAssign(self->s.origin, dest); + // Hence velocity + VectorScale(dest, (1.0 / FRAMETIME), self->velocity); + + if (self->moveinfo.state & 1) + { + VectorCopy(angle, self->s.angles); + } + } + Physics_Push(self); +} diff --git a/Toolkit/Programming/GameCode/game/g_Physics.h b/Toolkit/Programming/GameCode/game/g_Physics.h new file mode 100644 index 0000000..7c1562a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_Physics.h @@ -0,0 +1,45 @@ +#ifndef G_PHYSICS_H +#define G_PHYSICS_H + +#include "g_BoundingForm.h" +#include "q_Physics.h" + +#define FRICTION_STOPSPEED 100 +#define FRICTION_SURFACE 6 +#define FRICTION_WATER 1 + +#define MONSTER_STEPHEIGHT 30 +#define MONSTER_DROPHEIGHT 100 + +#define TRACE_FRACTION_FAIL_FOR_WHOLE_MOVE_CHECK 0.8 + +#define PF_ROTATIONAL_FRICTION 0x00000001 // angular friction +#define PF_RESIZE 0x00000002 // indicates the ents bounding form should be resized +#define PF_FORCEFUL_COLLISIONS 0x00000004 // the ent will knockback of other ents, and get knockback during + // collision resolution + +#define CH_ISBLOCKED 0x00000001 +#define CH_ISBLOCKING 0x00000002 +#define CH_BOUNCED 0x00000004 + +#define CH_STANDARD (CH_ISBLOCKED|CH_ISBLOCKING) + +extern void EntityPhysics(edict_t *ent); +extern void CheckEntityOn(edict_t *ent); +extern void ApplyGravity(edict_t *self, vec3_t move); +extern void HandleCollision(edict_t *self, trace_t *trace, vec3_t move, int forceful, int flags); +extern void HandleForcefulCollision(edict_t *forcer, edict_t *forcee, vec3_t move, int forceful); +extern void MoveEntity_Bounce(edict_t *self, FormMove_t *formMove); +extern void MoveEntity_Slide(edict_t *ent); +extern void ActivateTriggers(edict_t *ent); +extern qboolean ApplySurfaceFriction(edict_t *self); +extern void ApplyRotationalFriction(edict_t *ent); +extern void SetGroundEntFromTrace(edict_t *self, trace_t *trace); +extern void SetBlockingEntFromTrace(edict_t *self, trace_t *trace); +extern void CheckInWater(FormMove_t *formMove); +extern qboolean DiscreteMove_Step(edict_t *self, vec3_t move, FormMove_t *formMove); +extern void CreateMove_Step(edict_t *self, vec3_t move, float dist); + +qboolean CheckAnimMove(edict_t *self, vec3_t origin, vec3_t move, float *dist, float attemptDist, int recursionLevel); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_PhysicsInfo.c b/Toolkit/Programming/GameCode/game/g_PhysicsInfo.c new file mode 100644 index 0000000..b2c65e9 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_PhysicsInfo.c @@ -0,0 +1,45 @@ +#if 0 +#include "g_PhysicsInfo.h" +#include "ResourceManager.h" +#include "g_BoundingForm.h" + +#include + +static ResourceManager_t PhysicsInfoMngr; + +void InitPhysicsInfoMngr() +{ +#define PHYSICSINFO_BLOCK_SIZE 64 + + ResMngr_Con(&PhysicsInfoMngr, sizeof(PhysicsInfo_t), PHYSICSINFO_BLOCK_SIZE); +} + +void ReleasePhysicsInfoMngr() +{ + ResMngr_Des(&PhysicsInfoMngr); +} + +PhysicsInfo_t *PhysicsInfo_new() +{ + PhysicsInfo_t *newInfo; + + newInfo = ResMngr_AllocateResource(&PhysicsInfoMngr, sizeof(*newInfo)); + + memset(newInfo, 0, sizeof(*newInfo)); + + newInfo->gravity = 1.0f; + newInfo->friction = 1.0f; + + return newInfo; +} + +void PhysicsInfo_delete(PhysicsInfo_t *toDelete) +{ + if(toDelete->intentBoundingForm) + { + BoundingForm_delete(toDelete->intentBoundingForm); + } + + ResMngr_DeallocateResource(&PhysicsInfoMngr, toDelete, sizeof(*toDelete)); +} +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_PhysicsInfo.h b/Toolkit/Programming/GameCode/game/g_PhysicsInfo.h new file mode 100644 index 0000000..90c3592 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_PhysicsInfo.h @@ -0,0 +1,54 @@ +#ifndef G_PHYSICSINFO_H +#define G_PHYSICSINFO_H + +#if 0 +#include "q_Typedef.h" + + +typedef struct PhysicsInfo_s +{ + int type; + + int flags; + + float *origin; // pointer to owning entities origin vector + + vec3_t velocity; // linear velocity + vec3_t avelocity; // angular velocity + + int mass; + float gravity; // gravity multiplier; defaults to 1.0 + float friction; // friction multiplier; defaults to 1.0 + // Used to determine whether something will stop, slide, or bounce on impact + float elasticity; + + // Used for determining effects of liquids in the environment. + int watertype; // Used to indicate current liquid actor is in. + int waterlevel; // Used by monsters and players and grenades. + + + // called when self is the collider in a collision + void (*isBlocked)(edict_t *self, struct trace_s *trace); + + // called when self is the collidee in a collision + void (*isBlocking)(edict_t *self, struct trace_s *trace); + + edict_t *groundentity; // entity serving as ground + int groundentity_linkcount; // if self and groundentity's don't match, groundentity should be cleared + vec3_t groundNormal; // normal of the ground + + edict_t *blockingEntity; // entity serving as ground + int blockingEntity_linkcount; // if self and blockingEntity's don't match, blockingEntity should be + // cleared + vec3_t blockingNormal; // normal of the blocking surface + + struct BoundingForm_s *intentBoundingForm;// if PF_RESIZE is set, then physics will attempt to change + // the ents bounding form to the new one indicated + // If it was succesfully resized, the PF_RESIZE is turned off + // otherwise it will remain on. +} PhysicsInfo_t; + +extern PhysicsInfo_t *PhysicsInfo_new(); +extern void PhysicsInfo_delete(PhysicsInfo_t *toDelete); +#endif +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_ResourceManagers.c b/Toolkit/Programming/GameCode/game/g_ResourceManagers.c new file mode 100644 index 0000000..246a1e8 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_ResourceManagers.c @@ -0,0 +1,22 @@ +void InitMsgMngr(); +void ReleaseMsgMngr(); +#if G_NEW_SYSTEM +void InitBoundingFormMngr(); +void ReleaseBoundingFormMngr(); +#endif + +void G_InitResourceManagers() +{ + InitMsgMngr(); +#if G_NEW_SYSTEM + InitBoundingFormMngr(); +#endif +} + +void G_ReleaseResourceManagers() +{ + ReleaseMsgMngr(); +#if G_NEW_SYSTEM + ReleaseBoundingFormMngr(); +#endif +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_Skeletons.c b/Toolkit/Programming/GameCode/game/g_Skeletons.c new file mode 100644 index 0000000..2052bc1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_Skeletons.c @@ -0,0 +1,176 @@ +// +// g_Skeletons.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#include "g_Skeletons.h" +#include "ArrayedList.h" + +#include "g_local.h" + +#include + +G_SkeletalJoint_t skeletalJoints[MAX_ARRAYED_SKELETAL_JOINTS]; +ArrayedListNode_t jointNodes[MAX_ARRAYED_JOINT_NODES]; + +// ******************************************************************** +// Skeleton Managment stuff +// ******************************************************************** + +static int GetRootIndex(int max, int numJoints) +{ + int i, j, max2; + qboolean cont = false; + + for(i = 0; i < max; ++i) + { + if(!skeletalJoints[i].inUse) + { + max2 = i + numJoints; + + // check the size of the array + if(max2 > max) + { + assert(0); + return -1; + } + + // check for a big enough unused block + for(j = i + 1; j < max2; ++j) + { + if(skeletalJoints[j].inUse) + { + i = j; + cont = true; + break; + } + } + + if(cont) // not a big enough block, so continue searching + { + cont = false; + continue; + } + + // found a block, mark it as used + for(j = i; j < max2; ++j) + { + skeletalJoints[j].inUse = true; + } + + return i; + } + } + + // couldn't find a block + assert(0); + return -1; +} + +int CreateSkeleton(int structure) +{ + int index; + + index = GetRootIndex(MAX_ARRAYED_SKELETAL_JOINTS, numJointsInSkeleton[structure]); + + SkeletonCreators[structure](skeletalJoints, sizeof(G_SkeletalJoint_t), jointNodes, index); + + return index; +} + +void FreeSkeleton(int root) +{ + int child; + + for(child = skeletalJoints[root].children; child != ARRAYEDLISTNODE_NULL; child = jointNodes[child].next) + { + FreeSkeleton(jointNodes[child].data); + + FreeNode(jointNodes, child); + } + + skeletalJoints[root].inUse = false; +} + +void UpdateSkeletons() +{ + int i, j; + + for(i = 0; i < MAX_ARRAYED_SKELETAL_JOINTS; ++i) + { + G_SkeletalJoint_t *joint; + joint = &skeletalJoints[i]; + + if(joint->inUse) + { + for(j = 0; j < 3; ++j) + { + float destAngle, *angle; + + joint->changed[j] = false; + destAngle = joint->destAngles[j]; + angle = joint->angles + j; + + if(*angle != destAngle) + { + *angle += joint->angVels[j]*FRAMETIME; + + if(joint->angVels[j] > 0) + { + if(*angle > destAngle) + { + *angle = destAngle; + } + } + else if(joint->angVels[j] < 0) + { + if(*angle < destAngle) + { + *angle = destAngle; + } + } + } + } + } + } +} + +// ******************************************************************** +// Skeletal Manipulation stuff +// +// Mirrored in cl_Skeletons.c +// ******************************************************************** + +float GetJointAngle(int jointIndex, int angleIndex) +{ + return skeletalJoints[jointIndex].angles[angleIndex]; +} + +qboolean SetJointAngVel(int jointIndex, int angleIndex, float destAngle, float angSpeed) +{ + G_SkeletalJoint_t *joint; + + joint = &skeletalJoints[jointIndex]; + + if(destAngle < joint->destAngles[angleIndex]) + { + skeletalJoints[jointIndex].destAngles[angleIndex] = destAngle; + skeletalJoints[jointIndex].angVels[angleIndex] = -angSpeed; + skeletalJoints[jointIndex].changed[angleIndex] = true; + return true; + } + else if(destAngle > joint->destAngles[angleIndex]) + { + skeletalJoints[jointIndex].destAngles[angleIndex] = destAngle; + skeletalJoints[jointIndex].angVels[angleIndex] = angSpeed; + skeletalJoints[jointIndex].changed[angleIndex] = true; + return true; + } + else + { + return false; + } +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_Skeletons.h b/Toolkit/Programming/GameCode/game/g_Skeletons.h new file mode 100644 index 0000000..f0ee4c5 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_Skeletons.h @@ -0,0 +1,16 @@ +#ifndef G_SKELETON_H +#define G_SKELETON_H +#include "g_Skeleton.h" +#endif +#ifndef SKELETONS_H +#define SKELETONS_H +#include "Skeletons.h" +#endif + +extern G_SkeletalJoint_t skeletalJoints[MAX_ARRAYED_SKELETAL_JOINTS]; +extern struct ArrayedListNode_s jointNodes[MAX_ARRAYED_JOINT_NODES]; + +int CreateSkeleton(int structure); +void FreeSkeleton(int root); +float GetJointAngle(int jointIndex, int angleIndex); +qboolean SetJointAngVel(int jointIndex, int angleIndex, float destAngle, float angSpeed); \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_StateInfo.c b/Toolkit/Programming/GameCode/game/g_StateInfo.c new file mode 100644 index 0000000..3dddd2e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_StateInfo.c @@ -0,0 +1,33 @@ +#include "g_StateInfo.h" +#include "ResourceManager.h" +#include "g_local.h" + +static ResourceManager_t ActionInfoMngr; + +void InitActionInfoMngr() +{ +#define ActionINFO_BLOCK_SIZE 32 + + ResMngr_Con(&ActionInfoMngr, sizeof(ActionInfo_t), ActionINFO_BLOCK_SIZE); +} + +void ReleaseActionInfoMngr() +{ + ResMngr_Des(&ActionInfoMngr); +} + +ActionInfo_t *ActionInfo_new() +{ + ActionInfo_t *newInfo; + + newInfo = ResMngr_AllocateResource(&ActionInfoMngr, sizeof(*newInfo)); + + memset(newInfo, 0, sizeof(*newInfo)); + + return newInfo; +} + +void ActionInfo_delete(ActionInfo_t *toDelete) +{ + ResMngr_DeallocateResource(&ActionInfoMngr, toDelete, sizeof(*toDelete)); +} diff --git a/Toolkit/Programming/GameCode/game/g_StateInfo.h b/Toolkit/Programming/GameCode/game/g_StateInfo.h new file mode 100644 index 0000000..93cfb65 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_StateInfo.h @@ -0,0 +1,24 @@ +#ifndef G_ACTIONINFO_H +#define G_ACTIONINFO_H + +// hmm, this is pretty small now that MoveInfo has been created. . . +// Hopefully there will be more stuff to add to this +typedef struct ActionInfo_s +{ + int state; + int readiness; + int curWeaponID; +} ActionInfo_t; + +typedef enum WeaponID_s +{ + WEAPON_MELEE_0, + WEAPON_MISSILE_0, + WEAPON_SPELL_0, + NUM_WEAPON_IDS +} WeaponID_t; + +extern ActionInfo_t *ActionInfo_new(); +extern void ActionInfo_delete(ActionInfo_t *toDelete); + +#endif // G_ACTIONINFO_H diff --git a/Toolkit/Programming/GameCode/game/g_Typedef.h b/Toolkit/Programming/GameCode/game/g_Typedef.h new file mode 100644 index 0000000..9ba037e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_Typedef.h @@ -0,0 +1,10 @@ +#ifndef G_TYPEDEF_H +#define G_TYPEDEF_H + +#include "q_Typedef.h" + +typedef struct edict_s edict_t; +typedef struct trace_s trace_t; +typedef enum HitLocation_e HitLocation_t; + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_ai.c b/Toolkit/Programming/GameCode/game/g_ai.c new file mode 100644 index 0000000..7f108bd --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_ai.c @@ -0,0 +1,2533 @@ +// g_ai.c + +#include +#include "g_local.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "buoy.h" +#include "m_stats.h" +#include "p_anims2.h" + +qboolean FindTarget (edict_t *self); +extern cvar_t *maxclients; + +qboolean ai_checkattack (edict_t *self, float dist); +//void gkrokon_maintain_waypoints(edict_t *self, float mintel, float foo1, float foo2); +void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist); + +//void gkrokon_hopdown(edict_t *self); +void ssithraCheckJump (edict_t *self); +void ssithraStartle (edict_t *self); +void ssithraLookRight (edict_t *self); +void seraph_startle(edict_t *self); +void SV_FixCheckBottom (edict_t *ent); +qboolean clear_visible (edict_t *self, edict_t *other); +trace_t MG_WalkMove (edict_t *self, float yaw, float dist); +qboolean MG_MoveToGoal (edict_t *self, float dist); +float MG_ChangeYaw (edict_t *self); +void MG_BuoyNavigate(edict_t *self); +void MG_Pathfind(edict_t *self, qboolean check_clear_path); +float MG_FaceGoal (edict_t *self, qboolean doturn); +qboolean ok_to_wake (edict_t *monster, qboolean gorgon_roar, qboolean ignore_ambush); +qboolean EqualAngle(float angle1, float angle2, float leniency); + + + +// AI Targeting Globals +qboolean enemy_vis; // TRUE if enemy is visible +qboolean enemy_infront; // TRUE if enemy is in front +int enemy_range; // range from enemy RANGE_MELEE, RANGE_NEAR, RANGE_MID, RANGE_FAR +float enemy_yaw; // ideal yaw to face enemy + +//============================================================================ + +// **************************************************************************** +// ai_trystep +// +// Like other functions to attempt a step, but this will return exactly +// what happened to make it fail. +// **************************************************************************** +int ai_trystep(edict_t *ent, vec3_t move) +{ + vec3_t oldorg, neworg, copyorg, end, inf_mins, inf_maxs; + trace_t trace; + float stepsize = 18; + vec3_t test; + int contents; + + // try the move + VectorCopy (ent->s.origin, oldorg); + VectorCopy (ent->s.origin, copyorg); + + VectorCopy (ent->mins, inf_mins); + VectorCopy (ent->maxs, inf_maxs); + + VectorAdd (ent->s.origin, move, neworg); + + VectorScale(inf_mins, 2, inf_mins); + VectorScale(inf_maxs, 2, inf_maxs); + + // push down from a step height above the wished position + neworg[2] += stepsize; + VectorCopy (neworg, end); + end[2] -= stepsize*2; + + gi.trace (neworg, inf_mins, inf_maxs, end, ent, MASK_MONSTERSOLID,&trace); + + if (trace.allsolid) + return TRYSTEP_ALLSOLID; + + if (trace.startsolid) + { + neworg[2] -= stepsize; + gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID,&trace); + if (trace.allsolid || trace.startsolid) + return TRYSTEP_STARTSOLID; + } + + // don't go in to water unless only 40% hieght deep + if (ent->waterlevel == 0) + { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent->mins[2];// + 1; + test[2] += (ent->maxs[2] - ent->mins[2]) * 0.4; + contents = gi.pointcontents(test); + + if (contents & MASK_WATER) + return TRYSTEP_INWATER; + } + + if (trace.fraction == 1) + { + // if monster had the ground pulled out, go ahead and fall + if ( ent->flags & FL_PARTIALGROUND ) + { + VectorAdd (ent->s.origin, move, ent->s.origin); + ent->groundentity = NULL; + return TRYSTEP_OK; + } + + // walked off an edge + return TRYSTEP_OFFEDGE; + } + + + // check point traces down for dangling corners + VectorCopy (trace.endpos, ent->s.origin); + + if (!M_CheckBottom (ent)) + { + if ( ent->flags & FL_PARTIALGROUND ) + { + VectorCopy (oldorg, ent->s.origin); + return TRYSTEP_OK; + } + + VectorCopy (oldorg, ent->s.origin); + return TRYSTEP_NOSUPPORT; + } + + if ( ent->flags & FL_PARTIALGROUND ) + ent->flags &= ~FL_PARTIALGROUND; + + ent->groundentity = trace.ent; + ent->groundentity_linkcount = trace.ent->linkcount; + + VectorCopy (oldorg, ent->s.origin); + + return TRYSTEP_OK; +} + +/* +================= +AI_SetSightClient + +Called once each frame to set level.sight_client to the +player to be checked for in findtarget. + +If all clients are either dead or in notarget, sight_client +will be null. + +In coop games, sight_client will cycle between the clients. +================= +*/ +void AI_SetSightClient (void) +{ + edict_t *ent; + int start, check; + + if (level.sight_client == NULL) + start = 1; + else + start = level.sight_client - g_edicts; + + check = start; + while (1) + { + check++; + if (check > game.maxclients) + check = 1; + ent = &g_edicts[check]; + if (ent->inuse + && ent->health > 0 + && !(ent->flags & FL_NOTARGET) ) + { + level.sight_client = ent; + return; // got one + } + if (check == start) + { + level.sight_client = NULL; + return; // nobody to see + } + } +} + + +// **************************************************************************** +// ai_maintain_waypoints +// +// checks all waypoints and corrects all buoys +// **************************************************************************** + +void ai_maintain_waypoints(edict_t *self, float mintel, float foo1, float foo2) +{ + vec3_t vec; + float len; + + if (self->enemy) + { + if (visible(self, self->enemy)) + { + VectorCopy(self->pos1, self->pos2); + VectorCopy(self->enemy->s.origin, self->pos1); + } + } + + if (self->monsterinfo.searchType == SEARCH_COMMON) + return; + else if (self->monsterinfo.searchType == SEARCH_BUOY) + { + VectorSubtract(self->s.origin, self->monsterinfo.nav_goal, vec); + len = VectorLength(vec); + + if (len < 24) + { + //gi.dprintf("gkrokon_maintain_waypoints: arrived at target buoy\n"); + + if ((self->monsterinfo.stepState == PATHDIR_FORWARD && self->goalentity->enemy == NULL) || + (self->monsterinfo.stepState == PATHDIR_BACKWARD && self->goalentity->owner == NULL)) + { + //gi.dprintf("gkrokon_maintain_waypoints: path exhausted, seeking target"); + FindTarget(self); + self->monsterinfo.searchType = SEARCH_COMMON; + + return; + } + + if (self->monsterinfo.stepState == PATHDIR_FORWARD) + { + //gi.dprintf("gkrokon_maintain_waypoints: forward targetting %s\n", self->goalentity->targetname); + self->enemy = self->movetarget = self->goalentity = self->goalentity->enemy; + VectorCopy(self->goalentity->s.origin, self->monsterinfo.nav_goal); + } + else if (self->monsterinfo.stepState == PATHDIR_BACKWARD) + { + //gi.dprintf("gkrokon_maintain_waypoints: reverse targetting %s\n", self->goalentity->owner->targetname); + self->enemy = self->movetarget = self->goalentity = self->goalentity->owner; + VectorCopy(self->goalentity->s.origin, self->monsterinfo.nav_goal); + } + /*else + gi.dprintf("gkrokon_maintain_waypoints: volatile assignment\n");*/ + } + } +} + +// **************************************************************************** +// ai_hopdown +// +// Checks to see if entity can hop down safely +// **************************************************************************** +int ai_hopdown(edict_t *self, vec3_t goalpos, float height_max) +{ + vec3_t vf, source, source2; + vec3_t maxs; + trace_t trace; + + //Setup the trace + VectorCopy(self->maxs, maxs); + VectorCopy(self->s.origin, source); + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(source, 128, vf, source); + + maxs[2] += 128; + gi.trace (self->s.origin, self->mins, maxs, source, self, MASK_ALL,&trace); + + if (trace.fraction == 1) + { + VectorCopy(source, source2); + + source2[2] -= height_max; + + gi.trace (source, self->mins, self->maxs, source2, self, MASK_ALL,&trace); + + if (trace.allsolid || trace.startsolid) + return false; + + if (trace.fraction == 1) + { + if (stricmp(trace.ent->classname, "worldspawn")) + return false; + } + else + { + if (trace.ent == (struct edict_s *)-1) + return false; + + if (trace.contents != CONTENTS_SOLID) + return false; + else + { + VectorSubtract(trace.endpos, self->s.origin, source2); + VectorNormalize(source2); + self->ideal_yaw = vectoyaw(source2); + + return true; + } + } + } + + return false; +} + +//============================================================================ + +/* +============= +ai_eat + +Monster will eat until harm is done to him or the player moves within range +============== +*/ +void ai_eat (edict_t *self, float dist) +{ + + self->enemy = NULL; + + FindTarget (self); +} + + +/* +============= +ai_move + +Move the specified distance at current facing. +This replaces the QC functions: ai_forward, ai_back, ai_pain, and ai_painforward +============== +*/ +void ai_move (edict_t *self, float dist) +{ + MG_WalkMove (self, self->s.angles[YAW], dist); +} + + +/* +============= +ai_stand + +Used for standing around and looking for players +Distance is for slight position adjustments needed by the animations +============== +*/ +void ai_stand (edict_t *self, float dist) +{ + vec3_t v; + + if (dist) + M_walkmove (self, self->s.angles[YAW], dist); + + if(self->enemy) + return; + + if (self->monsterinfo.aiflags & AI_STAND_GROUND) + { + if (self->enemy) + { + VectorSubtract (self->enemy->s.origin, self->s.origin, v); + self->ideal_yaw = vectoyaw(v); + if (self->s.angles[YAW] != self->ideal_yaw && self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND) + { + self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND); + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + } + M_ChangeYaw (self); + ai_checkattack (self, 0); + } + else + FindTarget (self); + return; + } + + if (FindTarget (self)) + return; + + + //FIXME: walking a beat monsters, but that may not be working, need to test! + //check for target also? + if (self->monsterinfo.pausetime == -1) + { + self->spawnflags |= MSF_WANDER; + self->ai_mood = AI_MOOD_WANDER; + QPostMessage(self, MSG_CHECK_MOOD, PRI_DIRECTIVE, "i", AI_MOOD_WANDER); + return; + } + else if (level.time > self->monsterinfo.pausetime) + { + self->ai_mood = AI_MOOD_WALK; + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + return; + } + + if (!(self->spawnflags & MSF_AMBUSH) && (self->monsterinfo.idle) && (level.time > self->monsterinfo.idle_time)) + { + if (self->monsterinfo.idle_time) + { + self->monsterinfo.idle (self); + self->monsterinfo.idle_time = level.time + flrand(15.0F, 30.0F); + } + else + { + self->monsterinfo.idle_time = level.time + flrand(0.0F, 15.0F); + } + } +} + + +/* +============= +ai_walk + +The monster is walking it's beat +============= +*/ +qboolean MG_ReachedBuoy (edict_t *self, vec3_t pspot); +void ai_walk (edict_t *self, float dist) +{ + if (FindTarget (self)) + { + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + return; + } + + + if(self->monsterinfo.searchType == SEARCH_BUOY) + { + if(!(self->monsterinfo.aiflags&AI_STRAIGHT_TO_ENEMY)) + { + MG_BuoyNavigate(self);//only called if already wandering + MG_Pathfind(self, false); + } + } + else if(!self->enemy && !self->pathtarget) + { + if(self->movetarget) + { + if(self->movetarget->classname && strcmp(self->movetarget->classname, "path_corner")) + { + if(MG_ReachedBuoy(self, self->movetarget->s.origin)) + { + self->movetarget = NULL; + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } + } + } + else if(!irand(0, 30) || (Vec3NotZero(self->monsterinfo.nav_goal) && MG_ReachedBuoy(self, self->monsterinfo.nav_goal))) + { + self->monsterinfo.pausetime = 0; + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } + } + + MG_MoveToGoal (self, dist); +} + + +/* +============= +ai_charge + +Turns towards enemy and advances +Use this call with a distnace of 0 to replace ai_face +============== +*/ +void ai_charge (edict_t *self, float dist) +{ + vec3_t v; + + if(!self->enemy) + { + if(MGAI_DEBUG) + gi.dprintf("ERROR: AI_CHARGE at a NULL enemy!\n"); + MG_FaceGoal(self, true);//get ideal yaw and turn + return;//send stand MSG? + } + + VectorSubtract (self->enemy->s.origin, self->s.origin, v); + + self->ideal_yaw = vectoyaw(v); + + MG_ChangeYaw (self); + + if(self->spawnflags&MSF_FIXED) + return; + + if (dist) + MG_WalkMove (self, self->s.angles[YAW], dist); +} + +/* +============= +ai_moveright + +simple sliding right (or left if dist <0) +============== +*/ +void ai_moveright (edict_t *self, float dist) +{ + vec3_t right; + float movedir; + + if(self->spawnflags&MSF_FIXED) + return; + + if (!dist) + return; + + AngleVectors (self->s.angles, NULL, right, NULL); + + movedir = vectoyaw(right); + + MG_WalkMove (self, movedir, dist); +} + +/* +============= +ai_goal_charge + +Turns towards target and advances +Use this call with a distnace of 0 to replace ai_face +============== +*/ +void ai_goal_charge (edict_t *self, float dist) +{ + MG_FaceGoal(self, true); + + if(self->spawnflags&MSF_FIXED) + return; + + if (dist) + MG_WalkMove (self, self->s.angles[YAW], dist); +} + +/* +============= +ai_charge2 + +Turns towards target and advances +Use this call with a distnace of 0 to replace ai_face +============== +*/ +void ai_charge2 (edict_t *self, float dist) +{ + vec3_t v; + + if(!self->enemy) + return; + + VectorSubtract (self->enemy->s.origin, self->s.origin, v); + self->ideal_yaw = vectoyaw(v); + MG_ChangeYaw (self); + + if(self->spawnflags&MSF_FIXED) + return; + + if (dist) + MG_WalkMove (self, self->s.angles[YAW], dist); +} + +/* +============= +ai_turn + +don't move, but turn towards ideal_yaw +Distance is for slight position adjustments needed by the animations +============= +*/ +void ai_turn (edict_t *self, float dist) +{ + if(!(self->spawnflags&MSF_FIXED)) + if (dist) + M_walkmove (self, self->s.angles[YAW], dist); + + if (FindTarget (self)) + return; + + M_ChangeYaw (self); +} + + +/* + +.enemy +Will be world if not currently angry at anyone. + +.movetarget +The next path spot to walk toward. If .enemy, ignore .movetarget. +When an enemy is killed, the monster will try to return to it's path. + +.hunt_time +Set to time + something when the player is in sight, but movement straight for +him is blocked. This causes the monster to use wall following code for +movement direction instead of sighting on the player. + +.ideal_yaw +A yaw angle of the intended direction, which will be turned towards at up +to 45 deg / state. If the enemy is in view and hunt_time is not active, +this will be the exact line towards the enemy. + +.pausetime +A monster will leave it's stand state and head towards it's .movetarget when +time > .pausetime. + +walkmove(angle, speed) primitive is all or nothing +*/ + +int categorize_range (edict_t *self, edict_t *other, float len) +{ + float dist; + + if (self->monsterinfo.aiflags & AI_EATING) // Eating + { + if (len < MELEE_DISTANCE) // Melee distance + { + if ( len < (self->maxs[0] + other->maxs[0] + 15)) + return RANGE_MELEE; + } + + if (len < 175) // Attacking distance + return RANGE_NEAR; + if (len < 350) // Hissing distance + return RANGE_MID; + return RANGE_FAR; + } + else // Not eating + { + if (len < MELEE_DISTANCE) + { + if ( len < (self->maxs[0] + other->maxs[0] + 25)) + return RANGE_MELEE; + } + if (len < 500) + return RANGE_NEAR; + + if(self->wakeup_distance) + dist = self->wakeup_distance; + else + dist = MAX_SIGHT_PLAYER_DIST; + + if (len < dist) + return RANGE_MID; + return RANGE_FAR; + } +} +/* +============= +range + +returns the range catagorization of an entity reletive to self +0 melee range, will become hostile even if back is turned +1 visibility and infront, or visibility and show hostile +2 infront and show hostile +3 only triggered by damage +============= +*/ +int range (edict_t *self, edict_t *other) +{ + vec3_t v; + float len; + + VectorSubtract (self->s.origin, other->s.origin, v); + len = VectorLength (v); + + return categorize_range(self, other, len); +} + +/* +============= +visible + +returns 1 if the entity is visible to self, even if not infront () +============= +*/ +qboolean visible (edict_t *self, edict_t *other) +{ + vec3_t spot1; + vec3_t spot2; + trace_t trace; + + VectorCopy (self->s.origin, spot1); + spot1[2] += self->viewheight; + if(self->classID == CID_TBEAST) + { + vec3_t forward; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(spot1, self->maxs[0], forward, spot1); + } + VectorCopy (other->s.origin, spot2); + spot2[2] += other->viewheight; + gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE,&trace); + + if (trace.fraction == 1.0) + return true; + return false; +} + +/* +============= +clear_visible + +returns 1 if the entity is visible, but not through transparencies +============= +*/ +qboolean clear_visible (edict_t *self, edict_t *other) +{ + vec3_t spot1; + vec3_t spot2; + trace_t trace; + + if (!other) + return false; + + if (!self) + return false; + + VectorCopy (self->s.origin, spot1); + spot1[2] += self->viewheight; + VectorCopy (other->s.origin, spot2); + spot2[2] += other->viewheight; + gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, MASK_SOLID,&trace); + + if (trace.fraction == 1.0) + return true; + return false; +} + +/* +============= +infront + +returns 1 if the entity is in front (in sight) of self +============= +*/ +qboolean infront (edict_t *self, edict_t *other) +{ + vec3_t vec; + float dot; + vec3_t forward, check_angles; + + if(Vec3NotZero(self->v_angle_ofs)) + VectorAdd(self->v_angle_ofs,self->s.angles,check_angles); + else + VectorCopy(self->s.angles,check_angles); + + AngleVectors (check_angles, forward, NULL, NULL); + VectorSubtract (other->s.origin, self->s.origin, vec); + VectorNormalize (vec); + dot = DotProduct (vec, forward); + + if (dot > 0.3) + return true; + return false; +} + + +//============================================================================ + +/* +Alerted + +Checks and see if an alert entity is capable of waking up a monster +*/ +void alert_timed_out(alertent_t *self); +qboolean Alerted (edict_t *self) +{//This alert entity wakes up monsters, let's see what's up... + edict_t *enemy = NULL; + alertent_t *alerter; + vec3_t e_spot, viewspot, dir; + qboolean saw_it = false; + float dist; + + if(self->monsterinfo.aiflags&AI_NO_ALERT) + return false; + + //start the search from the most recent alert to the oldest + alerter = level.last_alert;//OOPS, SKIPS LAST + +alertloop: + + if(self->enemy) + goto loopagain; + + //alerter is gone + if(!alerter) + goto loopagain; + + if(!alerter->inuse)//loading a saved game invalidates all alerts + goto loopagain; + + if(alerter->lifetime < level.time) + {//alert timed out, remove from list + alert_timed_out(alerter); + goto loopagain; + } + + if(self->last_alert)//don't be woken up by the same alert twice + { + if(self->last_alert->inuse) + { + if(alerter == self->last_alert && self->last_alert->inuse) + goto loopagain; + } + else + self->last_alert = NULL; + } + + //alerter's enemy is gone + if(!alerter->enemy) + goto loopagain; + + if(alerter->enemy->client) + {//no alerts for notarget players + if(alerter->enemy->flags & FL_NOTARGET) + goto loopagain; + } + + //NEVER alert ambush monsters? + //if(!(self->spawnflags & MSF_AMBUSH)) + // goto loopagain; + + if(!(self->svflags&SVF_MONSTER)) + goto loopagain; + + if(self->health<=0) + goto loopagain; + + //eating or in a cinematic or not awake, leave them alone + if(!ok_to_wake(self, false, true)) + goto loopagain; + + //should we keep track of owner in case they move to move the alert with them? Only for monsters + //if(alerter->owner) + // VectorCopy(alerter->owner->s.origin, alerter->s.origin); + + VectorSubtract(self->s.origin, alerter->origin, dir); + dist = VectorLength(dir); + + //if monster's wakeup_distance is shorter than dist to alerter, leave it alone + if(dist > self->wakeup_distance) + goto loopagain; + + //closer means better chance to alert + //problem - different alerts might be more likely to be heard/seen... + if(dist > flrand(100, self->wakeup_distance))//if within 100 always wake up? + goto loopagain; + + //if not a player, a player's missile or a monster, goto loopagain? + //get center of alert enemy + enemy = alerter->enemy; + + VectorAdd(enemy->s.origin, enemy->mins, e_spot); + VectorMA(e_spot, 0.5, enemy->size, e_spot); + + //get my view spot + VectorCopy(self->s.origin, viewspot); + viewspot[2] += self->viewheight; + + //if being alerted by a monster and not waiting to ambush + if(alerter->alert_svflags&SVF_MONSTER && !(self->spawnflags&MSF_AMBUSH)) + {//can "see" the owner of the alert even around a corner + saw_it = gi.inPVS(e_spot, viewspot); + } + else + {//alerter not a monster, a projectile or player + //can I see (even through translucent brushes) the owner of the alert? + //if so, ok even if I'm an ambush monster + saw_it = visible_pos(self, e_spot); + + if(!saw_it&&!(self->spawnflags&MSF_AMBUSH)) + {//no line of sight and not an ambush monster + if(gi.inPVS(viewspot, alerter->origin)) + {//25% chance will see impact(alerter) and detect alert owner anyway + if(!irand(0,3)) + saw_it = true;//go ahead and go for it + } + } + } + + if(!saw_it) + goto loopagain; + + if(!self->monsterinfo.alert) + goto loopagain; + + self->last_alert = alerter; + return self->monsterinfo.alert(self, alerter, enemy); + +loopagain: + if(alerter) + { + alerter = alerter->prev_alert; + if(alerter) + goto alertloop; + } + + return false; +} + +/* +=========== +HuntTarget - a target has been found, it is visible, so do we attack it, watch it, or stand there? + +============ +*/ +void HuntTarget (edict_t *self) +{ + vec3_t vec; + int r; + + self->goalentity = self->enemy; + if (self->monsterinfo.aiflags & AI_STAND_GROUND) + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } + else + { + r = range(self,self->enemy); + if ((self->monsterinfo.aiflags & AI_EATING) && (r == RANGE_MID)) + { + QPostMessage(self, MSG_WATCH, PRI_DIRECTIVE, NULL); + } + else + { + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + } + } + VectorSubtract (self->enemy->s.origin, self->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + // wait a while before first attack + if (!(self->monsterinfo.aiflags & AI_STAND_GROUND)) + AttackFinished (self, 1); +} + +/* +=========== +FoundTarget - a target has been found, let other monsters know this. Then hunt it +============ +*/ +void FoundTarget (edict_t *self, qboolean setsightent) +{ + char *o_target; + // let other monsters see this monster for a while + if (!self->enemy) + return; + + if(self->classID == CID_OGLE) + self->spawnflags = 0; + + self->monsterinfo.awake = true; + self->spawnflags &= ~MSF_AMBUSH; + self->targetname = NULL; + self->monsterinfo.pausetime = -1;//was 0; + + if(self->wakeup_target) + { + o_target = self->target; + self->target = self->wakeup_target; + G_UseTargets(self, self->enemy); + self->target = o_target; + self->wakeup_target = NULL; + } + + if (self->enemy->client && setsightent) + { + level.sight_entity = self; + level.sight_entity_framenum = level.framenum; + level.sight_entity->light_level = 128; + } + + self->show_hostile = level.time + 1; // wake up other monsters + + VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting); + + if (!self->combattarget ) // Not going for a combat point? + { + // dont want to do this if we are a fish + if (self->classID != CID_FISH) + HuntTarget (self); + + if (!self->oldenemy) + { + if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) ) + QPostMessage(self, MSG_VOICE_SIGHT, PRI_DIRECTIVE, "be", SIGHT_SOUND_TARGET, self->enemy); + else + QPostMessage(self, MSG_VOICE_SIGHT, PRI_DIRECTIVE, "be", SIGHT_VISIBLE_TARGET, self->enemy); + } + + self->spawnflags &= ~MSF_AMBUSH; + return; + } + + self->goalentity = self->movetarget = G_PickTarget(self->combattarget); + + if (!self->movetarget) + { + self->goalentity = self->movetarget = self->enemy; + // dont want to do this if we are a fish + if (self->classID != CID_FISH) + HuntTarget (self); + + if (!self->oldenemy) + { + if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) ) + QPostMessage(self, MSG_VOICE_SIGHT, PRI_DIRECTIVE, "be", SIGHT_SOUND_TARGET, self->enemy); + else + QPostMessage(self, MSG_VOICE_SIGHT, PRI_DIRECTIVE, "be", SIGHT_VISIBLE_TARGET, self->enemy); + } + +// gi.dprintf("%s at %s, combattarget %s not found\n", self->classname, vtos(self->s.origin), self->combattarget); + self->spawnflags &= ~MSF_AMBUSH; + return; + } + + // clear out our combattarget, these are a one shot deal + self->combattarget = NULL; + self->monsterinfo.aiflags |= AI_COMBAT_POINT; + + // clear the targetname, that point is ours! + self->movetarget->targetname = NULL; + + // run for it , assuming we aren't a fish + if (self->classID != CID_FISH) + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + + //Make a sight sound + if (!self->oldenemy) + { + if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) ) + QPostMessage(self, MSG_VOICE_SIGHT, PRI_DIRECTIVE, "be", SIGHT_SOUND_TARGET, self->enemy); + else + QPostMessage(self, MSG_VOICE_SIGHT, PRI_DIRECTIVE, "be", SIGHT_VISIBLE_TARGET, self->enemy); + } + + self->spawnflags &= ~MSF_AMBUSH; +} + +/* +qboolean ok_to_wake (edict_t *monster, qboolean gorgon_roar) + +Can this monster be woken up by something other than direct line of sight to player +*/ + +qboolean ok_to_wake (edict_t *monster, qboolean gorgon_roar, qboolean ignore_ambush) +{ + if(gorgon_roar) + { + if(monster->monsterinfo.c_mode) + return false; + } + else if(monster->monsterinfo.aiflags & AI_EATING ||//eating or perching + monster->targetname ||//a monster that's supposed to be triggered - problem, one a monster is used and woken up, won't respond to alerts like others...? + monster->monsterinfo.c_mode ||//cinematic + monster->spawnflags & MSF_ASLEEP ||//shouldn't happen, but just in case + (monster->spawnflags & MSF_AMBUSH && !ignore_ambush)) + return false; + + return true; +} + +qboolean PlayerCreeping(playerinfo_t *playerinfo) +{ + if(playerinfo->upperseq == ASEQ_CREEPF || + playerinfo->upperseq == ASEQ_STAND || + playerinfo->upperseq == ASEQ_CREEPB || + playerinfo->upperseq == ASEQ_CREEPB_END || + playerinfo->upperseq == ASEQ_CROUCH_GO || + playerinfo->upperseq == ASEQ_CROUCH || + playerinfo->upperseq == ASEQ_CROUCH_END || + playerinfo->upperseq == ASEQ_CROUCH_WALK_F || + playerinfo->upperseq == ASEQ_CROUCH_WALK_B || + playerinfo->upperseq == ASEQ_CROUCH_WALK_L || + playerinfo->upperseq == ASEQ_CROUCH_WALK_R || + playerinfo->upperseq == ASEQ_WSWORD_ROUND_BACK || + playerinfo->lowerseq == ASEQ_CREEPF || + playerinfo->lowerseq == ASEQ_STAND || + playerinfo->lowerseq == ASEQ_CREEPB || + playerinfo->lowerseq == ASEQ_CREEPB_END || + playerinfo->lowerseq == ASEQ_CROUCH_GO || + playerinfo->lowerseq == ASEQ_CROUCH || + playerinfo->lowerseq == ASEQ_CROUCH_END|| + playerinfo->lowerseq == ASEQ_CROUCH_WALK_F || + playerinfo->lowerseq == ASEQ_CROUCH_WALK_B || + playerinfo->lowerseq == ASEQ_CROUCH_WALK_L || + playerinfo->lowerseq == ASEQ_CROUCH_WALK_R || + playerinfo->lowerseq == ASEQ_WSWORD_ROUND_BACK) + return (true); + + return (false); +} +/* +=========== +FindTarget + +Self is currently not attacking anything, so try to find a target + +Returns TRUE if an enemy was sighted + +When a player fires a missile or does other things to make noise, the +point of impact becomes an alertent so that monsters that see the +impact will respond as if they had seen the player. + +Since FindTarget is not called every frame for monsters (average +about once every 3 frames per monster), this does two potential checks. + +First it checks against the current sight_client which cycles through +the players. + +If that check fails, it will check for all the secondary alerts and +enemies. if it can't find any, it will check for another player if +it can find one other than the first one it checked. +============ +*/ +qboolean ogle_findtarget (edict_t *self); +qboolean FindTarget (edict_t *self) +{ + edict_t *client, *firstclient; + qboolean heardit = false; + int r; + edict_t *ent; + int flag; + qboolean clientonly = true; + qboolean e_infront = false; + vec3_t v; + float dist; + +//FIXME: wakeup_distance -1 never look? + if(self->classID == CID_OGLE) + return ogle_findtarget(self); + + if (self->monsterinfo.aiflags & AI_GOOD_GUY) + { + if (self->goalentity) + { + if (strcmp(self->goalentity->classname, "target_actor") == 0) + return false; + } + + //FIXME look for monsters? + return false; + } + + // if we're going to a combat point, just proceed + if (self->monsterinfo.aiflags & AI_COMBAT_POINT) + return false; + + if(self->ai_mood_flags&AI_MOOD_FLAG_IGNORE_ENEMY) + {//being forced to use buoys, and ignore enemy until get to forced_buoy + return false; + } + +// if the first spawnflag bit is set, the monster will only wake up on +// really seeing the player, not another monster getting angry or hearing +// something + +// revised behavior so they will wake up if they "see" a player make a noise +// but not weapon impact/explosion noises + +startcheck: + flag = 1; + if(clientonly) + {//look oly at the level.sight_client + firstclient = client = level.sight_client; + } + else + { + if(ANARCHY) + {//crazy monsters mode + int checkcnt = 0; + client = self; + while((!client || !client->inuse || !(client->svflags & SVF_MONSTER)||client->health<=0||client == self) && checkcnt < globals.num_edicts) + { + client = &g_edicts[irand(0, globals.num_edicts)]; + checkcnt++; + } + } + else + { + if(level.sight_entity == self) + { + level.sight_entity = NULL; + return false; + } + + if (level.sight_entity && (level.sight_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & MSF_AMBUSH) ) + {//go after the enemy another monster saw saw, but only if not in ambush + client = level.sight_entity; + if (client->enemy == self->enemy) + { + return false; + } + } + else if (Alerted(self)) + {//picked up an enemy from an alert + return true; + } + else + { + client = NULL; + // Looking for secondary enemies + if ((self->monsterinfo.otherenemyname) && (self->monsterinfo.chase_finished < level.time)) + { + ent = NULL; + while((ent=findradius(ent,self->s.origin,175)) != NULL) + { + if (!strcmp(ent->classname,self->monsterinfo.otherenemyname)&&ent!=self) + { + flag = 0; + client = ent; + break; + } + } + } + + // Look at the sight client + if (!client) + {//found no non-clients, cycle to next client and check it for second check + AI_SetSightClient(); + if(firstclient == level.sight_client) + return false;//same as first check, and that failed if we're here, so return. + client = level.sight_client; + } + } + } + } + if (!client) + goto nextcheck; // no clients to get mad at + + // if the entity went away, forget it + if (!client->inuse) + goto nextcheck; + + if (client == self) + goto nextcheck; //???? + + if (client == self->enemy) + return true; // JDC false; + + if (self->monsterinfo.otherenemyname) + { + if (!strcmp(client->classname,self->monsterinfo.otherenemyname)) + client->light_level = 128; // Let it be seen + } + + // if we are a fish - is the target in the water - have to be at least waist deep? + if (self->classID == CID_FISH && client->waterlevel < 2) + goto nextcheck; //???? + + if (client->client) + { + if (client->flags & FL_NOTARGET) + goto nextcheck; + } + else if (client->svflags & SVF_MONSTER) + { + if(flag) + {//not a secondary enemy + if(!ANARCHY) + { + if (ok_to_wake(self, false, true)) + {//eating or in a cinematic or not awake or targeted, leave them alone + goto nextcheck; + } + } + + if (!client->enemy) + { + if(!ANARCHY) + goto nextcheck; + } + else + { + if (client->enemy->health<0 && !ANARCHY) + goto nextcheck; + + if (client->enemy->flags & FL_NOTARGET) + goto nextcheck; + } + + if(!visible(self, client)) + goto nextcheck; + + if(!ANARCHY) + self->enemy = client->enemy; + else + self->enemy = client; + + if(client->ai_mood == AI_FLEE) + FoundTarget(self, false);//let them stay the sight entity + else + FoundTarget(self, true);//make me the sight entity + + /*if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET)) + QPostMessage(self, MSG_VOICE_SIGHT, PRI_DIRECTIVE, "e", self->enemy);*/ + //self->monsterinfo.sight (self, self->enemy); + + return true; + } + } + else if (heardit) + { + if (client->owner->flags & FL_NOTARGET) + goto nextcheck; + } + else + goto nextcheck; + + if (!heardit) + { + if(self->classID == CID_ASSASSIN) + e_infront = true; + else + e_infront = infront(self, client); + + if(!e_infront && client->client) + { + if(PlayerCreeping(&client->client->playerinfo)) + goto nextcheck; + } + + VectorSubtract(client->s.origin, self->s.origin, v); + dist = VectorLength(v); + + if(dist > self->wakeup_distance) + goto nextcheck; + + r = categorize_range (self, client, dist); + + if (r == RANGE_FAR) + goto nextcheck; + + if ((self->monsterinfo.aiflags & AI_EATING) && (r > RANGE_MID)) + { + self->enemy = client; + goto nextcheck; + } + +// this is where we would check invisibility + + // is client in an spot too dark to be seen? + if (client->light_level <= 5) + goto nextcheck; + + if(self->svflags&SVF_MONSTER && client->client) + { + if(skill->value < 2.0 && !(self->monsterinfo.aiflags & AI_NIGHTVISION)) + { + if(client->light_level < flrand(6, 77)) + { + goto nextcheck; + } + } + } + + if (r == RANGE_NEAR) + { + if (client->show_hostile < level.time && !e_infront) + { + goto nextcheck; + } + } + else if (r == RANGE_MID) + { + if (!e_infront) + { + goto nextcheck; + } + } + + //sfs--this check is much less trivial than infront: prolly wasn't a noticeable deal, + // since RANGE_FAR was first rejection check, but it's still better to try the + // dotproduct before the traceline + if (!visible (self, client)) + { + goto nextcheck; + } + + self->enemy = client; + + flag=1; + if (self->monsterinfo.otherenemyname) + { + if (strcmp(self->enemy->classname, self->monsterinfo.otherenemyname) == 0) // This is a secondary enemy + { + self->monsterinfo.chase_finished = level.time + 15; + flag=0; + } + } + + if (flag) // This is not a secondary enemy + { + self->monsterinfo.aiflags &= ~AI_SOUND_TARGET; + + if (!self->enemy->client) + { + self->enemy = self->enemy->enemy; + if (!self->enemy->client) + { + self->enemy = NULL; + goto nextcheck; + } + } + } + } + else // heardit + { + goto nextcheck; + + } + +// +// got one +// + FoundTarget (self, true); + + return true; + +nextcheck: + if(clientonly) + { + clientonly = false; + goto startcheck; + } + else + return false; +} + + +//============================================================================= + +/* +============ +FacingIdeal + +============ +*/ +qboolean FacingIdeal(edict_t *self) +{ + float delta; + + delta = anglemod(self->s.angles[YAW] - self->ideal_yaw); + if (delta > 45 && delta < 315) + return false; + return true; +} + + +//============================================================================= + +qboolean M_CheckAttack (edict_t *self) +{ + vec3_t spot1, spot2; + float chance; + trace_t tr; + + if (self->enemy->health > 0) + { + // see if any entities are in the way of the shot + VectorCopy (self->s.origin, spot1); + spot1[2] += self->viewheight; + VectorCopy (self->enemy->s.origin, spot2); + spot2[2] += self->enemy->viewheight; + + gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA,&tr); + + // do we have a clear shot? + if (tr.ent != self->enemy) + return false; + } + + // melee attack + + if (enemy_range == RANGE_MELEE) + { + // don't always melee in easy mode + if (skill->value == 0 && irand(0, 3) ) + return false; + + if (classStatics[self->classID].msgReceivers[MSG_MELEE]) + { + self->monsterinfo.attack_state = AS_MELEE; + } + else + { + self->monsterinfo.attack_state = AS_MISSILE; + } + return true; + } + + // missile attack + + if (!classStatics[self->classID].msgReceivers[MSG_MISSILE]) + return false; + + if (level.time < self->monsterinfo.attack_finished) + return false; + + if (enemy_range == RANGE_FAR) + return false; + + if (self->monsterinfo.aiflags & AI_STAND_GROUND) + { + chance = 0.4; + } + else if (enemy_range == RANGE_MELEE) + { + chance = 0.2; + } + else if (enemy_range == RANGE_NEAR) + { + chance = 0.1; + } + else if (enemy_range == RANGE_MID) + { + chance = 0.02; + } + else + { + return false; + } + + if (skill->value == 0) + chance *= 0.5; + else if (skill->value == 2) + chance *= 2; + + if (flrand(0.0, 1.0) < chance) + { + self->monsterinfo.attack_state = AS_MISSILE; + self->monsterinfo.attack_finished = level.time + flrand(0.0, 2.0); + return true; + } + + if (self->flags & FL_FLY) + { + if (!irand(0, 2)) + self->monsterinfo.attack_state = AS_SLIDING; + else + self->monsterinfo.attack_state = AS_STRAIGHT; + } + + return false; +} + + +/* +============= +ai_run_melee + +Turn and close until within an angle to launch a melee attack +============= +*/ +void ai_run_melee(edict_t *self) +{ + self->ideal_yaw = enemy_yaw; + M_ChangeYaw (self); + + if (FacingIdeal(self)) + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + self->monsterinfo.attack_state = AS_STRAIGHT; + } +} + + +/* +============= +ai_run_missile + +Turn in place until within an angle to launch a missile attack +============= +*/ +void ai_run_missile(edict_t *self) +{ + self->ideal_yaw = enemy_yaw; + M_ChangeYaw (self); + + if (FacingIdeal(self)) + { + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + self->monsterinfo.attack_state = AS_STRAIGHT; + } +}; + + +/* +============= +ai_run_slide + +Strafe sideways, but stay at aproximately the same range +============= +*/ +void ai_run_slide(edict_t *self, float distance) +{ + float ofs; + + self->ideal_yaw = enemy_yaw; + M_ChangeYaw (self); + + if (self->monsterinfo.lefty) + ofs = 90; + else + ofs = -90; + + if (M_walkmove (self, self->ideal_yaw + ofs, distance)) + return; + + self->monsterinfo.lefty = 1 - self->monsterinfo.lefty; + M_walkmove (self, self->ideal_yaw - ofs, distance); +} + + +/* +============= +ai_checkattack + +Decides if we're going to attack or do something else +used by ai_run, and ai_stand +============= +*/ +qboolean ai_checkattack (edict_t *self, float dist) +{ + vec3_t temp; + qboolean hesDeadJim; + + if ((self->monsterinfo.aiflags & AI_FLEE)||(self->monsterinfo.aiflags & AI_COWARD)) // He's running away, not attacking + { + return false; + } + + enemy_vis = false; + +// see if the enemy is dead + hesDeadJim = false; + if ((!self->enemy) || (!self->enemy->inuse)) + { + hesDeadJim = true; + } + else + { + if (self->monsterinfo.aiflags & AI_BRUTAL) + { + if (self->enemy->health <= -80) + hesDeadJim = true; + } + else + { + if (self->enemy->health <= 0) + hesDeadJim = true; + } + } + + if (hesDeadJim) + { + self->enemy = NULL; + // FIXME: look all around for other targets + if (self->oldenemy && self->oldenemy->health > 0) + { + self->enemy = self->oldenemy; + self->oldenemy = NULL; + HuntTarget (self); + } + else + { + if (self->movetarget) + { + self->goalentity = self->movetarget; + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + } + else + { + // we need the pausetime otherwise the stand code + // will just revert to walking with no target and + // the monsters will wonder around aimlessly trying + // to hunt the world entity + self->monsterinfo.pausetime = level.time + 100000000; + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } + return true; + } + } + + self->show_hostile = level.time + 1; // wake up other monsters + +// check knowledge of enemy + enemy_vis = clear_visible(self, self->enemy); + if (enemy_vis) + { + self->monsterinfo.search_time = level.time + 5; + VectorCopy (self->enemy->s.origin, self->monsterinfo.last_sighting); + } + +// look for other coop players here +// if (coop && self->monsterinfo.search_time < level.time) +// { +// if (FindTarget (self)) +// return true; +// } + + enemy_infront = infront(self, self->enemy); + enemy_range = range(self, self->enemy); + VectorSubtract (self->enemy->s.origin, self->s.origin, temp); + enemy_yaw = vectoyaw(temp); + + + // JDC self->ideal_yaw = enemy_yaw; + + if (self->monsterinfo.attack_state == AS_MISSILE) + { + ai_run_missile (self); + return true; + } + if (self->monsterinfo.attack_state == AS_MELEE) + { + ai_run_melee (self); + return true; + } + + // if enemy is not currently visible, we will never attack + if (!enemy_vis) + return false; + + return self->monsterinfo.checkattack (self); +} + + +qboolean ai_inpack(edict_t *self) +{ + edict_t *ent; + + ent = NULL; + while ((ent = findradius(ent, self->s.origin, 1024)) != NULL) + { + if (ent == self) + continue; + + if (stricmp(ent->classname, self->classname)) + continue; + + return true; + } + + return false; +} + +/* +============= +ai_runaway + +The monster has an enemy it is trying to flee +============= +*/ +void ai_runaway (edict_t *self, float dist) +{ + vec3_t move; + vec3_t vec, source, vf; + qboolean goleft = false; + vec3_t mins, maxs; + trace_t trace; + vec3_t na, nvr; + float yaw; + int ret; + + if (!self->enemy) + return; + +// gi.dprintf("%s running away from %s!\n", self->classname, self->enemy->classname); + //Setup the trace + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + VectorCopy(self->s.origin, source); + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(source, dist*2, vf, source); + + //Account for STEPSIZE + mins[2] += 18; + + gi.trace (self->s.origin, mins, self->maxs, source, self, MASK_SHOT,&trace); + + //We hit something + if (trace.fraction < 1) + { + vectoangles(trace.plane.normal,na); + AngleVectors(na,NULL,nvr,NULL); + + if(DotProduct(nvr,vf)>0) + self->ideal_yaw=vectoyaw(nvr); + else + { + VectorScale(nvr, -1, nvr); + self->ideal_yaw=vectoyaw(nvr); + } + + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + VectorCopy(self->s.origin, source); + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(source, dist*4, nvr, source); + + //Account for STEPSIZE + mins[2] += 18; + + gi.trace (self->s.origin, mins, self->maxs, source, self, MASK_SHOT,&trace); + + if (trace.fraction < 1) + { + //gi.dprintf("Failed next move!\n"); + VectorScale(nvr, -1, nvr); + self->ideal_yaw=vectoyaw(nvr); + } + + M_ChangeYaw (self); + + if (abs(self->s.angles[YAW] - self->ideal_yaw) < self->yaw_speed) + { + yaw = self->s.angles[YAW]; + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist * 4; + move[1] = sin(yaw)*dist * 4; + move[2] = 0; + + ret = ai_trystep(self, move); + + if ((ret != TRYSTEP_OK) && (self->monsterinfo.idle_time < level.time)) + { + self->monsterinfo.idle_time = level.time + flrand(1.0, 2.0); + SV_NewChaseDir(self, self->enemy, dist); + } + else if (!M_walkmove (self, self->s.angles[YAW], dist)) + { + self->monsterinfo.idle_time = level.time + flrand(1.0, 2.0); + SV_NewChaseDir(self, self->enemy, dist); + } + } + + return; + } + + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + + if (self->monsterinfo.idle_time < level.time) + { + self->ideal_yaw = vectoyaw(vec); + self->ideal_yaw += 180; + M_ChangeYaw (self); + } + + if (dist) //Going somewhere? + { + if(self->classID == CID_SSITHRA) + ssithraCheckJump(self); + if (!M_walkmove (self, self->s.angles[YAW], dist)) + { + if (self->monsterinfo.searchType == SEARCH_BUOY) + return; + + yaw = self->s.angles[YAW]; + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + ret = ai_trystep(self, move); + + if ((ret != TRYSTEP_OK) && (self->monsterinfo.idle_time < level.time)) + { + self->monsterinfo.idle_time = level.time + flrand(1.0, 2.0); + SV_NewChaseDir(self, self->enemy, dist); + } + else + { + M_ChangeYaw(self); + + if (!M_walkmove (self, self->s.angles[YAW], dist/2)&&(self->classID != CID_SSITHRA)) + { + if (ai_hopdown(self, self->enemy->s.origin, 1024)) + { + if (self->monsterinfo.jump_time < level.time) + { + //FIXME: Re-implement this! + //gkrokon_hopdown(self); + self->monsterinfo.jump_time = level.time + 1; + } + else return; + } + } + } + } + } +} + +float ai_face_goal (edict_t *self) +{ + vec3_t vec; + + if (self->monsterinfo.searchType == SEARCH_BUOY) + VectorSubtract(self->monsterinfo.nav_goal, self->s.origin, vec); + else if(self->goalentity) + VectorSubtract(self->goalentity->s.origin, self->s.origin, vec); + else if(self->enemy) + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + else + return false; + + if (self->monsterinfo.idle_time < level.time) + { + self->ideal_yaw = vectoyaw(vec); + return M_ChangeYaw(self); + } + else + return false; +} + +void old_ai_run (edict_t *self, float dist) +{//FIXME: only ssithra in water use this, let;s junk it! + vec3_t move; + vec3_t vec, source, vf; + qboolean goleft = false; + vec3_t mins, maxs; + trace_t trace; + vec3_t na, nvr;//, v; + float yaw, turnamt, distloss;//,bbox + int ret, oldyaw; + + if (!self->enemy) + return; + + + if(self->classID == CID_GORGON) + { + if(visible(self, self->enemy)) + { + if(Vec3IsZero(self->enemy->velocity)) + { + VectorCopy(self->enemy->s.origin, self->pos1); + } + else + VectorClear(self->pos1); + } + else + VectorClear(self->pos1); + } + + if (self->monsterinfo.attack_state == AS_SLIDING) + { + ai_run_slide (self, dist); + return; + } + + // He's done fleeing, time to stand and see what's happening + if ((self->monsterinfo.aiflags & AI_FLEE) && (self->monsterinfo.flee_finished < level.time)) + { + self->monsterinfo.aiflags &= ~AI_FLEE; + if(irand(0,10<2)) + { + self->enemy = NULL; + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } + return; + } + + if (self->monsterinfo.aiflags & AI_FLEE||self->monsterinfo.aiflags & AI_COWARD) + { + VectorSubtract (self->enemy->s.origin, self->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + self->ideal_yaw += 180; + ai_runaway(self, dist); + return; + } + + if (self->monsterinfo.aiflags & AI_STAND_GROUND) + { + turnamt = Q_fabs(ai_face_goal(self)); + return; + } + + if (self->monsterinfo.aiflags & AI_SOUND_TARGET) + { + self->monsterinfo.aiflags &= ~AI_SOUND_TARGET; + if (!FindTarget (self)) + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + return; + } + } + + if (!self->enemy) + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + return; + } + +// ai_maintain_waypoints(self, 0, 0, 0); + + //Setup the trace + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + VectorCopy(self->s.origin, source); + AngleVectors(self->s.angles, vf, NULL, NULL); + +/* if (self->maxs[0] > self->maxs[1]) // Add in monster's bounding box + bbox = self->maxs[0]; + else + bbox = self->maxs[1];*/ + + VectorMA(source, (dist*2)/*+bbox*/, vf, source); + + //Account for STEPSIZE + mins[2] += 18; + + gi.trace (self->s.origin, mins, self->maxs, source, self, MASK_SHOT,&trace); + + //We hit something + if (trace.fraction < 1) + { + if (trace.ent == self->enemy) + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + return; + } + else if(self->monsterinfo.otherenemyname) + { + if(!stricmp(trace.ent->classname, self->monsterinfo.otherenemyname))//&&irand(0,10)<3) + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + return; + } + } + if(trace.ent->takedamage && self->monsterinfo.aiflags & AI_SHOVE && trace.fraction <= 0.5) + {//hurt them some too? + if(self->classID == CID_GORGON && + self->s.scale >1.5 && + trace.ent->classID!=self->classID && + trace.ent->health <= 200&& + infront(self, self->enemy))//chomp! + { +// gi.dprintf("Chomp!\n"); + self->oldenemy = self->enemy; + self->enemy = trace.ent; + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + } + else + { +// gi.dprintf("Shove!\n"); + VectorSubtract(trace.ent->s.origin,self->s.origin,vec); + if(vec[2]<30) + vec[2] = 30; + VectorNormalize(vec); + VectorMA(trace.ent->velocity,200,vec,trace.ent->velocity); + trace.ent->groundentity = NULL; + } + } + + vectoangles(trace.plane.normal,na); + AngleVectors(na,NULL,nvr,NULL); + + if(DotProduct(nvr,vf)>0) + { + self->ideal_yaw=vectoyaw(nvr); + } + else + { + VectorScale(nvr, -1, nvr); + self->ideal_yaw=vectoyaw(nvr); + } + + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + VectorCopy(self->s.origin, source); + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(source, dist, nvr, source);//was 4? + + //Account for STEPSIZE + mins[2] += 18; + + gi.trace (self->s.origin, mins, self->maxs, source, self, MASK_SOLID,&trace);//was MASK_SHOT + + if (trace.fraction < 1||trace.allsolid||trace.startsolid) + { + VectorScale(nvr, -1, nvr); + self->ideal_yaw=vectoyaw(nvr); + } + + oldyaw = self->s.angles[YAW]; + turnamt = Q_fabs(M_ChangeYaw(self)); + + if (abs(anglemod(self->s.angles[YAW] - self->ideal_yaw)) < self->yaw_speed) + { + yaw = self->s.angles[YAW]; + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist * 2;//4 + move[1] = sin(yaw)*dist * 2;//4 + move[2] = 0; + + ret = ai_trystep(self, move); + + if ((ret != TRYSTEP_OK) && (self->monsterinfo.idle_time < level.time)) + { + self->ideal_yaw = -vectoyaw(nvr); + turnamt = Q_fabs(M_ChangeYaw(self)); + distloss = turnamt/self->yaw_speed * 0.3; + dist -= (dist * distloss); + if (!M_walkmove (self, self->s.angles[YAW], dist)) + { + self->monsterinfo.idle_time = level.time + flrand(0.5, 1.2); + SV_NewChaseDir(self, self->enemy, dist); + } + } + else + { + distloss = turnamt/self->yaw_speed * 0.3; + dist -= (dist * distloss); + M_walkmove (self, self->s.angles[YAW], dist); + } + //actually tried move + return; + } + } + else + turnamt = Q_fabs(ai_face_goal(self)); + + //greater the turn, lesser the dist, full yawspeed turn is 50% dist + //FIXME: also make this dist less if turn is high and close to enemy? + //(so you don't run around it in a circle)? + distloss = turnamt/self->yaw_speed * 0.3; + + dist -= (dist * distloss); + if (dist) //Going somewhere? + { + if(self->classID == CID_SSITHRA) + ssithraCheckJump(self); + if (!M_walkmove (self, self->s.angles[YAW], dist)) + { + yaw = self->s.angles[YAW]; + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + ret = ai_trystep(self, move); + + if ((ret != TRYSTEP_OK) && (self->monsterinfo.idle_time < level.time)) + { + //Jump down? + if ((self->enemy->s.origin[2] < self->s.origin[2])&&(self->classID != CID_SSITHRA)) + { + if (ai_hopdown(self, self->enemy->s.origin, 1024)) + { + if (self->monsterinfo.jump_time < level.time) + { + self->monsterinfo.jump_time = level.time + 1; + + return; + } + else return; + } + else + { + self->monsterinfo.idle_time = level.time + flrand(1.0, 2.0); + SV_NewChaseDir(self, self->enemy, dist); + } + } + else + { + self->monsterinfo.idle_time = level.time + flrand(0.5, 1.2); + SV_NewChaseDir(self, self->enemy, dist); + } + } + else + { + turnamt = Q_fabs(M_ChangeYaw(self)); + + if (!M_walkmove (self, self->s.angles[YAW], dist/2)&&(self->classID != CID_SSITHRA)) + { + if (ai_hopdown(self, self->enemy->s.origin, 1024)) + { + if (self->monsterinfo.jump_time < level.time) + { + self->monsterinfo.jump_time = level.time + 1; + + return; + } + else return; + } + } + } + } + } +} + + +/* +============= +ai_flee + +The monster has an enemy it is trying to get away from +============= +*/ +void ai_flee (edict_t *self, float dist) +{ + vec3_t vec; + + if (self->enemy) + { + VectorSubtract (self->enemy->s.origin, self->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + self->ideal_yaw = anglemod(self->ideal_yaw + self->best_move_yaw); + M_ChangeYaw(self); + if(!M_walkmove(self, self->s.angles[YAW], dist) && EqualAngle(self->s.angles[YAW], self->ideal_yaw, 5)) + self->best_move_yaw = flrand(60, 300); + else + self->best_move_yaw = 180; + + /* + VectorSubtract(self->s.origin, self->enemy->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + M_ChangeYaw(self); + M_MoveAwayFromGoal (self, dist);*/ + } +} + +/* +============================================================= +void extrapolateFiredir (edict_t *self,vec3_t p1,float pspeed,edict_t *targ,float accept,vec3_t vec2) + +MG + +Estimates where the "targ" will be by the time a projectile +travelling at "pspeed" leaving "org" arrives at "targ"'s origin. +It then calculates a new spot to shoot at so that the +projectile will arrive at such spot at the same time as +"targ". Will return '0 0 0' (FALSE) if there is not a clear +line of fire to the spot or if the new vector is out of the +acceptable range (based on dot product of original vec and +the new vec). + +PROPOSAL: Factor in skill->value? 0 = no leading, 4 = perfect leading, 1-3 innaccuracy levels for leading +============================================================= +*/ +void extrapolateFiredir (edict_t *self,vec3_t p1,float pspeed,edict_t *targ,float accept,vec3_t vec2) +{ + float dist1, dist2, tspeed, dot, eta1, eta2, eta_delta, tdist; + qboolean failed = false; + vec3_t p2, p3, targ_dir, vec1, tempv; + trace_t trace; + float offset; + + if(!targ) + { + VectorClear(vec2); + return; + } + + tdist = vhlen(targ->s.origin, self->s.origin); + if(!skill->value) + {//poor shot, take forward and screw it up + AngleVectors(self->s.angles, tempv, NULL, NULL); + VectorMA(p1, pspeed, tempv, p2); + + if(tdist < 128) + offset = 48 * tdist/128; + else + offset = 48; + + p2[0] += flrand(-offset, offset); + p2[1] += flrand(-offset, offset); + p2[2] += flrand(-offset/2, offset * 0.666); + VectorSubtract(p2, p1, vec2); + VectorNormalize(vec2); + return; + } + + offset = 2 - skill->value;//skill >= 2 = perfect aim, skill 1 is very poor + + if(tdist < 128) + offset *= tdist/128; + + if(offset<0) + offset = 0; + + if(skill->value < 2.0 && !(self->monsterinfo.aiflags & AI_NIGHTVISION)) + { + if(targ->client) + { + offset += targ->light_level/32; + } + } + + VectorCopy(targ->s.origin, p2); + if(offset) + { + p2[0] += flrand(-offset*12, offset*12); + p2[1] += flrand(-offset*12, offset*12); + p2[2] += flrand(-offset*8, offset*8); + } + + VectorSubtract(p2, p1, vec1); + + dist1 = VectorNormalize(vec1); + + VectorCopy(targ->velocity, targ_dir); + + tspeed = VectorNormalize(targ_dir); + eta1 = dist1/pspeed; //Estimated time of arrival of projectile to p2 + + VectorMA(p2, tspeed*eta1, targ_dir, p3); + VectorSubtract(p3, p1, tempv); + + dist2 = VectorNormalize(tempv); + eta2 = dist2/pspeed; //ETA of projectile to p3 + eta_delta = eta2-eta1; //change in ETA's + + VectorMA(p3, tspeed*eta_delta*flrand(0, 1), targ_dir, p3); +//careful, above version does not modify targ_dir + + gi.trace(p1, vec3_origin, vec3_origin, p3, self, MASK_SOLID,&trace); + if(trace.fraction<1.0) + failed = true; + + VectorSubtract(p3, p1, vec2); + VectorNormalize(vec2); + + dot = DotProduct(vec1, vec2); + + if(dotprev_alert) + { + if(self->next_alert) + self->prev_alert->next_alert = self->next_alert; + else + {//I'm the last one! + level.last_alert = self->prev_alert; + self->prev_alert->next_alert = NULL; + } + } + else + {//I'm the first one! + if(self->next_alert) + level.alert_entity = self->next_alert; + else + level.last_alert = level.alert_entity = NULL; + } + + //Clear out all fields + self->next_alert = NULL; + self->prev_alert = NULL; + self->enemy = NULL; + VectorClear(self->origin); + self->alert_svflags = 0; + self->lifetime = 0; + self->inuse = false; + ClearLastAlerts(self); + + level.num_alert_ents--; +} + +/* +GetFirstEmptyAlertInList + +returns the first alert in the level.alertents list that isn;t in use +*/ +alertent_t *GetFirstEmptyAlertInList(void) +{ + int i; + //have max number of alerts, remove the first one + if(level.num_alert_ents >= MAX_ALERT_ENTS) + alert_timed_out(level.alert_entity); + + for(i = 0; i < MAX_ALERT_ENTS; i++) + { + if(!level.alertents[i].inuse) + { + return &level.alertents[i]; + } + } + return NULL; +} + +/* +AlertMonsters + +allots an alertent monsters will check during FindTarget to see if they should be alerted by it + +self = used for sv_flags info and positioning of the alert entity +enemy = entity to make the monsters mad at if they're alerted +(float)lifetime = how many seconds the alert exists for +(qboolean)ignore_shadows = this alert gives away enemy's position, even if he is in shadows (I use this for staff hits on the floor and any other effect the player makes at his own location(like shooting a weapon), not for projectiles impacting) +*/ +void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows) +{//FIXME: if and stick new one at the end + alertent_t *alerter = level.alert_entity; + alertent_t *last_alert = NULL; + + if (deathmatch->value) // Don't need this if no monsters... + return; + + if(!lifetime) + lifetime = 1.0;//stick around for 1 second + + //stick into the level's alerter chain + if(alerter) + {//go down the list and find an empty slot + //fixme: just store the entnum? + while(alerter->next_alert) + { + last_alert = alerter; + alerter = alerter->next_alert; + } + level.last_alert = alerter = GetFirstEmptyAlertInList(); + } + else//we're the first one! + level.alert_entity = level.last_alert = alerter = GetFirstEmptyAlertInList(); + + if(!alerter) + { +#ifdef _DEVEL + gi.dprintf("Error: out of alerts and can't find any empty slots!\n"); +#endif + return; + } + + //I'm active, don't let my slot be used until I'm freed + alerter->inuse = true; + //point to the previous alerter, if any + alerter->prev_alert = last_alert; + //make the previous alerter point to me as the next one + if(alerter->prev_alert) + alerter->prev_alert->next_alert = alerter; + //put me in the "self"'s spot + VectorCopy(self->s.origin, alerter->origin); + alerter->enemy = enemy; + //should we keep track of owner in case they move to move the alert with them? Only for monsters + //alerter->owner = self; + alerter->alert_svflags = self->svflags; + if(ignore_shadows)//whatever happened would give away enemy's position, even in shadows + alerter->alert_svflags |= SVF_ALERT_NO_SHADE; + + //stick around until after this point in time + alerter->lifetime = level.time + lifetime; + + level.num_alert_ents++; +} + +void ai_spin (edict_t *self, float amount) +{ + self->s.angles[YAW] += amount; +} + +qboolean ai_have_enemy (edict_t *self) +{ + qboolean enemy_gone = false; + + if(!self->enemy) + enemy_gone = true; + else if(self->enemy->health <= 0) + enemy_gone = true; + + if(!enemy_gone) + return true; + else + { + if(self->oldenemy) + { + if(self->oldenemy->health>0) + { + self->enemy=self->oldenemy; + self->oldenemy = NULL; +// gi.dprintf("Going for old enemy\n"); + return true; + } + } + } + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +// gi.dprintf("Lost enemies\n"); + return false; +} + +qboolean movable (edict_t *ent) +{ + if( ent->movetype!=PHYSICSTYPE_NONE && + ent->movetype!=MOVETYPE_PUSH && + ent->movetype!=PHYSICSTYPE_PUSH) + return true; + + return false; +} diff --git a/Toolkit/Programming/GameCode/game/g_boundingform.h b/Toolkit/Programming/GameCode/game/g_boundingform.h new file mode 100644 index 0000000..68d0bfc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_boundingform.h @@ -0,0 +1,18 @@ +#ifndef G_BOUNDINGFORM_H +#define G_BOUNDINGFORM_H + +#include "q_Typedef.h" + +// sides for a nonrotating box +enum Box_BoundingForm_Sides_e +{ + BOX_BOUNDINGFORM_SIDE_WEST, + BOX_BOUNDINGFORM_SIDE_NORTH, + BOX_BOUNDINGFORM_SIDE_SOUTH, + BOX_BOUNDINGFORM_SIDE_EAST, + BOX_BOUNDINGFORM_SIDE_BOTTOM, + BOX_BOUNDINGFORM_SIDE_TOP, + NUM_BOX_BOUNDINGFORM_SIDES +} Box_BoundingForm_Sides_t; + +#endif // G_BOUNDINGFORM_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_breakable.c b/Toolkit/Programming/GameCode/game/g_breakable.c new file mode 100644 index 0000000..13f8c09 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_breakable.c @@ -0,0 +1,273 @@ +/* +============================================================================== + +// g_breakable.c +// +// Heretic II +// Copyright 1998 Raven Software + + +============================================================================== +*/ +#include "g_local.h" +#include "g_misc.h" +#include "fx.h" +#include "g_DefaultMessageHandler.h" +#include "vector.h" + +int BREAK_KILLALL = 1; +int BREAK_NOLINK = 2; +int BREAK_CHECKNAME = 4; +int BREAK_ORDERED = 8; +int BREAK_TRANSLUCENT = 16; +int BREAK_INVULNERABLE = 32; +int BREAK_INVISIBLE = 64; + + +/* +void KillBrushOrdered(edict_t *self) +{ + local entity starte, oself, other; + local float headNum; + + oself = starte = self; + headNum = self.count; + + do + { + if (self.count >= headNum) + self.th_die(); + + self = self.enemy; + } while ( (self != starte) && (self != world) && (self.frags != self.cnt)); +} +*/ + +void KillBrush(edict_t *targ,edict_t *inflictor,edict_t *attacker,int damage) +{ + edict_t *starte, *other; + + starte = targ; + + if (starte->spawnflags & BREAK_KILLALL) + { + do + { + other = targ->enemy; + + QPostMessage(targ,MSG_DEATH,PRI_DIRECTIVE,"eeei",targ,inflictor,attacker,damage); + + targ = other; + } while ( (targ != starte) ); + } +// else if (targ->spawnflags & BREAK_HIERARCH) +// { +// ; +// KillBrushOrdered(targ); +// } + else + { + QPostMessage(targ,MSG_DEATH,PRI_DIRECTIVE,"eeei",targ,inflictor,attacker,damage); + } + +// this was firing off targets twice... fix it if this is not good, +// but the MSG_DEATH handler for objects uses targets a second time! +// G_UseTargets(targ, targ); +} + + +void KillBrushUse(edict_t *targ,edict_t *inflictor,edict_t *attacker) +{ + QPostMessage(targ,MSG_DEATH,PRI_DIRECTIVE,"eeei",targ,inflictor,attacker,0); +} + +void BBrushStaticsInit(void) +{ + classStatics[CID_BBRUSH].msgReceivers[MSG_DEATH] = DefaultObjectDieHandler; +} + +void BBrushInit(edict_t *self) +{ + + self->movetype = PHYSICSTYPE_NONE; + self->msgHandler = DefaultMsgHandler; + self->classID = CID_BBRUSH; + + if (self->spawnflags & BREAK_INVULNERABLE) + { + self->takedamage = DAMAGE_NO; + } + else + { + self->takedamage = DAMAGE_YES; + } + +} + +qboolean EntitiesTouching(edict_t *e1,edict_t *e2) +{ + vec3_t e1max, e1min, e2max, e2min; + + VectorCopy(e1->maxs,e1max); + VectorCopy(e1->mins,e1min); + + VectorCopy(e2->maxs,e2max); + VectorCopy(e2->mins,e2min); + + if (e1min[0] > e2max[0]) + return (false); + if (e1min[1] > e2max[1]) + return (false); + if (e1min[2] > e2max[2]) + return (false); + if (e1max[0] < e2min[0]) + return (false); + if (e1max[1] < e2min[1]) + return (false); + if (e1max[2] < e2min[2]) + return (false); + return (true); +} + +/*-------------------------------------- + LinkBreakables - used to link up brushes that have KILLALL set +----------------------------------------*/ +void LinkBreakables(edict_t *self) +{ + edict_t *t, *ent; + vec3_t cmins, cmaxs; + + self->think = NULL; + + if (self->enemy) // already linked by another breakable + { + return; + } + + VectorCopy(self->mins,cmins); + VectorCopy(self->maxs,cmaxs); + + t = ent = self; + + do + { + ent->owner = self; // master breakable + + if (ent->health) + { + self->health = ent->health; + } + + if (ent->targetname) + { + self->targetname = ent->targetname; + } + + t = G_Find (t, FOFS(classname), ent->classname); + + + if (!t) + { + ent->enemy = self; // make the chain a loop + ent = ent->owner; + return; + } + + if (ent->spawnflags & BREAK_NOLINK) + continue; + + if (EntitiesTouching(self,t)) + { + if (t->enemy) + { + return; + } + + ent->enemy = t; + ent = t; + } + } while (1); +} + +/*QUAKED breakable_brush (1 .5 0) ? KILLALL NOLINK ORDERED TRANSLUCENT INVULNERABLE INVISIBLE PUSHPULL NOTPLAYERDAMAGE + + A brush that explodes. + +NOTPLAYERDAMAGE - players cannot damage this brush + +KILLALL - kills any brushes touching this one + +HIERARCH - kills any brushes touching this one + +NOLINK - can touch a KILLALL brush and not be linked to it + +INVULNERABLE - if set it can't be hurt + +*** VARIABLES *** +health - amount of damage the brush can take before exploding +materialtype - +0 = STONE +1 = GREYSTONE (default)map +2 = CLOTH +3 = METAL +4 = FLESH +5 = POTTERY +6 = GLASS +7 = LEAF +8 = WOOD +9 = BROWNSTONE +10 = NONE - just makes smoke + + +*/ +void SP_breakable_brush (edict_t *ent) +{ + vec3_t space; + float spacecube; + + BBrushInit(ent); + + if (!ent->materialtype) + ent->materialtype = MAT_GREYSTONE; + + if (!ent->health) + ent->health = 1; + + + if (ent->spawnflags & 16) // Invulnerable + { + ent->takedamage = DAMAGE_NO; + } + else + { + ent->takedamage = DAMAGE_YES; + } + + + if (ent->spawnflags & 64) + { + ent->movetype = PHYSICSTYPE_PUSH; +// ent->think = M_droptofloor; +// ent->nextthink = level.time + 2 * FRAMETIME; + } + else + ent->movetype = PHYSICSTYPE_NONE; + + if (ent->spawnflags & 128) + ent->svflags |= SVF_NO_PLAYER_DAMAGE; + + ent->solid = SOLID_BSP; + + ent->use = KillBrushUse; + + gi.setmodel (ent, ent->model); + gi.linkentity (ent); + + // Use size to calculate mass + VectorSubtract(ent->maxs, ent->mins, space); + spacecube = space[0] * space[1] * space[2]; + ent->mass = spacecube / 64; // + + ent->nextthink = level.time + FRAMETIME; + ent->think = LinkBreakables; +} diff --git a/Toolkit/Programming/GameCode/game/g_cmds.c b/Toolkit/Programming/GameCode/game/g_cmds.c new file mode 100644 index 0000000..5870afd --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_cmds.c @@ -0,0 +1,1378 @@ +#include "g_local.h" +#include "m_player.h" +#include "vector.h" +#include "g_items.h" +#include "random.h" +#include "g_playstats.h" +#include "p_actions2.h" +#include "p_anims2.h" +#include "p_main2.h" +#include "p_funcs.h" +#include "g_itemstats.h" +#include "cl_strings.h" + +extern gitem_armor_t silver_armor_info; +extern gitem_armor_t gold_armor_info; +extern void MorphPlayerToChicken(edict_t *self, edict_t *caster); +extern qboolean AddWeaponToInventory(gitem_t *it,edict_t *player); +extern void AddDefenseToInventory(gitem_t *it,edict_t *player); + +qboolean CheckFlood(edict_t *ent); +void ED_CallSpawn (edict_t *ent); +void MorphPlayerToChicken(edict_t *self, edict_t *caster); + +char *ClientTeam (edict_t *ent) +{ + char *p; + static char value[512]; + + value[0] = 0; + + if (!ent->client) + return value; + + strcpy(value, Info_ValueForKey (ent->client->playerinfo.pers.userinfo, "skin")); + + p = strchr(value, '/'); + if (!p) + return value; + + // if ((int)(dmflags->value) & DF_SKINTEAMS) + return ++p; +} + +qboolean OnSameTeam (edict_t *ent1, edict_t *ent2) +{ + char ent1Team [512]; + char ent2Team [512]; + + if (!((int)(dmflags->value) & DF_SKINTEAMS)) + return false; + + strcpy (ent1Team, ClientTeam (ent1)); + strcpy (ent2Team, ClientTeam (ent2)); + + if (strcmp(ent1Team, ent2Team) == 0) + return true; + return false; +} + +void SelectNextItem (edict_t *ent, int itflags) +{ + gclient_t *cl; + int i, index; + gitem_t *it; + + if(sv_cinematicfreeze->value) + return; + + cl = ent->client; + + // scan for the next valid one + for (i=1 ; i<=MAX_ITEMS ; i++) + { + index = (cl->playerinfo.pers.selected_item + i)%MAX_ITEMS; + if (!cl->playerinfo.pers.inventory.Items[index]) + continue; + + it = &p_itemlist[index]; + if (!it->use) + continue; + if (!(it->flags & itflags)) + continue; + + cl->playerinfo.pers.selected_item = index; + + return; + } + + cl->playerinfo.pers.selected_item = -1; +} + +void SelectPrevItem (edict_t *ent, int itflags) +{ + gclient_t *cl; + int i, index; + gitem_t *it; + + if(sv_cinematicfreeze->value) + return; + + cl = ent->client; + + // scan for the next valid one + for (i=1 ; i<=MAX_ITEMS ; i++) + { + index = (cl->playerinfo.pers.selected_item + MAX_ITEMS - i) % MAX_ITEMS; + if (!cl->playerinfo.pers.inventory.Items[index]) + continue; + + it = &p_itemlist[index]; + if (!it->use) + continue; + if (!(it->flags & itflags)) + continue; + + cl->playerinfo.pers.selected_item = index; + cl->playerinfo.pers.defence = it; + + return; + } + + cl->playerinfo.pers.selected_item = -1; +} + +void ValidateSelectedItem (edict_t *ent) +{ + gclient_t *cl; + + cl = ent->client; + + if (cl->playerinfo.pers.inventory.Items[cl->playerinfo.pers.selected_item]) + return; // valid + + SelectNextItem (ent, -1); +} + +//================================================================================= + +/* +================== +Cmd_Give_f + +Give items to a client +================== +*/ +void Cmd_Give_f (edict_t *ent) +{ + char *name; + gitem_t *it; + int index; + int i; + qboolean give_all; + + if (deathmatch->value && !sv_cheats->value) + { + gi.gamemsg_centerprintf (ent, GM_NOCHEATS); + return; + } + + name = gi.args(); + // FOR TESTING ONLY ! + + if ((Q_stricmp(name, "level") == 0)) + { + + if(level.offensive_weapons&4) + { + it=FindItem("hell"); + AddWeaponToInventory(it,ent); + } + + if(level.offensive_weapons&8) + { + it=FindItem("array"); + AddWeaponToInventory(it,ent); + } + + if(level.offensive_weapons&16) + { + it=FindItem("rain"); + AddWeaponToInventory(it,ent); + } + + if(level.offensive_weapons&32) + { + it=FindItem("sphere"); + AddWeaponToInventory(it,ent); + } + + if(level.offensive_weapons&64) + { + it=FindItem("phoen"); + AddWeaponToInventory(it,ent); + } + + if(level.offensive_weapons&128) + { + it=FindItem("mace"); + AddWeaponToInventory(it,ent); + } + + if(level.offensive_weapons&256) + { + it=FindItem("fwall"); + AddWeaponToInventory(it,ent); + } + + if(level.defensive_weapons&1) + { + it=FindItem("ring"); + AddDefenseToInventory(it,ent); + } + + if(level.defensive_weapons&2) + { + it=FindItem("lshield"); + AddDefenseToInventory(it,ent); + } + + if(level.defensive_weapons&4) + { + it=FindItem("tele"); + AddDefenseToInventory(it,ent); + } + + if(level.defensive_weapons&8) + { + it=FindItem("morph"); + AddDefenseToInventory(it,ent); + } + + if(level.defensive_weapons&16) + { + it=FindItem("meteor"); + AddDefenseToInventory(it,ent); + } + + SetupPlayerinfo_effects(ent); + PlayerUpdateModelAttributes(&ent->client->playerinfo); + WritePlayerinfo_effects(ent); + return; + } + + if (Q_stricmp(name, "all") == 0) + give_all = true; + else + give_all = false; + + if (give_all || Q_stricmp(name, "health") == 0) + { + if (gi.argc() == 3) + ent->health += atoi(gi.argv(2)); + else + ent->health = ent->max_health; + + if(give_all || ent->health == ent->max_health) + ResetPlayerBaseNodes (ent);//put back all your limbs! + + if (!give_all) + return; + } + + if (give_all || Q_stricmp(name, "weapons") == 0) + { + for (i=0 ; ipickup) + continue; + if (!(it->flags & IT_WEAPON)) + continue; + +#if DEMO_CODE + // don't allow certain things for demo + if ((int)it->info) + continue; +#endif + + + ent->client->playerinfo.pers.inventory.Items[i] += 1; + + if((it->playeranimseq == ASEQ_WRRBOW_GO)||(it->playeranimseq == ASEQ_WPHBOW_GO)) + { + // This is a bow, put the bow on his back. + + if (it->tag == ITEM_WEAPON_PHOENIXBOW) + ent->client->playerinfo.pers.bowtype = BOW_TYPE_PHOENIX; + else + ent->client->playerinfo.pers.bowtype = BOW_TYPE_REDRAIN; + + SetupPlayerinfo_effects(ent); + PlayerUpdateModelAttributes(&ent->client->playerinfo); + WritePlayerinfo_effects(ent); + } + } + if (!give_all) + return; + } + + if (give_all || Q_stricmp(name, "defences") == 0) + { + for (i=0 ; ipickup) + continue; + if (!(it->flags & IT_DEFENSE)) + continue; + +#if DEMO_CODE + // don't allow certain things for demo + if ((int)it->info) + continue; +#endif + + + ent->client->playerinfo.pers.inventory.Items[i] += 1; + } + + // if we don't already have a defence item, make the ring default + if (ent->client->playerinfo.pers.defence == NULL) + ent->client->playerinfo.pers.defence=FindItem("ring"); + + if (!give_all) + return; + } + + if (give_all || Q_stricmp(name, "mana") == 0) + { + for (i=0 ; ipickup) + continue; + if (!(it->flags & IT_AMMO)) + continue; + Add_Ammo (ent, it, 1000); + } + if (!give_all) + return; + } + + if (give_all || Q_stricmp(name, "armor") == 0) + { + if (ent->client->playerinfo.pers.armortype == ARMOR_TYPE_NONE) + { + ent->client->playerinfo.armor_count = silver_armor_info.max_armor; + ent->client->playerinfo.pers.armortype = ARMOR_TYPE_SILVER; + } + else // We'll assume there's armor, so load up with gold. + { + ent->client->playerinfo.armor_count = gold_armor_info.max_armor; + ent->client->playerinfo.pers.armortype = ARMOR_TYPE_GOLD; + + } + + SetupPlayerinfo_effects(ent); + PlayerUpdateModelAttributes(&ent->client->playerinfo); + WritePlayerinfo_effects(ent); + + if (!give_all) + return; + } + + // Give all does not give staff powerup + if (Q_stricmp(name, "staff") == 0) + { + if (ent->client->playerinfo.pers.stafflevel < (STAFF_LEVEL_MAX-1)) + ent->client->playerinfo.pers.stafflevel++; + else + ent->client->playerinfo.pers.stafflevel = STAFF_LEVEL_BASIC; + + gi.dprintf("Setting staff level to %d\n", ent->client->playerinfo.pers.stafflevel); + + SetupPlayerinfo_effects(ent); + PlayerUpdateModelAttributes(&ent->client->playerinfo); + WritePlayerinfo_effects(ent); + + return; + } + + // Give all does not give lungs + if (Q_stricmp(name, "lungs") == 0) + { + + // add gam time + 30 secs to lungs timer + + ent->client->playerinfo.lungs_timer = LUNGS_DURATION; + ent->air_finished = level.time + HOLD_BREATH_TIME; + + return; + } + + // Give all does not give powerups + if (Q_stricmp(name, "powerup") == 0) + { + + // add gam time + 30 secs to powerup timer + + ent->client->playerinfo.powerup_timer = POWERUP_DURATION + level.time; + + return; + } + + // Give all does not give reflection. + if (Q_stricmp(name, "reflection") == 0) + { + + // add gam time + 30 secs to reflect timer + + // add some time in on the timer for the reflectivity + ent->client->playerinfo.reflect_timer = level.time + REFLECT_DURATION_SINGLE; + + // turn on the relection at the client effect end through client flags that are passed down + ent->s.renderfx |= RF_REFLECTION; + + return; + } + + // Give all does not give ghost + if (Q_stricmp(name, "ghost") == 0) + { + // add some time in on the timer for the ghost effect + ent->client->playerinfo.ghost_timer = level.time + GHOST_DURATION; + + // turn on the ghosting at the client effect end through client flags that are passed down + ent->s.renderfx |= RF_TRANS_GHOST; + return; + } + + // Give all does not give chicken. + if (Q_stricmp(name, "chicken") == 0) + { + MorphPlayerToChicken(ent, ent); + + return; + } + + // Give all does not give plague + if (Q_stricmp(name, "plague") == 0) + { + if (ent->client->playerinfo.plaguelevel < PLAGUE_NUM_LEVELS-1) + ent->client->playerinfo.plaguelevel++; + else + ent->client->playerinfo.plaguelevel=0; + + gi.dprintf("Setting plague level to %d\n", ent->client->playerinfo.plaguelevel); + + SetupPlayerinfo_effects(ent); + PlayerUpdateModelAttributes(&ent->client->playerinfo); + WritePlayerinfo_effects(ent); + + return; + } + + if (give_all) + { + for (i=0 ; ipickup) && !(it->flags & IT_PUZZLE)) + continue; + if (it->flags & (IT_ARMOR|IT_WEAPON|IT_AMMO|IT_DEFENSE)) + continue; + + ent->client->playerinfo.pers.inventory.Items[i] = 1; + } + return; + } + + it = FindItem (name); + if (!it) + { + name = gi.argv(1); + it = FindItem (name); + if (!it) + { + gi.dprintf ("unknown item\n"); + return; + } + } + + if (!it->pickup) + { + gi.dprintf ("non-pickup item\n"); + return; + } + +#if DEMO_CODE + // don't allow certain things for demo + if ((int)it->info) + { + gi.cprintf (ent, PRINT_HIGH,"Non Selectable Item in Demo\n"); + return; + } +#endif + + index = ITEM_INDEX(it); + + if (it->flags & IT_WEAPON) + { + ent->client->playerinfo.pers.inventory.Items[index] += 1; + } + else if (it->flags & IT_AMMO) + { + if (gi.argc() == 3) + ent->client->playerinfo.pers.inventory.Items[index] += atoi(gi.argv(2)); + else + ent->client->playerinfo.pers.inventory.Items[index] += it->quantity; + } + else + { + ent->client->playerinfo.pers.inventory.Items[index] += 1; + } + + // if we don't already have a defence item, make this defence item default + if ((ent->client->playerinfo.pers.defence == NULL) && (it->flags & IT_DEFENSE)) + ent->client->playerinfo.pers.defence=it; + + +} + + +/* +================== +Cmd_God_f + +Sets client to godmode + +argv(0) god +================== +*/ +void Cmd_God_f (edict_t *ent) +{ + char *msg; + + if (deathmatch->value && !sv_cheats->value) + { + gi.gamemsg_centerprintf (ent, GM_NOCHEATS); + return; + } + + ent->flags ^= FL_GODMODE; + if (!(ent->flags & FL_GODMODE) ) + msg = "godmode OFF\n"; + else + msg = "godmode ON\n"; + + gi.cprintf (ent, PRINT_HIGH, msg); +} + + +/* +================== +Cmd_Notarget_f + +Sets client to notarget + +argv(0) notarget +================== +*/ +void Cmd_Notarget_f (edict_t *ent) +{ + char *msg; + + if (deathmatch->value && !sv_cheats->value) + { + gi.gamemsg_centerprintf (ent, GM_NOCHEATS); + return; + } + + ent->flags ^= FL_NOTARGET; + if (!(ent->flags & FL_NOTARGET) ) + msg = "notarget OFF\n"; + else + msg = "notarget ON\n"; + + gi.cprintf (ent, PRINT_HIGH, msg); +} + +/* +================== +Cmd_Noclip_f + +argv(0) noclip +================== +*/ +void Cmd_Noclip_f (edict_t *ent) +{ + char *msg; + + if (deathmatch->value && !sv_cheats->value) + { + gi.gamemsg_centerprintf (ent, GM_NOCHEATS); + return; + } + + if (ent->movetype == PHYSICSTYPE_NOCLIP) + { + ent->movetype = PHYSICSTYPE_STEP; + msg = "noclip OFF\n"; + } + else + { + ent->movetype = PHYSICSTYPE_NOCLIP; + msg = "noclip ON\n"; + } + + gi.cprintf (ent, PRINT_HIGH, msg); +} + +/* +================== +Cmd_Powerup_f + +argv(0) powerup +================== +*/ +void Cmd_Powerup_f (edict_t *ent) +{ + char *msg; + + if (deathmatch->value && !sv_cheats->value) + { + gi.gamemsg_centerprintf (ent, GM_NOCHEATS); + return; + } + + assert(ent->client); + if (ent->client->playerinfo.powerup_timer > level.time) + { // Turn OFF powerup + ent->client->playerinfo.powerup_timer = level.time-0.1; + msg = "Powerup OFF\n"; + } + else + { // Turn ON powerup + ent->client->playerinfo.powerup_timer = level.time + (60*60*24); // One full day + msg = "Powerup ON\n"; + } + + gi.cprintf (ent, PRINT_HIGH, msg); +} + + +/* +================== +Cmd_Use_f + +Use an inventory item +================== +*/ +void Cmd_Use_f (edict_t *ent, char *s) +{ + int index; + gitem_t *it; + + it = FindItem (s); + + if(sv_cinematicfreeze->value) + return; + + if (!it) + { + gi.cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s); + return; + } + if (!it->use) + { + gi.gamemsg_centerprintf (ent, GM_NOTUSABLE); + return; + } + index = ITEM_INDEX(it); + + if (!ent->client->playerinfo.pers.inventory.Items[index]) + { + if ((it->flags == IT_WEAPON) || (it->flags == IT_DEFENSE)) + // index is two off, since we can never run out of the staff or the flying fist + gi.gamemsg_centerprintf (ent, it->msg_nouse); + else + gi.gamemsg_centerprintf (ent, GM_NOITEM); + return; + } + + it->use(&ent->client->playerinfo,it); +} + +/* +================= +Cmd_WeapPrev_f +================= +*/ +void Cmd_WeapPrev_f (edict_t *ent) +{ + gclient_t *cl; + int i, index; + gitem_t *it; + int selected_weapon; + + cl = ent->client; + + if (!cl->playerinfo.pers.weapon || sv_cinematicfreeze->value) + return; + + selected_weapon = ITEM_INDEX(cl->playerinfo.pers.weapon); + + // scan for the next valid one + for (i=1 ; i<=MAX_ITEMS ; i++) + { + index = (selected_weapon + (MAX_ITEMS -i))%MAX_ITEMS; + + if (!cl->playerinfo.pers.inventory.Items[index]) + continue; + + it = &p_itemlist[index]; + if (!it->use) + continue; + if (! (it->flags & IT_WEAPON) ) + continue; + + // if we are in water, don't select any weapon that requires ammo + if ((ent->waterlevel >= 2) && + ((it->tag == ITEM_WEAPON_HELLSTAFF) || + (it->tag == ITEM_WEAPON_REDRAINBOW) || + (it->tag == ITEM_WEAPON_PHOENIXBOW))) + continue; + + it->use(&ent->client->playerinfo,it); + if (ent->client->playerinfo.pers.newweapon == it) + return; // successful + } +} + +/* +================= +Cmd_WeapNext_f +================= +*/ +void Cmd_WeapNext_f (edict_t *ent) +{ + gclient_t *cl; + int i, index; + gitem_t *it; + int selected_weapon; + + cl = ent->client; + + if (!cl->playerinfo.pers.weapon || sv_cinematicfreeze->value) + return; + + selected_weapon = ITEM_INDEX(cl->playerinfo.pers.weapon); + + // scan for the next valid one + for (i=1 ; i<=MAX_ITEMS ; i++) + { + index = (selected_weapon + i)%MAX_ITEMS; + + if (!cl->playerinfo.pers.inventory.Items[index]) + continue; + + it = &p_itemlist[index]; + if (!it->use) + continue; + if (! (it->flags & IT_WEAPON) ) + continue; + + // if we are in water, don't select any weapon that requires ammo + if ((ent->waterlevel >= 2) && + ((it->tag == ITEM_WEAPON_HELLSTAFF) || + (it->tag == ITEM_WEAPON_REDRAINBOW) || + (it->tag == ITEM_WEAPON_PHOENIXBOW))) + continue; + + it->use(&ent->client->playerinfo,it); + if (ent->client->playerinfo.pers.newweapon == it) + return; // successful + } +} +/* +================= +Cmd_DefPrev_f +================= +*/ +void Cmd_DefPrev_f (edict_t *ent) +{ + gclient_t *cl; + int i, index; + gitem_t *it; + int selected_defence; + int start_defence; + + if(sv_cinematicfreeze->value) + return; + + cl = ent->client; + + if (!cl->playerinfo.pers.defence) + selected_defence = 1; + else + selected_defence = ITEM_INDEX(cl->playerinfo.pers.defence); + start_defence = selected_defence; + + // scan for the next valid one + for (i=1 ; i<=MAX_ITEMS ; i++) + { + index = (selected_defence + (MAX_ITEMS-i))%MAX_ITEMS; + + if (!cl->playerinfo.pers.inventory.Items[index]) + continue; + + it = &p_itemlist[index]; + if (!it->use) + continue; + if (! (it->flags & IT_DEFENSE) ) + continue; + + it->use(&ent->client->playerinfo,it); + if (cl->playerinfo.pers.defence == it) + { + selected_defence = index; + break; // successful + } + } + + if ((selected_defence != 1) && (start_defence != selected_defence)) + cl->playerinfo.G_Sound(ent, + CHAN_AUTO, + cl->playerinfo.G_SoundIndex("Weapons/DefenseSelect.wav"), + 1, + ATTN_NORM, + 0); +} + +/* +================= +Cmd_DefNext_f +================= +*/ +void Cmd_DefNext_f (edict_t *ent) +{ + gclient_t *cl; + int i, index; + gitem_t *it; + int selected_defence; + int start_defence; + + if(sv_cinematicfreeze->value) + return; + + cl = ent->client; + + if (!cl->playerinfo.pers.defence) + selected_defence = 1; + else + selected_defence = ITEM_INDEX(cl->playerinfo.pers.defence); + start_defence = selected_defence; + + // scan for the next valid one + for (i=1 ; i<=MAX_ITEMS ; i++) + { + index = (selected_defence + i)%MAX_ITEMS; + + if (!cl->playerinfo.pers.inventory.Items[index]) + continue; + it = &p_itemlist[index]; + if (!it->use) + continue; + if (! (it->flags & IT_DEFENSE) ) + continue; + + it->use(&ent->client->playerinfo,it); + if (cl->playerinfo.pers.defence == it) + { + selected_defence = index; + break; // successful + } + } + + if ((selected_defence != 1) && (start_defence != selected_defence)) + cl->playerinfo.G_Sound(ent, + CHAN_AUTO, + cl->playerinfo.G_SoundIndex("Weapons/DefenseSelect.wav"), + 1, + ATTN_NORM, + 0); +} + +/* +================= +Cmd_WeapLast_f +================= +*/ +void Cmd_WeapLast_f (edict_t *ent) +{ + gclient_t *cl; + int index; + gitem_t *it; + + if(sv_cinematicfreeze->value) + return; + + cl = ent->client; + + if (!cl->playerinfo.pers.weapon || !cl->playerinfo.pers.lastweapon) + return; + + index = ITEM_INDEX(cl->playerinfo.pers.lastweapon); + if (!cl->playerinfo.pers.inventory.Items[index]) + return; + + it = &p_itemlist[index]; + if (!it->use) + return; + if (! (it->flags & IT_WEAPON) ) + return; + + it->use(&ent->client->playerinfo,it); +} + +/* +================= +Cmd_Kill_f +================= +*/ +void Cmd_Kill_f (edict_t *ent) +{ + if(ent->client->flood_nextkill > level.time) + { + gi.msgvar_centerprintf(ent, GM_NOKILL, (int)(ent->client->flood_nextkill - level.time) + 1); + return; + } + ent->flags &= ~FL_GODMODE; + + if(ent->health > -1) + { + // Make sure we gib as we don't want bodies lying around everywhere. + + ent->health = -100000; + ent->client->meansofdeath = MOD_SUICIDE; + player_die (ent, ent, ent, 100000, vec3_origin); + + // Don't even bother waiting for death frames. + + ent->deadflag = DEAD_DEAD; + + // Put us back in the game + + respawn(ent); + + // Set up the next valid suicide time. + + ent->client->flood_nextkill = level.time + flood_killdelay->value; + } +} + + +int PlayerSort (void const *a, void const *b) +{ + int anum, bnum; + + anum = *(int *)a; + bnum = *(int *)b; + + anum = game.clients[anum].ps.stats[STAT_FRAGS]; + bnum = game.clients[bnum].ps.stats[STAT_FRAGS]; + + if (anum < bnum) + return -1; + if (anum > bnum) + return 1; + return 0; +} + +/* +================= +Cmd_Players_f +================= +*/ +void Cmd_Players_f (edict_t *ent) +{ + int i; + int count; + char qsmall[64]; + char large[1280]; + int index[256]; + + count = 0; + for (i = 0 ; i < maxclients->value ; i++) + + if (game.clients[i].playerinfo.pers.connected) + { + index[count] = i; + count++; + } + + // sort by frags + qsort (index, count, sizeof(index[0]), PlayerSort); + + // print information + large[0] = 0; + + for (i = 0 ; i < count ; i++) + { + Com_sprintf (qsmall, sizeof(qsmall), "%3i %s\n", + + game.clients[index[i]].ps.stats[STAT_FRAGS], + + game.clients[index[i]].playerinfo.pers.netname); + + if (strlen (qsmall) + strlen(large) > sizeof(large) - 100 ) + { // can't print all of them in one packet + strcat (large, "...\n"); + break; + } + strcat (large, qsmall); + } + + gi.cprintf (ent, PRINT_HIGH, "%s\n%i players\n", large, count); +} + +/* +=================== +Spawn an item +=================== +*/ + +void Cmd_SpawnEntity_f(edict_t *ent) +{ +#if DEMO_CODE + gi.cprintf(ent, PRINT_HIGH, "Cannot spawn items in the Heretic II Demo.\n"); +#else + vec3_t forward; + edict_t *newent; + + if (deathmatch->value && !sv_cheats->value) + { + gi.gamemsg_centerprintf (ent, GM_NOCHEATS); + return; + } + gi.cprintf(ent, PRINT_HIGH, "Spawning : %s\n", gi.argv(1)); + + newent = G_Spawn(); + newent->classname = ED_NewString(gi.argv(1)); + AngleVectors(ent->s.angles, forward, NULL, NULL); + VectorScale(forward, 100, forward); + VectorAdd(ent->s.origin, forward, newent->s.origin); + VectorCopy(ent->s.angles, newent->s.angles); + ED_CallSpawn(newent); +#endif +} + +/* +=================== +Toggle the Inventory Console +=================== +*/ + +void Cmd_ToggleInventory_f(edict_t *ent) +{ + gclient_t *cl; + + cl = ent->client; + + if (cl->playerinfo.showpuzzleinventory) + cl->playerinfo.showpuzzleinventory = false; + else + cl->playerinfo.showpuzzleinventory = true; + +} + + +/* +=================== +Kill all monsters on a level +=================== +*/ + +extern void Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mod); +void Cmd_KillMonsters_f(edict_t *ent) +{ + edict_t *searchent; + + gi.cprintf(ent, PRINT_HIGH, "Killing all non-boss level monsters\n"); + + for (searchent = g_edicts; searchent < &g_edicts[globals.num_edicts]; searchent++) + { + if (!searchent->inuse) + continue; + if ((searchent->svflags & SVF_MONSTER) && !(searchent->monsterinfo.c_mode) && !(searchent->svflags & SVF_BOSS)) + { + gi.dprintf("Killing monster %s\n", searchent->classname); + Killed (searchent, ent, ent, 100000, searchent->s.origin, MOD_UNKNOWN); + searchent->health = 0; + } + } +} + +void Cmd_CrazyMonsters_f(edict_t *ent) +{ + edict_t *searchent; + edict_t *enemy_ent; + + gi.cprintf(ent, PRINT_HIGH, "Berzerking all level monsters\n"); + ANARCHY = true; + for (searchent = g_edicts; searchent < &g_edicts[globals.num_edicts]; searchent++) + { + if (!searchent->inuse) + continue; + if (searchent->svflags & SVF_MONSTER) + { + enemy_ent = NULL; + while(!enemy_ent || !enemy_ent->inuse || !(enemy_ent->svflags & SVF_MONSTER)||enemy_ent->health<0||enemy_ent == searchent) + { + enemy_ent = &g_edicts[irand(0, globals.num_edicts)]; + } + searchent->enemy = enemy_ent; + FoundTarget(searchent, false); + } + } +} + +void Cmd_AngerMonsters_f(edict_t *ent) +{ + edict_t *searchent; + + gi.cprintf(ent, PRINT_HIGH, "Angering all level monsters\n"); + for (searchent = g_edicts; searchent < &g_edicts[globals.num_edicts]; searchent++) + { + if (!searchent->inuse) + continue; + if (searchent->svflags & SVF_MONSTER) + { + searchent->enemy = ent; + FoundTarget(searchent, false); + } + } +} +/* +=================== +Go to next monster frame for frozen monsters +=================== +*/ + +extern qboolean MonsterAdvanceFrame; +void Cmd_NextMonsterFrame_f(edict_t *ent) +{ + MonsterAdvanceFrame = true; +} + +/* +================== +Cmd_Say_f +================== +*/ +void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0) +{ + int j; + edict_t *other; + char *p; + char text[2048]; + + if (gi.argc () < 2 && !arg0) + return; + + if (!((int)(dmflags->value) & DF_SKINTEAMS)) + team = false; + + Com_sprintf (text, sizeof(text), "%s: ", ent->client->playerinfo.pers.netname); + + if (arg0) + { + strcat (text, gi.argv(0)); + strcat (text, " "); + strcat (text, gi.args()); + } + else + { + p = gi.args(); + + if (*p == '"') + { + p++; + p[strlen(p)-1] = 0; + } + strcat(text, p); + } + + // don't let text be too long for malicious reasons + if (strlen(text) > 150) + text[150] = 0; + + strcat(text, "\n"); + + if (CheckFlood(ent)) + return; + + if (dedicated->value) + gi.cprintf(NULL, PRINT_CHAT, "%s", text); + + for (j = 1; j <= game.maxclients; j++) + { + other = &g_edicts[j]; + if (!other->inuse) + continue; + if (!other->client) + continue; + if (team) + { + if (!OnSameTeam(ent, other)) + continue; + gi.cprintf(other, PRINT_TEAM, "%s", text); + } + else + { + gi.cprintf(other, PRINT_CHAT, "%s", text); + } + } +} + + +void Cmd_ShowCoords_f (edict_t *ent) +{ + assert(ent->client); + + Com_Printf("Player Location: (%d, %d, %d)\n", + (int)(ent->s.origin[0]), (int)(ent->s.origin[1]), (int)(ent->s.origin[2])); + Com_Printf(" Angle: Facing=%2.2f, Pitch=%2.2f\n", ent->client->aimangles[YAW], -ent->client->aimangles[PITCH]); +} + + +void Cmd_TestFX_f (edict_t *ent) +{ + int i; + + if (ent->client == NULL) + return; + + i = irand(0, 15); + gi.dprintf("Setting pain skin number %d\n", i); + ent->client->playerinfo.pers.altparts |= 1<client->playerinfo); + WritePlayerinfo_effects(ent); +} + +/* +================= +ClientCommand +================= +*/ +void ClientCommand (edict_t *ent) +{ + char *cmd; + + if (!ent->client) + return; // not fully in game yet + + cmd = gi.argv(0); + + if (Q_stricmp (cmd, "players") == 0) + { + Cmd_Players_f (ent); + return; + } + if (Q_stricmp (cmd, "say") == 0) + { + Cmd_Say_f (ent, false, false); + return; + } + if (Q_stricmp (cmd, "say_team") == 0) + { + Cmd_Say_f (ent, true, false); + return; + } + if (Q_stricmp (cmd, "score") == 0) + { + Cmd_Score_f (ent); + return; + } + + if (level.intermissiontime) + return; + + else if (Q_stricmp (cmd, "playbetter") == 0) // else if (Q_stricmp (cmd, "god") == 0) + Cmd_God_f (ent); + else if (Q_stricmp (cmd, "kiwi") == 0) // else if (Q_stricmp (cmd, "noclip") == 0) + Cmd_Noclip_f (ent); + else if (Q_stricmp (cmd, "victor") == 0) // else if (Q_stricmp (cmd, "notarget") == 0) + Cmd_Notarget_f (ent); + else if (Q_stricmp (cmd, "suckitdown") == 0) // else if (Q_stricmp (cmd, "give") == 0) + Cmd_Give_f (ent); + else if (Q_stricmp (cmd, "twoweeks") == 0) // else if (Q_stricmp (cmd, "powerup") == 0) + Cmd_Powerup_f (ent); + else if (Q_stricmp (cmd, "meatwagon") == 0) // else if (Q_stricmp (cmd, "killmonsters") == 0) + Cmd_KillMonsters_f (ent); + else if (Q_stricmp (cmd, "use") == 0) + Cmd_Use_f (ent, gi.args()); + else if (Q_stricmp (cmd, "toggleinventory") == 0) + Cmd_ToggleInventory_f (ent); + else if (Q_stricmp (cmd, "invnextw") == 0) + SelectNextItem (ent, IT_WEAPON); + else if (Q_stricmp (cmd, "invprevw") == 0) + SelectPrevItem (ent, IT_WEAPON); + else if (Q_stricmp (cmd, "invnextp") == 0) + SelectNextItem (ent, IT_DEFENSE); + else if (Q_stricmp (cmd, "invprevp") == 0) + SelectPrevItem (ent, IT_DEFENSE); + else if (Q_stricmp (cmd, "weapprev") == 0) + Cmd_WeapPrev_f (ent); + else if (Q_stricmp (cmd, "weapnext") == 0) + Cmd_WeapNext_f (ent); + else if (Q_stricmp (cmd, "defprev") == 0) + Cmd_DefPrev_f (ent); + else if (Q_stricmp (cmd, "defnext") == 0) + Cmd_DefNext_f (ent); + else if (Q_stricmp (cmd, "weaplast") == 0) + Cmd_WeapLast_f (ent); + else if (Q_stricmp (cmd, "kill") == 0) + Cmd_Kill_f (ent); + else if (Q_stricmp (cmd, "spawn") == 0) + Cmd_SpawnEntity_f (ent); + else if (Q_stricmp (cmd, "nextmonsterframe") == 0) + Cmd_NextMonsterFrame_f(ent); + else if (Q_stricmp (cmd, "crazymonsters") == 0) + Cmd_CrazyMonsters_f (ent); + else if (Q_stricmp (cmd, "angermonsters") == 0) + Cmd_AngerMonsters_f (ent); + else if (Q_stricmp (cmd, "showcoords") == 0) + Cmd_ShowCoords_f (ent); + else if (Q_stricmp (cmd, "testfx") == 0) + Cmd_TestFX_f(ent); + else if (Q_stricmp (cmd, "gameversion") == 0) + { + gi.cprintf (ent, PRINT_HIGH, "%s : %s\n", GAMEVERSION, __DATE__); + } + else if (Q_stricmp (cmd, "fov") == 0) + { + ent->client->ps.fov = atoi(gi.argv(1)); + if (ent->client->ps.fov < 1) + ent->client->ps.fov = 90; + else if (ent->client->ps.fov > 160) + ent->client->ps.fov = 160; + } + else // anything that doesn't match a command will be a chat + Cmd_Say_f (ent, false, true); +} + +// Flood protection + +qboolean CheckFlood(edict_t *ent) +{ + int i; + + if (flood_msgs->value) + { + if (level.time < ent->client->flood_locktill) + { + gi.msgvar_centerprintf(ent, GM_SHUTUP, (int)(ent->client->flood_locktill - level.time)); + return true; + } + i = ent->client->flood_whenhead - flood_msgs->value + 1; + if (i < 0) + { + i = (sizeof(ent->client->flood_when) / sizeof(ent->client->flood_when[0])) + i; + } + if (ent->client->flood_when[i] && (level.time - ent->client->flood_when[i] < flood_persecond->value)) + { + ent->client->flood_locktill = level.time + flood_waitdelay->value; + gi.msgvar_centerprintf(ent, GM_SHUTUP, (int)flood_waitdelay->value); + return true; + } + ent->client->flood_whenhead = (ent->client->flood_whenhead + 1) % (sizeof(ent->client->flood_when) / sizeof(ent->client->flood_when[0])); + ent->client->flood_when[ent->client->flood_whenhead] = level.time; + } + return false; +} + +// end diff --git a/Toolkit/Programming/GameCode/game/g_combat.c b/Toolkit/Programming/GameCode/game/g_combat.c new file mode 100644 index 0000000..ccf0308 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_combat.c @@ -0,0 +1,1276 @@ +// g_combat.c + +#include "g_local.h" +#include "Utilities.h" +#include "g_HitLocation.h" +#include "g_DefaultMessageHandler.h" +#include "FX.h" +#include "vector.h" +#include "random.h" +#include "g_misc.h" +#include "p_main2.h" +#include "g_playstats.h" +#include "buoy.h" +#include "g_itemstats.h" +#include "m_stats.h" + +gitem_armor_t silver_armor_info = {MAX_SILVER_ARMOR, SILVER_HIT_MULT, SILVER_SPELL_MULT}; +gitem_armor_t gold_armor_info = {MAX_GOLD_ARMOR, GOLD_HIT_MULT, GOLD_SPELL_MULT}; + +void pitch_roll_for_slope (edict_t *forwhom, vec3_t *slope); +void MG_PostDeathThink (edict_t *self); +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); + +/* +============ +CanDamage + +Returns true if the inflictor can directly damage the target. Used for +explosions and melee attacks. +============ +*/ + +qboolean CanDamage (edict_t *targ, edict_t *inflictor) +{ + vec3_t dest, diff; + trace_t trace; + + // bmodels need special checking because their origin is 0,0,0 + if (targ->movetype == PHYSICSTYPE_PUSH || targ->classID == CID_BBRUSH) + { + VectorAdd (targ->absmin, targ->absmax, dest); + VectorScale (dest, 0.5, dest); + gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + + if (trace.fraction == 1.0) + return true; + + if (trace.ent == targ) + return true; + + return false; + } + + // Try a basic trace straight to the origin. This takes care of 99% of the tests. + gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, MASK_SOLID,&trace); + if (trace.fraction == 1.0) + return true; + + // Well, a trace from origin to origin didn't work, so try tracing to the edges of the victim. + + // If there are no edges, let's skip the rest of these checks.. + if (Vec3IsZero(targ->mins) || Vec3IsZero(targ->maxs)) + return false; + + // First figure out which two sides of the victim to check. + VectorSubtract(inflictor->s.origin, targ->s.origin, diff); + + // If the X is greater than the Y difference, then the perpendicular edges, north and south, should be checked. + if (fabs(diff[0]) > fabs(diff[1])) + { // check north and south edges. + // South edge + VectorCopy(targ->s.origin, dest); + dest[1] += targ->mins[1]; + gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + + // North edge + VectorCopy(targ->s.origin, dest); + dest[1] += targ->maxs[1]; + gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + } + else + { // check east and west edges. + // West edge + VectorCopy(targ->s.origin, dest); + dest[0] += targ->mins[0]; + gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + + // East edge + VectorCopy(targ->s.origin, dest); + dest[0] += targ->maxs[0]; + gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + } + + // Since the side checks didn't work, check the top and bottom. + // bottom edge + VectorCopy(targ->s.origin, dest); + dest[2] += targ->mins[2]; + gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + + // top edge + VectorCopy(targ->s.origin, dest); + dest[2] += targ->maxs[2]; + gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + + // None of the traces were successful, so no good. + return false; +} + + +// Same function, except the origin point of the damage doesn't have to be the same as the inflictor's +qboolean CanDamageFromLoc (edict_t *targ, edict_t *inflictor, vec3_t origin) +{ + vec3_t dest, diff; + trace_t trace; + + // bmodels need special checking because their origin is 0,0,0 + if (targ->movetype == PHYSICSTYPE_PUSH || targ->classID == CID_BBRUSH) + { + VectorAdd (targ->absmin, targ->absmax, dest); + VectorScale (dest, 0.5, dest); + gi.trace (origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + + if (trace.fraction == 1.0) + return true; + + if (trace.ent == targ) + return true; + + return false; + } + + // Try a basic trace straight to the origin. This takes care of 99% of the tests. + gi.trace (origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, MASK_SOLID,&trace); + if (trace.fraction == 1.0) + return true; + + // Well, a trace from origin to origin didn't work, so try tracing to the edges of the victim. + + // If there are no edges, let's skip the rest of these checks.. + if (Vec3IsZero(targ->mins) || Vec3IsZero(targ->maxs)) + return false; + + // First figure out which two sides of the victim to check. + VectorSubtract(origin, targ->s.origin, diff); + + // If the X is greater than the Y difference, then the perpendicular edges, north and south, should be checked. + if (fabs(diff[0]) > fabs(diff[1])) + { // check north and south edges. + // South edge + VectorCopy(targ->s.origin, dest); + dest[1] += targ->mins[1]; + gi.trace(origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + + // North edge + VectorCopy(targ->s.origin, dest); + dest[1] += targ->maxs[1]; + gi.trace(origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + } + else + { // check east and west edges. + // West edge + VectorCopy(targ->s.origin, dest); + dest[0] += targ->mins[0]; + gi.trace(origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + + // East edge + VectorCopy(targ->s.origin, dest); + dest[0] += targ->maxs[0]; + gi.trace(origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + } + + // Since the side checks didn't work, check the top and bottom. + // bottom edge + VectorCopy(targ->s.origin, dest); + dest[2] += targ->mins[2]; + gi.trace(origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + + // top edge + VectorCopy(targ->s.origin, dest); + dest[2] += targ->maxs[2]; + gi.trace(origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID,&trace); + if (trace.fraction > .99) + return true; + + // None of the traces were successful, so no good. + return false; +} + +void SpawnReward(edict_t *self, edict_t *attacker) +{ + gitem_t *item, *lookup; + edict_t *newitem; + vec3_t forward, holdorigin; + float health_chance, off_chance, def_chance; + char *item_name; + int off_amount, off_max, def_amount, def_max, index, chance; + + //MG: Assassins always give you something + if (self->classID != CID_ASSASSIN) + { + //Randomly refuse to give them anything + if (coop->value) + { + if ( !irand(0, (maxclients->value+1)/2) ) + return; + } + else if ( irand(0, (ITEM_REWARD_CHANCE + (int)skill->value)) ) + return; + } + + //Only intelligent monsters produce items, not creatures (and not Ogles) + if ( (self->classID == CID_RAT) || (self->classID == CID_HARPY) || (self->classID == CID_GKROKON) || (self->classID == CID_GORGON) || (self->classID == CID_FISH) || (self->classID == CID_OGLE) ) + return; + + //Bosses don't spawn a reward either + if ( self->svflags & SVF_BOSS ) + return; + + //Check the health amount on the attacker + health_chance = (attacker->health < attacker->max_health) ? ( (float) attacker->health / (float) attacker->max_health) : 9999; + + //Check the offensive mana amount on the attacker + lookup = FindItemByClassname("item_mana_offensive_half"); + index = ITEM_INDEX(lookup); + off_max = attacker->client->playerinfo.pers.max_offmana; + off_amount = attacker->client->playerinfo.pers.inventory.Items[index]; + + off_chance = (off_amount < off_max) ? ( (float) off_amount / (float) off_max ) : 9999; + + //Check the offensive mana amount on the attacker + lookup = FindItemByClassname("item_mana_defensive_half"); + index = ITEM_INDEX(lookup); + def_max = attacker->client->playerinfo.pers.max_defmana; + def_amount = attacker->client->playerinfo.pers.inventory.Items[index]; + + def_chance = (def_amount < def_max) ? ( (float) def_amount / (float) def_max ) : 9999; + + //We don't need anything + if ( (health_chance == 9999) && (off_chance == 9999) && (def_chance == 9999)) + return; + + //Determine what they get + if ( (health_chance < off_chance) && (health_chance < def_chance) ) + { + item_name = "item_health_half"; + } + else if ( (off_chance < health_chance) && (off_chance < def_chance) ) + { + item_name = "item_mana_offensive_half"; + } + else if ( (def_chance < health_chance) && (def_chance < off_chance) ) + { + item_name = "item_mana_defensive_half"; + } + else + { + chance = irand(0,2); + + if (chance==0) + item_name = "item_health_half"; + else if (chance==1) + item_name = "item_mana_offensive_half"; + else + item_name = "item_mana_defensive_half"; + } + + //We know what we want to give them, so create it! + item = FindItemByClassname(item_name); + + newitem = G_Spawn(); + + newitem->movetype = PHYSICSTYPE_STEP; + AngleVectors(self->s.angles,forward,NULL,NULL); + VectorCopy(self->s.origin,newitem->s.origin); + + SpawnItem(newitem, item); + + VectorCopy(newitem->s.origin,holdorigin); + + //Make the effect + gi.CreateEffect(NULL, FX_PICKUP, 0, holdorigin, ""); +} + +/* +============ +Killed +============ +*/ + +void Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mod) +{ + vec3_t hitdir; + + if (targ->classID == CID_MORK) + { + targ->die(targ, inflictor, attacker, damage, vec3_origin); + return; + } + + if (attacker->svflags & SVF_MONSTER) + {//clear special enemy attack stuff + //FIXME? Make attacking monster look for a new target? + //OR: Search for all monsters with targ as enemy and + //find new target for them? + attacker->monsterinfo.aiflags &= ~AI_STRAIGHT_TO_ENEMY; + } + + if (targ->classID != CID_BBRUSH) + targ->enemy = attacker; + + if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD)) + { + MG_RemoveBuoyEffects(targ); + //What about if off ledge or on steep slope- slide off? + pitch_roll_for_slope(targ, NULL); + + targ->dead_size = Q_fabs( (targ->maxs[2] - targ->mins[2]) ) * 0.5; + MG_PostDeathThink(targ); + + if(!(targ->svflags & SVF_WAIT_NOTSOLID)) + targ->svflags |= SVF_DEADMONSTER; // now treat as a different content type + if (!(targ->monsterinfo.aiflags & AI_GOOD_GUY)) + { + level.killed_monsters++; + } + targ->enemy = attacker; + AlertMonsters (targ, attacker, 7, true); + //spawns an ent that will alert other monsters to my enemy's presence for 7 seconds + + //Spawn a reward for the kill + if (attacker->client) + SpawnReward(targ, attacker); + } + if (targ->movetype == PHYSICSTYPE_PUSH || targ->movetype == PHYSICSTYPE_STOP || targ->movetype == PHYSICSTYPE_NONE) + { + // Doors, triggers, breakable brushes, etc. die with their own KillBrush() routine. + if (targ->classID == CID_BBRUSH) + { + KillBrush(targ,inflictor,attacker,damage); + } + else + { + if((!targ->classID || !classStatics[targ->classID].msgReceivers[MSG_PAIN]) && targ->die) + { + targ->die(targ, inflictor, attacker, damage, vec3_origin); + } + else + { + QPostMessage(targ,MSG_DEATH,PRI_DIRECTIVE,"eeei",targ,inflictor,attacker,damage); + } + } + return; + } + + // Also, put the flag of fire on the entity- makes fire lower when die + if(targ->size[2] > 32) + targ->s.effects |= EF_DISABLE_EXTRA_FX; + + if (targ->deadflag != DEAD_DEAD) + { +// ClientObituary(self, inflictor, attacker); + + targ->touch = NULL; + + monster_death_use (targ); + } + + if(targ->client) + { //FIXME: Make sure you can still dismember and gib player while dying + targ->client->meansofdeath = mod; + player_die(targ, inflictor, attacker, damage, point); + } + else + { + //CID_RAT SHOULD NOT BE ZERO!!! CID_NONE SHOULD BE + if((!targ->classID || !classStatics[targ->classID].msgReceivers[MSG_PAIN]) && targ->die) + { + targ->die(targ, inflictor, attacker, damage, vec3_origin); + } + else + QPostMessage(targ,MSG_DEATH,PRI_DIRECTIVE,"eeei",targ,inflictor,attacker,damage); + } + + if(Vec3IsZero(targ->velocity) && (damage != 12345)) + {//fall back some! + VectorSubtract(targ->s.origin, inflictor->s.origin, hitdir); + hitdir[2] = 50; + VectorNormalize(hitdir); + VectorMA(targ->velocity, damage*3, hitdir, targ->velocity); + } +} + +/* +============ +M_ReactToDamage +============ +*/ +void M_ReactToDamage (edict_t *targ, edict_t *attacker) +{ + if (!(attacker->client) && !(attacker->svflags & SVF_MONSTER)) + return; + + if (attacker == targ) + return; + + //FIXME: in SP, after player dead, allow this? Or Make attacker lose it's enemy? + if(!ANARCHY && attacker->classID == targ->classID) + return;//monsters of same type won't fight each other + + if (targ->classID == CID_OGLE && (!targ->monsterinfo.awake || attacker->client))//ogles do their own checks to get angry at their first enemy + return; + + if (attacker == targ->enemy) + {//ok, no more stalking- now we get serious + targ->ai_mood_flags &= ~AI_MOOD_FLAG_BACKSTAB; + if(!targ->monsterinfo.awake) + FoundTarget(targ, true); + return; + } + + if (!attacker->takedamage)//world, etc. + return; + + if(targ->monsterinfo.c_mode)//don't anger cinematic monsters + return; + + if (attacker->client) + { + targ->monsterinfo.chase_finished = level.time + 4; // When the monster can notice secondary enemies + + if (targ->enemy && targ->enemy->client) + targ->oldenemy = targ->enemy; + targ->enemy = attacker; + FoundTarget (targ, true); + return; + } + + if (targ->monsterinfo.aiflags & AI_GOOD_GUY) + { + if (!(attacker->client) && !(attacker->monsterinfo.aiflags & AI_GOOD_GUY)) + { + targ->enemy = attacker; + FoundTarget (targ, true); + return; + } + } + + // if attacker is a client or + // it's the same base (walk/swim/fly) type and a different classname and it's a monster that sprays too much + // get mad at them + if (((targ->flags & (FL_FLY|FL_SWIM)) == (attacker->flags & (FL_FLY|FL_SWIM))) && + (targ->classID != attacker->classID)&& + (targ->enemy))//targ has an enemy, otherwise always get mad + { + if (targ->enemy->client) + targ->oldenemy = targ->enemy; + targ->enemy = attacker; + FoundTarget (targ, true); + } + else// otherwise get mad at whoever they are mad at (help our buddy) + { + if (attacker->enemy) // This really should be an assert, but there are problems with this. + { + if(attacker->enemy==targ && attacker->classID==targ->classID && !(targ->monsterinfo.aiflags&AI_AGRESSIVE)) + {//attacker was shooting at me(targ) and is my class, but I'm not agressive so I didn't hit him first + if(irand(0,10)<7) + {//run away! + if(targ->enemy==attacker&&irand(0,10)<3&&stricmp(attacker->classname, "player")) + { + targ->monsterinfo.flee_finished = 0; + } + else if(targ->monsterinfo.flee_finished < level.time + 7.0) + { + targ->monsterinfo.aiflags |= AI_FLEE; + targ->monsterinfo.flee_finished = level.time + flrand(3.0, 7.0); + } + } + targ->enemy = attacker; + FoundTarget (targ, true); + } + else if(attacker->enemy != targ && (!targ->enemy || targ->enemy->health <= 0)) + {//attacker wasn't after me and my enemy is invalid or don't have one... go after atacker's enemy + if (targ->enemy) + { + if (targ->enemy->client||ANARCHY) + targ->oldenemy = targ->enemy; + } + targ->enemy = attacker->enemy; + FoundTarget (targ, true); + } + else if( (attacker->classID!=targ->classID&&!irand(0,2)) ||ANARCHY) + {//30% chance to get mad (only if they're not my class), or always get mad if ANARCHY + if (targ->enemy) + { + if (targ->enemy->client||ANARCHY) + targ->oldenemy = targ->enemy; + } + targ->enemy = attacker; + FoundTarget (targ, true); + } + } + else + {//attacker's on crack, kill him + targ->enemy = attacker; + FoundTarget (targ, true); + } + } +} + +// ************************************************************************************************ +// CheckTeamDamage +// --------------- +// ************************************************************************************************ + +qboolean CheckTeamDamage (edict_t *targ, edict_t *attacker) +{ + //FIXME: Make the next line real and uncomment this block. + //if ((ability to damage a teammate == OFF) && (targ's team == attacker's team)) + return(false); +} + +qboolean flammable (edict_t *targ) +{ + if(targ->materialtype == MAT_CLOTH|| + targ->materialtype == MAT_FLESH|| + targ->materialtype == MAT_POTTERY|| + targ->materialtype == MAT_LEAF|| + targ->materialtype == MAT_WOOD|| + targ->materialtype == MAT_INSECT) + return (true); + + return (false); +} + +/* +============ +T_Damage + +targ entity that is being damaged +inflictor entity that is causing the damage +attacker entity that caused the inflictor to damage targ + +example: targ=monster, inflictor=rocket, attacker=player + +dir direction of the attack: + Directional vector (velocity is acceptable), in the direction the force is GOING. + Normalized in the function, if (0,0,0) then vector from inflictor to target is used. + Used for knockback (scale force by this vector) + Also used for blood and puffs when objects are struck + CANNOT BE NULL. +point point at which the damage is being inflicted + Absolute point at which the damage is generated. + Used for hit locations, and blood (generation point) + CANNOT BE NULL +normal normal vector from that point + Directional vector, assumed to be normalized.(of course) + Used for blood from monsters and players (squirts in this direction). + Checked for NULL +damage amount of damage being inflicted +knockback force to be applied against targ as a result of the damage + +dflags these flags are used to control how T_Damage works: + +DAMAGE_RADIUS damage was indirect (from a nearby explosion) +DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles +DAMAGE_NO_PROTECTION kills godmode, armor, everything +DAMAGE_DISMEMBER to force MSG_DISMEMBER to be used +============ +*/ +void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t pdir, vec3_t ppoint, vec3_t pnormal, + int damage, int knockback, int dflags,int MeansOfDeath) +{ + vec3_t hit_spot; + gclient_t *client; + int take, dsm_dmg; + HitLocation_t hl; + gitem_armor_t *info; + int force_pain = 0; + qboolean was_dead = false; + vec3_t dir, normal, point; + float knockbacktime; + char armor_sound[50]; + int armorabsorb, orig_dmg; + int violence=VIOLENCE_DEFAULT; + + if (blood_level) + violence = blood_level->value; + + // Prevent players harming fellow players in non-deathmatch games. The attacking player can + // still harm himself of course. + + if((!deathmatch->value)&&(targ!=attacker)&&(targ->client)&&(attacker->client)&&(!(dflags&DAMAGE_HURT_FRIENDLY))) + return; + + if (!targ->takedamage) + return; + + if (targ->client) + { + if (targ->client->RemoteCameraLockCount) // In a remote camera so he can't be hurt + return; + + if (targ->client->playerinfo.c_mode) // In cinematic mode so he can't be hurt + return; + } + + + if(dflags & DAMAGE_ALIVE_ONLY) + if (targ->materialtype != MAT_FLESH||targ->health<=0) + return; + + if(targ->svflags&SVF_NO_PLAYER_DAMAGE) + if(attacker->client) + return; + + if(targ->health <= 0) + { + if(targ->client)//can't keep killing a dead player + return; + + if(targ->classID) + { + if(classStatics[targ->classID].msgReceivers[MSG_DEATH_PAIN]) + { + if(dflags & DAMAGE_SUFFOCATION || dflags & DAMAGE_BLEEDING || dflags == DAMAGE_BURNING) + return; + else + was_dead = true; + } + } + } + + // if we are on a shrine or teleporting we are not to be harmed - assuming we haven't been telefragged, in which case kill us dead + if (targ->client && (targ->client->shrine_framenum > level.time) && !(dflags & DAMAGE_NO_PROTECTION) ) + return; + +//So we don't overwrite the passed-in vectors!!! + if(pdir && Vec3NotZero(pdir)) + VectorCopy(pdir, dir); + else + VectorSet(dir, 0, 0, -1); + + if(pnormal && Vec3NotZero(pnormal)) + VectorCopy(pnormal, normal); + else + VectorSet(normal, 0, 0, 1); + + if(ppoint) + VectorCopy(ppoint, point); + else + VectorCopy(inflictor->s.origin, point); + + if (deathmatch->value == 0) + { // Not deathmatch game. + // In easy skill-level, the player only takes half damage. + if ((skill->value == 0) && targ->client) + damage = ceil(damage * 0.5); + } + else + { // In deathmatch game. + // Factor in deathmatch to increase hit points + if (targ->client) + damage = ceil(damage * 2.0 / (4.0 - skill->value)); // Skill 0: 1/2 damage, skill 1: 2/3 damage, skill 2: full + } + + if (!damage) + damage = 1; + + orig_dmg = damage; + + // deal with armor - if we have any + // are we a player ? + if (targ->client && !(dflags&DAMAGE_BLEEDING)) + { + // figure out where the armor details are located at + // do we actually have any armor anyway ? + // dont let armor effect us if we are drowning, in slime, or in lava + if (!(dflags & DAMAGE_AVOID_ARMOR) && + targ->client->playerinfo.armor_count && + (dflags != DAMAGE_SUFFOCATION) && + (dflags != DAMAGE_SLIME) && + (dflags != DAMAGE_LAVA)) + { + if (targ->client->playerinfo.pers.armortype == ARMOR_TYPE_SILVER) + info = &silver_armor_info; + else + info = &gold_armor_info; + + // Figure out how much the armor takes + armorabsorb = damage; + + // effect damage dependant on what type of effect hit us + if (dflags & DAMAGE_SPELL) + damage *= info->spell_protection; + else + damage *= info->normal_protection; + + // make the little sparkle effect at the hit point + gi.CreateEffect(NULL, + FX_ARMOR_HIT, + 0, + point, + "d", + normal); + + if (dflags & DAMAGE_SPELL) + gi.sound(targ,CHAN_WEAPON,gi.soundindex("weapons/spellric.wav"),2,ATTN_NORM,0); + else + { + // don't always make sound - being attacked by rats makes this go off incesantly + if (!(irand(0,2))) + { + sprintf(armor_sound, "weapons/armorric%d.wav",irand(1,3)); + gi.sound(targ,CHAN_WEAPON,gi.soundindex(armor_sound),2,ATTN_NORM,0); + } + } + + // be sure we still have some damage + if (!damage) + { + damage = 1; + armorabsorb = 1; + } + else + { // Everything not taken by the player is taken by the armor + armorabsorb -= damage; + if (armorabsorb > targ->client->playerinfo.armor_count) + { + damage += armorabsorb - targ->client->playerinfo.armor_count; + armorabsorb = targ->client->playerinfo.armor_count; + } + } + + targ->client->playerinfo.armor_count -= armorabsorb; + // dec armor count. are we down to zero armor ? + if (targ->client->playerinfo.armor_count <= 0) + { + // stop drawing the armor + targ->client->playerinfo.pers.armortype = ARMOR_NONE; + targ->client->playerinfo.armor_count = 0; + + SetupPlayerinfo_effects(targ); + PlayerUpdateModelAttributes(&targ->client->playerinfo); + WritePlayerinfo_effects(targ); + + // Play the out-of-armor sound. + gi.sound(targ, CHAN_WEAPON, gi.soundindex("weapons/armorgone.wav"), 1, ATTN_NORM, 0); + } + } + } + + client = targ->client; + + VectorNormalize(dir); + + // The player does bonus damage for suprising a monster. + // Bad idea for us. +// if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0)) +// damage *= 2; + + if (targ->flags & FL_NO_KNOCKBACK || targ->svflags & SVF_BOSS || + (targ->svflags & SVF_MONSTER && sv_freezemonsters->value == 2.0)) // Freezemonster = 2 means no knockback + { + knockback = 0; + } + + // Figure out the knockback momentum to impart to the target. + if (!(dflags & DAMAGE_NO_KNOCKBACK) && !(targ->svflags & SVF_BOSS)) + {//hey, knockback of less than about 25 isn't going to do squat... + if ((knockback) && + (targ->movetype != PHYSICSTYPE_NONE) && + (targ->movetype != PHYSICSTYPE_PUSH) && + (targ->movetype != PHYSICSTYPE_STOP)) + { + vec3_t kvel; + float mass, force, upvel; + + if(Vec3IsZero(dir)) + { + VectorSubtract(targ->s.origin, inflictor->s.origin, dir); + if(dir[2]<0) + dir[2] = 0; + VectorNormalize(dir); + } + + mass = VectorLength(targ->size) * 3; + /* + if (targ->mass < 50) + mass = 50; + else + mass = targ->mass;*/ + +// if (targ->client && attacker == targ) +// force = 900.0 * (float)knockback / mass; //rocketjump hack... More knockback to source. +// else + force = 600.0 * (float)knockback / mass; + + // Players are not as affected by velocities when they are on the ground, so increase what players experience. + if (targ->client && targ->groundentity) + force *= 4.0; + else if (targ->client) // && !(targ->groundentity) + force *= 0.25; // Too much knockback + + if (dflags & DAMAGE_EXTRA_KNOCKBACK) + force *= 3.0; + + if (force > 512) // Cap this speed so it doesn't get insane + force=512; + VectorScale (dir, force, kvel); + + if (targ->client) // Don't force players up quite so much as monsters. + upvel=30; + else + upvel=60; + // Now if the player isn't being forced DOWN very far, let's force them UP a bit. + if ((dir[2] > -0.5 || targ->groundentity) && kvel[2] < upvel && force > 30) + { // Don't knock UP the player more than we do across... + if (force < upvel) + kvel[2] = force; + else + kvel[2] = upvel; + } + + VectorAdd (targ->velocity, kvel, targ->velocity); + + if (targ->client) // If player, then set the player flag that will affect this. + { + targ->client->playerinfo.flags |= PLAYER_FLAG_USE_ENT_POS; + // The knockbacktime indicates how long this knockback affects the player. + if (force>500) + knockbacktime = level.time + 1.25; + else + knockbacktime = level.time + (force/400.0); + if (knockbacktime > targ->client->playerinfo.knockbacktime) + targ->client->playerinfo.knockbacktime = knockbacktime; + } + + //so knockback doesn't gib them unless it really really should + if(force<300) + targ->jump_time = level.time + 0.5; + } + } + + take = damage; + + // If the target has godmode in effect, they take no damage. + if (targ->flags & FL_GODMODE && !(dflags & DAMAGE_NO_PROTECTION)) + take = 0; + + // If the player is invincible, or on a shrine, they take no damage. + if ( (client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION)) + { + if (targ->pain_debounce_time < level.time) + { +// gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0); + targ->pain_debounce_time = level.time + 2; + } + + take = 0; + } + + // If target and attacker are on the same team, don't inflict any damage. + + if(CheckTeamDamage (targ, attacker)) + return; + + // Okay, we got all the way here, so do the damage. + if(take && !(targ->svflags & SVF_MONSTER && sv_freezemonsters->value != 0.0) && !(dflags & DAMAGE_ALL_KNOCKBACK)) + { + int scale; + int duration; + + //not damage_burning because that is coming from you being on fire already... + if (dflags & DAMAGE_FIRE && flammable(targ) && dflags != DAMAGE_BURNING && !(targ->svflags & SVF_BOSS)) + {//FIXME: not on BBRUSHES - have no origin! + + if (dflags & DAMAGE_FIRE_LINGER) + duration = orig_dmg*0.4; + else + duration = orig_dmg*0.2; + + if (!duration) + duration = 1; + + if (duration > 8) + duration = 8; + + scale = (int)(VectorLength(targ->size)*(0.5 * 0.25)); //is scled up drediculously on other side, quarter it + if (scale > 255) + scale = 255; + + if(!(gi.pointcontents(targ->s.origin) & (CONTENTS_WATER|CONTENTS_SLIME))) + {//need to check if under water! + if(targ->fire_damage_time < level.time && !(targ->svflags & SVF_BOSS)) + {//not already on fire + if(targ->client && deathmatch->value) + targ->fire_damage_time = level.time + duration * 0.25;//burn for 3.2 seconds- length of effect, if effect length changed, this should too! + else + targ->fire_damage_time = level.time + duration * 0.5;//burn for 3.2 seconds- length of effect, if effect length changed, this should too! + + targ->s.effects &= ~(EF_MARCUS_FLAG1|EF_DISABLE_EXTRA_FX); // The flag causes the fire to stop generating. + gi.CreateEffect(&targ->s, FX_FIRE_ON_ENTITY, CEF_OWNERS_ORIGIN, NULL, "bbb", (int)scale, 255, 1);//we'll turn this off manually + } + else + targ->fire_damage_time += duration; + + if(!targ->fire_damage_enemy) + targ->fire_damage_enemy = attacker; + } + } + else if(!(dflags & DAMAGE_NO_BLOOD)) + { + if ((targ->svflags & SVF_MONSTER) || (client)) + { + int bloodamt; + vec3_t vel, diff, loc; + + if (take > 80) + bloodamt = 20; + else + bloodamt = take/4; + + // Normal will be NULL from time to time. FIXME: Hellbolts will damage with a plane.normal that is null. + if (normal==NULL || Vec3IsZero(normal)) + { + VectorClear(vel); + VectorCopy(point, loc); + } + else + { + VectorScale(normal, -64.0, vel); + + // Now let's try moving the hit point towards the hit object. + VectorSubtract(targ->s.origin, point, diff); + // We can't be assured that the vertical origin is the center... + diff[2] += (targ->maxs[2] + targ->mins[2])*0.5; + // Take half that distance, since the hit always tends to be on the outside of the bbox. + VectorMA(point, 0.5, diff, loc); + } + + if(violence == VIOLENCE_NONE) + gi.CreateEffect(NULL, FX_HITPUFF, CEF_FLAG6, point, "db", dir, 5); + else if(targ->materialtype == MAT_INSECT) + gi.CreateEffect(NULL, FX_BLOOD, CEF_FLAG8, loc, "ub", vel, bloodamt); + else + gi.CreateEffect(NULL, FX_BLOOD, 0, loc, "ub", vel, bloodamt); + } + else + { + if ((targ->svflags & SVF_DEADMONSTER ||targ->materialtype == MAT_INSECT||targ->materialtype == MAT_FLESH) && violence > VIOLENCE_NONE) + { + if(targ->materialtype == MAT_INSECT) + gi.CreateEffect(NULL, FX_BLOOD, CEF_FLAG8, point, "ub", dir, 8); + else + gi.CreateEffect(NULL, FX_BLOOD, 0, point, "ub", dir, 8); + } + else + gi.CreateEffect(NULL, FX_HITPUFF, 0, point, "db", dir, 5); + } + } + else if (dflags & DAMAGE_BUBBLE) + { + vec3_t bubbleloc; + + VectorSet(bubbleloc, flrand(-10, 10), flrand(-10,10), targ->viewheight); + VectorAdd(bubbleloc, targ->s.origin, bubbleloc); + gi.CreateEffect(NULL, FX_BUBBLE, 0, bubbleloc, ""); + } + + targ->health -= take; + + if(targ!=attacker && violence > VIOLENCE_BLOOD)//can't dismember yourself + { + if(attacker==inflictor) + VectorCopy(point, hit_spot); + else + VectorCopy(inflictor->s.origin, hit_spot); + + if(targ->classID != CID_HARPY)//use new hitlocation function + hl = MG_GetHitLocation(targ, inflictor, point, dir); + else if (!(targ->svflags & SVF_MONSTER)&&!(client))//target not a monster or client + hl = T_GetHitLocation(targ, inflictor, hit_spot); + else + hl = T_GetHitLocation(targ, attacker, hit_spot); + + if(dflags&DAMAGE_DISMEMBER) + hl |= hl_MeleeHit;//only melee can dismember Add the 16th bit to it for melee hit + + if(!(targ->svflags & SVF_PARTS_GIBBED) && !(dflags & DAMAGE_SUFFOCATION) && !(dflags & DAMAGE_BLEEDING)) + {//don't dismember someone who's already gibbed or gibbing, no dismember damage from suffocation or bleeding + if(dflags&DAMAGE_DOUBLE_DISMEMBER) + dsm_dmg = take * 2; + else + dsm_dmg = take; + + if(targ->client) + player_dismember(targ, attacker, dsm_dmg, hl); + else + QPostMessage(targ, MSG_DISMEMBER, PRI_DIRECTIVE, "ii", dsm_dmg, hl); + } + } + + if (targ->health <= 0) + { +// if ((targ->svflags & SVF_MONSTER) || (client)) +// targ->flags |= FL_NO_KNOCKBACK; + + // Target has died, so kill it good and dead. + if(was_dead) + {//FIXME: if on fire, Become a charred husk, no gib. + if(!(dflags & DAMAGE_SUFFOCATION) && !(dflags & DAMAGE_BLEEDING) && dflags != DAMAGE_BURNING) + {//drowning, bleeding and burning do not gib + if(targ->health<=-100) + { + if(targ->think != BecomeDebris && targ->think != G_SetToFree) + { + targ->post_think = BecomeDebris; + targ->next_post_think = level.time; + } + } + else if(violence > VIOLENCE_BLOOD) + { + hl|=hl_MeleeHit;//force dismember + QPostMessage(targ, MSG_DEATH_PAIN, PRI_DIRECTIVE,"ii", take, hl); + } + } + return; + } + + if(targ->client) + { + if(dflags & DAMAGE_FIRE && !(targ->svflags & SVF_BOSS)) + { + scale = (int)(VectorLength(targ->size)*(0.5*8.0)); // eight times the value is sent over, no more than 32 wide. + if (scale > 255) + scale = 255; + targ->fire_damage_time = -1;//so we know we died from fire + + //spawn a fire to keep burning for @ 6 secs + targ->s.effects &= ~EF_MARCUS_FLAG1; // The flag causes the fire to stop generating. + gi.CreateEffect(&targ->s, FX_FIRE_ON_ENTITY, CEF_OWNERS_ORIGIN, NULL, "bbb", (int)scale, 40, 0); + } + } + + if(!targ->takedamage)//already killed by decapitation or some other killing dismemberment + return; + + Killed (targ, inflictor, attacker, take, point, MeansOfDeath); + + return; + } + } + + if (targ->svflags & SVF_MONSTER && sv_freezemonsters->value != 0.0) + { + // Do do anything. Frozen monsters take no damage, don't die. + } + else if (targ->svflags & SVF_MONSTER) + { + if(!targ->enemy) + force_pain = true; + else + force_pain = false; + + targ->spawnflags &= ~MSF_AMBUSH; + targ->targetname = NULL; + + M_ReactToDamage (targ, attacker); + + if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take) && + (targ->pain_debounce_time < level.time)) + { + if(targ->classID == CID_ASSASSIN) + QPostMessage(targ,MSG_PAIN,PRI_DIRECTIVE,"eeiii", inflictor, attacker, force_pain, take, hl); + else + QPostMessage(targ,MSG_PAIN,PRI_DIRECTIVE,"eeiii", targ, attacker, force_pain, take, hl); + + // In Nightmare skill-level, monsters don't go into pain frames often. + + if (skill->value == 3) + targ->pain_debounce_time = level.time + 5; + } + } + else if (client) + { + if (!(targ->flags & FL_GODMODE) && (take)) + QPostMessage(targ,MSG_PAIN,PRI_DIRECTIVE,"eeiii", targ, attacker, knockback, take, hl); + } + else if (take) + { + if (targ->pain) + { + if(!targ->classID || !classStatics[targ->classID].msgReceivers[MSG_PAIN]) + { + if(!stricmp(targ->classname, "NATE")) + targ->activator = inflictor; + targ->pain(targ, attacker, knockback, take);//pass spot too + } + else + QPostMessage(targ,MSG_PAIN,PRI_DIRECTIVE,"eeiii", targ, attacker, knockback, take, hl); + } + } + + // Add to the damage inflicted on a player this frame. The total will be turned into screen + // blends and view angle kicks at the end of the frame. + + if(client) + { + client->damage_gas = (!stricmp(inflictor->classname, "plague_mist") || !stricmp(inflictor->classname, "spreader_grenade")) ? true : false; + + client->damage_blood += take; + client->damage_knockback += knockback; + VectorCopy (point, client->damage_from); + } +} + +// ************************************************************************************************ +// T_DamageRadius +// -------------- +// ************************************************************************************************ + +void T_DamageRadius(edict_t *inflictor, edict_t *attacker, edict_t *ignore, float radius, + float maxdamage, float mindamage, int dflags,int MeansOfDeath) +{ + float points, dist; + edict_t *ent = NULL; + vec3_t v, center; + vec3_t dir, hitspot; + edict_t *damageenemy = NULL; + + assert(radius>0); + + if (dflags & DAMAGE_ENEMY_MAX) + { + damageenemy = inflictor->enemy; + + if (damageenemy && damageenemy->takedamage) + { + VectorAdd (damageenemy->mins, damageenemy->maxs, center); + VectorMA (damageenemy->s.origin, 0.5, center, center); + VectorSubtract (inflictor->s.origin, center, v); + dist = VectorNormalize(v); + VectorScale(v, -1, dir); + VectorMA(center, damageenemy->maxs[0], v, hitspot);//estimate a good hit spot + + T_Damage(damageenemy, inflictor, attacker, dir, hitspot, vec3_origin, + (int)maxdamage, (int)maxdamage, DAMAGE_RADIUS|dflags,MeansOfDeath); + } + } + while ((ent = findradius(ent, inflictor->s.origin, radius)) != NULL) + { + if (ent == ignore) + continue; + if (!ent->takedamage||ent->takedamage==DAMAGE_NO_RADIUS) + continue; + if (ent == attacker && dflags & DAMAGE_ATTACKER_IMMUNE) + continue; + if ((dflags & DAMAGE_ALIVE_ONLY) && (ent->materialtype != MAT_FLESH||ent->health<=0)) + continue; + if (ent==damageenemy) // We already dealt with the damageenemy above... + continue; + + VectorAdd (ent->mins, ent->maxs, center); + VectorMA (ent->s.origin, 0.5, center, center); + VectorSubtract (inflictor->s.origin, center, v); + dist = VectorNormalize(v); + VectorScale(v, -1, dir); + + // Scale from maxdamage at center to mindamage at outer edge + points = maxdamage - ((maxdamage-mindamage) * (dist/radius)); + + if (points > 0) + { + if (CanDamage (ent, inflictor)) + { + VectorMA(center, ent->maxs[0], v, hitspot);//estimate a good hit spot + + if (ent == attacker) + { + if (dflags & DAMAGE_ATTACKER_KNOCKBACK) + T_Damage(ent, inflictor, attacker, dir, hitspot, vec3_origin, //hitspot was ent->s.origin + 0, (int)points, DAMAGE_RADIUS|dflags, MOD_KILLED_SLF); + else if (dflags & DAMAGE_POWERPHOENIX) + T_Damage(ent, inflictor, attacker, dir, hitspot, vec3_origin, // extra knockback, .25 damage. + (int)(points*0.25), (int)(points*0.5), DAMAGE_RADIUS|dflags,MOD_KILLED_SLF); + else + T_Damage(ent, inflictor, attacker, dir, hitspot, vec3_origin, + (int)points, (int)points, DAMAGE_RADIUS|dflags, MOD_KILLED_SLF); + } + else + T_Damage(ent, inflictor, attacker, dir, hitspot, vec3_origin, + (int)points, (int)points, DAMAGE_RADIUS|dflags,MeansOfDeath); + } + } + } +} + + +// Same function, except the origin point of the damage doesn't have to be the same as the inflictor's +void T_DamageRadiusFromLoc(vec3_t origin, edict_t *inflictor, edict_t *attacker, edict_t *ignore, float radius, + float maxdamage, float mindamage, int dflags,int MeansOfDeath) +{ + float points, dist; + edict_t *ent = NULL; + vec3_t v, center, dir; + vec3_t hitspot; + + + assert(radius>0); + + while ((ent = findradius(ent, origin, radius)) != NULL) + { + if (ent == ignore) + continue; + if (!ent->takedamage||ent->takedamage==DAMAGE_NO_RADIUS) + continue; + if (ent == attacker && dflags & DAMAGE_ATTACKER_IMMUNE) + continue; + if ((dflags & DAMAGE_ALIVE_ONLY) && (ent->materialtype != MAT_FLESH||ent->health<=0)) + continue; + + VectorAdd (ent->mins, ent->maxs, center); + VectorMA (ent->s.origin, 0.5, center, center); + VectorSubtract (origin, center, v); + dist = VectorNormalize(v); + VectorScale(v, -1, dir); + // Scale from maxdamage at center to mindamage at outer edge + points = maxdamage - ((maxdamage-mindamage) * (dist/radius)); + + if (points > 0) + { + if (CanDamageFromLoc (ent, inflictor, origin)) + { + VectorMA(center, ent->maxs[0], v, hitspot);//estimate a good hit spot + + if (ent == attacker) + { + if (dflags & DAMAGE_ATTACKER_KNOCKBACK) + T_Damage(ent, inflictor, attacker, dir, hitspot, vec3_origin, //hitspot was ent->s.origin + 0, (int)points, DAMAGE_RADIUS|dflags, MOD_KILLED_SLF); + else if (dflags & DAMAGE_POWERPHOENIX) + T_Damage(ent, inflictor, attacker, dir, hitspot, vec3_origin, // extra knockback, .25 damage. + (int)(points*0.25), (int)(points*2.0), DAMAGE_RADIUS|dflags,MOD_KILLED_SLF); + else + T_Damage(ent, inflictor, attacker, dir, hitspot, vec3_origin, + (int)points, (int)points, DAMAGE_RADIUS|dflags,MOD_KILLED_SLF); + } + else + T_Damage(ent, inflictor, attacker, dir, hitspot, vec3_origin, + (int)points, (int)points, DAMAGE_RADIUS|dflags, MeansOfDeath); + } + } + } +} diff --git a/Toolkit/Programming/GameCode/game/g_env.c b/Toolkit/Programming/GameCode/game/g_env.c new file mode 100644 index 0000000..5038323 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_env.c @@ -0,0 +1,182 @@ +/* +============================================================================== +// g_env.c +// +// Heretic II +// Copyright 1998 Raven Software +============================================================================== +*/ +#include "fx.h" +#include "g_local.h" +#include "vector.h" +#include "random.h" + + +void env_dust_use(edict_t *self, edict_t *other, edict_t *activator) +{ + byte count, magb; + float mag; + + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE,self->moveinfo.sound_middle, 2, ATTN_NORM, 0); + + if(!self->count) + { + count = (byte)(self->size[0] * self->size[1] / 800.0); // 28 x 28 + if (count > 16) + { + count = 16; + } + } + else + { + count = self->count; + } + + mag = VectorLength(self->size); + magb = Clamp(mag, 1.0, 255.0); + gi.CreateEffect(NULL, + FX_DUST, + 0, + self->mins, + "bdb", + (byte) count, + self->size, + magb + ); + +} + +/*QUAKED env_dust (1 .5 0) ? +Generates dust and rock over an area. This is triggerable. +-------KEYS-------- +count - number of rocks (default 1 rock per 28 x 28 square) +*/ +void SP_env_dust (edict_t *self) +{ + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_NOT; + + self->svflags |= SVF_NOCLIENT; + + self->use = env_dust_use; + + self->moveinfo.sound_middle = gi.soundindex ("world/quakeshort.wav"); + + gi.setmodel (self, self->model); + gi.linkentity (self); +} + +#define START_OFF 8 + +void smoke_use (edict_t *self, edict_t *other, edict_t *activator) +{ + vec3_t dir; + byte scale,speed,wait,maxrange; + if (self->spawnflags & START_OFF) + { + scale = (byte)(self->s.scale * 32.0); + AngleVectors(self->s.angles, dir, NULL, NULL); + + speed = Q_ftol(self->speed); + wait = Q_ftol(self->wait); + maxrange = Q_ftol(self->maxrange); + + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, + FX_ENVSMOKE, + CEF_BROADCAST,self->s.origin, + "bdbbb",scale,dir,speed,wait,maxrange); + + self->s.sound = gi.soundindex("ambient/fountainloop.wav"); + self->s.sound_data = (127 & ENT_VOL_MASK) | ATTN_STATIC; + self->spawnflags &= ~START_OFF; + } + else + { + gi.RemovePersistantEffect(self->PersistantCFX); + self->PersistantCFX = 0; + gi.RemoveEffects(&self->s, FX_ENVSMOKE); + self->spawnflags |= START_OFF; + } +} + +/*QUAKED env_smoke (1 .5 0) (-4 -4 -4) (4 4 4) START_OFF +Generates steady puffs of smoke. This is triggerable. +START_OFF - smoke will start off +-------KEYS-------- +scale - size of puff (default 1) range 0 - 8. +angle - direction puff is to move (default 0) +speed - how quickly puffs move (default 100) range 10 - 2500 +distance - how far smoke will move before disappearing (default 100) range 1 - 255 +wait - time in seconds between puffs (default 5) range 1 - 255 +*/ +void SP_env_smoke (edict_t *self) +{ + vec3_t dir; + byte scale,speed,wait,maxrange; + + // set scale + if (!self->s.scale) + self->s.scale = 1; + scale = (byte)(self->s.scale * 32.0); + + // allow us to use this stuff + if (self->targetname) + self->use = smoke_use; + + // set the wait between puffs + if (!self->wait) + self->wait = 5; + + // set the distance + if (st.distance) + self->maxrange = st.distance; + else + self->maxrange = 100; + + // set the speed + if (!self->speed) + self->speed = 100; + + // reduce out the resolution + self->speed = self->speed / 10; + + // make us all bytes + speed = Q_ftol(self->speed); + wait = Q_ftol(self->wait); + maxrange = Q_ftol(self->maxrange); + + self->s.effects |= EF_NODRAW_ALWAYS_SEND; + gi.linkentity(self); + + if (self->spawnflags & START_OFF) // Start off + { + return; + } + + else + { + AngleVectors(self->s.angles, dir, NULL, NULL); + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, + FX_ENVSMOKE, + CEF_BROADCAST,self->s.origin, + "bdbbb",scale,dir,speed,wait,maxrange); + } +} + +/*QUAKED env_muck (1 .5 0) ? +-------KEYS-------- +*/ +void SP_env_muck (edict_t *self) +{ + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_NOT; + + self->svflags |= SVF_NOCLIENT; + + self->use = env_dust_use; + + gi.setmodel (self, self->model); + gi.linkentity (self); +} diff --git a/Toolkit/Programming/GameCode/game/g_field.c b/Toolkit/Programming/GameCode/game/g_field.c new file mode 100644 index 0000000..fe47186 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_field.c @@ -0,0 +1,635 @@ +#include "g_local.h" +#include "p_types.h" +#include "Vector.h" +#include "p_actions2.h" +#include "g_DefaultMessageHandler.h" +#include "p_main2.h" +#include "buoy.h" +#include "m_stats.h" +#include "g_teleport.h" + +extern void SP_misc_teleporter (edict_t *self); + + +void InitTrigger(edict_t *self); + +void InitField(edict_t *self) +{ + if(!Vec3IsZero(self->s.angles)) + { + G_SetMovedir(self->s.angles, self->movedir); + } + + self->classID = CID_TRIGGER; // fields are basically triggers + self->solid = SOLID_TRIGGER; + self->movetype = PHYSICSTYPE_NONE; + gi.setmodel (self, self->model); + self->svflags = SVF_NOCLIENT; + + gi.linkentity(self); +} + + + +void FogDensity_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + player_state_t *ps; + + // Only players can know about fog density changes + if(other->client) + { + ps = &other->client->ps; + + if (!self->target) + { + ps->fog_density = 0.0; + return; + } + ps->fog_density = strtod(self->target, NULL); + } +} + +/*QUAKED trigger_fogdensity (.5 .5 .5) ? +Sets the value of r_fog_density +and the fog color +---------KEY---------------- +target - fog density (.01 - .0001) +color - red green blue values (0 0 0) + range of 1.0 - 0 +---------------------------- +*/ +void SP_trigger_fogdensity(edict_t *self) +{ + InitField(self); + + self->touch = FogDensity_touch; + self->solid = SOLID_TRIGGER; +} + + +//---------------------------------------------------------------------- +// Force Field +//---------------------------------------------------------------------- + +#define FIELD_FORCE_ONCE 1 + + +void push_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + vec3_t forward,up; + + if(other->health > 0) + { + if (other->client) // A player??? + { + // don't take falling damage immediately from this + VectorCopy(other->velocity, other->client->playerinfo.oldvelocity); + other->client->playerinfo.flags |= PLAYER_FLAG_USE_ENT_POS; + other->groundentity = NULL; + } + + AngleVectors(self->s.angles,forward,NULL,up); + + VectorMA(other->velocity,self->speed,forward,other->velocity); + VectorMA(other->velocity,self->speed,up,other->velocity); + + } + + G_UseTargets(self, self); + + if(self->spawnflags & FIELD_FORCE_ONCE) + { + G_FreeEdict (self); + } +} + +void push_touch_trigger(edict_t *self, edict_t *activator) +{ + push_touch(self,activator,NULL,NULL); +} + +void TrigPush_Deactivate(edict_t *self, G_Message_t *msg) +{ + self->solid = SOLID_NOT; + self->touch = NULL; +} + + +void TrigPush_Activate(edict_t *self, G_Message_t *msg) +{ + self->solid = SOLID_TRIGGER; + self->touch = push_touch; + gi.linkentity (self); +} + + +void TrigPushStaticsInit() +{ + classStatics[CID_TRIG_PUSH].msgReceivers[G_MSG_SUSPEND] = TrigPush_Deactivate; + classStatics[CID_TRIG_PUSH].msgReceivers[G_MSG_UNSUSPEND] = TrigPush_Activate; +} + +/*QUAKED trigger_push (.5 .5 .5) ? FORCE_ONCE +Pushes the player +---------KEYS---------- +speed - how fast the player is pushed (default 500) +angle - the angle to push the player along the X,Y +zangle - the up direction to push the player (0 is straight up, 180 is straight down) +------------------------------------ +-------FLAGS--------------- +FORCE_ONCE - pushes once and then goes away +------------------------------------ +*/ +void SP_trigger_push(edict_t *self) +{ + InitTrigger(self); + self->solid = SOLID_TRIGGER; + self->msgHandler = DefaultMsgHandler; + self->classID = CID_TRIG_PUSH; + + if (!self->speed) + { + self->speed = 500; + } + + self->s.angles[2] = st.zangle; + + // Can't really use the normal trigger setup cause it doesn't update velocity often enough + self->touch = push_touch; + self->TriggerActivated = push_touch_trigger; +} + + + +//---------------------------------------------------------------------- +// Damage Field +//---------------------------------------------------------------------- + +void DamageField_Use(edict_t *self, edict_t *other, edict_t *activator); +void DamageField_Touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); + +void TrigDamage_Deactivate(edict_t *self, G_Message_t *msg) +{ + self->solid = SOLID_NOT; + self->use = NULL; +} + + +void TrigDamage_Activate(edict_t *self, G_Message_t *msg) +{ + self->solid = SOLID_TRIGGER; + self->use = DamageField_Use; + gi.linkentity (self); +} + + +void TrigDamageStaticsInit() +{ + classStatics[CID_TRIG_DAMAGE].msgReceivers[G_MSG_SUSPEND] = TrigDamage_Deactivate; + classStatics[CID_TRIG_DAMAGE].msgReceivers[G_MSG_UNSUSPEND] = TrigDamage_Activate; +} + + +/*QUAKED trigger_Damage (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW +Any entity that Touches this will be Damage. + +It does dmg points of Damage each server frame + +SILENT supresses playing the sound +SLOW changes the Damage rate to once per second +NO_PROTECTION *nothing* stops the Damage + +"dmg" default 5 (whole numbers only) + +*/ +void SP_trigger_Damage(edict_t *self) +{ + if(deathmatch->value && self->dmg > 100) + { + self->spawnflags = DEATHMATCH_RANDOM; + SP_misc_teleporter(self); + return; + } + + InitField(self); + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_TRIG_DAMAGE; + + self->touch = DamageField_Touch; + + if (!self->dmg) + self->dmg = 5; + + if (self->spawnflags & 1) + self->solid = SOLID_NOT; + else + self->solid = SOLID_TRIGGER; + + if (self->spawnflags & 2) + self->use = DamageField_Use; + + self->movetype = PHYSICSTYPE_NONE; + gi.linkentity (self); +} + +void DamageField_Use(edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->solid == SOLID_NOT) + self->solid = SOLID_TRIGGER; + else + self->solid = SOLID_NOT; + + if (!(self->spawnflags & 2)) + self->use = NULL; + +} + + +void DamageField_Touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + int dflags; + + if (!other->takedamage) + return; + + if (self->timestamp > level.time) + return; + + if (self->spawnflags & 16) + self->timestamp = level.time + 1; + else + self->timestamp = level.time + FRAMETIME; + + if (!(self->spawnflags & 4)) + { + if ((level.framenum % 10) == 0) + gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0); + } + + if (self->spawnflags & 8) + dflags = DAMAGE_NO_PROTECTION; + else + dflags = 0; + + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags | DAMAGE_SPELL|DAMAGE_AVOID_ARMOR,MOD_DIED); + + G_UseTargets(self, self); +} + +//---------------------------------------------------------------------- +// Gravity Field +//---------------------------------------------------------------------- + +void GravityField_Touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); + +/*QUAKED trigger_Gravity (.5 .5 .5) ? +Changes the Touching entites Gravity to +the value of "Gravity". 1.0 is standard +Gravity for the level. +*/ +void SP_trigger_Gravity(edict_t *self) +{ + if (st.gravity == 0) + { + gi.dprintf("trigger_Gravity without gravity set at %s\n", vtos(self->s.origin)); + G_FreeEdict (self); + return; + } + + InitField(self); + self->gravity = atoi(st.gravity); + self->touch = GravityField_Touch; +} + +void GravityField_Touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + other->gravity = self->gravity; + G_UseTargets(self, self); + +} + +//---------------------------------------------------------------------- +// Monster Jump Field +//---------------------------------------------------------------------- + +void MonsterJumpField_Touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (other->flags & (FL_FLY | FL_SWIM) ) + return; + if (other->svflags & SVF_DEADMONSTER) + return; + if ( !(other->svflags & SVF_MONSTER)) + return; + + VectorMA(other->velocity, self->speed, self->movedir, other->velocity); + other->velocity[2] += self->accel; + + other->groundentity = NULL; +} + +/*QUAKED trigger_MonsterJump (.5 .5 .5) ? +Walking monsters that Touch this will jump in the direction of the trigger's angle +"speed" default to 200, the speed thrown forward +"height" default to 200, the speed thrown upwards +*/ +void SP_trigger_MonsterJump(edict_t *self) +{ + if (self->s.angles[YAW] == 0) + self->s.angles[YAW] = 360; + + InitField(self); + + if (!self->speed) + self->speed = 200; + + if (!st.height) + self->accel = 200; + else + self->accel = st.height; + + self->touch = MonsterJumpField_Touch; +} + +//---------------------------------------------------------------------- +// Monster Go to Buoy Trigger +//---------------------------------------------------------------------- +#define TSF_BUOY_TOUCH 1 +#define TSF_BUOY_IGNORE_ENEMY 2 +#define TSF_BUOY_TELEPORT_SAFE 4 +#define TSF_BUOY_TELEPORT_UNSAFE 8 +#define TSF_BUOY_FIXED 16 +#define TSF_BUOY_STAND 32 +#define TSF_BUOY_WANDER 64 + +extern qboolean MG_MakeConnection(edict_t *self, buoy_t *first_buoy, qboolean skipjump); +qboolean MG_MonsterAttemptTeleport(edict_t *self, vec3_t destination, qboolean ignoreLOS); +void trigger_goto_buoy_execute (edict_t *self, edict_t *monster, edict_t *activator) +{ + qboolean found = false; + buoy_t *found_buoy = NULL; + int i; + + for(i = 0; i < level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + if(found_buoy->targetname) + { + if(!strcmp(found_buoy->targetname, self->pathtarget)) + { + found = true; + break; + } + } + } + + if(!found) + { + vec3_t org; + + VectorMA(self->mins, 0.5, self->maxs, org); + gi.dprintf("G.D.E. FAULT: trigger_goto_buoy at %s can't find it's pathtargeted buoy %s\n", vtos(org), self->pathtarget); + return; + } + + if(self->spawnflags & TSF_BUOY_TELEPORT_SAFE) + { + if(MG_MonsterAttemptTeleport(monster, found_buoy->origin, false)) + { + if(BUOY_DEBUG) + gi.dprintf("%s was teleported(safely) to %s by trigger_goto_buoy\n", monster->classname, found_buoy->targetname); + } + return; + } + else if(self->spawnflags & TSF_BUOY_TELEPORT_UNSAFE) + { + if(MG_MonsterAttemptTeleport(monster, found_buoy->origin, true)) + { + if(BUOY_DEBUG) + gi.dprintf("%s was teleported(unsafely) to %s by trigger_goto_buoy\n", monster->classname, found_buoy->targetname); + } + return; + } + + if(BUOY_DEBUG) + gi.dprintf("%s forced to go to buoy %s by trigger_goto_buoy\n", monster->classname, self->pathtarget); + + if(self->spawnflags&TSF_BUOY_IGNORE_ENEMY)//make him ignore enemy until gets to dest buoy + { + monster->ai_mood_flags|=AI_MOOD_FLAG_IGNORE_ENEMY; + if(BUOY_DEBUG) + gi.dprintf("%s forced to ignore enemy by trigger_goto_buoy\n", monster->classname, self->pathtarget); + } + + monster->spawnflags &= ~MSF_FIXED; + monster->ai_mood_flags|=AI_MOOD_FLAG_FORCED_BUOY; + monster->forced_buoy = found_buoy->id; + monster->ai_mood = AI_MOOD_NAVIGATE; + + if(!monster->enemy) + monster->enemy = activator; + + MG_RemoveBuoyEffects(monster); + MG_MakeConnection(monster, NULL, false); + + if(self->spawnflags&TSF_BUOY_FIXED) + monster->ai_mood_flags|=AI_MOOD_FLAG_GOTO_FIXED; + + if(self->spawnflags&TSF_BUOY_STAND) + monster->ai_mood_flags|=AI_MOOD_FLAG_GOTO_STAND; + + if(self->spawnflags&TSF_BUOY_WANDER) + monster->ai_mood_flags|=AI_MOOD_FLAG_GOTO_WANDER; + + //make him check mood NOW and get going! Don't wait for current anim to finish! + if(classStatics[monster->classID].msgReceivers[MSG_CHECK_MOOD]) + QPostMessage(monster, MSG_CHECK_MOOD,PRI_DIRECTIVE, "i", monster->ai_mood); + else + {//no check mood message handler, just send a run and let him wait, i guess! + monster->mood_nextthink = 0; + QPostMessage(monster, MSG_RUN,PRI_DIRECTIVE, NULL); + } + +} + +void trigger_goto_buoy_touch_go (edict_t *self) +{ + if(!self->enemy) + return; + + if(!(self->enemy->svflags&SVF_MONSTER)) + return; + + if(self->enemy->health<=0) + return; + + if(!(self->enemy->monsterinfo.aiflags&AI_USING_BUOYS)) + return; + + trigger_goto_buoy_execute(self, self->enemy, self->activator); +} + +void trigger_goto_buoy_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if(level.time < self->air_finished) + return; + + if(!(other->svflags & SVF_MONSTER)) + return; + + if(!(other->monsterinfo.aiflags&AI_USING_BUOYS)) + return; + + if(other->health<=0) + return; + + self->activator = other->enemy; + + if(self->delay) + { + self->enemy = other; + self->think = trigger_goto_buoy_touch_go; + self->nextthink = level.time + self->delay; + return; + } + + trigger_goto_buoy_execute(self, other, self->activator); + + if(self->wait == -1) + { + self->touch = NULL; + self->use = NULL; + } + else + self->air_finished = level.time + self->wait; +} + +void trigger_goto_buoy_use_go (edict_t *self) +{ + edict_t *monster = NULL; + + monster = G_Find(monster, FOFS(targetname), self->target); + + if(!monster) + { + if(BUOY_DEBUG) + gi.dprintf("ERROR: trigger_goto_buoy can't find it's target monster %s\n", self->pathtarget); + return; + } + + if(!(monster->svflags&SVF_MONSTER)) + return; + + if(monster->health<=0) + return; + + if(!(monster->monsterinfo.aiflags&AI_USING_BUOYS)) + return; + + trigger_goto_buoy_execute(self, monster, self->activator); +} + +void trigger_goto_buoy_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if(level.time < self->air_finished) + return; + + self->activator = activator; + + if(self->delay) + { + self->think = trigger_goto_buoy_use_go; + self->nextthink = level.time + self->delay; + return; + } + + trigger_goto_buoy_use_go(self); + + self->air_finished = level.time + self->wait; +} + +void trigger_goto_buoy_find_target(edict_t *self) +{ + qboolean found = false; + buoy_t *found_buoy = NULL; + int i; + + self->think = NULL; + self->nextthink = -1; + + + for(i = 0; i < level.active_buoys; i++) + { + if(!stricmp(level.buoy_list[i].targetname, self->pathtarget)) + { + found = true; + break; + } + } + + if(!found) + { + vec3_t org; + + VectorMA(self->mins, 0.5, self->maxs, org); + gi.dprintf("G.D.E. FAULT: trigger_goto_buoy at %s can't find it's pathtargeted buoy %s\n", vtos(org), self->pathtarget); + return; + } +} + +/*QUAKED trigger_goto_buoy (.5 .5 .5) ? Touch IgnoreEnemy TeleportSafe TeleportUnSafe FIXED STAND WANDER +A monster touching this trigger will find the buoy with the "pathtarget" targetname and head for it if it can. + +This is NOT a touch trigger for a player, only monsters should ever touch it and only if the TOUCH spawnflag is on. + +To have a player touch-trigger it, have the player touch a normal trigger that fires this trigger... (sorry!) + +Otherwise, acts like a normal trigger. + +"pathtarget" - targetname of buoy monster should head to + +Touch - should be able to be touch-activated by monsters- NOTE: This will try to force the entity touching the trigger to it's buoy- should NOT be intended to be touched by anything but monsters + +IgnoreEnemy - Monster will ignore his enemy until he gets to his target buoy (or until attacked or woken up some other way, working on preventing this if desired) + +TeleportSafe - Make monster teleport to target buoy only if there is nothing there and the player cannot see the monster and/or desination buoy + +TeleportUnSafe - Same as TeleportSafe, but ignores whether or not the player can see the monster and/or desination buoy + +If you wish to make an assassin teleport to a buoy, use TeleportUnsafe since he doesn't need to hide the teleport from the player + +FIXED - Upon arriving at the target buoy, the monster will become fixed and wait for an enemy (will not move from that spot no matter what) + +STAND - Upon arriving at the target buoy, the monster will forget any aenemy it has and simply stand around there until it sees another enemy + +WANDER - Upon arriving at the target buoy, the monster will forget any aenemy it has and begin to wander around that buoy's vicinity + +"wait" how long to wait between firings +"delay" how long to wait after being activated to actually try to send the monster away +*/ +void SP_trigger_goto_buoy(edict_t *self) +{ + InitField(self); + + if(!self->pathtarget) + { + gi.dprintf("G.D.E. FAULT: trigger_goto_buoy with no pathtarget!\n"); + G_FreeEdict(self); + return; + } + else if(BUOY_DEBUG) + { + self->think = trigger_goto_buoy_find_target; + self->nextthink = level.time + 0.5; + } + + if(self->spawnflags&TSF_BUOY_TOUCH) + self->touch = trigger_goto_buoy_touch; + + if(self->targetname) + { + if(!self->target) + gi.dprintf("G.D.E. FAULT: targeted trigger_goto_buoy with no monster target!\n"); + self->use = trigger_goto_buoy_use; + } +} diff --git a/Toolkit/Programming/GameCode/game/g_flamethrow.c b/Toolkit/Programming/GameCode/game/g_flamethrow.c new file mode 100644 index 0000000..e8a12f1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_flamethrow.c @@ -0,0 +1,167 @@ +// G_flamethrow.c +// Heretic II +// +// jweier + +#include "g_local.h" +#include "Vector.h" +#include "FX.h" +#include "g_playstats.h" +#include "g_DefaultMessageHandler.h" + +#define FLAMETHROWER_STEAM 1 +#define FLAMETHROWER_MONSTERTOUCH 2 + +void flamethrower_use( edict_t *self, edict_t *other, edict_t *activator ); +void flamethrower_touch( edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf ); + +void FlameThrower_Deactivate(edict_t *self, G_Message_t *msg) +{ + self->solid = SOLID_NOT; + self->touch = NULL; + self->use = NULL; +} + + +void FlameThrower_Activate(edict_t *self, G_Message_t *msg) +{ + self->solid = SOLID_TRIGGER; + self->use = flamethrower_use; + self->touch = flamethrower_touch; + gi.linkentity (self); +} + + +void FlameThrowerStaticsInit() +{ + classStatics[CID_FLAMETHROWER].msgReceivers[G_MSG_SUSPEND] = FlameThrower_Deactivate; + classStatics[CID_FLAMETHROWER].msgReceivers[G_MSG_UNSUSPEND] = FlameThrower_Activate; +} + + +void flamethrower_trigger( edict_t *self ) +{ + vec3_t dir; + int flags = 0; + + AngleVectors(self->s.angles, dir, NULL, NULL); + + if (self->spawnflags & FLAMETHROWER_STEAM) + flags |= CEF_FLAG6; + + gi.CreateEffect( NULL, FX_FLAMETHROWER, flags, self->s.origin, "df", dir, self->speed); + + self->monsterinfo.attack_finished = level.time + self->wait; + + if (self->wait == -2) + { + self->nextthink = level.time + 1; + self->think = flamethrower_trigger; + } + else + { + self->think = NULL; + } +} + +void flamethrower_use( edict_t *self, edict_t *other, edict_t *activator ) +{ + vec3_t dir; + int flags = 0; + + AngleVectors(self->s.angles, dir, NULL, NULL); + + if (self->monsterinfo.attack_finished < level.time) + { + //Toggle off? + if (self->wait == -2) + { + //Toggle off + self->wait = -1; + //gi.RemoveEffects( &self->s, FX_FLAMETHROWER ); + } + else if (self->wait == -1) + { + //Denote that we are toggled on + self->wait = -2; + } + + flamethrower_trigger( self ); + } +} + +void flamethrower_touch( edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf ) +{ + vec3_t dir; + int flags = 0; + + //Not toggled on, so don't damage + if (self->wait == -1) + return; + + if (!other->client && (!(other->svflags & SVF_MONSTER) || !(self->spawnflags&FLAMETHROWER_MONSTERTOUCH))) + return; + + AngleVectors(self->s.angles, dir, NULL, NULL); + + if (other->takedamage) + { + if (self->spawnflags & FLAMETHROWER_STEAM) + T_Damage(other, self, self, dir, other->s.origin, plane->normal, self->dmg, 0, + DAMAGE_AVOID_ARMOR|DAMAGE_NO_BLOOD,MOD_DIED); + else + T_Damage(other, self, self, dir, other->s.origin, plane->normal, self->dmg, 0, + DAMAGE_FIRE|DAMAGE_FIRE_LINGER|DAMAGE_AVOID_ARMOR|DAMAGE_NO_BLOOD,MOD_DIED); + } + + if (self->monsterinfo.attack_finished < level.time && (self->wait > 0)) + { + if (self->spawnflags & FLAMETHROWER_STEAM) + flags |= CEF_FLAG6; + + gi.CreateEffect( NULL, FX_FLAMETHROWER, flags, self->s.origin, "df", dir, self->speed); + self->monsterinfo.attack_finished = level.time + self->wait; + } +} + +/*QUAKED flamethrower (.5 .5 .5) ? STEAM MONSTERTOUCH +A jet of flame + +If steam is checked, it is a steam jet + +MONSTERTOUCH - will allow monsters to set it off + +--------SETUP---------- + +------KEYS----------- +dmg - damage per frame (1/10 of a second) (default 2) +wait - delay between each burst (default 2) (-1 signifies it is a toggled effect) +angles - Direction burst is to move in +speed - velocity of the burst (default 400) +*/ + +void SP_flamethrower(edict_t *self) +{ + self->msgHandler = DefaultMsgHandler; + self->classID = CID_FLAMETHROWER; + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_TRIGGER; + + if (!self->wait) + self->wait = 2; + + if (!self->dmg) + self->dmg = 2; + + if (!self->speed) + self->speed = 400.0f; + + self->svflags |= SVF_NOCLIENT; + gi.setmodel (self, self->model); + + self->use = flamethrower_use; + self->touch = flamethrower_touch; + gi.linkentity (self); +} + diff --git a/Toolkit/Programming/GameCode/game/g_func.c b/Toolkit/Programming/GameCode/game/g_func.c new file mode 100644 index 0000000..6459cee --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_func.c @@ -0,0 +1,3013 @@ +#include "g_local.h" +#include "g_misc.h" +#include "FX.h" +#include "Random.h" +#include "vector.h" +#include "g_DefaultMessageHandler.h" +#include "m_stats.h" +#include "buoy.h" + +void ED_CallSpawn (edict_t *ent); +void TrainAngleMove_Calc (edict_t *self,edict_t *targ,vec3_t dest); +int MG_SetFirstBuoy(edict_t *self); +qboolean MG_MonsterAttemptTeleport(edict_t *self, vec3_t destination, qboolean ignoreLOS); +buoy_t *find_next_buoy(edict_t *self, int sb_id, int fb_id); +void door_sounds (edict_t *ent); + +#define DSF_SWINGAWAY 0x00002000//8192 + +typedef enum MonsterSpawnerID_e +{ + MS_NOTHING = 0, + MS_RAT, + MS_PLAGUEELF, + MS_SPREADER, + MS_GORGON, + MS_CHKROKTK, + MS_TCHEKRIK_MALE, + MS_TCHEKRIK_FEMALE, + MS_TCHEKRIK_MOTHERS, + MS_HIGH_PRIESTESS, + MS_OGLE, + MS_SERAPH_OVERLORD, + MS_SERAPH_GUARD, + MS_ASSASSIN, + MS_MORCALAVIN, + MS_DRANOR, + MS_SIDHE_GUARD, + MS_SIERNAN, + MS_SSITHRA_SCOUT, + MS_SSITHRA_VICTIM, + MS_MSSITHRA, + MS_HARPY, + MS_FISH, + MS_CHICKEN, + MS_SSITHRA, + MS_GKROKON, + MS_RAT_GIANT, + MS_PALACE_PLAGUE_GUARD, + MS_INVISIBLE_PALACE_PLAGUE_GUARD, + MS_MAX +} MonsterSpawnerID_t; + +struct +{ + char *name; +} MonsterSpawnerClassname [] = +{ + "monster_nothing", + "monster_rat", // MS_RAT + "monster_plagueElf", // MS_PLAGUEELF + "monster_spreader", // MS_SPREADER + "monster_gorgon", // MS_GORGON + "monster_rat", // MS_CHKROKTK + "monster_tcheckrik_male", // TCHEKRIK_MALE + "monster_tcheckrik_female", // TCHEKRIK_FEMALE + "monster_plagueElf", // TCHEKRIK_MOTHERS + "monster_highPriestess", // HIGH_PRIESTESS + "monster_ogle", // MS_OGLE + "monster_seraph_overlord", // MS_SERAPH_OVERLORD + "monster_seraph_guard", // MS_SERAPH_GUARD + "monster_assassin", // MS_ASSASSIN + "monster_morcalavin", // MS_MORCALAVIN + "character_dranor", // MS_DRANOR + "monster_plagueElf", // MS_SIDHE_GUARD + "character_siernan1", // MS_SIERNAN + "character_ssithra_scout", // MS_SSITHRA_SCOUT + "character_ssithra_victim", // MS_SSITHRA_VICTIM + "monster_mssithra", // MS_MSSITHRA + "monster_harpy", // MS_HARPY + "monster_fish", // MS_FISH + "monster_chicken", // MS_CHICKEN + "monster_ssithra", // MS_SSITHRA + "monster_gkrokon", // MS_GKROKON + "monster_rat_giant", // MS_RAT_GIANT + "monster_palace_plague_guard", //MS_PALACE_PLAGUE_GUARD, + "monster_palace_plague_guard_invisible", //MS_INVISIBLE_PALACE_PLAGUE_GUARD, +}; + +int CIDForSpawnerStyle[MS_MAX] = +{ + CID_NONE, + CID_RAT, + CID_PLAGUEELF, + CID_SPREADER, + CID_GORGON, + CID_GKROKON, + CID_TCHECKRIK, + CID_TCHECKRIK, + CID_MOTHER, + CID_HIGHPRIESTESS, + CID_OGLE, + CID_SERAPH_OVERLORD, + CID_SERAPH_GUARD, + CID_ASSASSIN, + CID_MORK, + CID_DRANOR, + CID_PLAGUEELF, + CID_C_SIERNAN1, + CID_SSITHRA_SCOUT, + CID_SSITHRA_VICTIM, + CID_MSSITHRA, + CID_HARPY, + CID_FISH, + CID_CHICKEN, + CID_SSITHRA, + CID_GKROKON, + CID_RAT, + CID_PLAGUEELF, + CID_PLAGUEELF, +}; + +/* +========================================================= + + PLATS + + movement options: + + linear + smooth start, hard stop + smooth start, smooth stop + + start + end + acceleration + speed + deceleration + begin sound + end sound + target fired when reaching end + wait at end + + object characteristics that use move segments + --------------------------------------------- + PHYSICSTYPE_PUSH, or PHYSICSTYPE_STOP + action when touched + action when blocked + action when used + disabled? + auto trigger spawning + + +========================================================= +*/ + +#define PLAT_LOW_TRIGGER 1 + +#define STATE_TOP 0 +#define STATE_BOTTOM 1 +#define STATE_UP 2 +#define STATE_DOWN 3 + +#define DOOR_START_OPEN 1 +#define DOOR_REVERSE 2 +#define DOOR_CRUSHER 4 +#define DOOR_NOMONSTER 8 +#define DOOR_TOGGLE 32 +#define DOOR_X_AXIS 64 +#define DOOR_Y_AXIS 128 + + +// +// Support routines for movement (changes in origin using velocity) +// + +void Move_Done (edict_t *ent) +{ + VectorClear (ent->velocity); +// VectorClear (ent->avelocity); + + ent->think = NULL; + + if (ent->moveinfo.endfunc) + { + ent->moveinfo.endfunc (ent); + } +} + +void Move_Final (edict_t *ent) +{ + VectorScale (ent->moveinfo.dir, ent->moveinfo.remaining_distance / FRAMETIME, ent->velocity); + + ent->think = Move_Done; + ent->nextthink = level.time + FRAMETIME; +} + +void Move_Begin (edict_t *ent) +{ + float frames; + + if ((ent->moveinfo.speed * FRAMETIME) >= ent->moveinfo.remaining_distance) + { + Move_Final (ent); + return; + } + VectorScale (ent->moveinfo.dir, ent->moveinfo.speed, ent->velocity); + frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME); + ent->moveinfo.remaining_distance -= frames * ent->moveinfo.speed * FRAMETIME; + ent->nextthink = level.time + (frames * FRAMETIME); + ent->think = Move_Final; +} + +void Think_AccelMove (edict_t *ent); + +void Move_Calc (edict_t *ent, vec3_t dest, void(*func)(edict_t*)) +{ + VectorClear (ent->velocity); + + VectorSubtract (dest, ent->s.origin, ent->moveinfo.dir); + ent->moveinfo.remaining_distance = VectorNormalize (ent->moveinfo.dir); + ent->moveinfo.endfunc = func; + + if (ent->moveinfo.speed == ent->moveinfo.accel && ent->moveinfo.speed == ent->moveinfo.decel) + { + if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent)) + { + Move_Begin (ent); + } + else + { + ent->nextthink = level.time + FRAMETIME; + ent->think = Move_Begin; + } + } + else + { + // accelerative + ent->moveinfo.current_speed = 0; + ent->think = Think_AccelMove; + ent->nextthink = level.time + FRAMETIME; + } +} + +// +// Support routines for angular movement of trains (changes in angle using avelocity) +// + +void TrainAngleMove_Calc(edict_t *self, edict_t *ent, vec3_t dest) +{ + float len; + float traveltime; + float holdtime; + vec3_t angles; + + VectorClear(self->avelocity); + + if (!ent) + { + return; + } + + if (Vec3IsZero(ent->s.angles)) + { + return; + } + + // Put angles into wacky order (required) + angles[0] = ent->s.angles[1]; + angles[1] = ent->s.angles[2]; + angles[2] = ent->s.angles[0]; + + // length to travel + len = VectorSeparation (self->s.origin, dest); + // divide by speed to get time to reach dest + traveltime = (len / self->moveinfo.speed) + self->moveinfo.wait; + + if (traveltime < FRAMETIME) + { + VectorScale (angles, 1.0 / FRAMETIME, self->avelocity); + VectorAdd(self->s.angles, angles, self->moveinfo.end_angles); + return; + } + + // scale the destdelta vector by the time spent traveling to get velocity + // .95 is used because we want the train to change angles a little slow, that + // way it never over shoots the angle it should be at. In train_next the final + // angle is set using en_angles. + holdtime = 0.97 / traveltime; + VectorScale (angles, holdtime, self->avelocity); + + VectorAdd(self->s.angles, angles, self->moveinfo.end_angles); +} + +// +// Support routines for angular movement (changes in angle using avelocity) +// + +void AngleMove_Done (edict_t *ent) +{ + VectorClear (ent->avelocity); + + ent->think = NULL; + + if (ent->moveinfo.endfunc) + { + ent->moveinfo.endfunc (ent); + } +} + +void AngleMove_Final (edict_t *ent) +{ + vec3_t move; + + if (ent->moveinfo.state == STATE_UP) + VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, move); + else + VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, move); + + VectorScale (move, 1.0 / FRAMETIME, ent->avelocity); + + ent->think = AngleMove_Done; + ent->nextthink = level.time + FRAMETIME; +} + +void AngleMove_Begin (edict_t *ent) +{ + vec3_t destdelta; + float len; + float traveltime; + float frames; + + // set destdelta to the vector needed to move + if (ent->moveinfo.state == STATE_UP) + VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, destdelta); + else + VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, destdelta); + + // calculate length of vector + len = VectorLength (destdelta); + + // divide by speed to get time to reach dest + traveltime = len / ent->moveinfo.speed; + + if (traveltime < FRAMETIME) + { + AngleMove_Final (ent); + return; + } + + frames = floor(traveltime / FRAMETIME); + + // scale the destdelta vector by the time spent traveling to get velocity + VectorScale (destdelta, 1.0 / traveltime, ent->avelocity); + + // set nextthink to trigger a think when dest is reached + ent->nextthink = level.time + frames * FRAMETIME; + ent->think = AngleMove_Final; +} + +void AngleMove_Calc (edict_t *ent, void(*func)(edict_t*)) +{ + VectorClear (ent->avelocity); + ent->moveinfo.endfunc = func; + if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent)) + { + AngleMove_Begin (ent); + } + else + { + ent->nextthink = level.time + FRAMETIME; + ent->think = AngleMove_Begin; + } +} + + +/* +============== +Think_AccelMove + +The team has completed a frame of movement, so +change the speed for the next frame +============== +*/ +#define AccelerationDistance(target, rate) (target * ((target / rate) + 1) / 2) + +void plat_CalcAcceleratedMove(moveinfo_t *moveinfo) +{ + float accel_dist; + float decel_dist; + + moveinfo->move_speed = moveinfo->speed; + + if (moveinfo->remaining_distance < moveinfo->accel) + { + moveinfo->current_speed = moveinfo->remaining_distance; + return; + } + + accel_dist = AccelerationDistance (moveinfo->speed, moveinfo->accel); + decel_dist = AccelerationDistance (moveinfo->speed, moveinfo->decel); + + if ((moveinfo->remaining_distance - accel_dist - decel_dist) < 0) + { + float f; + + f = (moveinfo->accel + moveinfo->decel) / (moveinfo->accel * moveinfo->decel); + moveinfo->move_speed = (-2 + sqrt(4 - 4 * f * (-2 * moveinfo->remaining_distance))) / (2 * f); + decel_dist = AccelerationDistance (moveinfo->move_speed, moveinfo->decel); + } + + moveinfo->decel_distance = decel_dist; +}; + +void plat_Accelerate (moveinfo_t *moveinfo) +{ + // are we decelerating? + if (moveinfo->remaining_distance <= moveinfo->decel_distance) + { + if (moveinfo->remaining_distance < moveinfo->decel_distance) + { + if (moveinfo->next_speed) + { + moveinfo->current_speed = moveinfo->next_speed; + moveinfo->next_speed = 0; + return; + } + if (moveinfo->current_speed > moveinfo->decel) + moveinfo->current_speed -= moveinfo->decel; + } + return; + } + + // are we at full speed and need to start decelerating during this move? + if (moveinfo->current_speed == moveinfo->move_speed) + if ((moveinfo->remaining_distance - moveinfo->current_speed) < moveinfo->decel_distance) + { + float p1_distance; + float p2_distance; + float distance; + + p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance; + p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / moveinfo->move_speed)); + distance = p1_distance + p2_distance; + moveinfo->current_speed = moveinfo->move_speed; + moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance); + return; + } + + // are we accelerating? + if (moveinfo->current_speed < moveinfo->speed) + { + float old_speed; + float p1_distance; + float p1_speed; + float p2_distance; + float distance; + + old_speed = moveinfo->current_speed; + + // figure simple acceleration up to move_speed + moveinfo->current_speed += moveinfo->accel; + if (moveinfo->current_speed > moveinfo->speed) + moveinfo->current_speed = moveinfo->speed; + + // are we accelerating throughout this entire move? + if ((moveinfo->remaining_distance - moveinfo->current_speed) >= moveinfo->decel_distance) + return; + + // during this move we will accelrate from current_speed to move_speed + // and cross over the decel_distance; figure the average speed for the + // entire move + p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance; + p1_speed = (old_speed + moveinfo->move_speed) / 2.0; + p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / p1_speed)); + distance = p1_distance + p2_distance; + moveinfo->current_speed = (p1_speed * (p1_distance / distance)) + (moveinfo->move_speed * (p2_distance / distance)); + moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance); + return; + } + + // we are at constant velocity (move_speed) + return; +}; + +void Think_AccelMove (edict_t *ent) +{ + ent->moveinfo.remaining_distance -= ent->moveinfo.current_speed; + + if (ent->moveinfo.current_speed == 0) // starting or blocked + plat_CalcAcceleratedMove(&ent->moveinfo); + + plat_Accelerate (&ent->moveinfo); + + // will the entire move complete on next frame? + if (ent->moveinfo.remaining_distance <= ent->moveinfo.current_speed) + { + Move_Final (ent); + return; + } + + VectorScale (ent->moveinfo.dir, ent->moveinfo.current_speed*10, ent->velocity); + ent->nextthink = level.time + FRAMETIME; + ent->think = Think_AccelMove; +} + + +void plat_go_down (edict_t *ent); + +void plat_hit_top (edict_t *ent) +{ + if (!(ent->flags & FL_TEAMSLAVE)) + { + if (ent->moveinfo.sound_end) + gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_IDLE, 0); + ent->s.sound = 0; + } + ent->moveinfo.state = STATE_TOP; + + ent->think = plat_go_down; + ent->nextthink = level.time + 3; +} + +void plat_hit_bottom (edict_t *ent) +{ + if (!(ent->flags & FL_TEAMSLAVE)) + { + if (ent->moveinfo.sound_end) + gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_IDLE, 0); + ent->s.sound = 0; + } + ent->moveinfo.state = STATE_BOTTOM; +} + +void plat_go_down (edict_t *ent) +{ + if (!(ent->flags & FL_TEAMSLAVE)) + { + if (ent->moveinfo.sound_start) + gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_IDLE, 0); + ent->s.sound = ent->moveinfo.sound_middle; + ent->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_IDLE; + } + ent->moveinfo.state = STATE_DOWN; + Move_Calc (ent, ent->moveinfo.end_origin, plat_hit_bottom); +} + +void plat_go_up (edict_t *ent) +{ + if (!(ent->flags & FL_TEAMSLAVE)) + { + if (ent->moveinfo.sound_start) + gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_IDLE, 0); + ent->s.sound = ent->moveinfo.sound_middle; + ent->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_IDLE; + } + ent->moveinfo.state = STATE_UP; + Move_Calc (ent, ent->moveinfo.start_origin, plat_hit_top); +} + +void plat_blocked (edict_t *self, edict_t *other) +{ + if ((other->svflags & SVF_MONSTER) && (!other->client) && !(other->svflags & SVF_MONSTER)) + { + // give it a chance to go away on it's own terms (like gibs) + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 3000, 1, DAMAGE_AVOID_ARMOR,MOD_CRUSH); + // if it's still there, nuke it + if(other->health > 0) + BecomeDebris(other); + return; + } + + if (self->spawnflags & DOOR_CRUSHER) + { + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg * 10, 1, 0,MOD_CRUSH); + return; + } + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0,MOD_CRUSH); + + if (self->moveinfo.state == STATE_UP) + plat_go_down (self); + else if (self->moveinfo.state == STATE_DOWN) + plat_go_up (self); +} + + +void Use_Plat (edict_t *ent, edict_t *other, edict_t *activator) +{ + if (ent->think) + return; // already down + plat_go_down (ent); +} + + +void Touch_Plat_Center (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (!other->client) + return; + + if (other->health <= 0) + return; + + ent = ent->enemy; // now point at the plat, not the trigger + if (ent->moveinfo.state == STATE_BOTTOM) + plat_go_up (ent); + else if (ent->moveinfo.state == STATE_TOP) + ent->nextthink = level.time + 1; // the player is still on the plat, so delay going down +} + +void plat_spawn_inside_trigger (edict_t *ent) +{ + edict_t *trigger; + vec3_t tmin, tmax; + +// +// middle trigger +// + trigger = G_Spawn(); + + trigger->touch = Touch_Plat_Center; + trigger->movetype = PHYSICSTYPE_NONE; + trigger->solid = SOLID_TRIGGER; + trigger->enemy = ent; + + tmin[0] = ent->mins[0] + 25; + tmin[1] = ent->mins[1] + 25; + tmin[2] = ent->mins[2]; + + tmax[0] = ent->maxs[0] - 25; + tmax[1] = ent->maxs[1] - 25; + tmax[2] = ent->maxs[2] + 8; + + tmin[2] = tmax[2] - (ent->pos1[2] - ent->pos2[2] + st.lip); + + if (ent->spawnflags & PLAT_LOW_TRIGGER) + tmax[2] = tmin[2] + 8; + + if (tmax[0] - tmin[0] <= 0) + { + tmin[0] = (ent->mins[0] + ent->maxs[0]) *0.5; + tmax[0] = tmin[0] + 1; + } + if (tmax[1] - tmin[1] <= 0) + { + tmin[1] = (ent->mins[1] + ent->maxs[1]) *0.5; + tmax[1] = tmin[1] + 1; + } + + VectorCopy (tmin, trigger->mins); + VectorCopy (tmax, trigger->maxs); + + gi.linkentity (trigger); +} + +void FuncRotate_Deactivate(edict_t *self, G_Message_t *msg) +{ + VectorClear(self->velocity); + VectorClear(self->avelocity); +} + +void FuncRotate_Activate(edict_t *self, G_Message_t *msg) +{ + self->use(self,NULL,NULL); + gi.linkentity (self); +} + +void FuncRotateStaticsInit() +{ + classStatics[CID_FUNC_ROTATE].msgReceivers[G_MSG_SUSPEND] = FuncRotate_Deactivate; + classStatics[CID_FUNC_ROTATE].msgReceivers[G_MSG_UNSUSPEND] = FuncRotate_Activate; +} + + + +void FuncDoor_Deactivate(edict_t *self, G_Message_t *msg) +{ + VectorClear(self->velocity); + VectorClear(self->avelocity); +} + +void FuncDoor_Activate(edict_t *self, G_Message_t *msg) +{ + self->use(self,NULL,NULL); + gi.linkentity (self); +} + +void FuncDoorStaticsInit() +{ + classStatics[CID_FUNC_DOOR].msgReceivers[G_MSG_SUSPEND] = FuncRotate_Deactivate; + classStatics[CID_FUNC_DOOR].msgReceivers[G_MSG_UNSUSPEND] = FuncRotate_Activate; +} + + + +/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER +speed default 150 + +Plats are always drawn in the extended position, so they will light correctly. + +If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat. + +"speed" overrides default 200. +"accel" overrides default 500 +"lip" overrides default 8 pixel lip + +If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determoveinfoned by the model's height. + +"sounds" +0) silent +1) generic door +2) heavy stone door +3) for swing arm on palace level +4) for stone bridge in palace level +5) small/medium wood door swinging +6) large/huge wood door swinging +7) medium sized stone/wood door sliding +8) large stone/wood sliding door or portcullis +9) average metal door swinging +10) Fast sliding doors +11) Hive, Metal, Multipaneled sliding +12) Huge stone door swinging +13) Medium/large elevator +14) Crane (warehouse) +15) hammerlike pump in oglemine1 +16) sliding metal table in cloudlabs +17) lab table which rotates up to ceiling - cloublabs +18) piston sound +19) short, sharp metal clang +20) something going under water +21) the bam sound + +*/ +void SP_func_plat (edict_t *ent) +{ + VectorClear (ent->s.angles); + + ent->solid = SOLID_BSP; + ent->movetype = PHYSICSTYPE_PUSH; + ent->clipmask = MASK_PLAYERSOLID; + ent->blocked = plat_blocked; + ent->use = Use_Plat; + + if (!ent->speed) + ent->speed = 20; + else + ent->speed *= 0.1; + + if (!ent->accel) + ent->accel = 5; + else + ent->accel *= 0.1; + + if (!ent->decel) + ent->decel = 5; + else + ent->decel *= 0.1; + + if (!ent->dmg) + ent->dmg = 2; + + if (!st.lip) + st.lip = 8; + + // pos1 is the top position, pos2 is the bottom + VectorCopy (ent->s.origin, ent->pos1); + VectorCopy (ent->s.origin, ent->pos2); + if (st.height) + ent->pos2[2] -= st.height; + else + ent->pos2[2] -= (ent->maxs[2] - ent->mins[2]) - st.lip; + + if (ent->targetname) + { + ent->moveinfo.state = STATE_UP; + } + else + { + VectorCopy (ent->pos2, ent->s.origin); + ent->moveinfo.state = STATE_BOTTOM; + } + ent->moveinfo.speed = ent->speed; + ent->moveinfo.accel = ent->accel; + ent->moveinfo.decel = ent->decel; + ent->moveinfo.wait = ent->wait; + + VectorCopy (ent->pos1, ent->moveinfo.start_origin); + VectorCopy (ent->s.angles, ent->moveinfo.start_angles); + VectorCopy (ent->pos2, ent->moveinfo.end_origin); + VectorCopy (ent->s.angles, ent->moveinfo.end_angles); + + VectorSubtract(ent->maxs, ent->mins, ent->s.bmodel_origin); + Vec3ScaleAssign(0.5, ent->s.bmodel_origin); + VectorAdd(ent->mins, ent->s.bmodel_origin, ent->s.bmodel_origin); + + door_sounds (ent); + + gi.setmodel (ent, ent->model); + gi.linkentity (ent); + + plat_spawn_inside_trigger (ent); // the "start moving" trigger + +} + +void rotate_sounds (edict_t *ent) +{ + if (ent->sounds == 0) + { + ent->moveinfo.sound_start = 0; + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = 0; + } + else if (ent->sounds == 1) + { + ent->moveinfo.sound_middle = gi.soundindex ("doors/stoneloop.wav"); + } + else if (ent->sounds == 2) + { + ent->moveinfo.sound_middle = gi.soundindex ("objects/hugewheel.wav"); + } + else if (ent->sounds == 3) + { + ent->moveinfo.sound_middle = gi.soundindex ("objects/pizzawheel.wav"); + } + else if (ent->sounds == 4) + { + ent->moveinfo.sound_start = gi.soundindex ("objects/spankers.wav"); + } + else + { + ent->moveinfo.sound_start = 0; + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = 0; + } +} + +//==================================================================== + +/*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS TOUCH_PAIN STOP ANIMATED ANIMATED_FAST CRUSHER +You need to have an origin brush as part of this entity. The center of that brush will be +the point around which it is rotated. It will rotate around the Z axis by default. You can +check either the X_AXIS or Y_AXIS box to change that. +----------KEYS------------- +"speed" determines how fast it moves; default value is 100. +"dmg" damage to inflict when blocked (2 default) +"sounds" +0 - silent +1 - generic rotate +2 - huge wheel ogles push in cloudlabs +3 - rock crusher which turns at end of conveyor on ogle2 +4 - 'spanking' paddles on gauntlet +--------SPAWNFLAGS------------ +REVERSE will cause the it to rotate in the opposite direction. +STOP mean it will stop moving instead of pushing entities +*/ + +void rotating_blocked (edict_t *self, edict_t *other) +{ + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0,MOD_CRUSH); +} + +void rotating_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (self->avelocity[0] || self->avelocity[1] || self->avelocity[2]) + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0,MOD_CRUSH); +} + +void rotating_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (!VectorCompare (self->avelocity, vec3_origin)) + { + self->s.sound = 0; + VectorClear (self->avelocity); + self->touch = NULL; + } + else + { + self->s.sound = self->moveinfo.sound_middle; + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_IDLE; + VectorScale (self->movedir, self->speed, self->avelocity); + if (self->spawnflags & 16) + self->touch = rotating_touch; + } +} + +void SP_func_rotating (edict_t *ent) +{ + + ent->msgHandler = DefaultMsgHandler; + ent->classID = CID_FUNC_ROTATE; + + ent->solid = SOLID_BSP; + if (ent->spawnflags & 32) + ent->movetype = PHYSICSTYPE_STOP; + else + ent->movetype = PHYSICSTYPE_PUSH; + + rotate_sounds(ent); + + // set the axis of rotation + VectorClear(ent->movedir); + if (ent->spawnflags & 4) + ent->movedir[2] = 1.0; + else if (ent->spawnflags & 8) + ent->movedir[0] = 1.0; + else // Z_AXIS + ent->movedir[1] = 1.0; + + // check for reverse rotation + if (ent->spawnflags & 2) + VectorNegate (ent->movedir, ent->movedir); + + if (!ent->speed) + ent->speed = 100; + if (!ent->dmg) + ent->dmg = 2; + +// ent->moveinfo.sound_middle = "doors/hydro1.wav"; + + ent->use = rotating_use; + + if (ent->dmg) + ent->blocked = rotating_blocked; + + if (ent->spawnflags & 1) + ent->use (ent, NULL, NULL); + + if (ent->spawnflags & 64) + ent->s.effects |= EF_ANIM_ALL; + if (ent->spawnflags & 128) + ent->s.effects |= EF_ANIM_ALLFAST; + + if (ent->spawnflags & 256) // Because of a mixup in flags + ent->spawnflags |= 4; + + VectorSubtract(ent->maxs, ent->mins, ent->s.bmodel_origin); + Vec3ScaleAssign(0.5, ent->s.bmodel_origin); + VectorAdd(ent->mins, ent->s.bmodel_origin, ent->s.bmodel_origin); + + gi.setmodel (ent, ent->model); + gi.linkentity (ent); +} + +/* +====================================================================== + +BUTTONS + +====================================================================== +*/ + + +void button_fire (edict_t *self); + +void button_killed2(edict_t *self, G_Message_t *msg) +{ + + self->activator = self->enemy; + button_fire (self); + self->health = self->max_health; + +} + + +void ButtonStaticsInit() +{ + classStatics[CID_BUTTON].msgReceivers[MSG_DEATH] = button_killed2; +} + +void button_done (edict_t *self) +{ + self->moveinfo.state = STATE_BOTTOM; + self->s.frame = 0; +} + +void button_return (edict_t *self) +{ + self->moveinfo.state = STATE_DOWN; + + Move_Calc (self, self->moveinfo.start_origin, button_done); + + self->s.frame = 0; + + if (self->health) + self->takedamage = DAMAGE_YES; +} + +void button_wait (edict_t *self) +{ + self->moveinfo.state = STATE_TOP; + G_UseTargets (self, self->activator); + self->s.frame = 1; + if (self->moveinfo.wait >= 0) + { + self->nextthink = level.time + self->moveinfo.wait; + self->think = button_return; + } +} + +void button_fire (edict_t *self) +{ + if (self->moveinfo.state == STATE_UP || self->moveinfo.state == STATE_TOP) + return; + + self->moveinfo.state = STATE_UP; + if (self->moveinfo.sound_start && !(self->flags & FL_TEAMSLAVE)) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_IDLE, 0); + Move_Calc (self, self->moveinfo.end_origin, button_wait); +} + +void button_use (edict_t *self, edict_t *other, edict_t *activator) +{ + self->activator = activator; + button_fire (self); +} + +void button_touch (edict_t *self, trace_t *trace) +{ + edict_t *other; + + other = trace->ent; + + if (!other->client) + return; + + if (other->health <= 0) + return; + + self->activator = other; + button_fire (self); +} + +int button_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ + self->activator = attacker; + self->health = self->max_health; + self->takedamage = DAMAGE_NO; + button_fire (self); + return(0); +} + +void button_sounds(edict_t *self) +{ + if (self->sounds == 1) + self->moveinfo.sound_start = gi.soundindex ("doors/basicbutton.wav"); + else if (self->sounds == 2) + self->moveinfo.sound_start = gi.soundindex ("doors/clankybutton.wav"); + else if (self->sounds == 3) + self->moveinfo.sound_start = gi.soundindex ("doors/steambutton.wav"); +} + +/*QUAKED func_button (0 .5 .8) ? TOUCH +When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again. + +"angle" determines the opening direction +"target" all entities with a matching targetname will be used +"speed" override the default 40 speed +"wait" override the default 1 second wait (-1 = never return) +"lip" override the default 4 pixel lip remaining at end of move +"health" if set, the button must be killed instead of touched +"sounds" +0) silent +1) Basic Button +2) Clanky Button +3) Steam Button + +--------SPAWNFLAGS-------- +TOUCH - player can touch button to set it off +*/ +void SP_func_button (edict_t *ent) +{ + vec3_t abs_movedir; + float dist; + + G_SetMovedir (ent->s.angles, ent->movedir); + ent->movetype = PHYSICSTYPE_STOP; + ent->solid = SOLID_BSP; + ent->takedamage = DAMAGE_NO; + gi.setmodel (ent, ent->model); + gi.linkentity(ent); + + button_sounds(ent); + +// ent->health = 5; + if (!ent->speed) + ent->speed = 40; + if (!ent->accel) + ent->accel = ent->speed; + if (!ent->decel) + ent->decel = ent->speed; + + if (!ent->wait) + ent->wait = 3; + if (!st.lip) + st.lip = 4; + + VectorCopy (ent->s.origin, ent->pos1); + VectorAbs(ent->movedir, abs_movedir); + dist = DotProduct(abs_movedir, ent->size) - st.lip; + VectorMA (ent->pos1, dist, ent->movedir, ent->pos2); + + ent->use = button_use; + + if (ent->health) + { + ent->max_health = ent->health; +// ent->die = button_killed; + ent->takedamage = DAMAGE_YES; + } + + if ((! ent->targetname) || (ent->spawnflags & 1)) + { + ent->isBlocking = button_touch; + } + + ent->moveinfo.state = STATE_BOTTOM; + + ent->moveinfo.speed = ent->speed; + ent->moveinfo.accel = ent->accel; + ent->moveinfo.decel = ent->decel; + ent->moveinfo.wait = ent->wait; + VectorCopy (ent->pos1, ent->moveinfo.start_origin); + VectorCopy (ent->s.angles, ent->moveinfo.start_angles); + VectorCopy (ent->pos2, ent->moveinfo.end_origin); + VectorCopy (ent->s.angles, ent->moveinfo.end_angles); + + ent->msgHandler = DefaultMsgHandler; +} + +/* +====================================================================== + +DOORS + + spawn a trigger surrounding the entire team unless it is + allready targeted by another + +====================================================================== +*/ + + +void door_use_areaportals (edict_t *self, qboolean open) +{ + edict_t *t = NULL; + + if (!self->target) + return; + + while ((t = G_Find (t, FOFS(targetname), self->target))) + { + if (Q_stricmp(t->classname, "func_areaportal") == 0) + { + gi.SetAreaPortalState (t->style, open); + } + } +} + +void door_go_down (edict_t *self); + +void door_hit_top (edict_t *self) +{ + if (!(self->flags & FL_TEAMSLAVE)) + { + if (self->moveinfo.sound_end) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_IDLE, 0); + self->s.sound = 0; + } + self->moveinfo.state = STATE_TOP; + if (self->spawnflags & DOOR_TOGGLE) + return; + if (self->moveinfo.wait >= 0) + { + self->think = door_go_down; + self->nextthink = level.time + self->moveinfo.wait; + } + else if (self->moveinfo.wait == -2) + { + self->think = door_go_down; + self->nextthink = level.time + FRAMETIME; // Next frame is soon enough to fire this off + } + +} +void door_go_up (edict_t *self, edict_t *activator); + +void door_hit_bottom (edict_t *self) +{ + if (!(self->flags & FL_TEAMSLAVE)) + { + if (self->moveinfo.sound_end) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_IDLE, 0); + self->s.sound = 0; + } + self->moveinfo.state = STATE_BOTTOM; + + if (self->moveinfo.wait == -2) // Endlessly cycle + { + door_go_up (self, NULL); + } + else + door_use_areaportals (self, false); + +} + +void door_go_down (edict_t *self) +{ + if (!(self->flags & FL_TEAMSLAVE)) + { + if (self->moveinfo.sound_start) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_IDLE, 0); + self->s.sound = self->moveinfo.sound_middle; + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_IDLE; + } + if (self->max_health) + { + self->takedamage = DAMAGE_YES; + self->health = self->max_health; + } + + self->moveinfo.state = STATE_DOWN; + if (strcmp(self->classname, "func_door") == 0) + Move_Calc (self, self->moveinfo.start_origin, door_hit_bottom); + else if (strcmp(self->classname, "func_door_rotating") == 0) + AngleMove_Calc (self, door_hit_bottom); +} + +void door_go_up (edict_t *self, edict_t *activator) +{ + if (self->moveinfo.state == STATE_UP) + return; // already going up + + if (self->moveinfo.state == STATE_TOP) + { // reset top wait time + if (self->moveinfo.wait >= 0) + self->nextthink = level.time + self->moveinfo.wait; + else if (self->moveinfo.wait == -2) + self->nextthink = level.time; + + return; + } + + if (!(self->flags & FL_TEAMSLAVE)) + { + if (self->moveinfo.sound_start) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_IDLE, 0); + self->s.sound = self->moveinfo.sound_middle; + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_IDLE; + } + self->moveinfo.state = STATE_UP; + if (strcmp(self->classname, "func_door") == 0) + Move_Calc (self, self->moveinfo.end_origin, door_hit_top); + else if (strcmp(self->classname, "func_door_rotating") == 0) + AngleMove_Calc (self, door_hit_top); + + G_UseTargets (self, activator); + door_use_areaportals (self, true); +} + +/* +qboolean smart_door_side_check (edict_t *self, edict_t *activator) + + By Dan Kramer, da Man. Stolen wholesale from SoF (No Kill I, Rick!) + + Checks to see if a rotating door will get in activator's way when it opens + */ + +qboolean smart_door_side_check (edict_t *self, edict_t *activator) +{ + vec3_t doorpoints[3], inplane[2], normal, toplayer; + + if (!activator) + { + return false; + } + +// make a plane containing the origins of the origin brush, the door, and a point +// which is the sum of movedir (slightly rearranged (x, z, y)) and one of the others + VectorCopy(self->s.origin, doorpoints[0]); // origin brush origin + VectorAdd(self->s.origin, self->mins, doorpoints[1]); + VectorMA(doorpoints[1], .5, self->size, doorpoints[1]); // door center + doorpoints[2][0] = self->s.origin[0] + self->movedir[2]; + doorpoints[2][1] = self->s.origin[1] + self->movedir[0]; + doorpoints[2][2] = self->s.origin[2] + self->movedir[1]; // third point + VectorSubtract(doorpoints[1],doorpoints[0],inplane[0]); + VectorSubtract(doorpoints[2],doorpoints[0],inplane[1]); + CrossProduct(inplane[0], inplane[1], normal); + VectorSubtract(activator->s.origin, doorpoints[1], toplayer); + if ( DotProduct(normal, toplayer) < 0 ) + { + return true; + } + return false; +} + +edict_t *TestEntityPosition(edict_t *self); +void door_use (edict_t *self, edict_t *other, edict_t *activator) +{ + edict_t *ent; + + if(Vec3IsZero(self->avelocity)) + { + if (strcmp(self->classname, "func_door_rotating") == 0) + { + if(self->spawnflags & DSF_SWINGAWAY) + { + if(smart_door_side_check(self, activator)) + { + VectorNegate(self->movedir, self->movedir); + VectorNegate(self->moveinfo.end_angles, self->moveinfo.end_angles); + } + } + } + } + + if (self->flags & FL_TEAMSLAVE) + return; + + if (self->spawnflags & DOOR_TOGGLE) + { + if (self->moveinfo.state == STATE_UP || self->moveinfo.state == STATE_TOP) + { + // trigger all paired doors + for (ent = self ; ent ; ent = ent->teamchain) + { + ent->message = NULL; + ent->isBlocking = NULL; + door_go_down (ent); + } + return; + } + } + + // trigger all paired doors + for (ent = self ; ent ; ent = ent->teamchain) + { + ent->message = NULL; + ent->isBlocking = NULL; + door_go_up (ent, activator); + } +}; + +void Touch_DoorTrigger (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (other->health <= 0) + return; + + if (!(other->svflags & SVF_MONSTER) && (!other->client)) + return; + + if ((self->owner->spawnflags & DOOR_NOMONSTER) && (other->svflags & SVF_MONSTER)) + return; + + if (level.time < self->touch_debounce_time) + return; + self->touch_debounce_time = level.time + 1.0; + + door_use (self->owner, other, other); +} + +void Think_CalcMoveSpeed (edict_t *self) +{ + edict_t *ent; + float min; + float time; + float newspeed; + float ratio; + float dist; + + if (self->flags & FL_TEAMSLAVE) + { + self->think = NULL; + return; // only the team master does this + } + + // find the smallest distance any member of the team will be moving + min = Q_fabs(self->moveinfo.distance); + for (ent = self->teamchain; ent; ent = ent->teamchain) + { + dist = Q_fabs(ent->moveinfo.distance); + if (dist < min) + min = dist; + } + + time = min / self->moveinfo.speed; + + // adjust speeds so they will all complete at the same time + for (ent = self; ent; ent = ent->teamchain) + { + newspeed = Q_fabs(ent->moveinfo.distance) / time; + ratio = newspeed / ent->moveinfo.speed; + if (ent->moveinfo.accel == ent->moveinfo.speed) + ent->moveinfo.accel = newspeed; + else + ent->moveinfo.accel *= ratio; + if (ent->moveinfo.decel == ent->moveinfo.speed) + ent->moveinfo.decel = newspeed; + else + ent->moveinfo.decel *= ratio; + ent->moveinfo.speed = newspeed; + } + + gi.linkentity(self); + self->think = NULL; +} + +void Think_SpawnDoorTrigger (edict_t *ent) +{ + edict_t *other; + vec3_t mins, maxs; + + ent->think = NULL; + + if (ent->flags & FL_TEAMSLAVE) + return; // only the team leader spawns a trigger + + VectorCopy (ent->absmin, mins); + VectorCopy (ent->absmax, maxs); + + for (other = ent->teamchain ; other ; other=other->teamchain) + { + AddPointToBounds (other->absmin, mins, maxs); + AddPointToBounds (other->absmax, mins, maxs); + } + + // expand + mins[0] -= 60; + mins[1] -= 60; + maxs[0] += 60; + maxs[1] += 60; + + other = G_Spawn (); + VectorCopy (mins, other->mins); + VectorCopy (maxs, other->maxs); + other->owner = ent; + other->solid = SOLID_TRIGGER; + other->movetype = PHYSICSTYPE_NONE; + other->touch = Touch_DoorTrigger; + + if (ent->spawnflags & DOOR_START_OPEN) + door_use_areaportals (ent, true); + + Think_CalcMoveSpeed (ent); + + gi.linkentity (other); +} + +void door_blocked (edict_t *self, edict_t *other) +{ + edict_t *ent; + + if ((other->svflags & SVF_MONSTER) && !other->client && !(other->svflags & SVF_BOSS)) + { + // give it a chance to go away on it's own terms (like gibs) + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 3000, 1, DAMAGE_AVOID_ARMOR,MOD_CRUSH); + // if it's still there, nuke it + if(other->health > 0) + BecomeDebris(other); + return; + } + + if (self->spawnflags & DOOR_CRUSHER) + { + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg * 10, 1, 0,MOD_CRUSH); + return; + } + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0,MOD_CRUSH); + +// if a door has a negative wait, it would never come back if blocked, (unless -2) +// so let it just squash the object to death real fast + if ((self->moveinfo.wait >= 0) || (self->moveinfo.wait == -2)) + { + if (self->moveinfo.state == STATE_DOWN) + { + for (ent = self->teammaster ; ent ; ent = ent->teamchain) + door_go_up (ent, ent->activator); + } + else + { + for (ent = self->teammaster ; ent ; ent = ent->teamchain) + door_go_down (ent); + } + } +} + +int door_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ + edict_t *ent; + + for (ent = self->teammaster ; ent ; ent = ent->teamchain) + { + ent->health = ent->max_health; + ent->takedamage = DAMAGE_NO; + } + door_use (self->teammaster, attacker, attacker); + return(0); + +} + +void door_touch (edict_t *self, trace_t *trace) +{ + edict_t *other; + + other = trace->ent; + + if (!other->client) + return; + + if (level.time < self->touch_debounce_time) + return; + + self->touch_debounce_time = level.time + 5.0; + gi.levelmsg_centerprintf (other, (short)atoi(self->message)); +} + +void door_sounds (edict_t *ent) +{ + switch((int)(ent->sounds)) + { + case DS_NONE: + ent->moveinfo.sound_start = 0; + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = 0; + break; + case DS_GENERIC: + ent->moveinfo.sound_start = gi.soundindex ("doors/gendoorstart.wav"); + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = gi.soundindex ("doors/gendoorstop.wav"); + break; + case DS_HEAVYSTONE: + ent->moveinfo.sound_start = gi.soundindex ("doors/stonestart.wav"); + ent->moveinfo.sound_middle = gi.soundindex ("doors/stoneloop.wav"); + ent->moveinfo.sound_end = gi.soundindex ("doors/stoneend.wav"); + break; + case DS_SWINGARM: + ent->moveinfo.sound_start = gi.soundindex ("doors/bigcreak.wav"); + break; + case DS_SWINGBRIDGE: + ent->moveinfo.sound_start = gi.soundindex ("doors/stoneloop.wav"); + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = gi.soundindex ("doors/stoneend.wav"); + break; + case DS_MEDIUMWOOD: + ent->moveinfo.sound_start = gi.soundindex ("doors/kchunk2.wav"); + ent->moveinfo.sound_middle = gi.soundindex ("doors/creak4.wav"); + ent->moveinfo.sound_end = gi.soundindex ("doors/doorclose1.wav"); + break; + case DS_HUGEWOOD: + ent->moveinfo.sound_start = gi.soundindex ("doors/kchunk1.wav"); + ent->moveinfo.sound_middle = gi.soundindex ("doors/creak2.wav"); + ent->moveinfo.sound_end = gi.soundindex ("doors/doorshut1.wav"); + break; + case DS_MEDIUMSTONE: + ent->moveinfo.sound_start = gi.soundindex ("doors/kchunk7.wav"); + ent->moveinfo.sound_middle = gi.soundindex ("doors/stndoor.wav"); + ent->moveinfo.sound_end = gi.soundindex ("doors/thud7.wav"); + break; + case DS_LARGESTONE: + ent->moveinfo.sound_start = gi.soundindex ("doors/kchunk6.wav"); + ent->moveinfo.sound_middle = gi.soundindex ("doors/stoneloop.wav"); + ent->moveinfo.sound_end = gi.soundindex ("doors/thud3.wav"); + break; + case DS_MEDIUMMETAL: + ent->moveinfo.sound_start = gi.soundindex ("doors/kchunk3.wav"); + ent->moveinfo.sound_middle = gi.soundindex ("doors/metal1.wav"); + ent->moveinfo.sound_end = gi.soundindex ("doors/thud2.wav"); + break; + case DS_FASTSLIDING: + ent->moveinfo.sound_start = gi.soundindex ("doors/fastdoor.wav"); + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = 0; + break; + case DS_METALSLIDING: + ent->moveinfo.sound_start = gi.soundindex ("doors/kchunk5.wav"); + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = gi.soundindex ("doors/thud2.wav"); + break; + case DS_HUGESTONE: + ent->moveinfo.sound_start = gi.soundindex ("doors/kchunk5.wav"); + ent->moveinfo.sound_middle = gi.soundindex ("objects/creak2a.wav"); + ent->moveinfo.sound_end = gi.soundindex ("doors/thud4.wav"); + break; + case DS_HUGEELEVATOR: + ent->moveinfo.sound_start = gi.soundindex ("doors/elevatorstart.wav"); + ent->moveinfo.sound_middle = gi.soundindex ("doors/elevatormove.wav"); + ent->moveinfo.sound_end = gi.soundindex ("doors/elevatorstop.wav"); + break; + case DS_CRANEWAREHOUSE: + ent->moveinfo.sound_start = gi.soundindex ("doors/kchunk6.wav"); + ent->moveinfo.sound_middle = gi.soundindex ("objects/winch2.wav"); + ent->moveinfo.sound_end = gi.soundindex ("objects/cratedown.wav"); + break; + case DS_HAMMERPUMP: + ent->moveinfo.sound_start = gi.soundindex ("objects/oilpump.wav"); + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = 0; + break; + case DS_METALTABLE: + ent->moveinfo.sound_start = gi.soundindex ("objects/slabslide.wav"); + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = 0; + break; + case DS_LABTABLE: + ent->moveinfo.sound_start = gi.soundindex ("objects/globebottomstart.wav"); + ent->moveinfo.sound_end = gi.soundindex ("objects/globebottomend.wav"); + break; + case DS_PISTON: + ent->moveinfo.sound_start = gi.soundindex ("objects/piston.wav"); + break; + case DS_CLANG: + ent->moveinfo.sound_start = gi.soundindex ("objects/klang.wav"); + break; + case DS_UNDERWATER: + ent->moveinfo.sound_start = gi.soundindex ("objects/submerge.wav"); + break; + case DS_BAM: + ent->moveinfo.sound_start = gi.soundindex ("objects/bam1.wav"); + break; + default: + ent->moveinfo.sound_start = 0; + ent->moveinfo.sound_middle = 0; + ent->moveinfo.sound_end = 0; + break; + } +} + +/*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER NOMONSTER ANIMATED TOGGLE ANIMATED_FAST +TOGGLE wait in both the start and end states for a trigger event. +START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors). +NOMONSTER monsters will not trigger this door + +"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet +"angle" determines the opening direction +"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door. +"health" if set, door must be shot open +"height" if set, tells how far up door opens +"speed" movement speed (100 default) +"wait" wait before returning (3 default, -1 = never return,-2 = never stop cycle) +"lip" lip remaining at end of move (8 default) +"dmg" damage to inflict when blocked (2 default) +"sounds" +0) silent +1) generic door +2) heavy stone door +3) for swing arm on palace level +4) for stone bridge in palace level +5) small/medium wood door swinging +6) large/huge wood door swinging +7) medium sized stone/wood door sliding +8) large stone/wood sliding door or portcullis +9) average metal door swinging +10) Fast sliding doors +11) Hive, Metal, Multipaneled sliding +12) Huge stone door swinging +13) Medium/large elevator +14) Crane (warehouse) +15) hammerlike pump in oglemine1 +16) sliding metal table in cloudlabs +17) lab table which rotates up to ceiling - cloublabs +18) piston sound +19) short, sharp metal clang +20) something going under water +21) the bam sound + */ +void SP_func_door (edict_t *self) +{ + vec3_t abs_movedir; + + door_sounds(self); + + G_SetMovedir (self->s.angles, self->movedir); + self->movetype = PHYSICSTYPE_PUSH; + self->solid = SOLID_BSP; + self->blocked = door_blocked; + self->use = door_use; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_FUNC_DOOR; + + gi.setmodel (self, self->model); + gi.linkentity (self); + + if (!self->speed) + self->speed = 100; + if (!self->accel) + self->accel = self->speed; + if (!self->decel) + self->decel = self->speed; + + if (!self->wait) + self->wait = 3; + if (!st.lip) + st.lip = 8; + if (!self->dmg) + self->dmg = 2; + + // calculate second position + VectorCopy (self->s.origin, self->pos1); + VectorAbs(self->movedir, abs_movedir); + + if (!st.height) + self->moveinfo.distance = DotProduct(abs_movedir, self->size) - st.lip; + else + self->moveinfo.distance = abs_movedir[0] * self->size[0] + abs_movedir[1] * self->size[1] + abs_movedir[2] * st.height; + + VectorMA (self->pos1, self->moveinfo.distance, self->movedir, self->pos2); + + // if it starts open, switch the positions + if (self->spawnflags & DOOR_START_OPEN) + { + VectorCopy (self->pos2, self->s.origin); + VectorCopy (self->pos1, self->pos2); + VectorCopy (self->s.origin, self->pos1); + } + + self->moveinfo.state = STATE_BOTTOM; + + if (self->health) + { + self->takedamage = DAMAGE_YES; + self->die = door_killed; + self->max_health = self->health; + } + else if (self->targetname && self->message) + { + gi.soundindex ("misc/talk.wav"); + self->isBlocking = door_touch; + } + + self->moveinfo.speed = self->speed; + self->moveinfo.accel = self->accel; + self->moveinfo.decel = self->decel; + self->moveinfo.wait = self->wait; + VectorCopy (self->pos1, self->moveinfo.start_origin); + VectorCopy (self->s.angles, self->moveinfo.start_angles); + VectorCopy (self->pos2, self->moveinfo.end_origin); + VectorCopy (self->s.angles, self->moveinfo.end_angles); + + VectorSubtract(self->maxs, self->mins, self->s.bmodel_origin); + Vec3ScaleAssign(0.5, self->s.bmodel_origin); + VectorAdd(self->mins, self->s.bmodel_origin, self->s.bmodel_origin); + + if (self->spawnflags & 16) + self->s.effects |= EF_ANIM_ALL; + if (self->spawnflags & 64) + self->s.effects |= EF_ANIM_ALLFAST; + + // to simplify logic elsewhere, make non-teamed doors into a team of one + if (!self->team) + self->teammaster = self; + + self->nextthink = level.time + FRAMETIME; + if (self->health || self->targetname) + self->think = Think_CalcMoveSpeed; + else + self->think = Think_SpawnDoorTrigger; +} + +/*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN REVERSE CRUSHER NOMONSTER ANIMATED TOGGLE X_AXIS Y_AXIS SWINGAWAY x x x x x x x +TOGGLE causes the door to wait in both the start and end states for a trigger event. + +START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors). +NOMONSTER monsters will not trigger this door + +You need to have an origin brush as part of this entity. The center of that brush will be +the point around which it is rotated. It will rotate around the Z axis by default. You can +check either the X_AXIS or Y_AXIS box to change that. + +"distance" is how many degrees the door will be rotated. +"speed" determines how fast the door moves; default value is 100. + +REVERSE will cause the door to rotate in the opposite direction. + +SWINGAWAY door will always swing away from the activator... + +"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet +"angle" determines the opening direction +"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door. +"health" if set, door must be shot open +"speed" movement speed (100 default) +"wait" wait before returning (3 default, -1 = never return,-2 = never stop cycle) +"dmg" damage to inflict when blocked (2 default) +"sounds" +0) silent +1) generic door +2) heavy stone door +3) for swing arm on palace level +4) for stone bridge in palace level +5) small/medium wood door swinging +6) large/huge wood door swinging +7) medium sized stone/wood door sliding +8) large stone/wood sliding door or portcullis +9) average metal door swinging +10) Fast sliding doors +11) Hive, Metal, Multipaneled sliding +12) Huge stone door swinging +13) Medium/large elevator +14) Crane (warehouse) +15) hammerlike pump in oglemine1 +16) sliding metal table in cloudlabs +17) lab table which rotates up to ceiling - cloublabs +18) piston sound +19) short, sharp metal clang +20) something going under water +21) the bam sound +*/ + +void SP_func_door_rotating (edict_t *ent) +{ + VectorClear (ent->s.angles); + + // set the axis of rotation + VectorClear(ent->movedir); + if (ent->spawnflags & DOOR_X_AXIS) + ent->movedir[2] = 1.0; + else if (ent->spawnflags & DOOR_Y_AXIS) + ent->movedir[0] = 1.0; + else // Z_AXIS + ent->movedir[1] = 1.0; + + // check for reverse rotation + if (ent->spawnflags & DOOR_REVERSE) + VectorNegate (ent->movedir, ent->movedir); + + if (!st.distance) + { + gi.dprintf("%s at %s with no distance set\n", ent->classname, vtos(ent->s.origin)); + st.distance = 90; + } + + gi.setmodel (ent, ent->model); + gi.linkentity (ent); + + VectorCopy (ent->s.angles, ent->pos1); + VectorMA (ent->s.angles, st.distance, ent->movedir, ent->pos2); + ent->moveinfo.distance = st.distance; + + ent->movetype = PHYSICSTYPE_PUSH; + ent->solid = SOLID_BSP; + ent->blocked = door_blocked; + ent->use = door_use; + + if (!ent->speed) + ent->speed = 100; + if (!ent->accel) + ent->accel = ent->speed; + if (!ent->decel) + ent->decel = ent->speed; + + if (!ent->wait) + ent->wait = 3; + if (!ent->dmg) + ent->dmg = 2; + + door_sounds(ent); + + // if it starts open, switch the positions + if (ent->spawnflags & DOOR_START_OPEN) + { + VectorCopy (ent->pos2, ent->s.angles); + VectorCopy (ent->pos1, ent->pos2); + VectorCopy (ent->s.angles, ent->pos1); + VectorNegate (ent->movedir, ent->movedir); + } + + if (ent->health) + { + ent->takedamage = DAMAGE_YES; + ent->die = door_killed; + ent->max_health = ent->health; + } + + if (ent->targetname && ent->message) + { + gi.soundindex ("misc/talk.wav"); + ent->isBlocking = door_touch; + } + + ent->moveinfo.state = STATE_BOTTOM; + ent->moveinfo.speed = ent->speed; + ent->moveinfo.accel = ent->accel; + ent->moveinfo.decel = ent->decel; + ent->moveinfo.wait = ent->wait; + VectorCopy (ent->s.origin, ent->moveinfo.start_origin); + VectorCopy (ent->pos1, ent->moveinfo.start_angles); + VectorCopy (ent->s.origin, ent->moveinfo.end_origin); + VectorCopy (ent->pos2, ent->moveinfo.end_angles); + + VectorSubtract(ent->maxs, ent->mins, ent->s.bmodel_origin); + Vec3ScaleAssign(0.5, ent->s.bmodel_origin); + VectorAdd(ent->mins, ent->s.bmodel_origin, ent->s.bmodel_origin); + + if (ent->spawnflags & 16) + ent->s.effects |= EF_ANIM_ALL; + + ent->nextthink = level.time + FRAMETIME; + if (ent->health || ent->targetname) + ent->think = Think_CalcMoveSpeed; + else + ent->think = Think_SpawnDoorTrigger; +} + + +/*QUAKED func_water (0 .5 .8) ? START_OPEN +func_water is a moveable water brush. It must be targeted to operate. Use a non-water texture at your own risk. + +START_OPEN causes the water to move to its destination when spawned and operate in reverse. + +"angle" determines the opening direction (up or down only) +"speed" movement speed (25 default) +"wait" wait before returning (-1 default, -1 = TOGGLE) +"lip" lip remaining at end of move (0 default) +"sounds" (yes, these need to be changed) +0) no sound +1) water +2) lava +*/ + +void SP_func_water (edict_t *self) +{ + vec3_t abs_movedir; + + G_SetMovedir (self->s.angles, self->movedir); + self->movetype = PHYSICSTYPE_PUSH; + self->solid = SOLID_BSP; + gi.setmodel (self, self->model); + gi.linkentity (self); + + // calculate second position + VectorCopy (self->s.origin, self->pos1); + VectorAbs(self->movedir, abs_movedir); + self->moveinfo.distance = DotProduct(abs_movedir, self->size) - st.lip; + VectorMA (self->pos1, self->moveinfo.distance, self->movedir, self->pos2); + + // if it starts open, switch the positions + if (self->spawnflags & DOOR_START_OPEN) + { + VectorCopy (self->pos2, self->s.origin); + VectorCopy (self->pos1, self->pos2); + VectorCopy (self->s.origin, self->pos1); + } + + VectorCopy (self->pos1, self->moveinfo.start_origin); + VectorCopy (self->s.angles, self->moveinfo.start_angles); + VectorCopy (self->pos2, self->moveinfo.end_origin); + VectorCopy (self->s.angles, self->moveinfo.end_angles); + + VectorSubtract(self->maxs, self->mins, self->s.bmodel_origin); + Vec3ScaleAssign(0.5, self->s.bmodel_origin); + VectorAdd(self->mins, self->s.bmodel_origin, self->s.bmodel_origin); + + self->moveinfo.state = STATE_BOTTOM; + + if (!self->speed) + self->speed = 25; + self->moveinfo.accel = self->moveinfo.decel = self->moveinfo.speed = self->speed; + + if (!self->wait) + self->wait = -1; + self->moveinfo.wait = self->wait; + + self->use = door_use; + + if (self->wait == -1) + self->spawnflags |= DOOR_TOGGLE; + + self->classname = "func_door"; + +} + +void train_next (edict_t *self); + +void train_anim(edict_t *self) +{ + + if ((self->s.frame == 0) && (self->moveinfo.sound_middle)) // Start sound if there is one + gi.sound(self, CHAN_VOICE, self->moveinfo.sound_middle, 1, ATTN_NORM, 0); + + if ((self->s.frame + 1) < self->count) + { + ++self->s.frame; + self->nextthink = level.time + FRAMETIME; + self->think = train_anim; + } + else + train_next (self); +} + +void train_animbackwards(edict_t *self) +{ + + if (((self->s.frame + 1) == self->count) && (self->moveinfo.sound_middle)) // Start sound if there is one + gi.sound(self, CHAN_VOICE, self->moveinfo.sound_middle, 1, ATTN_NORM, 0); + + if (self->s.frame > 0) + { + --self->s.frame; + self->nextthink = level.time + FRAMETIME; + self->think = train_animbackwards; + } + else + train_next (self); +} +#define TRAIN_START_ON 1 +#define TRAIN_TOGGLE 2 +#define TRAIN_BLOCK_STOPS 4 + +/*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS HASORIGIN NO_CLIP PUSHPULL +Trains are moving platforms that players can ride. +The targets origin specifies the min point of the train at each corner. +The train spawns at the first target it is pointing at. +If the train is the target of a button or trigger, it will not begin moving until activated. This means if it has a targetname it won't move unless triggered. + +-------KEYS------ +NO_CLIP - train will not block anything. + +----------SPAWNFLAGS----------- +HASORIGIN - makes train move from an origin brush rather than the lower left point of the train. +-----KEYS------- + +speed - default 100 +dmg - default 2 +noise - looping file to play when the train is in motion +- objects/piston.wav for large steam pistons in ogle2 and cloudlabs +- objects/winch2.wav for wooden ore hauler going across river + +rotate - speed train should rotate at +wait - -1 : stop and don't move again until triggered + -3 : stop and explode + -4 : go through animations (only if a model) +file - specifies the train is a model. This is the exact directory of the model. +count - number of frames in animation (only if a model) +example models/objects/broom/tris.fm +materialtype - + 0 = MAT_WOOD + 1 = MAT_GREYSTONE (default) + 2 = MAT_CLOTH + 3 = MAT_METAL + + 9 = MAT_BROWNSTONE + 10 = MAT_NONE - just makes smoke + +*/ +void train_blocked (edict_t *self, edict_t *other) +{ + if ((other->svflags & SVF_MONSTER) && (!other->client) && !(other->svflags & SVF_BOSS)) + { + // give it a chance to go away on it's own terms (like gibs) + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 3000, 1, DAMAGE_AVOID_ARMOR,MOD_CRUSH); + // if it's still there, nuke it + if(other->health > 0) + BecomeDebris(other); + return; + } + + if (level.time < self->touch_debounce_time) + return; + + if (!self->dmg) + return; + self->touch_debounce_time = level.time + 0.5; + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0,MOD_CRUSH); +} + +void train_wait (edict_t *self) +{ + + if (self->target_ent->moveinfo.sound_middle) + gi.sound(self->target_ent, CHAN_VOICE, self->target_ent->moveinfo.sound_middle, 1, ATTN_NORM, 0); + + if (self->target_ent->pathtarget) + { + char *savetarget; + edict_t *ent; + + ent = self->target_ent; + savetarget = ent->target; + ent->target = ent->pathtarget; + + G_UseTargets (ent, self->activator); + ent->target = savetarget; + + // make sure we didn't get killed by a killtarget + if (!self->inuse) + return; + } + + if (self->moveinfo.wait) + { + if (self->moveinfo.wait > 0) + { + self->nextthink = level.time + self->moveinfo.wait; + self->think = train_next; + } + else if (self->moveinfo.wait == -3) + { + BecomeDebris(self); + return; + } + else if (self->moveinfo.wait == -4) // Make model animate + { + if ((self->s.frame + 1) < self->count) + { + train_anim(self); + } + else + { + train_animbackwards(self); + } + } + else if (self->spawnflags & TRAIN_TOGGLE) // && wait < 0 + { + train_next (self); + self->spawnflags &= ~TRAIN_START_ON; + VectorClear (self->velocity); + self->nextthink = 0; + } + + if (!(self->flags & FL_TEAMSLAVE)) + { + if (self->moveinfo.sound_end) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_IDLE, 0); + self->s.sound = 0; + } + } + else + { + train_next (self); + } + +} + +void train_next (edict_t *self) +{ + edict_t *ent; + vec3_t dest; + qboolean first; + + first = true; +again: + if (!self->target) + { + return; + } + + ent = G_PickTarget (self->target); + if (!ent) + { + gi.dprintf ("train_next: bad target %s\n", self->target); + return; + } + + self->target = ent->target; + + // check for a teleport path_corner + if (ent->spawnflags & 1) + { + if (!first) + { + gi.dprintf ("connected teleport path_corners, see %s at %s\n", ent->classname, vtos(ent->s.origin)); + return; + } + first = false; + VectorSubtract (ent->s.origin, self->mins, self->s.origin); + VectorCopy (self->s.origin, self->s.old_origin); + gi.linkentity (self); + goto again; + } + + self->moveinfo.wait = ent->wait; + self->target_ent = ent; + + if (!(self->flags & FL_TEAMSLAVE)) + { + if (self->moveinfo.sound_start) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_IDLE, 0); + self->s.sound = self->moveinfo.sound_middle; + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_IDLE; + } + + + if (self->spawnflags & 8) // Has an origin + VectorCopy (ent->s.origin, dest); + else // No origin + VectorSubtract (ent->s.origin, self->mins, dest); + self->moveinfo.state = STATE_TOP; + + VectorCopy (self->s.origin, self->moveinfo.start_origin); + VectorCopy (dest, self->moveinfo.end_origin); + + if (ent->speed) + { + self->moveinfo.speed = self->speed = ent->speed; + self->moveinfo.accel = self->moveinfo.decel = self->moveinfo.speed; + } + + Move_Calc (self, dest, train_wait); + + self->spawnflags |= TRAIN_START_ON; + + // Snap the train to the last ending angle + VectorCopy(self->moveinfo.end_angles, self->s.angles); + // Recalc new angles + TrainAngleMove_Calc(self, ent, dest); +} + +void train_resume (edict_t *self) +{ + edict_t *ent; + vec3_t dest; + + ent = self->target_ent; + + VectorSubtract (ent->s.origin, self->mins, dest); + self->moveinfo.state = STATE_TOP; + VectorCopy (self->s.origin, self->moveinfo.start_origin); + VectorCopy (dest, self->moveinfo.end_origin); + Move_Calc (self, dest, train_wait); + self->spawnflags |= TRAIN_START_ON; +} + +void func_train_find (edict_t *self) +{ + edict_t *ent; + + if (!self->target) + { + gi.dprintf ("train_find: no target\n"); + self->think = NULL; + return; + } + ent = G_PickTarget (self->target); + if (!ent) + { + gi.dprintf ("train_find: target %s not found\n", self->target); + self->think = NULL; + return; + } + self->target = ent->target; + if (Vec3NotZero(self->s.origin)) + VectorCopy (ent->s.origin, self->s.origin); + else + VectorSubtract (ent->s.origin, self->mins, self->s.origin); + gi.linkentity (self); + + // if not triggered, start immediately + if (!self->targetname) + self->spawnflags |= TRAIN_START_ON; + + if (self->spawnflags & TRAIN_START_ON) + { + self->nextthink = level.time + FRAMETIME; + self->think = train_next; + self->activator = self; + } + else + { + self->think = NULL; + } +} + +void train_use (edict_t *self, edict_t *other, edict_t *activator) +{ + self->activator = activator; + + if (Vec3NotZero(self->velocity)) + return; + + if (self->spawnflags & TRAIN_START_ON) + { + if (!(self->spawnflags & TRAIN_TOGGLE)) + return; + self->spawnflags &= ~TRAIN_START_ON; + VectorClear (self->velocity); + self->nextthink = 0; + } + else + { + if (self->target_ent) + train_resume(self); + else + train_next(self); + } +} + +void SP_func_train (edict_t *self) +{ + vec3_t space; + float spacecube; + + self->movetype = PHYSICSTYPE_PUSH; + + self->blocked = train_blocked; + if (self->spawnflags & TRAIN_BLOCK_STOPS) + self->dmg = 0; + else + { + if (!self->dmg) + { + self->dmg = 100; + } + } + + if (st.file) + { + if (self->spawnflags & 16) // Non-blocking? + self->solid = SOLID_NOT; + else + self->solid = SOLID_BBOX; + self->s.modelindex = gi.modelindex(st.file); + VectorCopy(self->s.angles,self->moveinfo.end_angles); + } + else + { + VectorClear (self->s.angles); + if (self->spawnflags & 16) // Non-blocking? + self->solid = SOLID_NOT; + else + self->solid = SOLID_BSP; + gi.setmodel (self, self->model); + } + + if (st.noise) + self->moveinfo.sound_middle = gi.soundindex (st.noise); + + if (!self->speed) + self->speed = 100; + + if (!self->materialtype) + self->materialtype = MAT_GREYSTONE; + + self->moveinfo.speed = self->speed; + self->moveinfo.accel = self->moveinfo.decel = self->moveinfo.speed; + + self->use = train_use; + + VectorClear(self->movedir); + + if (st.rotate) + VectorScale (self->movedir, st.rotate, self->avelocity); + else + VectorClear(self->avelocity); + + VectorSubtract(self->maxs, self->mins, space); + spacecube = space[0] * space[1] * space[2]; + self->mass = spacecube / 64; // + + VectorSubtract(self->maxs, self->mins, self->s.bmodel_origin); + Vec3ScaleAssign(0.5, self->s.bmodel_origin); + VectorAdd(self->mins, self->s.bmodel_origin, self->s.bmodel_origin); + + gi.linkentity (self); + + if (self->target) + { + // start trains on the second frame, to make sure their targets have had + // a chance to spawn + self->nextthink = level.time + FRAMETIME; + self->think = func_train_find; + } + else + { + gi.dprintf ("func_train without a target at %s\n", vtos(self->absmin)); + } +} + +/*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON +"wait" base time between triggering all targets, default is 1 +"random" wait variance, default is 0 + +so, the basic time between firing is a random time between +(wait - random) and (wait + random) + +"delay" delay before first firing when turned on, default is 0 + +"pausetime" additional delay used only the very first time + and only if spawned with START_ON + +These can used but not touched. +*/ +void func_timer_think (edict_t *self) +{ + G_UseTargets (self, self->activator); + self->nextthink = level.time + self->wait + flrand(-self->random, self->random); +} + +void func_timer_use (edict_t *self, edict_t *other, edict_t *activator) +{ + self->activator = activator; + + // if on, turn it off + if (self->nextthink) + { + self->nextthink = 0; + return; + } + + // turn it on + if (self->delay) + self->nextthink = level.time + self->delay; + else + func_timer_think (self); +} + +void SP_func_timer (edict_t *self) +{ + if (!self->wait) + self->wait = 1.0; + + self->use = func_timer_use; + self->think = func_timer_think; + + if (self->random >= self->wait) + { + self->random = self->wait - FRAMETIME; + gi.dprintf("func_timer at %s has random >= wait\n", vtos(self->s.origin)); + } + + if (self->spawnflags & 1) + { + self->nextthink = level.time + 1.0 + st.pausetime + self->delay + self->wait + flrand(-self->random, self->random); + self->activator = self; + } + + self->svflags = SVF_NOCLIENT; +} + + +/*QUAK-ED func_conveyor (0 .5 .8) ? START_ON TOGGLE +Conveyors are stationary brushes that move what's on them. +The brush should be have a surface with at least one current content enabled. +speed default 100 +*/ +/* +void func_conveyor_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->spawnflags & 1) + { + self->speed = 0; + self->spawnflags &= ~1; + } + else + { + self->speed = self->count; + self->spawnflags |= 1; + } + + if (!(self->spawnflags & 2)) + self->count = 0; +} +*/ +/* +void SP_func_conveyor (edict_t *self) +{ + if (!self->speed) + self->speed = 100; + + if (!(self->spawnflags & 1)) + { + self->count = self->speed; + self->speed = 0; + } + + self->use = func_conveyor_use; + + gi.setmodel (self, self->model); + self->solid = SOLID_BSP; + gi.linkentity (self); +} +*/ + +/*QUAKED func_door_secret (0 .5 .8) ? always_shoot 1st_left 1st_down +A secret door. Slide back and then to the side. + +open_once doors never closes +1st_left 1st move is left of arrow +1st_down 1st move is down from arrow +always_shoot door is shootebale even if targeted + +"angle" determines the direction +"dmg" damage to inflic when blocked (default 2) +"wait" how long to hold in the open position (default 5, -1 means hold) +"sounds" +0) silent +1) generic door +2) heavy stone door +3) for swing arm on palace level +4) for stone bridge in palace level +5) small/medium wood door swinging +6) large/huge wood door swinging +7) medium sized stone/wood door sliding +8) large stone/wood sliding door or portcullis +9) average metal door swinging +10) Fast sliding doors +11) Hive, Metal, Multipaneled sliding +12) Huge stone door swinging +13) Medium/large elevator +14) Crane (warehouse) +15) hammerlike pump in oglemine1 +16) sliding metal table in cloudlabs +17) lab table which rotates up to ceiling - cloublabs +18) piston sound +19) short, sharp metal clang +20) something going under water +21) the bam sound +*/ + +#define SECRET_ALWAYS_SHOOT 1 +#define SECRET_1ST_LEFT 2 +#define SECRET_1ST_DOWN 4 + +void door_secret_move1 (edict_t *self); +void door_secret_move2 (edict_t *self); +void door_secret_move3 (edict_t *self); +void door_secret_move4 (edict_t *self); +void door_secret_move5 (edict_t *self); +void door_secret_move6 (edict_t *self); +void door_secret_done (edict_t *self); + +void door_secret_use (edict_t *self, edict_t *other, edict_t *activator) +{ + // make sure we're not already moving + if (!VectorCompare(self->s.origin, vec3_origin)) + return; + + if (self->moveinfo.sound_start) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_IDLE, 0); + + Move_Calc (self, self->pos1, door_secret_move1); + door_use_areaportals (self, true); +} + +void door_secret_move1 (edict_t *self) +{ + self->nextthink = level.time + 1.0; + self->think = door_secret_move2; +} + +void door_secret_move2 (edict_t *self) +{ + if (self->moveinfo.sound_middle) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_middle, 1, ATTN_IDLE, 0); + + Move_Calc (self, self->pos2, door_secret_move3); +} + +void door_secret_move3 (edict_t *self) +{ + if (self->moveinfo.sound_end) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_IDLE, 0); + + if (self->wait == -1) + return; + self->nextthink = level.time + self->wait; + self->think = door_secret_move4; +} + +void door_secret_move4 (edict_t *self) +{ + if (self->moveinfo.sound_middle) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_middle, 1, ATTN_IDLE, 0); + + Move_Calc (self, self->pos1, door_secret_move5); +} + +void door_secret_move5 (edict_t *self) +{ + if (self->moveinfo.sound_end) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_IDLE, 0); + + self->nextthink = level.time + 1.0; + self->think = door_secret_move6; +} + +void door_secret_move6 (edict_t *self) +{ + if (self->moveinfo.sound_start) + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_IDLE, 0); + + Move_Calc (self, vec3_origin, door_secret_done); +} + +void door_secret_done (edict_t *self) +{ + if (!(self->targetname) || (self->spawnflags & SECRET_ALWAYS_SHOOT)) + { + self->health = 0; + self->takedamage = DAMAGE_YES; + } + door_use_areaportals (self, false); +} + +void door_secret_blocked (edict_t *self, edict_t *other) +{ + if ((other->svflags & SVF_MONSTER) && (!other->client) && !(other->svflags & SVF_BOSS)) + { + // give it a chance to go away on it's own terms (like gibs) + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 3000, 1, DAMAGE_AVOID_ARMOR,MOD_CRUSH); + // if it's still there, nuke it + if(other->health > 0) + BecomeDebris(other); + return; + } + + if (level.time < self->touch_debounce_time) + return; + self->touch_debounce_time = level.time + 0.5; + + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0,MOD_CRUSH); +} + +int door_secret_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ + self->takedamage = DAMAGE_NO; + door_secret_use (self, attacker, attacker); + return(0); + +} + +void SP_func_door_secret (edict_t *ent) +{ + vec3_t forward, right, up; + float side; + float width; + float length; + + door_sounds(ent); + +// ent->moveinfo.sound_start = gi.soundindex ("doors/stonestart.wav"); +// ent->moveinfo.sound_middle = gi.soundindex ("doors/stoneloop.wav"); +// ent->moveinfo.sound_end = gi.soundindex ("doors/stoneend.wav"); + + ent->movetype = PHYSICSTYPE_PUSH; + ent->solid = SOLID_BSP; + gi.setmodel (ent, ent->model); + gi.linkentity (ent); + + ent->blocked = door_secret_blocked; + ent->use = door_secret_use; + + if (!(ent->targetname) || (ent->spawnflags & SECRET_ALWAYS_SHOOT)) + { + ent->health = 0; + ent->takedamage = DAMAGE_YES; + ent->die = door_secret_die; + } + + if (!ent->dmg) + ent->dmg = 2; + + if (!ent->wait) + ent->wait = 5; + + ent->moveinfo.accel = + ent->moveinfo.decel = + ent->moveinfo.speed = 50; + + // calculate positions + AngleVectors (ent->s.angles, forward, right, up); + VectorClear (ent->s.angles); + side = 1.0 - (ent->spawnflags & SECRET_1ST_LEFT); + if (ent->spawnflags & SECRET_1ST_DOWN) + width = Q_fabs(DotProduct(up, ent->size)); + else + width = Q_fabs(DotProduct(right, ent->size)); + length = Q_fabs(DotProduct(forward, ent->size)); + if (ent->spawnflags & SECRET_1ST_DOWN) + VectorMA (ent->s.origin, -1 * width, up, ent->pos1); + else + VectorMA (ent->s.origin, side * width, right, ent->pos1); + + if (st.lip) + length = length - st.lip; + + VectorMA (ent->pos1, length, forward, ent->pos2); + if (ent->health) + { + ent->takedamage = DAMAGE_YES; + ent->die = door_killed; + ent->max_health = ent->health; + } + else if (ent->targetname && ent->message) + { + gi.soundindex ("misc/talk.wav"); + ent->isBlocking = door_touch; + } + + ent->classname = "func_door"; + +} + +void monsterspawner_go (edict_t *self) +{ + edict_t *monster; + vec3_t angle,holdorigin; + vec3_t forward; + trace_t trace; + edict_t *victim = NULL; + buoy_t *start_buoy, *end_buoy; + int end_buoy_index; + int num_attempts = 0; + byte o_mintel; + vec3_t buoydist; + + if (self->count<=0) + { + self->think = NULL; + return; + } + + VectorCopy(self->s.origin,holdorigin); + holdorigin[2] -= 8; + + gi.trace(self->s.origin,self->mins, self->maxs, holdorigin, self, MASK_MONSTERSOLID,&trace); + if (trace.fraction != 1) + return; + + monster = G_Spawn(); + monster->classname = ED_NewString(MonsterSpawnerClassname[self->style].name); + +//copy my designer-modified fields to the monster to overrride defaults + monster->classID = CIDForSpawnerStyle[self->style]; + if(self->mintel) + monster->mintel = self->mintel; + else + monster->mintel = MaxBuoysForClass[monster->classID]; + monster->melee_range = self->melee_range; + monster->missile_range = self->missile_range; + monster->min_missile_range = self->min_missile_range; + monster->bypass_missile_chance = self->bypass_missile_chance; + monster->jump_chance = self->jump_chance; + monster->wakeup_distance = self->wakeup_distance; + + monster->s.scale = self->s.scale; + + VectorScale(STDMinsForClass[monster->classID], monster->s.scale, monster->mins); + VectorScale(STDMaxsForClass[monster->classID], monster->s.scale, monster->maxs); + + if (self->maxrange) + { + VectorClear(angle); + angle[0] = flrand(0,360); + AngleVectors(angle, forward, NULL, NULL); + VectorMA(self->s.origin, self->maxrange, forward, monster->s.origin); + } + else if(self->spawnflags & 2)//randombuoy + { + //STEP 0: who are we after? + if(self->enemy) + { + if(self->enemy->client) + { + victim = self->enemy; + } + } + + if(!victim) + victim = level.sight_client; + + if(!victim)//no players + { + G_FreeEdict(monster); + return; + } + +pickbuoy: + num_attempts++;//avoid infinite loops + if(num_attempts>100) + { + G_FreeEdict(monster); + return;//can't find any buoys close enough + } + + //step1: pick a random buoy + start_buoy = &level.buoy_list[irand(0, level.active_buoys - 1)]; + + //step2: make sure the buoy is within a certain range of the player (500) + + VectorSubtract(start_buoy->origin, victim->s.origin, buoydist); + + if(VectorLengthSquared(buoydist) > 250000)//more than 500 away + goto pickbuoy; + + //step3: make sure the buoy is not visible to the player (unless assassin) + if(monster->classID != CID_ASSASSIN) + { + if(visible_pos(victim, start_buoy->origin)) + goto pickbuoy; + } + //step4: if the player_buoy is defined, pick it, if not, find player's buoy + if(level.player_buoy[victim->s.number] > NULL_BUOY)//could use player_last_buoy, but may not be reliable, and don't want to spend the time checking + end_buoy = &level.buoy_list[level.player_buoy[victim->s.number]]; + else + { + end_buoy_index = MG_SetFirstBuoy(victim); + if(end_buoy_index == NULL_BUOY) + { + G_FreeEdict(monster); + return;//can't find a buoy for player + } + + end_buoy = &level.buoy_list[end_buoy_index]; + } + + //step5: make sure the buoy is within 1/2 the mintel (no more than 10) buoys of the player's buoy + monster->lastbuoy = NULL_BUOY; + + if(monster->mintel > 7) + o_mintel = 7; + else if(monster->mintel < 3) + o_mintel = 3; + else + o_mintel = monster->mintel; + + monster->mintel = ceil(monster->mintel * 0.5); + if(!find_next_buoy(monster, start_buoy->id, end_buoy->id)) + { + monster->mintel = o_mintel; + goto pickbuoy;//can't make connection within 1/2 mintel steps + } + monster->mintel = o_mintel; + + //step6: make sure nothing blocking is standing there + monster->clipmask = MASK_MONSTERSOLID; + if(!MG_MonsterAttemptTeleport(monster, start_buoy->origin, true))//ignorLOS since we checked above and can't see smonster at this point yet + goto pickbuoy;//can't teleport there, there's something obstructing that spot- try another + + if(BUOY_DEBUG) + gi.dprintf("%s monsterspawn-teleported to buoy %s\n", monster->classname, start_buoy->targetname); + //step7: ok, put them there, let's continue + } + else + VectorCopy(self->s.origin, monster->s.origin); + + VectorCopy(self->s.angles, monster->s.angles); + ED_CallSpawn(monster); + + --self->count; + if (self->count > 0) + monster->owner = self; + + if(self->enemy && !(self->spawnflags & 1)) + {//was activated + if(self->enemy->client) + {//monster_start_go will check their enemy and do a FoundTarget + monster->enemy = self->enemy; + } + self->enemy = NULL; + } + + if ((self->count > 0) && !(self->spawnflags & 1))//this ! was inside quotes, ! is before & in order of operations + { + self->think = monsterspawner_go; + self->nextthink = level.time + self->wait; + } + else + { + self->think = NULL; + } +} + +void monsterspawner_use(edict_t *self, edict_t *other, edict_t *activator) +{ + self->enemy = activator; + monsterspawner_go(self); +} + +/*QUAKED func_monsterspawner (0 .5 .8) (-8 -8 -8) (8 8 8) ONDEATH RANDOMBUOY PEACEFUL +Triggerable monster spawner +-----SPAWNFLAGS-------------- +ONDEATH - the next monster will not spawn until the current one is dead +RANDOMBUOY - the monster will be teleported to a random buoy that the player cannot see +PEACEFUL - Monsters are NOT spawned agry at ent that triggered spawner (monstrers will spawn angry only if the spawner was triggered by a player) +-----------KEYS-------------- +count - number of monsters to spawn before stopping (default 1) +distance - radius which monster can spawn from monsterspawner +style - type of monster to spawn + 0 - nothing will spawn + 1 - RAT, + 2 - PLAGUEELF, + 3 - SPREADER, + 4 - GORGON, + 5 - CHKROKTK, + 6 - TCHEKRIK_MALE, + 7 - TCHEKRIK_FEMALE, + 8 - TCHEKRIK_MOTHERS, + 9 - HIGH_PRIESTESS, +10 - OGLE, +11 - SERAPH_OVERLORD, +12 - SERAPH_GUARD, +13 - ASSASSIN, +14 - MORCALAVIN, +15 - DRANOR, +16 - SIDHE_GUARD, +17 - SIERNAN, +18 - SSITHRA_SCOUT, +19 - SSITHRA_VICTIM, +20 - Mutant Ssithra +21 - Harpy +22 - Fish +23 - Chicken +24 - Plague Ssithra +25 - Gkrokon +26 - Giant Rat +27 - Palace Plague Guard +28 - Invisible Palace Plague Guard + + + +wait - time to wait between spawnings (default 10) + + +The following fields can be applied to the func_monsterspawner so that the monsters spawned from it will have the values you give them. The defaults are the monster's normal defaults. Monsters who do not use buoys may not use all of these fields (ie: rats, harpies, fish, imps, etc.) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. +*/ +void SP_func_monsterspawner (edict_t *self) +{ + + self->solid = SOLID_NOT; + + if (self->style == MS_NOTHING) + { + gi.dprintf ("func_monsterspawner with a style of 0 at %s\n", vtos(self->s.origin)); + } + else if (self->style >= MS_MAX) + { + gi.dprintf ("func_monsterspawner with a bad style of %d at %s\n", + self->style, vtos(self->s.origin)); + } + + if (!self->count) + self->count = 1; + + if (!self->wait) + self->wait = 10; + + if(!self->s.scale) + self->s.scale = 1.0f; + + if (self->targetname) + self->use = monsterspawner_use; + else + { + self->think = monsterspawner_go; + self->nextthink = level.time + self->wait; + } + + self->maxrange = st.distance; + + self->enemy = NULL; + + gi.linkentity (self); + +} + + +/*QUAK-ED func_killbox (1 0 0) ? +Kills everything inside when fired, irrespective of protection. +*/ +/* +void use_killbox (edict_t *self, edict_t *other, edict_t *activator) +{ + KillBox (self); +} +*/ +/* +void SP_func_killbox (edict_t *ent) +{ + gi.setmodel (ent, ent->model); + ent->use = use_killbox; + ent->svflags = SVF_NOCLIENT; +} + +*/ + + +//=========================== +// These are just temp entities until the actual code is written for each monster +//=========================== + +/*QUAKED monster_chkroktk (1 .5 0) (-16 -16 -26) (16 16 26) AMBUSH ASLEEP +The chkroktk +*/ +void SP_monster_chkroktk (edict_t *self) +{ + self->style = MS_CHKROKTK; + monsterspawner_go(self); +} + + + +/*QUAKED character_sidhe_guard (1 .5 0) (-16 -16 -26) (16 16 26) AMBUSH ASLEEP +The Sidhe Guard +*/ +void SP_character_sidhe_guard (edict_t *self) +{ + self->style = MS_SIDHE_GUARD; + monsterspawner_go(self); +} + diff --git a/Toolkit/Programming/GameCode/game/g_items.c b/Toolkit/Programming/GameCode/game/g_items.c new file mode 100644 index 0000000..969f9fa --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_items.c @@ -0,0 +1,1415 @@ +// +// g_items.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "p_item.h" +#include "g_items.h" +#include "p_types.h" +#include "p_weapon.h" +#include "p_weapon2.h" +#include "p_anims2.h" +#include "p_anim_data2.h" +#include "fx.h" +#include "random.h" +#include "vector.h" +#include "g_itemstats.h" + +#define HEALTH_IGNORE_MAX 1 +#define HEALTH_TIMED 2 + +#define ITEM_COOP_ONLY 1 +#define ITEM_NO_DROP 2 + +// ************************************************************************************************ +// RespawnedThink +// -------------- +// ************************************************************************************************ + +void RespawnedThink(edict_t *ent) +{ + ent->think = NULL; +// ent->svflags |= SVF_NOCLIENT; +} + +// ************************************************************************************************ +// DoRespawn +// --------- +// ************************************************************************************************ + +void DoRespawn(edict_t *ent) +{ + if(ent->team) + { + edict_t *Master; + int Count; + int Choice; + + Master=ent->teammaster; + + for(Count=0,ent=Master;ent;ent=ent->chain,Count++) + ; + + Choice=irand(0, Count - 1); + + for(Count=0,ent=Master;Countchain,Count++) + ; + } + + ent->solid=SOLID_TRIGGER; + + gi.linkentity(ent); + + // Create a respawn client-effect (this isn't currenlty doing anything on the client). + + //gi.CreateEffect(&ent->s,FX_ITEM_RESPAWN,CEF_OWNERS_ORIGIN,ent->s.origin,NULL); + + // So it'll get sent to the client again. + +// ent->svflags &= ~SVF_NOCLIENT; + + // Re-enable the persistent effect. + + ent->s.effects &= ~EF_DISABLE_ALL_CFX; + + // So it'll get displayed again. + + ent->s.effects |= EF_ALWAYS_ADD_EFFECTS; + + // And the rest. + + ent->think = RespawnedThink; + ent->nextthink = level.time + FRAMETIME; +} + +// ************************************************************************************************ +// PreRespawnThink +// --------------- +// ************************************************************************************************ + +void PreRespawnThink(edict_t *ent) +{ + int delay; + float clients; + + // The equation for respawn: + // --The respawn times should be normal for 8 players. + // --For 32 players the respawn should be halved + // --For 2 players the respawn should be doubled. + if (deathmatch->value) + { +/* // You know what? I thought I was being clever here, but I just screwed up the eq and made the game not respawn enough. + delay = ent->delay * sqrt((float)game.num_clients/8.0); // This makes it a nice curve. Clever, no? + // Lemme see here: sqrt(2/8) = sqrt(1/4) = 1/2 + // sqrt(8/8) = sqrt(1) = 1 + // sqrt(32/8) = sqrt(4) = 2 +*/ + clients=(float)game.num_clients; + if (clients<2.0) + clients=2.0; + delay = ent->delay * sqrt(2.0/clients); // Spawn more frequently when more players. + // Lemme see here: sqrt(2/2) = sqrt(1) = 1 + // sqrt(2/8) = sqrt(1/4) = 1/2 + // sqrt(2/32) = sqrt(1/16) = 1/4 + } + else + { + delay = ent->delay; + } + ent->nextthink = level.time + delay - FRAMETIME; + ent->think = DoRespawn; +// ent->svflags |= SVF_NOCLIENT; +} + +// ************************************************************************************************ +// SetRespawn +// ---------- +// ************************************************************************************************ + +void SetRespawn(edict_t *ent) +{ + // So it'll get sent to the client again. + +// ent->svflags &= ~SVF_NOCLIENT; + + // Disables all the effects on the entity. + + ent->s.effects |= EF_DISABLE_ALL_CFX; + + // Take off the EF_ALWAYS_ADD_EFFECTS or EF_DISABLE_ALL_CFX wont have an effect. + + ent->s.effects &= ~EF_ALWAYS_ADD_EFFECTS; + + // And the rest. + + ent->solid = SOLID_NOT; + + if(deathmatch->value && game.num_clients > 8) + { + // No less than 1/4th the delay. + + ent->nextthink = level.time + (ent->delay) / 4; + } + if(deathmatch->value && game.num_clients > 2) + { + // So things respawn faster with a lot of players. + + ent->nextthink = level.time + (ent->delay) / (game.num_clients/2); + } + else + { + ent->nextthink = level.time + ent->delay; + } + + ent->think = PreRespawnThink; +} + +// ************************************************************************************************ +// Pickup_Puzzle +// ------------- +// ************************************************************************************************ + +qboolean Pickup_Puzzle(edict_t *ent, edict_t *other) +{ + gitem_t *item; + + item = FindItemByClassname(ent->classname); + + if (!other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(ent->item)]) + { + other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(ent->item)] = 1; + + gi.gamemsg_centerprintf(other, ent->item->msg_pickup); + + return(true); + } + else + { + return(false); + } +} + +// ************************************************************************************************ +// AddWeaponToInventory +// -------------------- +// ************************************************************************************************ + +qboolean AddWeaponToInventory(gitem_t *item,edict_t *player) +{ + gitem_t *newitem; + int count; + + // Do we already have this weapon? + + if(!player->client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)]) + { + // We don't already have it, so get the weapon and some ammo. + + if (item->tag == ITEM_WEAPON_SWORDSTAFF) + count= 0; + else if (item->tag == ITEM_WEAPON_HELLSTAFF) + count = AMMO_COUNT_HELLSTAFF; + else if (item->tag == ITEM_WEAPON_REDRAINBOW) + { + // give us the bowtype + player->client->playerinfo.pers.bowtype = BOW_TYPE_REDRAIN; + count = AMMO_COUNT_REDRAINBOW; + } + else if (item->tag == ITEM_WEAPON_PHOENIXBOW) + { + // give us the bowtype + player->client->playerinfo.pers.bowtype = BOW_TYPE_PHOENIX; + count = AMMO_COUNT_PHOENIXBOW; + } + else + count = AMMO_COUNT_MOST; + + player->client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + if(count) + { + newitem = FindItem(item->ammo); + Add_Ammo(player, newitem,count); + } + + // Now decide if we want to swap weapons or not. + + if (player->client->playerinfo.pers.autoweapon) + { + // If this new weapon is a higher value than the one we currently have, swap the current + // weapon for the new one. + + if (ITEM_INDEX(item) > ITEM_INDEX(player->client->playerinfo.pers.weapon)) + { + item->use(&player->client->playerinfo,item); + } + } + + return(true); + } + else + { + // We already have it... + + if(!((deathmatch->value&&((int)dmflags->value&DF_WEAPONS_STAY))||coop->value)) + { + // ...and DF_WEPONS_STAY is off and we're not in coop, so just try to up the ammo counts. + + if (item->tag == ITEM_WEAPON_HELLSTAFF) + { + newitem = FindItemByClassname("item_ammo_hellstaff"); + count = AMMO_COUNT_HELLSTAFF; + } + else if (item->tag == ITEM_WEAPON_REDRAINBOW) + { + newitem = FindItemByClassname("item_ammo_redrain"); + count = AMMO_COUNT_REDRAINBOW; + } + else if (item->tag == ITEM_WEAPON_PHOENIXBOW) + { + newitem = FindItemByClassname("item_ammo_phoenix"); + count = AMMO_COUNT_PHOENIXBOW; + } + else + { + newitem = FindItemByClassname("item_mana_offensive_half"); + count = AMMO_COUNT_MOST; + } + + if(Add_Ammo(player, newitem,count)) + { + // Have space in our inventory, so add ammo. + + return(true); + } + else + { + // No space in inventory to add the ammo. + + return(false); + } + } + else + { + // ...but we're not able to pick it up. + + return(false); + } + } +} + +// ************************************************************************************************ +// Pickup_Weapon +// ------------- +// ************************************************************************************************ + +qboolean Pickup_Weapon(edict_t *ent,edict_t *other) +{ + if(AddWeaponToInventory(ent->item,other)) + { + gi.gamemsg_centerprintf(other, ent->item->msg_pickup); + + return(true); + } + else + { + // We already have it. + + return(false); + } +} + +// ************************************************************************************************ +// AddDefenseToInventory +// --------------------- +// ************************************************************************************************ + +qboolean AddDefenseToInventory(gitem_t *item,edict_t *player) +{ + if(!player->client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)]) + { + player->client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)]=1; + + // Now decide if we want to swap defenses or not. + +// if(player->client->playerinfo.pers.autoweapon || !player->client->playerinfo.pers.defence) + if(player->client->playerinfo.pers.autoweapon ) + { + item->use(&player->client->playerinfo,item); + } + + return(true); + } + else + { + // We already have it... + + return(false); + } +} + +// ************************************************************************************************ +// Pickup_Defense +// -------------- +// ************************************************************************************************ + +qboolean Pickup_Defense (edict_t *ent, edict_t *other) +{ + if(AddDefenseToInventory(ent->item,other)) + { + gi.gamemsg_centerprintf(other, ent->item->msg_pickup); + + return(true); + } + else + { + return(false); + } +} + +// ************************************************************************************************ +// Add_AmmoToInventory +// ------------------- +// ************************************************************************************************ + +qboolean Add_AmmoToInventory (edict_t *ent, gitem_t *item, int count,int max) +{ + int index; + + index = ITEM_INDEX(item); + + if (ent->client->playerinfo.pers.inventory.Items[index] == max) + return(false); + + ent->client->playerinfo.pers.inventory.Items[index] += count; + + if (ent->client->playerinfo.pers.inventory.Items[index] > max) + ent->client->playerinfo.pers.inventory.Items[index] = max; + + return(true); +} + +/* +=============== +Add_Ammo +=============== +*/ + +qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count) +{ + int bo; + int max; + + if (!ent->client) + return(false); + + if ((item->tag == ITEM_AMMO_MANA_OFFENSIVE_HALF) || (item->tag == ITEM_AMMO_MANA_OFFENSIVE_FULL)) + { + item = FindItemByClassname("item_mana_offensive_half"); + max = ent->client->playerinfo.pers.max_offmana; + return(Add_AmmoToInventory (ent,item,count,max)); + } + else if ((item->tag == ITEM_AMMO_MANA_DEFENSIVE_HALF) || (item->tag == ITEM_AMMO_MANA_DEFENSIVE_FULL)) + { + item = FindItemByClassname("item_mana_defensive_half"); + max = ent->client->playerinfo.pers.max_defmana; + return(Add_AmmoToInventory (ent,item,count,max)); + } + else if ((item->tag == ITEM_AMMO_MANA_COMBO_QUARTER) || (item->tag == ITEM_AMMO_MANA_COMBO_HALF)) + { + item = FindItemByClassname("item_mana_offensive_half"); + max = ent->client->playerinfo.pers.max_offmana; + + bo = Add_AmmoToInventory (ent,item,count,max); + + item = FindItemByClassname("item_mana_defensive_half"); + max = ent->client->playerinfo.pers.max_defmana; + bo |= Add_AmmoToInventory (ent,item,count,max); + + return(bo); + } + else if (item->tag == ITEM_AMMO_REDRAIN) + { + max = ent->client->playerinfo.pers.max_redarrow; + return(Add_AmmoToInventory (ent,item,count,max)); + } + else if (item->tag == ITEM_AMMO_PHOENIX) + { + max = ent->client->playerinfo.pers.max_phoenarr; + return(Add_AmmoToInventory (ent,item,count,max)); + } + else if (item->tag == ITEM_AMMO_HELLSTAFF) + { + max = ent->client->playerinfo.pers.max_hellstaff; + return(Add_AmmoToInventory (ent,item,count,max)); + } + else + return(false); +} + +/* +=============== +Pickup_Ammo +=============== +*/ + +qboolean Pickup_Ammo (edict_t *ent, edict_t *other) +{ + int count; + + if (ent->count) + count = ent->count; + else + count = ent->item->quantity; + + if (!Add_Ammo (other, ent->item, count)) + return(false); + + gi.gamemsg_centerprintf(other, ent->item->msg_pickup); + + return(true); +} + +/* +=============== +Pickup_Manna + +Separate routine so we can distinguish between ammo and mana. +=============== +*/ + +qboolean Pickup_Mana (edict_t *ent, edict_t *other) +{ + return(Pickup_Ammo(ent, other)); +} + +/* +=============== +Drop_Ammo +=============== +*/ + +void Drop_Ammo (edict_t *ent, gitem_t *item) +{ + edict_t *dropped; + int index; + + index = ITEM_INDEX(item); + dropped = Drop_Item (ent, item); + + if (ent->client->playerinfo.pers.inventory.Items[index] >= item->quantity) + dropped->count = item->quantity; + else + dropped->count = ent->client->playerinfo.pers.inventory.Items[index]; + ent->client->playerinfo.pers.inventory.Items[index] -= dropped->count; + + ValidateSelectedItem (ent); +} + +/* +=============== +Pickup_Health +=============== +*/ + +qboolean Pickup_Health (edict_t *ent, edict_t *other) +{ + if (!(ent->style & HEALTH_IGNORE_MAX)) + { + if (other->health >= other->max_health) + { + return(false); + } + } + + other->health += ent->item->quantity; + + if(other->fire_damage_time>level.time) + { + other->fire_damage_time -= ent->item->quantity/10; + if(other->fire_damage_time<=0) + { + other->fire_damage_time = 0; +// gi.RemoveEffects(&other->s, FX_FIRE_ON_ENTITY);//turn off CFX too + other->s.effects |= EF_MARCUS_FLAG1; // Notify the effect to turn itself off. + } + } + + if (!(ent->style & HEALTH_IGNORE_MAX)) + { + if (other->health > other->max_health) + { + other->health = other->max_health; + } + } + + if(other->client) + player_repair_skin(other); + + gi.gamemsg_centerprintf(other, ent->item->msg_pickup); + + return(true); +} + +/* +=============== +Touch_Item +=============== +*/ + +void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if(strcmp(other->classname,"player")) + { + // Only players can touch items. + + return; + } + + if(other->health <= 0) + { + // Dead players can't pickup. + + return; + } + + + if(!ent->item->pickup) + { + // Not a grabbable item. + + return; + } + + assert(ent->item->pickup); + + if((other->client->playerinfo.edictflags & FL_CHICKEN) && (ent->item->pickup == Pickup_Health)) + { + // chickens can't pickup health + + return; + } + + if(!ent->item->pickup(ent, other)) + { + // Player can't hold it. + + return; + } + + gi.sound(other, CHAN_ITEM, gi.soundindex(ent->item->pickup_sound), 1, ATTN_NORM, 0); + + gi.CreateEffect(NULL, FX_PICKUP, 0, ent->s.origin, ""); + + G_UseTargets (ent, other); + + // Handle respawn / removal of the item. + + if(((ent->item->pickup==Pickup_Weapon)||(ent->item->pickup==Pickup_Defense)||(ent->item->pickup==Pickup_Puzzle))&& + ((deathmatch->value&&((int)dmflags->value&DF_WEAPONS_STAY))||coop->value)) + { + // The item is a weapon or a defence or a puzzle piece AND (deathmatch rule DF_WEAPONS_STAY + // is on OR we are playing coop), so just return right now, as we don't care about respawn + // or removal. + + return; + } + + if(ent->flags&FL_RESPAWN) + { + // The item should respawn. + + SetRespawn(ent); + } + else + { + // Going away for good, so make it noclipping. + + ent->solid = SOLID_NOT; + + // Once picked up, the item is gone forever, so remove it's client effect(s). + + gi.RemoveEffects(&ent->s,0); + + // The persistent part is removed from the server here. + + G_SetToFree(ent); + } +} + +/* +================ +drop_temp_touch +================ +*/ + +static void drop_temp_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (other == ent->owner) + return; + + Touch_Item (ent, other, plane, surf); +} + +/* +================ +drop_make_touchable +================ +*/ + +static void drop_make_touchable (edict_t *ent) +{ + ent->touch = Touch_Item; + + if (deathmatch->value) + { + ent->nextthink = level.time + 29; + ent->think = G_FreeEdict; + } +} + +/* +================ +Drop_Item +================ +*/ + +edict_t *Drop_Item (edict_t *ent, gitem_t *item) +{ + edict_t *dropped; + vec3_t forward, right; + vec3_t offset; + + dropped = G_Spawn(); + + dropped->classname = item->classname; + dropped->item = item; + dropped->spawnflags = DROPPED_ITEM; + dropped->s.effects = item->world_model_flags; + dropped->s.renderfx = RF_GLOW; + VectorSet (dropped->mins, -15, -15, -15); + VectorSet (dropped->maxs, 15, 15, 15); + gi.setmodel (dropped, dropped->item->world_model); + dropped->solid = SOLID_TRIGGER; + dropped->movetype = PHYSICSTYPE_NONE; + dropped->touch = drop_temp_touch; + dropped->owner = ent; + + if (ent->client) + { + trace_t trace; + + AngleVectors (ent->client->v_angle, forward, right, NULL); + VectorSet(offset, 24, 0, -16); + G_ProjectSource (ent->s.origin, offset, forward, right, dropped->s.origin); + gi.trace (ent->s.origin, dropped->mins, dropped->maxs, + dropped->s.origin, ent, CONTENTS_SOLID,&trace); + VectorCopy (trace.endpos, dropped->s.origin); + } + else + { + AngleVectors (ent->s.angles, forward, right, NULL); + VectorCopy (ent->s.origin, dropped->s.origin); + } + + VectorScale (forward, 100, dropped->velocity); + dropped->velocity[2] = 300; + + dropped->think = drop_make_touchable; + dropped->nextthink = level.time + 1; + + gi.linkentity (dropped); + + return dropped; +} + +/* +================ +Use_Item +================ +*/ +/* +void Use_Item (edict_t *ent, edict_t *other, edict_t *activator) +{ +// ent->svflags &= ~SVF_NOCLIENT; + ent->use = NULL; + + if (ent->spawnflags & 2) // NO_TOUCH + { + ent->solid = SOLID_BBOX; + ent->touch = NULL; + } + else + { + ent->solid = SOLID_TRIGGER; + ent->touch = Touch_Item; + } + + gi.linkentity (ent); +} +*/ + +// ************************************************************************************************ +// ValidItem +// --------- +// ************************************************************************************************ + +qboolean ValidItem(gitem_t *item) +{ + // Some items will be prevented in deathmatch. + + if(deathmatch->value) + { + if ( (int)dmflags->value & DF_NO_DEFENSIVE_SPELL ) + { + if (item->pickup == Pickup_Defense) + { + return false; + } + } + if ( (int)dmflags->value & DF_NO_OFFENSIVE_SPELL ) + { + if ((item->pickup == Pickup_Ammo) || (item->pickup == Pickup_Weapon)) + { + return false; + } + } + if ( (int)dmflags->value & DF_NO_HEALTH ) + { + if (item->pickup == Pickup_Health) + { + return false; + } + } + } + + +#if DEMO_CODE + // don't spawn this item in Demo game + if ((int)item->info) + return false; +#endif + + return true; +} + +// ************************************************************************************************ +// SpawnItemEffect +// --------------- +// ************************************************************************************************ + +void SpawnItemEffect(edict_t *ent, gitem_t *item) +{ + + if(!ValidItem(item)) + { + G_FreeEdict (ent); + return; + } + + assert(!ent->PersistantCFX); + + if ((ent->spawnflags & ITEM_COOP_ONLY) && (!coop->value)) + return; + + if(ent->item->flags & IT_PUZZLE) + { + ent->PersistantCFX = gi.CreatePersistantEffect(&ent->s, FX_PICKUP_PUZZLE, CEF_BROADCAST, ent->s.origin, "bv", ent->item->tag,ent->s.angles); + } + else if(ent->item->flags & IT_WEAPON) + { + ent->PersistantCFX = gi.CreatePersistantEffect(&ent->s, FX_PICKUP_WEAPON, CEF_BROADCAST, ent->s.origin, "b", ent->item->tag); + } + else if(ent->item->flags & IT_DEFENSE) + { + ent->PersistantCFX = gi.CreatePersistantEffect(&ent->s, FX_PICKUP_DEFENSE, CEF_BROADCAST, ent->s.origin, "b", ent->item->tag); + } + else if(ent->item->flags & IT_AMMO) + { + ent->PersistantCFX = gi.CreatePersistantEffect(&ent->s, FX_PICKUP_AMMO, CEF_BROADCAST, ent->s.origin, "b", ent->item->tag); + } + else + { + if (ent->item->tag) + ent->PersistantCFX = gi.CreatePersistantEffect(&ent->s, FX_PICKUP_HEALTH, CEF_FLAG6|CEF_BROADCAST, ent->s.origin, ""); + else + ent->PersistantCFX = gi.CreatePersistantEffect(&ent->s, FX_PICKUP_HEALTH, CEF_BROADCAST, ent->s.origin, ""); + } +} + + +/* +================ +droptofloor +================ +*/ + +void itemsdroptofloor (edict_t *ent) +{ + trace_t tr; + vec3_t dest; + + ent->movetype = PHYSICSTYPE_STATIC; + ent->solid = SOLID_TRIGGER; + ent->touch = Touch_Item; + ent->think = NULL; + + if (!(ent->spawnflags & ITEM_NO_DROP)) + { + VectorSet(dest, 0.0, 0.0, -128.0); + Vec3AddAssign (ent->s.origin, dest); + + gi.linkentity (ent); + + gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID, &tr); + if (tr.startsolid) + { + gi.dprintf ("droptofloor: %s startsolid at %s (inhibited)\n", ent->classname, vtos(ent->s.origin)); + G_FreeEdict (ent); + return; + } + + tr.endpos[2] += 24; + VectorCopy(tr.endpos,ent->s.origin); + } + + + gi.linkentity (ent); + + // if we loading a saved game - the objects will already be out there + if (!ent->PersistantCFX) + SpawnItemEffect(ent, ent->item); +} + + +/* +=============== +PrecacheItem + +Precaches all data needed for a given item. This will be called for each item +spawned in a level, and for each item in each client's inventory. +=============== +*/ + +void PrecacheItem (gitem_t *it) +{ + gitem_t *ammo; + + if (!it) + return; + + if (it->pickup_sound) + gi.soundindex (it->pickup_sound); + if (it->world_model) + gi.modelindex (it->world_model); + if (it->icon) + gi.imageindex (it->icon); + + // parse everything for its ammo + if (it->ammo && it->ammo[0]) + { + ammo = FindItem (it->ammo); + if (ammo != it) + PrecacheItem (ammo); + } +} +// ************************************************************************************************ +// SpawnItem +// --------- +// Sets the clipping size and plants the object on the floor. Items can't be immediately dropped to +// the floor because they might be on an entity that hasn't spawned yet. +// ************************************************************************************************ + +void SpawnItem (edict_t *ent, gitem_t *item) +{ + if ((ent->spawnflags & ITEM_COOP_ONLY) && (!coop->value)) + return; + + PrecacheItem(item); + + if(!ValidItem(item)) + { + G_FreeEdict (ent); + return; + } + + ent->item = item; + ent->nextthink = level.time + (2 * FRAMETIME); // items start after other solids + ent->think = itemsdroptofloor; + + ent->s.effects = item->world_model_flags; + ent->s.renderfx = RF_GLOW; +// ent->svflags |= SVF_ALWAYS_SEND; // make sure SVF_NOCLIENT gets set in think + ent->s.effects |= EF_ALWAYS_ADD_EFFECTS; + + if (item->flags & IT_WEAPON) + { + if (item->tag == ITEM_WEAPON_MACEBALLS) + ent->delay = RESPAWN_TIME_MACEBALL; // Maceballs shouldn't come back as fast... + else + ent->delay = RESPAWN_TIME_WEAPON; + } + else if (item->flags & IT_DEFENSE) + { + if (item->tag == ITEM_DEFENSE_REPULSION) + ent->delay = RESPAWN_TIME_RING; + else if (item->tag == ITEM_DEFENSE_TELEPORT) + ent->delay = RESPAWN_TIME_TELEPORT; + else if (item->tag == ITEM_DEFENSE_POLYMORPH) + ent->delay = RESPAWN_TIME_MORPH; + else + ent->delay = RESPAWN_TIME_DEFENSE; + } + else if (item->flags & IT_AMMO) + { + if (item->tag == ITEM_AMMO_REDRAIN || item->tag == ITEM_AMMO_PHOENIX) + ent->delay = RESPAWN_TIME_ARROWS; + else + ent->delay = RESPAWN_TIME_AMMO; + } + else // Health and anything else + { + ent->delay = RESPAWN_TIME_MISC; + } + + ent->flags = item->flags; + ent->clipmask = MASK_MONSTERSOLID; + + if (item->flags == IT_PUZZLE) + { + VectorCopy(ent->item->mins, ent->mins); + VectorCopy(ent->item->maxs, ent->maxs); + } + + // FIXME: Until all objects have bounding boxes, default to these vals. + if (Vec3IsZero(ent->mins)) + { + VectorSet (ent->mins, -10.0, -10.0, -10.0); + VectorSet (ent->maxs, 10.0, 10.0, 10.0); + } + + ent->classname = item->classname; + if(deathmatch->value) + { + ent->flags |= FL_RESPAWN; + } +} +// ************************************************************************************************ +// IsItem +// ------ +// ************************************************************************************************ + +gitem_t *IsItem(edict_t *ent) +{ + gitem_t *item; + int i; + + if(!ent->classname) + { + return NULL; + } + + for(i = 0, item = p_itemlist; i < game.num_items; ++i, ++item) + { + if(!item->classname) + { + continue; + } + + if(!strcmp(item->classname, ent->classname)) + { + // Found it. + + return item; + } + } + + return NULL; +} + +// ************************************************************************************************ +// G_InitItems +// ----------- +// ************************************************************************************************ + +void G_InitItems(void) +{ + // ******************************************************************************************** + // Setup item function pointers which yield pick-up, use, drop and weaponthink functionality. + // ******************************************************************************************** + + // Leave index 0 empty. + + // weapon_swordstaff + // This can't be placed in the editor + + p_itemlist[1].pickup=Pickup_Weapon; + p_itemlist[1].use=Weapon_EquipSwordStaff; + p_itemlist[1].weaponthink=WeaponThink_SwordStaff; + + // weapon_flyingfist + // This can't be placed in the editor + + p_itemlist[2].pickup=Pickup_Weapon; + p_itemlist[2].use=Weapon_EquipSpell; + p_itemlist[2].weaponthink=WeaponThink_FlyingFist; + + // item_weapon_hellstaff +/*QUAKED item_weapon_hellstaff (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the hellstaff weapon. +*/ + + p_itemlist[3].pickup=Pickup_Weapon; + p_itemlist[3].use=Weapon_EquipHellStaff; + p_itemlist[3].weaponthink=WeaponThink_HellStaff; + + // item_weapon_magicmissile +/*QUAKED item_weapon_magicmissile (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Magic Missile weapon. +*/ + + p_itemlist[4].pickup=Pickup_Weapon; + p_itemlist[4].use=Weapon_EquipSpell; + p_itemlist[4].weaponthink=WeaponThink_MagicMissileSpread; + + // item_weapon_redrain_bow +/*QUAKED item_weapon_redrain_bow (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Red Rain Bow weapon. +*/ + + p_itemlist[5].pickup=Pickup_Weapon; + p_itemlist[5].use=Weapon_EquipBow; + p_itemlist[5].weaponthink=WeaponThink_RedRainBow; + + // item_weapon_firewall +/*QUAKED item_weapon_firewall (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Fire Wall weapon. +*/ + + p_itemlist[6].pickup=Pickup_Weapon; + p_itemlist[6].use=Weapon_EquipSpell; + p_itemlist[6].weaponthink=WeaponThink_Firewall; + + // item_weapon_phoenixbow +/*QUAKED item_weapon_phoenixbow (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Phoenix Bow weapon. +*/ + + p_itemlist[7].pickup=Pickup_Weapon; + p_itemlist[7].use=Weapon_EquipBow; + p_itemlist[7].weaponthink=WeaponThink_PhoenixBow; + + // item_weapon_sphereofannihilation +/*QUAKED item_weapon_sphereofannihilation (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Sphere Annihilation weapon. +*/ + + p_itemlist[8].pickup=Pickup_Weapon; + p_itemlist[8].use=Weapon_EquipSpell; + p_itemlist[8].weaponthink=WeaponThink_SphereOfAnnihilation; + + // item_weapon_maceballs +/*QUAKED item_weapon_maceballs (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Mace Balls weapon. +*/ + + p_itemlist[9].pickup=Pickup_Weapon; + p_itemlist[9].use=Weapon_EquipSpell; + p_itemlist[9].weaponthink=WeaponThink_Maceballs; + + // item_defense_powerup + // This can't be placed in the editor + + p_itemlist[10].pickup=Pickup_Defense; + p_itemlist[10].use=Use_Defence; + p_itemlist[10].weaponthink=DefenceThink_Powerup; + + // item_defense_ringofrepulsion +/*QUAKED item_defense_ringofrepulsion (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Ring of Repulsion defensive spell. +*/ + + p_itemlist[11].pickup=Pickup_Defense; + p_itemlist[11].use=Use_Defence; + p_itemlist[11].weaponthink=DefenceThink_RingOfRepulsion; + + // item_defense_shield +/*QUAKED item_defense_shield (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Shield defensive spell. +*/ + + p_itemlist[12].pickup=Pickup_Defense; + p_itemlist[12].use=Use_Defence; + p_itemlist[12].weaponthink=DefenceThink_Shield; + + // item_defense_teleport +/*QUAKED item_defense_teleport (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Teleport defensive spell. +*/ + + p_itemlist[13].pickup=Pickup_Defense; + p_itemlist[13].use=Use_Defence; + p_itemlist[13].weaponthink=DefenceThink_Teleport; + + // item_defense_polymorph +/*QUAKED item_defense_polymorph (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Polymorph Barrier defensive spell. +*/ + + p_itemlist[14].pickup=Pickup_Defense; + p_itemlist[14].use=Use_Defence; + p_itemlist[14].weaponthink=DefenceThink_Morph; + + // item_defense_meteorbarrier +/*QUAKED item_defense_meteorbarrier (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the Meteor Barrier defensive spell. +*/ + + p_itemlist[15].pickup=Pickup_Defense; + p_itemlist[15].use=Use_Defence; + p_itemlist[15].weaponthink=DefenceThink_MeteorBarrier; + + // item_mana_offensive_half +/*QUAKED item_mana_offensive_half (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the offensive mana (50 points). +*/ + p_itemlist[16].pickup=Pickup_Mana; + + // item_mana_offensive_full +/*QUAKED item_mana_offensive_full (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the offensive mana (100 points). +*/ + + p_itemlist[17].pickup=Pickup_Mana; + + // item_mana_defensive_half +/*QUAKED item_mana_defensive_half (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the defensive mana (50 points). +*/ + + p_itemlist[18].pickup=Pickup_Mana; + + // item_mana_defensive_full +/*QUAKED item_mana_defensive_full (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for the defensive mana (100 points). +*/ + + p_itemlist[19].pickup=Pickup_Mana; + + // item_mana_combo_quarter +/*QUAK-ED item_mana_combo_quarter (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for both defensive & offensive mana (25 points). +*/ + + p_itemlist[20].pickup=Pickup_Mana; + + // item_mana_combo_half +/*QUAKED item_mana_combo_half (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup for both defensive & offensive mana (50 points). +*/ + + p_itemlist[21].pickup=Pickup_Mana; + + // item_ammo_redrain +/*QUAKED item_ammo_redrain (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup ammo for the Red Rain Bow +*/ + + p_itemlist[22].pickup=Pickup_Ammo; + + // item_ammo_phoenix +/*QUAKED item_ammo_phoenix (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup ammo for the Phoenix Bow +*/ + + p_itemlist[23].pickup=Pickup_Ammo; + + // item_ammo_hellstaff +/*QUAKED item_ammo_hellstaff (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup ammo for the Hellstaff +*/ + + p_itemlist[24].pickup=Pickup_Ammo; + + // item_health_half +/*QUAKED item_health_half (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup health (10 points) +*/ + + p_itemlist[25].pickup=Pickup_Health; + + // item_health_full +/*QUAKED item_health_full (.3 .3 1) (-16 -16 -16) (16 16 16) COOP_ONLY +Pickup health (30 points) +*/ + + p_itemlist[26].pickup=Pickup_Health; + +/*QUAKED item_puzzle_townkey (.3 .3 1) (-8 -8 -4) (8 8 4) x NO_DROP +Key puzzle piece +Town Level +NO_DROP - won't drop to ground + +*/ + p_itemlist[27].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_cog (.3 .3 1) (-10 -10 -24) (10 10 20) x NO_DROP +Cog puzzle piece +Palace level +NO_DROP - won't drop to ground +*/ + p_itemlist[28].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_shield (.3 .3 1) (-2 -6 -12) (2 6 12) x NO_DROP +Sithra Shield puzzle item +Healer Level +NO_DROP - won't drop to ground +*/ + p_itemlist[29].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_potion (.3 .3 1) (-3 -3 -10) (3 3 10) x NO_DROP +Potion puzzle item +Healer Level +NO_DROP - won't drop to ground +*/ + p_itemlist[30].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_plazacontainer (.3 .3 1) (-6 -6 -8) (6 6 6) x NO_DROP +Container puzzle item +Plaza Level +NO_DROP - won't drop to ground +*/ + p_itemlist[31].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_slumcontainer (.3 .3 1) (-6 -6 -8) (6 6 6) x NO_DROP +Full Container puzzle item +Slum Level +NO_DROP - won't drop to ground +*/ + p_itemlist[32].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_crystal (.3 .3 1) (-16 -16 -16) (16 16 16) x NO_DROP +Crystal puzzle item +Academic Level +NO_DROP - won't drop to ground +*/ + p_itemlist[33].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_canyonkey (.3 .3 1) (-16 -16 -16) (16 16 16) x NO_DROP +Key puzzle item +Canyon Level +NO_DROP - won't drop to ground +*/ + p_itemlist[34].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_hive2amulet (.3 .3 1) (-16 -16 -16) (16 16 16) x NO_DROP +Amulet puzzle item +Hive 2 Level +NO_DROP - won't drop to ground +*/ + p_itemlist[35].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_hive2spear (.3 .3 1) (-16 -16 -16) (16 16 16) x NO_DROP +Spear puzzle item +Hive 2 Level +NO_DROP - won't drop to ground +*/ + p_itemlist[36].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_hive2gem (.3 .3 1) (-16 -16 -16) (16 16 16) x NO_DROP +Gem puzzle item +Hive 2 Level +NO_DROP - won't drop to ground +*/ + p_itemlist[37].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_minecartwheel (.3 .3 1) (-1 -6 -6) (1 6 6) x NO_DROP +Mine Cart Wheel puzzle item +Mine 1 Level +NO_DROP - won't drop to ground +*/ + p_itemlist[38].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_ore (.3 .3 1) (-10 -10 -8) (10 10 8) x NO_DROP +Unrefined Ore puzzle item +Mine 2 Level +NO_DROP - won't drop to ground +*/ + p_itemlist[39].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_refinedore (.3 .3 1) (-3 -12 -2) (3 12 2) x NO_DROP +Refined Ore puzzle item +Mine 2 Level +NO_DROP - won't drop to ground +*/ + p_itemlist[40].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_dungeonkey (.3 .3 1) (-1 -18 -9) (1 18 9) x NO_DROP +Amulet puzzle item +Dungeon Level +NO_DROP - won't drop to ground +*/ + p_itemlist[41].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_cloudkey (.3 .3 1) (-8 -8 -3) (8 8 6) x NO_DROP +Key puzzle item +Cloud Quarters 2 Level +NO_DROP - won't drop to ground +*/ + p_itemlist[42].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_highpriestesskey (.3 .3 1) (-12 -12 -6) (12 12 6) x NO_DROP +Key puzzle item +High Priestess Level +NO_DROP - won't drop to ground +*/ + p_itemlist[43].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_highpriestesssymbol (.3 .3 1) (-12 -12 -4) (12 12 4) x NO_DROP +Key puzzle item +High Priestess Level +NO_DROP - won't drop to ground +*/ + p_itemlist[44].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_tome (.3 .3 1) (-12 -12 -4) (12 12 4) x NO_DROP +Tome puzzle piece +2 Cloud Levels +NO_DROP - won't drop to ground +*/ + p_itemlist[45].pickup = Pickup_Puzzle; + +/*QUAKED item_puzzle_tavernkey (.3 .3 1) (-8 -8 -4) (8 8 4) x NO_DROP +Key puzzle piece +Ssdocks Level +NO_DROP - won't drop to ground +*/ + p_itemlist[46].pickup = Pickup_Puzzle; + + // ******************************************************************************************** + // Initialise game variables. + // ******************************************************************************************** + + game.num_items=p_num_items; +} + +/* +=============== +SetItemNames - called by worldspawn. +=============== +*/ + +void SetItemNames(void) +{ + int i; + gitem_t *it; + + for (i=0 ; ipickup_name); + } +} diff --git a/Toolkit/Programming/GameCode/game/g_items.h b/Toolkit/Programming/GameCode/game/g_items.h new file mode 100644 index 0000000..17f397e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_items.h @@ -0,0 +1,62 @@ +#ifndef G_ITEMS_H +#define G_ITEMS_H + +// ************************************************************************************************ +// itemhealth_t +// ------ +// ************************************************************************************************ +typedef enum +{ + ITEM_HEALTH1, + ITEM_HEALTH2 +} itemhealth_t; + +// ************************************************************************************************ +// itemweapon_t +// ------ +// ************************************************************************************************ +typedef enum +{ + ITEM_WEAPON_SWORDSTAFF, + ITEM_WEAPON_FLYINGFIST, + ITEM_WEAPON_HELLSTAFF, + ITEM_WEAPON_MAGICMISSILE, + ITEM_WEAPON_REDRAINBOW, + ITEM_WEAPON_SPHEREOFANNIHILATION, + ITEM_WEAPON_PHOENIXBOW, + ITEM_WEAPON_MACEBALLS, + ITEM_WEAPON_FIREWALL, +} itemweapon_t; + +// ************************************************************************************************ +// itemdefense_t +// ------ +// ************************************************************************************************ +typedef enum +{ + ITEM_DEFENSE_REPULSION, + ITEM_DEFENSE_METEORBARRIER, + ITEM_DEFENSE_POLYMORPH, + ITEM_DEFENSE_TELEPORT, + ITEM_DEFENSE_SHIELD, + ITEM_DEFENSE_POWERUP, +} itemdefense_t; + +// ************************************************************************************************ +// itemammo_t +// ------ +// ************************************************************************************************ +typedef enum +{ + ITEM_AMMO_MANA_DEFENSIVE_HALF, + ITEM_AMMO_MANA_DEFENSIVE_FULL, + ITEM_AMMO_MANA_OFFENSIVE_HALF, + ITEM_AMMO_MANA_OFFENSIVE_FULL, + ITEM_AMMO_MANA_COMBO_QUARTER, + ITEM_AMMO_MANA_COMBO_HALF, + ITEM_AMMO_HELLSTAFF, + ITEM_AMMO_REDRAIN, + ITEM_AMMO_PHOENIX, +} itemammo_t; + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_items_pickups.c b/Toolkit/Programming/GameCode/game/g_items_pickups.c new file mode 100644 index 0000000..a9cd666 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_items_pickups.c @@ -0,0 +1,6 @@ +// +// g_items_pickups.c +// +// Heretic II +// Copyright 1998 Raven Software +// \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_itemstats.h b/Toolkit/Programming/GameCode/game/g_itemstats.h new file mode 100644 index 0000000..404bd19 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_itemstats.h @@ -0,0 +1,93 @@ +// *************************************** +// ** SHRINE STATS +// *************************************** + +// duration of shrine light on player - in seconds +#define LIGHT_DURATION 90 +// duration of shrine reflect on player - in seconds +#define REFLECT_DURATION_SINGLE 30 +// duration of shrine reflect on player - in seconds +#define REFLECT_DURATION_DEATHMATCH 20 +// duration of shrine ghosting on player - in seconds +#define GHOST_DURATION 60 +// duration of shrine powerup on player weapons - in seconds +#define POWERUP_DURATION 30 +// duration of shrine lungs on player - in seconds +#define LUNGS_DURATION 20 +// time till Shrine is useable again if so toggled - in seconds +#define SHRINE_DELAY 45 +// duration of shrine speed on player - in seconds +#define SPEED_DURATION 30 + +// amount of armor you get at a shrine - note support is in for gold armor - you just can't actually get it at this stage +#define MAX_GOLD_ARMOR 250 // amount of damage it can absorb +#define MAX_SILVER_ARMOR 100 // amount of damage it can absorb +#define SILVER_HIT_MULT 0.5 // percentage of hit damage we take on a physical hit - silver armor +#define SILVER_SPELL_MULT 0.5 // percentage of hit damage we take on a spell hit - silver armor +#define GOLD_HIT_MULT 0.25 // percentage of hit damage we take on a physical hit - gold armor +#define GOLD_SPELL_MULT 0.25 // percentage of hit damage we take on a spell hit - gold armor + +#define SHRINE_HEALTH 100 +#define SHRINE_MAX_HEALTH 150 + + +// *************************************** +// ** MANA ITEM STATS +// *************************************** + +#define HALF_OFF_MANA 20 +#define FULL_OFF_MANA 40 + +#define HALF_DEF_MANA 20 +#define FULL_DEF_MANA 40 + +#define HALF_COMBO_MANA 30 +#define FULL_COMBO_MANA 30 + + +// *************************************** +// ** SPELL ITEM STATS +// *************************************** + +#define RESPAWN_TIME_WEAPON 30 // seconds +#define RESPAWN_TIME_MACEBALL 60 // seconds +#define RESPAWN_TIME_DEFENSE 30 // seconds +#define RESPAWN_TIME_RING 20 // seconds +#define RESPAWN_TIME_TELEPORT 25 // seconds +#define RESPAWN_TIME_MORPH 40 // seconds +#define RESPAWN_TIME_AMMO 20 // seconds +#define RESPAWN_TIME_ARROWS 30 // seconds +#define RESPAWN_TIME_MISC 20 // seconds + + +// Ammunition usage +#define AMMO_USE_FIREBALL 2 +#define AMMO_USE_HELLSTAFF 1 +#define AMMO_USE_MAGICMISSILE 3 +#define AMMO_USE_REDRAIN 1 +#define AMMO_USE_SPHERE 7 +#define AMMO_USE_PHOENIX 1 +#define AMMO_USE_MACEBALL 12 +#define AMMO_USE_FIREWALL 5 + +#define MANA_USE_POWERUP 60 +#define MANA_USE_RING 5 +#define MANA_USE_SHIELD 20 +#define MANA_USE_TELEPORT 15 +#define MANA_USE_POLYMORPH 30 +#define MANA_USE_METEORS 5 // Five PER meteor: Total of 20 + + + +#define AMMO_COUNT_MOST 20 +#define AMMO_COUNT_REDRAINBOW 5 +#define AMMO_COUNT_PHOENIXBOW 5 +#define AMMO_COUNT_HELLSTAFF 50 + + +#define MAX_OFF_MANA 100 +#define MAX_DEF_MANA 100 +#define MAX_RAIN_AMMO 30 +#define MAX_PHOENIX_AMMO 20 +#define MAX_HELL_AMMO 200 + diff --git a/Toolkit/Programming/GameCode/game/g_light.c b/Toolkit/Programming/GameCode/game/g_light.c new file mode 100644 index 0000000..80e2eac --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_light.c @@ -0,0 +1,773 @@ +// +// g_light.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "fx.h" +#include "effectflags.h" +#include "g_local.h" +#include "g_misc.h" +#include "g_DefaultMessageHandler.h" +#include "vector.h" + +#define LIGHT_STARTOFF 8 + +#define LIGHT_NOHALO 16 + +static void TorchUse (edict_t *self, edict_t *other, edict_t *activator); +static void TorchStart (edict_t *self); +void SpawnClientAnim(edict_t *self, byte type, char *sound); +void create_fire_touch (edict_t *owner,vec3_t origin); + +void LightStaticsInit() +{ + +} + +void LightInit(edict_t *self) +{ + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_BBOX; + self->msgHandler = DefaultMsgHandler; + self->classID = CID_LIGHT; + self->takedamage = DAMAGE_NO; + + BboxYawAndScale(self); + + gi.linkentity (self); +} + +void TorchInit (edict_t *self) +{ + // no targeted lights in deathmatch, because they cause global messages + if (self->targetname && deathmatch->value) + { + G_FreeEdict (self); + return; + } + + if (self->style >= 32) + { + self->use = TorchUse; + + self->nextthink = level.time + 1.5; // If you don't wait a little they don't light right + self->think = TorchStart; + } +} + +void fire_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (!other->client) + return; + + if (self->touch_debounce_time > level.time) + return; + + self->touch_debounce_time = level.time + 1; + + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 0, + DAMAGE_AVOID_ARMOR|DAMAGE_FIRE|DAMAGE_FIRE_LINGER, MOD_BURNT); +} + +#define OBJ_NOPUSH 8 + +// This creates an entity that will burn the player if he's standing in the fire. + +void create_fire_touch (edict_t *owner,vec3_t origin) +{ + edict_t *flame; + + // Now create the flame. + + flame = G_Spawn(); + + VectorCopy(origin,flame->s.origin); + + flame->s.scale = owner->s.scale; + flame->dmg = 3 * owner->s.scale; + + VectorSet(flame->mins, -8, -8, -2); + VectorSet(flame->maxs, 8, 8, 14); + + flame->spawnflags |= OBJ_NOPUSH; + + flame->movetype = PHYSICSTYPE_NONE; + flame->touch = fire_touch; + + ObjectInit(flame,2,2,MAT_NONE,SOLID_TRIGGER); + + owner->enemy = flame; +} + +void SpawnFlame(edict_t *self,vec3_t origin) +{ + byte scale; + + // NOTE - LIMIT ON SCALE is x 8. + + if (self->s.scale >= 8.0) + scale = 255; + else + scale = self->s.scale * 32; + + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, + FX_FIRE, + CEF_BROADCAST, + origin, + "b",scale); + + create_fire_touch (self,origin); +} + + +/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF + + Non-displayed light. + Default light value is 300. + Default style is 0. + If targeted, will toggle between on and off. + Default _cone value is 10 (used to set size of light for spotlights) +*/ + +#define START_OFF 1 + +static void light_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->spawnflags & START_OFF) + { + gi.configstring (CS_LIGHTS+self->style, "m"); + self->spawnflags &= ~START_OFF; + } + else + { + gi.configstring (CS_LIGHTS+self->style, "a"); + self->spawnflags |= START_OFF; + } +} + +void SP_light (edict_t *self) +{ + // no targeted lights in deathmatch, because they cause global messages + if (!self->targetname || deathmatch->value) + { + G_FreeEdict (self); + return; + } + + if (self->style >= 32) + { + self->use = light_use; + if (self->spawnflags & START_OFF) + gi.configstring (CS_LIGHTS+self->style, "a"); + else + gi.configstring (CS_LIGHTS+self->style, "m"); + } +} + +#define FIRE_OFF 8 +#define FIRE_MOVEABLE 16 + +void fire_use (edict_t *self, edict_t *other, edict_t *activator) +{ + byte scale; + if (self->spawnflags & FIRE_OFF) + { + // NOTE - LIMIT ON SCALE is x 8 + if (self->s.scale >= 8.0) + scale = 255; + else + scale = self->s.scale * 32; + + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, + FX_FIRE, + CEF_BROADCAST, + self->s.origin, + "b",scale); + + create_fire_touch (self,self->s.origin); + + if (self->s.scale < 1) + self->s.sound = gi.soundindex("ambient/smallfire.wav"); + else + self->s.sound = gi.soundindex("ambient/fireplace.wav"); + self->s.sound_data = (127 & ENT_VOL_MASK) | ATTN_STATIC; + self->spawnflags &= ~FIRE_OFF; + } + else + { + gi.RemovePersistantEffect(self->PersistantCFX); + self->PersistantCFX = 0; + self->s.sound = 0; + gi.RemoveEffects(&self->s, FX_FIRE); + self->spawnflags |= FIRE_OFF; + G_FreeEdict(self->enemy); + + } +} + + +void firemove_think(edict_t *self) +{ + byte scale; + + scale = self->s.scale * 8; + + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, + FX_FIRE_ON_ENTITY, + CEF_BROADCAST | CEF_OWNERS_ORIGIN, + self->s.origin, + "bbb",scale,0,1); + + self->think = NULL; +} + +/*QUAKED env_fire (1 .5 0) (0 -10 -24) (20 10 0) INVULNERABLE ANIMATE EXPLODING FIRE_OFF MOVEABLE LIGHT_ON +A fire about the size of a campfire. Triggerable. +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +FIRE_OFF - fire will start off +MOVEABLE - fire will move if given a velocity +LIGHT_ON - fire will have light attached to it - if moveable, not required +----------------------------------- +scale - size of flame (default 1) (no bigger than 8) +*/ +void SP_env_fire (edict_t *self) +{ + byte scale; + int flags; + edict_t *controller; + + + if (!self->s.scale) + self->s.scale = 1; + + if (self->targetname) + { + self->use = fire_use; + controller = G_Find(NULL, FOFS(target), self->targetname); + if(controller) + {//set it up to throw firey chunks + if(controller->materialtype == MAT_WOOD) + { + controller->svflags |= SVF_ONFIRE; + } + } + } + + + if (self->spawnflags & FIRE_MOVEABLE) + { + VectorSet(self->mins, -2, -2, -2); + VectorSet(self->maxs, 2, 2, 2); + self->mass = 250; + self->friction = 0; + self->gravity = 0; + self->s.effects |= EF_NODRAW_ALWAYS_SEND|EF_ALWAYS_ADD_EFFECTS; +// self->svflags |= SVF_ALWAYS_SEND; + self->movetype = PHYSICSTYPE_FLY; + + self->model = 0; + self->solid = SOLID_NOT; + self->clipmask = MASK_MONSTERSOLID; + + } + else + { + VectorSet(self->mins, 0, -10, -24); + VectorSet(self->maxs, 20, 10, 0); + self->s.effects |= EF_NODRAW_ALWAYS_SEND|EF_ALWAYS_ADD_EFFECTS; + } + + gi.linkentity(self); + + if (self->spawnflags & FIRE_OFF) + return; + + if (self->s.scale < 1) + self->s.sound = gi.soundindex("ambient/smallfire.wav"); + else + self->s.sound = gi.soundindex("ambient/fireplace.wav"); + self->s.sound_data = (127 & ENT_VOL_MASK) | ATTN_STATIC; + + // NOTE - LIMIT ON SCALE is x 8 + if (self->s.scale >= 8.0) + scale = 255; + else + scale = self->s.scale * 32; + + if (self->spawnflags & FIRE_MOVEABLE) + { + self->think = firemove_think; + self->nextthink = level.time + 2; + } + + // add a light or no ? + flags = CEF_BROADCAST; + if (self->spawnflags & 32) + flags |= CEF_FLAG6; + + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, + FX_FIRE, + flags, + self->s.origin, + "b",scale); + + create_fire_touch (self,self->s.origin); +} + +static void TorchUse (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->spawnflags & LIGHT_STARTOFF) + { + gi.configstring (CS_LIGHTS+self->style, "m"); + self->spawnflags &= ~LIGHT_STARTOFF; + } + else + { + gi.configstring (CS_LIGHTS+self->style, "a"); + self->spawnflags |= LIGHT_STARTOFF; + } +} + +static void TorchStart (edict_t *self) +{ + if (self->spawnflags & LIGHT_STARTOFF) + { + gi.configstring (CS_LIGHTS+self->style, "a"); + } + else + { + gi.configstring (CS_LIGHTS+self->style, "m"); + } + + self->think = NULL; +} + + +/*QUAKED light_walltorch (1 .5 0) (-16 -10 -12) (10 10 12) INVULNERABLE ANIMATE EXPLODING STARTOFF +A torch that sticks out of a wall +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - Places a flame on it +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +----------------------------------- +*/ +void SP_light_walltorch (edict_t *self) +{ + vec3_t holdorigin; + + self->s.modelindex = gi.modelindex("models/objects/lights/walltorch/tris.fm"); + self->s.sound = gi.soundindex("ambient/smallfire.wav"); + self->s.sound_data = (127 & ENT_VOL_MASK) | ATTN_STATIC; + + VectorSet(self->mins, -16, -10, -12); + VectorSet(self->maxs, 10, 10, 12); + + LightInit(self); + + if (self->spawnflags & 2) // Animate it + { + VectorCopy(self->s.origin,holdorigin); + holdorigin[2] += 28; + SpawnFlame(self,holdorigin); + } + + TorchInit(self); + +} + +/*QUAKED light_floortorch (1 .5 0) (-14 -14 -17) (14 14 17) INVULNERABLE ANIMATE EXPLODING STARTOFF +A stand for a torch that sits on the floor. +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - Places a flame on it +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +----------------------------------- +*/ +void SP_light_floortorch (edict_t *self) +{ + vec3_t holdorigin; + + self->s.modelindex = gi.modelindex("models/objects/lights/floortorch/tris.fm"); + self->s.sound = gi.soundindex("ambient/smallfire.wav"); + self->s.sound_data = (127 & ENT_VOL_MASK) | ATTN_STATIC; + + VectorSet(self->mins, -14, -14, -18); + VectorSet(self->maxs, 14, 14, 18); + + LightInit(self); + + if (self->spawnflags & 2) // Animate it + { + VectorCopy(self->s.origin,holdorigin); + holdorigin[2] += 33; + SpawnFlame(self,holdorigin); + } + + TorchInit(self); +} + + +/*QUAK-ED light_flame (1 .5 0) (-16 -16 0) (16 16 34) INVULNERABLE ANIMATE EXPLODING STARTOFF +A 30 frame flame. +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +----------------------------------- +*/ +/*void SP_light_flame (edict_t *self) +{ + VectorSet(self->mins, -16, -16, -34); + VectorSet(self->maxs, 16, 16, 0); + + self->nextthink = level.time + 2; + self->think = flamethink; + + LightInit(self); + + TorchInit(self); +} +*/ + + + +/*QUAKED light_torch1 (1 .5 0) (-4 -6 -5) (6 6 20) INVULNERABLE ANIMATE EXPLODING STARTOFF NOHALO +Wall torch that uses a blue gem +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +NOHALO - turns off halo effect +----------------------------------- +*/ +void SP_light_torch1 (edict_t *self) +{ + vec3_t origin, vf; + + self->s.modelindex=gi.modelindex("models/objects/lights/sinkcity/light-3/tris.fm"); + + VectorSet(self->mins, -4, -6, -5); + VectorSet(self->maxs, 6, 6, 20); + + LightInit(self); + + VectorCopy(self->s.origin, origin); + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(origin, 2, vf, origin); + + origin[2] += 16; + + if (!(self->spawnflags & LIGHT_NOHALO)) + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_HALO, CEF_FLAG6|CEF_FLAG7, origin, ""); + + TorchInit(self); +} + +/*QUAKED light_gem2 (1 .5 0) (-1 -6 -8) (4 6 8) INVULNERABLE ANIMATE EXPLODING STARTOFF NOHALO +A yellow gem in an octogonal frame +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +NOHALO - turns off halo effect +----------------------------------- +style +- 0 yellow light +- 1 green light + +*/ +void SP_light_gem2 (edict_t *self) +{ + vec3_t origin; + + self->s.modelindex = gi.modelindex("models/objects/lights/sinkcity/light-2/tris.fm"); + + VectorSet(self->mins, -1, -6, -8); + VectorSet(self->maxs, 4, 6, 8); + + if (self->style == 1) + self->s.skinnum = 1; + + LightInit(self); + + VectorCopy(self->s.origin, origin); + + if (!(self->spawnflags & LIGHT_NOHALO)) + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_HALO, CEF_FLAG6|CEF_FLAG8, origin, ""); + + TorchInit(self); +} + +/*QUAKED light_chandelier1 (1 .5 0) (-36 -36 -43) (34 34 43) INVULNERABLE ANIMATE EXPLODING STARTOFF +A big gold chandelier for the great hall +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +----------------------------------- +*/ +void SP_light_chandelier1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chandelier/chan1/tris.fm"); + + VectorSet(self->mins, -36, -36,-43); + VectorSet(self->maxs, 36, 36, 43); + + LightInit(self); + TorchInit(self); +} + + +/*QUAKED light_chandelier2 (1 .5 0) (-18 -18 -40) (18 18 40) INVULNERABLE ANIMATE EXPLODING STARTOFF +A very heavy chandelier that doesn't have a skin yet. +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - The flame flickers +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +----------------------------------- +*/ +void SP_light_chandelier2 (edict_t *self) +{ + VectorSet(self->mins, -18, -18, -40); + VectorSet(self->maxs, 18, 18, 40); + + SpawnClientAnim(self, FX_ANIM_CHANDELIER2, NULL); + + LightInit(self); + TorchInit(self); +} + +/*QUAKED light_chandelier3 (1 .5 0) (-34 -34 -80) (34 34 0) INVULNERABLE ANIMATE EXPLODING STARTOFF +A thin gold chandelier +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +----------------------------------- +*/ +void SP_light_chandelier3 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chandelier/chan3/tris.fm"); + + VectorSet(self->mins, -34, -34,-80); + VectorSet(self->maxs, 34, 34, 0); + + LightInit(self); + + TorchInit(self); +} + +/*QUAKED light_lantern1 (1 .5 0) (-28 -8 -22) (4 8 22) INVULNERABLE ANIMATE EXPLODING STARTOFF NOHALO +lantern on a wooden arm +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +NOHALO - turns off halo effect +----------------------------------- +*/ +void SP_light_lantern1 (edict_t *self) +{ + vec3_t origin; + + self->s.modelindex = gi.modelindex("models/objects/lights/lantern-1/tris.fm"); + + VectorSet(self->mins, -28, -8,-22); + VectorSet(self->maxs, 4, 8, 22); + + LightInit(self); + + VectorCopy(self->s.origin, origin); + origin[2] -=10; + + if (!(self->spawnflags & LIGHT_NOHALO)) + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_HALO, 0, origin, ""); + + TorchInit(self); +} + +/*QUAKED light_lantern2 (1 .5 0) (-6 -6 -24) (6 6 40) INVULNERABLE ANIMATE EXPLODING STARTOFF NOHALO +Lanern on a chain +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +NOHALO - turns off halo effect +----------------------------------- +*/ +void SP_light_lantern2 (edict_t *self) +{ + vec3_t origin; + + self->s.modelindex = gi.modelindex("models/objects/lights/lantern-2/tris.fm"); + + VectorSet(self->mins, -6, -6,-24); + VectorSet(self->maxs, 6, 6, 40); + + LightInit(self); + + VectorCopy(self->s.origin, origin); + origin[2] -=10; + + if (!(self->spawnflags & LIGHT_NOHALO)) + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_HALO, 0, origin, ""); + + TorchInit(self); +} + +/*QUAKED light_lantern3 (1 .5 0) (-6 -6 -12) (6 6 11) INVULNERABLE ANIMATE EXPLODING STARTOFF NOHALO +Ceiling lantern +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +NOHALO - turns off halo effect +----------------------------------- +*/ +void SP_light_lantern3 (edict_t *self) +{ + vec3_t origin; + + self->s.modelindex = gi.modelindex("models/objects/lights/lantern-3/tris.fm"); + + VectorSet(self->mins, -6, -6,-12); + VectorSet(self->maxs, 6, 6, 11); + + LightInit(self); + + VectorCopy(self->s.origin, origin); + origin[2] -=2; + + if (!(self->spawnflags & LIGHT_NOHALO)) + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_HALO, 0, origin, ""); + + TorchInit(self); +} + +/*QUAKED light_lantern4 (1 .5 0) (-18 -7 -7) (7 7 14) INVULNERABLE ANIMATE EXPLODING STARTOFF NOHALO +Wall lantern +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +NOHALO - turns off halo effect +----------------------------------- +*/ +void SP_light_lantern4 (edict_t *self) +{ + vec3_t origin; + + self->s.modelindex = gi.modelindex("models/objects/lights/lantern-4/tris.fm"); + + VectorSet(self->mins, -18, -7,-7); + VectorSet(self->maxs, 7, 7, 14); + + LightInit(self); + + VectorCopy(self->s.origin, origin); + + if (!(self->spawnflags & LIGHT_NOHALO)) + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_HALO, 0, origin, ""); + + TorchInit(self); +} + +/*QUAKED light_lantern5 (1 .5 0) (-7 -7 -7) (7 7 14) INVULNERABLE ANIMATE EXPLODING STARTOFF NOHALO +Lantern to place on a table +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +NOHALO - turns off halo effect +----------------------------------- +*/ +void SP_light_lantern5 (edict_t *self) +{ + vec3_t origin; + + self->s.modelindex = gi.modelindex("models/objects/lights/lantern-4/tris.fm"); + + VectorSet(self->mins, -7, -7,-7); + VectorSet(self->maxs, 7, 7, 14); + + LightInit(self); + + VectorCopy(self->s.origin, origin); + self->s.frame = 1; + + if (!(self->spawnflags & LIGHT_NOHALO)) + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_HALO, 0, origin, ""); + + TorchInit(self); +} + + + +/*QUAKED light_buglight (1 .5 0) (-7 -7 -7) (7 7 25) INVULNERABLE ANIMATE EXPLODING STARTOFF NOHALO +A light shaped like a bug +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +STARTOFF - Light will start off if targeted (default is on) +NOHALO - turns off halo effect +----------------------------------- +*/ +void SP_light_buglight (edict_t *self) +{ + vec3_t origin; + + self->s.modelindex = gi.modelindex("models/objects/lights/bug/tris.fm"); + + VectorSet(self->mins, -7, -7,-7); + VectorSet(self->maxs, 7, 7, 25); + + LightInit(self); + + VectorCopy(self->s.origin, origin); + self->s.frame = 1; + + if (!(self->spawnflags & LIGHT_NOHALO)) + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_HALO, 0, origin, ""); + + TorchInit(self); +} + + +/*QUAKED env_sun1 (1 .5 0) (-12 -12 0) (12 12 38) INVULNERABLE ANIMATE EXPLODING +Places two suns in the world and attaches a lens flare to them. +One sun is blue, the other is yellow +*/ +void SP_env_sun1 (edict_t *self) +{ + vec3_t origin; + + self->solid = SOLID_NOT; + self->movetype = PHYSICSTYPE_NONE; + +// VectorSet(origin, 200, -100, 4000); + +// gi.CreatePersistantEffect(NULL, FX_LENSFLARE, CEF_FLAG7, origin, "ibbbf", -1, (byte) 64, (byte) 64, (byte) 146, 0.75); + + VectorSet(origin, 200, -100, 4000); + gi.CreatePersistantEffect(NULL, FX_LENSFLARE, CEF_FLAG7 | CEF_FLAG6, origin, "ibbbf", -1, (byte) 128, (byte) 108, (byte) 64, 0.75); +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_local.h b/Toolkit/Programming/GameCode/game/g_local.h new file mode 100644 index 0000000..7703add --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_local.h @@ -0,0 +1,1325 @@ +// g_local.h -- local definitions for game module. + +#ifndef G_LOCAL_H +#define G_LOCAL_H + +#include "q_shared.h" +#include "q_ClientServer.h" +#include "buoy.h" + +#if 0 +#define G_NOAMMO +#endif + +// Defined so I can insert hooks into code without breaking anything +#define PAGAN 0 + +// Define GAME_INCLUDE so that game.h does not define the short, server-visible 'gclient_t' and +// 'edict_t' structures because we define the game versions in this file. + +#define GAME_INCLUDE + +#include "game.h" +#include "p_types.h" + +// The "gameversion" client command will print this plus compile date. + +#if DEMO_CODE +#define GAMEVERSION "Heretic2Dmo" +#else +#define GAMEVERSION "Heretic2 v1" +#endif + +// Protocol bytes that can be directly added to messages. + +#define svc_layout 1 +#define svc_inventory 2 + + +// volume mask for ent->sound_data - makes room for attn value in the lower bits +#define ENT_VOL_MASK 0xf8 + +// ************************************************************************************************ +// AI_MOOD_XXX +// ------------- +// Held in 'edict_t'->ai_mood. Used by higher level AI functions to relay states to lower functions +// ************************************************************************************************ + +#define AI_MOOD_NORMAL 0 //Not using any high level functionality (TEMP) +#define AI_MOOD_ATTACK 1 //Used in conjuntion with ai_mood_flags to attack the target +#define AI_MOOD_NAVIGATE 2 //Just walk towards the guide, ignoring everything else +#define AI_MOOD_STAND 3 //Just stand there and wait to be adivsed +#define AI_MOOD_PURSUE 4 //Run towards your enemy but don't attack +#define AI_MOOD_FALLBACK 5 //Back away from your enemy, but face him +#define AI_MOOD_DELAY 6 //Same as stand, but will allow interruption anywhere +#define AI_MOOD_WANDER 7 //Wandering around buoy to buoy in a walk +#define AI_MOOD_JUMP 8 //Jump towards goalentity +#define AI_MOOD_REST 9 //The Ogle at rest +#define AI_MOOD_POINT_NAVIGATE 10 //Navigate to a point, not an entity +#define AI_MOOD_FLEE 11 //run away! +#define AI_MOOD_BACKUP 12 //backstep while attacking +#define AI_MOOD_WALK 13 //walking, no buoys +#define AI_MOOD_EAT 14 //sitting around, eating + +// ************************************************************************************************ +// AI_MOOD_FLAG_XXX +// ------------- +// Held in 'edict_t'->ai_mood_flags. Used in conjuction with ai_mood +// ************************************************************************************************ + +#define AI_MOOD_FLAG_MISSILE 0x00000001 //Check for a missile attack +#define AI_MOOD_FLAG_MELEE 0x00000002 //Check for a melee attack +#define AI_MOOD_FLAG_WHIP 0x00000004 //Check for a whipping attack (no damage) +#define AI_MOOD_FLAG_PREDICT 0x00000008 //Monster will predict movement on target +#define AI_MOOD_FLAG_IGNORE 0x00000010 //Monster will ignore moods +#define AI_MOOD_FLAG_FORCED_BUOY 0x00000020 //Monster will head towards it's forced_buoy +#define AI_MOOD_FLAG_IGNORE_ENEMY 0x00000040 //Monster will ignore it's enemy unless attacked or otherwise directed +#define AI_MOOD_FLAG_BACKSTAB 0x00000080 //Monster will advance on and attack enemy only from behind +#define AI_MOOD_FLAG_DUMB_FLEE 0x00000100 //Monster will flee by simply running directly away from player +#define AI_MOOD_FLAG_GOTO_FIXED 0x00000200 //Monster will become fixed upon getting to it's forced_buoy +#define AI_MOOD_FLAG_GOTO_STAND 0x00000400 //Monster will stand upon getting to it's forced_buoy +#define AI_MOOD_FLAG_GOTO_WANDER 0x00000800 //Monster will wander upon getting to it's forced_buoy +#define AIMF_CANT_FIND_ENEMY 0x00001000 //Monster can't find enemy with buoys or vision +#define AIMF_SEARCHING 0x00002000 //Monster now in dumb search mode... + +// ************************************************************************************************ +// SPAWNFLAG_XXX +// ------------- +// Held in 'edict_t'->spawnflags. These are set with checkboxes on each entity in the map editor. +// ************************************************************************************************ + +#define SPAWNFLAG_NOT_EASY 0x00000100 +#define SPAWNFLAG_NOT_MEDIUM 0x00000200 +#define SPAWNFLAG_NOT_HARD 0x00000400 +#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800 +#define SPAWNFLAG_NOT_COOP 0x00001000 + +// ************************************************************************************************ +// Timing constants that define the world heartbeat. +// ************************************************************************************************ + +#define FRAMETIME 0.1 +#define MONSTER_THINK_INC 0.099 +#define FRAMES_PER_SECOND 10.0 + +// ************************************************************************************************ +// TAG_XXX +// ------- +// Memory tags to allow dynamic memory to be selectively cleaned up. +// ************************************************************************************************ + +#define TAG_GAME 765 // clear when unloading the dll +#define TAG_LEVEL 766 // clear when loading a new level + +// ************************************************************************************************ +// damage_t +// -------- +// ************************************************************************************************ + +typedef enum +{ + DAMAGE_NO, + DAMAGE_YES, // Will take damage if hit. + DAMAGE_AIM, // Auto targeting recognizes this. + DAMAGE_NO_RADIUS, // Will not take damage from radius blasts +} damage_t; + +#define GIB_ORGANIC 1 + +#define BODY_QUEUE_SIZE 8 + +// ************************************************************************************************ +// RANGE_XXX +// --------- +// ************************************************************************************************ + +#define RANGE_MELEE 0 +#define RANGE_NEAR 1 +#define RANGE_MID 2 +#define RANGE_FAR 3 + +#define MELEE_DISTANCE 80 + +// ************************************************************************************************ +// ARMOR_XXX +// ---------- +// Armor types. +// ************************************************************************************************ + +#define ARMOR_NONE 0 +#define ARMOR_JACKET 1 +#define ARMOR_COMBAT 2 +#define ARMOR_BODY 3 +#define ARMOR_SHARD 4 + +// ************************************************************************************************ +// SHRINE_XXX +// ---------- +// ************************************************************************************************ + +enum +{ + SHRINE_MANA, + SHRINE_LUNGS, + SHRINE_ARMOR_SILVER, + SHRINE_ARMOR_GOLD, + SHRINE_LIGHT, + SHRINE_SPEED, + SHRINE_HEAL, + SHRINE_STAFF, + SHRINE_GHOST, + SHRINE_REFLECT, + SHRINE_POWERUP, + SHRINE_RANDOM +}; + +// ************************************************************************************************ +// SFL_CROSS_TRIGGER_XXX +// --------------------- +// game.'serverflags' values. +// ************************************************************************************************ + +#define SFL_CROSS_TRIGGER_1 0x00000001 +#define SFL_CROSS_TRIGGER_2 0x00000002 +#define SFL_CROSS_TRIGGER_3 0x00000004 +#define SFL_CROSS_TRIGGER_4 0x00000008 +#define SFL_CROSS_TRIGGER_5 0x00000010 +#define SFL_CROSS_TRIGGER_6 0x00000020 +#define SFL_CROSS_TRIGGER_7 0x00000040 +#define SFL_CROSS_TRIGGER_8 0x00000080 +#define SFL_CROSS_TRIGGER_MASK 0x000000ff + +#define MAX_MESSAGESTRINGS 1000 +typedef struct +{ + char *string; + char *wav; +} trig_message_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + extern trig_message_t message_text[]; +#ifdef __cplusplus +} +#endif + +unsigned *messagebuf; + +// ************************************************************************************************ +// game_locals_t +// ------------- +// This structure is left intact through an entire game. It should be initialized at game.dll load +// time and read from / written to the 'server.ssv' file for savegames. +// ************************************************************************************************ + +typedef struct +{ + char helpmessage1[512]; + char helpmessage2[512]; + + // Flash F1 icon if not 0, play sound and increment only if 1, 2, or 3. + + int helpchanged; + + // [maxclients]. + + gclient_t *clients; + + // Needed for co-op respawns... can't store spawnpoint in level, because it would get + // overwritten by the savegame restore. + + char spawnpoint[512]; + + // Store latched cvars that we want to get at often here. + + int maxclients; + int maxentities; + + //updated every frame in DM, for pick-up and shrine respawn times + int num_clients; + + // Cross level triggers. + + int serverflags; + + // Items. + + int num_items; + + // Flag that we've autosaved. + + qboolean autosaved; + + qboolean entitiesSpawned; + +} game_locals_t; + +#include "ICScript.h" + +// ************************************************************************************************ +// alertent_t +// --------- +// This structure is used for alert entities, which are spawned a lot +// ************************************************************************************************ +#define MAX_ALERT_ENTS 1024//no more that 1024 alertents allowed +typedef struct alertent_s alertent_t; +struct alertent_s +{ + alertent_t *next_alert; + alertent_t *prev_alert; + edict_t *enemy; + vec3_t origin; + qboolean inuse; + int alert_svflags; + float lifetime; +}; + +// ************************************************************************************************ +// level_locals_t +// -------------- +// This structure is cleared as each map is entered. It is read/written to the 'level.sav' file for +// savegames. +// ************************************************************************************************ + +typedef struct +{ + int framenum; + float time; + + char level_name[MAX_QPATH]; // The descriptive name (e.g. 'Outer Base'). + char mapname[MAX_QPATH]; // The server name (e.g. 'base1'). + char nextmap[MAX_QPATH]; // Go here when fraglimit is hit. + + // Intermission state information. + + float intermissiontime; // Time the intermission was started. + char *changemap; + int exitintermission; + vec3_t intermission_origin; + vec3_t intermission_angle; + + edict_t *sight_client; // Changed once each frame for coop games. + + edict_t *sight_entity; + int sight_entity_framenum; + + int pic_health; + + int total_secrets; + int found_secrets; + + int total_goals; + int found_goals; + + int total_monsters; + int killed_monsters; + + float far_clip_dist_f; + float fog; + float fog_density; + + edict_t *current_entity; // Entity running from G_RunFrame(). + int body_que; // Dead bodies. + + ICScript_t inGameCin; + qboolean cinActive; + + buoy_t buoy_list[MAX_MAP_BUOYS]; //Buoy information for this map + int active_buoys; //Number of actual buoys on the level + int fucked_buoys; //Number of buoys that can't be fixed + int fixed_buoys; //Number of buoys that had to be fixed + + int player_buoy[MAX_CLIENTS]; //stores current bestbuoy for a player enemy (if any) + int player_last_buoy[MAX_CLIENTS]; //when player_buoy is invalid, saves it here so monsters can check it first instead of having to do a whole search + + + int offensive_weapons, + defensive_weapons; + + alertent_t alertents[MAX_ALERT_ENTS]; //all the alert ents on the map + int num_alert_ents; //Number of actual alert entities on the level + alertent_t *alert_entity, //the alert entity linked list start + *last_alert; //the last entity in alert entity linked list + + qboolean fighting_beast; //fighting a beast, do extra checks with trace instant weapons + +} level_locals_t; + +// ************************************************************************************************ +// MOD_XXX +// ------- +// Means of death. +// ************************************************************************************************ + +typedef enum +{ + MOD_UNKNOWN , + + MOD_STAFF , + MOD_FIREBALL , + MOD_MMISSILE , + MOD_SPHERE , + MOD_SPHERE_SPL , + MOD_IRONDOOM , + MOD_FIREWALL , + MOD_STORM , + MOD_PHOENIX , + MOD_PHOENIX_SPL , + MOD_HELLSTAFF , + + MOD_P_STAFF , + MOD_P_FIREBALL , + MOD_P_MMISSILE , + MOD_P_SPHERE , + MOD_P_SPHERE_SPL , + MOD_P_IRONDOOM , + MOD_P_FIREWALL , + MOD_P_STORM , + MOD_P_PHOENIX , + MOD_P_PHOENIX_SPL , + MOD_P_HELLSTAFF , + + MOD_KICKED , + MOD_METEORS , + MOD_ROR , + MOD_SHIELD , + MOD_CHICKEN , + MOD_TELEFRAG , + MOD_WATER , + MOD_SLIME , + MOD_LAVA , + MOD_CRUSH , + MOD_FALLING , + MOD_SUICIDE , + MOD_BARREL , + MOD_EXIT , + MOD_BURNT , + MOD_BLEED , + MOD_SPEAR , + MOD_DIED , + MOD_KILLED_SLF , + MOD_DECAP , + MOD_MAX +} MOD_t; + +#define MOD_FRIENDLY_FIRE 0x8000000 + +// ************************************************************************************************ +// spawn_temp_t +// ------------ +// This is used to hold entity field values that can be set from the editor, but aren't actualy +// present in 'edict_t' during gameplay. +// ************************************************************************************************ + +typedef struct +{ + // Sky variables. + + char *sky; + float skyrotate; + vec3_t skyaxis; + + // Nextmap. Is this used? + + char *nextmap; + + int lip; + int distance; + int height; + char *noise; + float pausetime; + char *item; + char *gravity; + + float minyaw; + float maxyaw; + float minpitch; + float maxpitch; + int rotate; + float zangle; + char *file; + int radius; + + // Weapons to be given to the player on spawning. + + int offensive; + int defensive; + int spawnflags2; + + // Time to wait (in seconds) for all clients to have joined a map in coop. + + int cooptimeout; + + // Scripting stuff. + + char *script; + char *parms[16]; +} spawn_temp_t; + +// ************************************************************************************************ +// moveinfo_t +// ---------- +// This is used to hold information pertaining to an entity's movement. +// ************************************************************************************************ + +typedef struct +{ + // Fixed data. + + vec3_t start_origin; + vec3_t start_angles; + vec3_t end_origin; + vec3_t end_angles; + + int sound_start; + int sound_middle; + int sound_end; + + float accel; + float speed; + float decel; + float distance; + + float wait; + + // State data. + + int state; + vec3_t dir; + float current_speed; + float move_speed; + float next_speed; + float remaining_distance; + float decel_distance; + void (*endfunc)(edict_t *); +} moveinfo_t; + +// ************************************************************************************************ +// AI_XXX +// ------ +// Monster AI flags. +// ************************************************************************************************ + +#define AI_STAND_GROUND 0x00000001 +#define AI_TEMP_STAND_GROUND 0x00000002 +#define AI_SOUND_TARGET 0x00000004 +#define AI_LOST_SIGHT 0x00000008 +#define AI_PURSUIT_LAST_SEEN 0x00000010 +#define AI_PURSUE_NEXT 0x00000020 +#define AI_PURSUE_TEMP 0x00000040 +#define AI_HOLD_FRAME 0x00000080 +#define AI_GOOD_GUY 0x00000100 +#define AI_BRUTAL 0x00000200 +#define AI_NOSTEP 0x00000400 //1024 +#define AI_DUCKED 0x00000800 +#define AI_COMBAT_POINT 0x00001000 +#define AI_EATING 0x00002000 +#define AI_RESURRECTING 0x00004000 +#define AI_FLEE 0x00008000 +#define AI_FALLBACK 0x00010000 +#define AI_COWARD 0x00020000 //Babies (FLEE to certain distance & WATCH) +#define AI_AGRESSIVE 0x00040000 //never run away +#define AI_SHOVE 0x00080000 //shove others out of the way. +#define AI_DONT_THINK 0x00100000 //animate, don't think or move +#define AI_SWIM_OK 0x00200000 //ok to go in water +#define AI_OVERRIDE_GUIDE 0x00400000 +#define AI_NO_MELEE 0x00800000 //not allowed to melee +#define AI_NO_MISSILE 0x01000000 //not allowed to missile +#define AI_USING_BUOYS 0x02000000 //Using Buoyah! Navigation System(tm) +#define AI_STRAIGHT_TO_ENEMY 0x04000000 //Charge straight at enemy no matter what anything else tells you +#define AI_NIGHTVISION 0x08000000 //light level does not effect this monster's vision or aim +#define AI_NO_ALERT 0x10000000 //monster does not pay attemntion to alerts + +// ************************************************************************************************ +// AS_XXX +// ------ +// Monster attack states. +// ************************************************************************************************ + +#define AS_STRAIGHT 1 +#define AS_SLIDING 2 +#define AS_MELEE 3 +#define AS_MISSILE 4 +#define AS_DIVING 5 + +// ************************************************************************************************ +// C_ANIM_XXX +// ------ +// Cinmatic Animation flags +// ************************************************************************************************ +#define C_ANIM_MOVE 1 +#define C_ANIM_REPEAT 2 +#define C_ANIM_DONE 4 +#define C_ANIM_IDLE 8 + +// ************************************************************************************************ +// OBJ_XXX +// ------ +// Flags for object entities +// ************************************************************************************************ +#define OBJ_INVULNERABLE 1 +#define OBJ_ANIMATE 2 +#define OBJ_EXPLODING 4 +#define OBJ_NOPUSH 8 + + +// ************************************************************************************************ +// SIGHT_XXX +// ------ +// Type of target aquisition +// ************************************************************************************************ +#define SIGHT_SOUND_TARGET 0 //Heard the target make this noise +#define SIGHT_VISIBLE_TARGET 1 //Saw this target +#define SIGHT_ANNOUNCED_TARGET 2 //Target was announced by another monster + + +// ************************************************************************************************ +// mframe_t +// -------- +// ************************************************************************************************ + +typedef struct +{ + int framenum; // Index to current animation frame. + void (*aifunc)(edict_t *self, float dist); // AI function for this animation frame. + float dist; // Distance the AI function should move the + // entity this frame. + void (*thinkfunc)(edict_t *self); // Think function for this frame. +} mframe_t; + +// ************************************************************************************************ +// mmove_t +// ------- +// ************************************************************************************************ + +typedef struct +{ + int framecount; // Number of frames in the animation frame array. + mframe_t *frame; + void (*endfunc)(edict_t *self); +} mmove_t; + + +// ************************************************************************************************ +// animframe_t +// ----------- +// ************************************************************************************************ + +typedef struct +{ + int framenum; + void (*movefunc)(edict_t *self, float var1, float var2, float var3); + float var1, var2, var3; + void (*actionfunc)(edict_t *self, float var4); + float var4; + void (*thinkfunc)(edict_t *self); +} animframe_t; + +// ************************************************************************************************ +// animmove_t +// ---------- +// ************************************************************************************************ + +typedef struct +{ + int numframes; + animframe_t *frame; + void (*endfunc)(edict_t *self); +} animmove_t; + + +// ************************************************************************************************ +// c_animflags_t +// ---------- +// ************************************************************************************************ +typedef struct +{ + qboolean moving; // Does this action support moving + qboolean repeat; // Does this action support repeating + qboolean turning; // Does this action support turning +} c_animflags_t; + + +// ************************************************************************************************ +// monsterinfo_t +// ------------- +// ************************************************************************************************ + +typedef struct +{ +// Not used in new system + char *otherenemyname; // ClassName of secondary enemy (other than player). + // E.g. a Rat's secondary enemy is a gib. + + animmove_t *currentmove; + int aiflags; + int aistate; // Last order given to the monster (ORD_XXX). + int currframeindex; // Index to current monster frame. + int nextframeindex; // Used to force the next frameindex. + float thinkinc; // Time between thinks for this entity. + float scale; + + void (*idle)(edict_t *self); + void (*search)(edict_t *self); + void (*dodge)(edict_t *self, edict_t *other, float eta); + int (*attack)(edict_t *self); + void (*sight)(edict_t *self, edict_t *other); + void (*dismember)(edict_t *self, int damage, int HitLocation); + qboolean (*alert)(edict_t *self, alertent_t *alerter, edict_t *enemy); + qboolean (*checkattack)(edict_t *self); + + float pausetime; + float attack_finished; + float flee_finished; // When a monster is done fleeing + float chase_finished; // When the monster can look for secondary monsters. + + vec3_t saved_goal; + float search_time; + float misc_debounce_time; + vec3_t last_sighting; + int attack_state; + int lefty; + float idle_time; + int linkcount; + + int searchType; + vec3_t nav_goal; + float jump_time; + + int stepState; + + int ogleflags; //Ogles have special spawnflags stored in here at spawntime + + int supporters; //Number of supporting monsters (with common type) in the area when awoken + + float sound_finished; //Amount of time until the monster will be finishing talking (used for voices) + float sound_start; //The amount of time to wait before playing the pending sound + int sound_pending; //This monster is waiting to make a sound (used for voices) (0 if false, else sound ID) + + // Cinematic fields + int c_dist; // Distance left to move + int c_repeat; // # of times to repeat the anim cycle + void (*c_callback)(struct edict_s *self); // Callback function when action is done + int c_anim_flag; // Shows if current cinematic anim supports moving, turning, or repeating + qboolean c_mode; // in cinematic mode or not? + edict_t *c_ent; // entity passed from a cinematic command + + qboolean awake; // has found an anemy AND gone after it. + qboolean roared; // Gorgon has roared or been woken up by a roar + + float last_successful_enemy_tracking_time; //last time successfully saw enemy or found a path to him + float coop_check_debounce_time; +} monsterinfo_t; + +// ************************************************************************************************ +// aceldata_t +// ---------- +// ************************************************************************************************ + +typedef struct +{ + animmove_t *move; + void (*animfunc)(edict_t *self, int animcell); + short fly; + short lockmove; + int playerflags; +} aceldata_t; + +// ************************************************************************************************ +// acelsizes_t +// ----------- +// ************************************************************************************************ + +typedef struct +{ + vec3_t boundbox[2]; + int altmove; + float viewheight; + float waterheight; +} acelsizes_t; + +// The structure for each monster class. + +#define FOFS(x) (int)&(((edict_t *)0)->x) +#define STOFS(x) (int)&(((spawn_temp_t *)0)->x) +#define LLOFS(x) (int)&(((level_locals_t *)0)->x) +#define CLOFS(x) (int)&(((gclient_t *)0)->x) +#define BYOFS(x) (int)&(((buoy_t *)0)->x) + +extern game_locals_t game; +#ifdef __cplusplus +extern "C" +{ +#endif +extern level_locals_t level; +extern edict_t *g_edicts; +extern game_import_t gi; +extern spawn_temp_t st; +extern game_export_t globals; +#ifdef __cplusplus +} +#endif + +extern int sm_meat_index; +extern int snd_fry; + +extern cvar_t *maxentities; +extern cvar_t *deathmatch; +extern cvar_t *coop; +extern cvar_t *dmflags; +extern cvar_t *skill; +extern cvar_t *fraglimit; +extern cvar_t *timelimit; +extern cvar_t *password; +extern cvar_t *g_select_empty; +extern cvar_t *dedicated; +extern cvar_t *filterban; + +extern cvar_t *sv_gravity; +extern cvar_t *sv_friction; +extern cvar_t *sv_maxvelocity; + +extern cvar_t *gun_x,*gun_y,*gun_z; +extern cvar_t *sv_rollspeed; +extern cvar_t *sv_rollangle; + +extern cvar_t *run_pitch; +extern cvar_t *run_roll; +extern cvar_t *bob_up; +extern cvar_t *bob_pitch; +extern cvar_t *bob_roll; + +extern cvar_t *sv_cheats; +extern cvar_t *sv_nomonsters; +extern cvar_t *blood_level; +extern cvar_t *showbuoys; +extern cvar_t *showlitebuoys; +extern cvar_t *mgai_debug; +extern cvar_t *deactivate_buoys; +extern cvar_t *anarchy; +extern cvar_t *impact_damage; +extern cvar_t *cheating_monsters; +extern cvar_t *singing_ogles; + + +#ifdef __cplusplus +extern "C" +{ +#endif + extern cvar_t *sv_cinematicfreeze; + extern cvar_t *sv_jumpcinematic; +#ifdef __cplusplus +} +#endif + +extern cvar_t *sv_freezemonsters; + +extern cvar_t *maxclients; +extern cvar_t *sv_maplist; + +extern cvar_t *autorotate; +extern cvar_t *blood; + +extern cvar_t *checkanim; // specifies whether monsters should check to see if most of the + // distance of a move animation is unobstructed before setting it + +extern cvar_t *monster_speeds; +extern cvar_t *pvs_cull; + +extern cvar_t *game_test; // sfs--for testing the speed impact of code changes + +extern cvar_t *player_dll; + +extern cvar_t *flood_msgs; +extern cvar_t *flood_persecond; +extern cvar_t *flood_waitdelay; +extern cvar_t *flood_killdelay; + +extern edict_t *g_edicts; +#define world (&g_edicts[0]) + +// ************************************************************************************************ +// 'DROPPED_XXX'. +// -------------- +// ************************************************************************************************ + +#define DROPPED_ITEM 0x00008000 +#define DROPPED_PLAYER_ITEM 0x00010000 + +// fields are needed for spawning from the entity string +// and saving / loading games + +#define FFL_SPAWNTEMP 1 + +// ************************************************************************************************ +// fieldtype_t +// ----------- +// ************************************************************************************************ + +typedef enum { + F_INT, + F_FLOAT, + F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL + F_GSTRING, // string on disk, pointer in memory, TAG_GAME + F_VECTOR, + F_ANGLEHACK, + F_EDICT, // index on disk, pointer in memory + F_ITEM, // index on disk, pointer in memory + F_CLIENT, // index on disk, pointer in memory + F_RGBA, + F_RGB, + F_IGNORE, +} fieldtype_t; + +// ************************************************************************************************ +// field_t +// ------- +// ************************************************************************************************ + +typedef struct +{ + char *name; + int ofs; + fieldtype_t type; + int flags; +} field_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + extern field_t fields[]; +#ifdef __cplusplus +} +#endif + +// +// g_cmds.c +// + +void Cmd_Help_f (edict_t *ent); +void Cmd_Score_f (edict_t *ent); + +// +// g_items.c +// + +void PrecacheItem (gitem_t *it); +void G_InitItems (void); +void SetItemNames (void); +edict_t *Drop_Item (edict_t *ent, gitem_t *item); +void SetRespawn (edict_t *ent); +void SpawnItem (edict_t *ent, gitem_t *item); +void SpawnItemEffect(edict_t *ent, gitem_t *item); +gitem_t *IsItem(edict_t *ent); +void Think_Weapon (edict_t *ent); +int ArmorIndex (edict_t *ent); +qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count); + +// +// g_utils.c +// + +qboolean KillBox (edict_t *ent); +void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result); + +#ifdef __cplusplus +extern "C" +{ +#endif + edict_t *G_Find (edict_t *from, int fieldofs, char *match); + edict_t *G_Spawn (void); +#ifdef __cplusplus +} +#endif + +edict_t *oldfindradius (edict_t *from, vec3_t org, float rad); +edict_t *findradius (edict_t *from, vec3_t org, float rad); +edict_t *findinblocking (edict_t *from, edict_t *checkent); +edict_t *findinbounds(edict_t *from, vec3_t min, vec3_t max); +edict_t *oldfindinbounds(edict_t *from, vec3_t min, vec3_t max); +edict_t *finddistance (edict_t *from, vec3_t org, float mindist, float maxdist); +edict_t *findonpath(edict_t *startent, vec3_t startpos, vec3_t endpos, vec3_t mins, vec3_t maxs, vec3_t *resultpos); +edict_t *G_PickTarget (char *targetname); + +//commonly used functions +int range (edict_t *self, edict_t *other); +qboolean clear_visible (edict_t *self, edict_t *other); +qboolean visible (edict_t *self, edict_t *other); +qboolean visible_pos (edict_t *self, vec3_t spot2); +qboolean infront (edict_t *self, edict_t *other); +qboolean infront_pos (edict_t *self, vec3_t pos); +qboolean ahead (edict_t *self, edict_t *other); + +void G_UseTargets (edict_t *ent, edict_t *activator); +void G_SetMovedir (vec3_t angles, vec3_t movedir); +void G_InitEdict (edict_t *e); +void G_FreeEdict (edict_t *e); +void G_SetToFree (edict_t *); +void G_TouchTriggers (edict_t *ent); +void G_TouchSolids (edict_t *ent); +void G_LinkMissile(edict_t *ent); +char *G_CopyString (char *in); +char *vtos (vec3_t v); +float vectoyaw (vec3_t vec); + +// +// g_combat.c +// + +qboolean CanDamage (edict_t *targ, edict_t *inflictor); +qboolean CanDamageFromLoc (edict_t *targ, edict_t *inflictor, vec3_t origin); +void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, + int damage, int knockback, int dflags,int MeansOfDeath); +void T_DamageRadius(edict_t *inflictor, edict_t *attacker, edict_t *ignore, float radius, + float maxdamage, float mindamage, int dflags,int MeansOfDeath); +void T_DamageRadiusFromLoc(vec3_t origin, edict_t *inflictor, edict_t *attacker, edict_t *ignore, float radius, + float maxdamage, float mindamage, int dflags,int MeansOfDeath); + +// ************************************************************************************************ +// DAMAGE_XXX +// ---------- +// ************************************************************************************************ + +#define DAMAGE_NORMAL 0x00000000 // No modifiers to damage +#define DAMAGE_RADIUS 0x00000001 // damage was indirect +#define DAMAGE_NO_KNOCKBACK 0x00000002 // do not affect velocity, just view angles +#define DAMAGE_ALL_KNOCKBACK 0x00000004 // Ignore damage +#define DAMAGE_EXTRA_KNOCKBACK 0x00000008 // throw in some extra z +#define DAMAGE_NO_PROTECTION 0x00000010 // invulnerability, and godmode have no effect +#define DAMAGE_NO_BLOOD 0x00000020 // don't spawn any blood +#define DAMAGE_EXTRA_BLOOD 0x00000040 // Lots of blood +#define DAMAGE_SPELL 0x00000080 // this came from a spell, - for use in calcing armor effects +#define DAMAGE_DISMEMBER 0x00000100 // Force this hit to use dismemberment message +#define DAMAGE_ATTACKER_IMMUNE 0x00000200 // Inflictor receives no effect +#define DAMAGE_ATTACKER_KNOCKBACK 0x00000400 // Inflictor takes knockback only +#define DAMAGE_REDRAIN 0x00000800 // Red rain acid damage +#define DAMAGE_BUBBLE 0x00001000 // Drowning damage +#define DAMAGE_FIRE 0x00002000 // Fire damage +#define DAMAGE_ALIVE_ONLY 0x00004000 // Only damage living things made of flesh +#define DAMAGE_BLEEDING 0x00008000 // No protection +#define DAMAGE_AVOID_ARMOR 0x00010000 // don't do the armor effect +#define DAMAGE_DOUBLE_DISMEMBER 0x00020000 // Force this hit to use dismemberment message with TWICE the chance of cutting +#define DAMAGE_HURT_FRIENDLY 0x00040000 // Always hurt friendly entities (e.g. fellow coop players). +#define DAMAGE_POWERPHOENIX 0x00080000 // Extra knockback to shooter, 1/4 damage. +#define DAMAGE_FIRE_LINGER 0x00100000 // Do extra fire linger damage. +#define DAMAGE_ENEMY_MAX 0x00200000 // Do maximum damage directly to the enemy in radius +#define DAMAGE_ONFIRE 0x00400000 // If the damage is FROM a fire... + +#define DAMAGE_SUFFOCATION (DAMAGE_NO_KNOCKBACK|DAMAGE_NO_BLOOD|DAMAGE_BUBBLE|DAMAGE_AVOID_ARMOR) +#define DAMAGE_LAVA (DAMAGE_NO_KNOCKBACK|DAMAGE_NO_BLOOD|DAMAGE_FIRE|DAMAGE_AVOID_ARMOR) +#define DAMAGE_SLIME (DAMAGE_NO_KNOCKBACK|DAMAGE_NO_BLOOD|DAMAGE_AVOID_ARMOR) +#define DAMAGE_BURNING (DAMAGE_ONFIRE|DAMAGE_NO_KNOCKBACK|DAMAGE_NO_BLOOD|DAMAGE_FIRE|DAMAGE_AVOID_ARMOR) + +// +// g_monster.c +// + +void M_droptofloor (edict_t *ent); +void monster_think (edict_t *self); +qboolean walkmonster_start (edict_t *self); +qboolean swimmonster_start (edict_t *self); +qboolean flymonster_start (edict_t *self); +void AttackFinished (edict_t *self, float time); +void PauseTime(edict_t *self, float time); +void monster_death_use (edict_t *self); +void M_CatagorizePosition (edict_t *ent); +qboolean M_CheckAttack (edict_t *self); +void M_CheckGround (edict_t *ent); + +// +// g_misc.c +// + +void ThrowClientHead (edict_t *self, int damage); +void ThrowGib (edict_t *self, char *gibname, int damage, int type); +void BecomeExplosion1(edict_t *self); + +// +// g_ai.c +// + +void AI_SetSightClient (void); +void ai_stand (edict_t *self, float dist); +void ai_move (edict_t *self, float dist); +void ai_walk (edict_t *self, float dist); +void ai_turn (edict_t *self, float dist); +void ai_run (edict_t *self, float dist); +void ai_charge (edict_t *self, float dist); +void ai_eat (edict_t *self, float dist); +void ai_generic(edict_t *self); +void ai_flee(edict_t *self, float dist); +int range (edict_t *self, edict_t *other); +void FoundTarget (edict_t *self, qboolean setsightent); +qboolean infront (edict_t *self, edict_t *other); +qboolean visible (edict_t *self, edict_t *other); +qboolean FacingIdeal(edict_t *self); + +// +// g_client.c +// + +void respawn (edict_t *ent); +void BeginIntermission (edict_t *targ); +void PutClientInServer (edict_t *ent); +void InitClientPersistant (edict_t *player); +void InitClientResp (gclient_t *client); +void InitBodyQue (void); +void ClientBeginServerFrame (edict_t *ent); +int SexedSoundIndex (edict_t *ent, char *base); + +// +// g_player.c +// + +int player_pain (edict_t *self, edict_t *other, float kick, int damage); +int player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); +void player_dismember (edict_t *self, edict_t *other, int damage, int HitLocation); +void ResetPlayerBaseNodes (edict_t *ent); +void player_repair_skin (edict_t *self); + +// +// g_svcmds.c +// + +void ServerCommand (void); +qboolean SV_FilterPacket (char *from); + +// +// p_view.c +// + +extern void ClientEndServerFrame(edict_t *ent); +extern qboolean CheckButton(edict_t *self); +extern void SetupPlayerinfo(edict_t *ent); +extern void WritePlayerinfo(edict_t *ent); +extern void SetupPlayerinfo_effects(edict_t *ent); +extern void WritePlayerinfo_effects(edict_t *ent); + +// +// p_hud.c +// + +void MoveClientToIntermission(edict_t *client); +void MoveClientsToIntermission(vec3_t ViewOrigin,vec3_t ViewAngles); +void G_SetStats (edict_t *ent); +void ValidateSelectedItem (edict_t *ent); +void SelectPrevItem (edict_t *ent, int itflags); +void SelectNextItem (edict_t *ent, int itflags); +void DeathmatchScoreboardMessage (edict_t *client, edict_t *killer); + +// +// g_pweapon.c +// + +void PlayerNoise(edict_t *who, vec3_t where, int type); + +// +// m_move.c +// + +qboolean M_CheckBottom (edict_t *ent); +qboolean M_CheckTop (edict_t *ent); +qboolean M_walkmove (edict_t *ent, float yaw, float dist); +void M_MoveToGoal (edict_t *ent, float dist); +float M_ChangeYaw (edict_t *ent); +void M_ChangePitch (edict_t *ent); +void M_MoveAwayFromGoal (edict_t *ent, float dist); + +// +// g_phys.c +// + +void G_RunEntity (edict_t *ent); + +// +// g_main.c +// + +void SaveClientData (void); +void FetchClientEntData (edict_t *ent); + + +// +// g_breakable.c +// +void KillBrush(edict_t *targ,edict_t *inflictor,edict_t *attacker,int damage); + + + +// +// g_obj.c +// +void ObjectInit(edict_t *self,int health,int mass, int materialtype,int solid); + + +// +// g_spawnf.c +// + +//sfs--this is used to get a classname for guys spawned while game is running +#ifdef __cplusplus +extern "C" +{ +#endif + char *ED_NewString (char *string); + void ED_CallSpawn (edict_t *ent); +#ifdef __cplusplus +} +#endif + +//============================================================================ + + + + + + + + +// ************************************************************************************************ +// TRYSTEP_ +// -------- +// Used for ai_trystep (g_ai) +// ************************************************************************************************ + +#define TRYSTEP_OK 0 +#define TRYSTEP_ALLSOLID 1 +#define TRYSTEP_STARTSOLID 2 +#define TRYSTEP_OFFEDGE 3 +#define TRYSTEP_NOSUPPORT 4 +#define TRYSTEP_INWATER 5 + +// ************************************************************************************************ +// client_respawn_t +// ---------------- +// Client data that stays across deathmatch respawns. +// ************************************************************************************************ + +typedef struct +{ + client_persistant_t coop_respawn; // What to set 'client'->pers to on a respawn. + int enterframe; // The level.framenum when the client entered the game. + int score; // Frags, etc. + vec3_t cmd_angles; // Angles sent over in the last command. + int game_helpchanged; + int helpchanged; +} client_respawn_t; + +// ************************************************************************************************ +// gclient_t +// --------- +// This structure is cleared on each PutClientInServer() except for 'client->pers'. +// ************************************************************************************************ + +typedef struct gclient_s +{ + // The following two fields are known to the server. + + player_state_t ps; // Communicated by server to clients. + int ping; + + // All other fields below are private to the game. + + client_respawn_t resp; + pmove_state_t old_pmove; // For detecting out-of-pmove changes. + + // Damage stuff. Sum up damage over an entire frame. + + qboolean damage_gas; // Did damage come from plague mist? + int damage_blood; // Damage taken out of health. + int damage_knockback; // Impact damage. + vec3_t damage_from; // Origin for vector calculation. + + // + + usercmd_t pcmd; + short oldcmdangles[3]; + vec3_t aimangles; // Spell / weapon aiming direction. + vec3_t oldviewangles; + vec3_t v_angle; // Entity facing angles. + float bobtime; // So off-ground doesn't change it. + float next_drown_time; + int old_waterlevel; + + // Client can respawn when time > respawn_time. + + float respawn_time; + int complete_reset; + + // Remote and walkby camera stuff. + + int RemoteCameraLockCount; + int RemoteCameraNumber; + int savedtargetcount; + edict_t *savedtarget; + + // Teleport stuff. + + vec3_t tele_dest; + vec3_t tele_angles; + int tele_count; + int tele_type; /// Note only a byte of this is used. + int old_solid; + + // Weapon / defense stuff. + + edict_t *lastentityhit; + edict_t *Meteors[4]; + + // Powerup timers. + + float invincible_framenum; + + // Shrine stuff. + + float shrine_framenum; + + // Data for the player obituaries + + MOD_t meansofdeath; + + // Anti flooding vars + + float flood_locktill; // locked from talking + float flood_when[10]; // when messages were said + int flood_whenhead; // head pointer for when said + float flood_nextnamechange; // next time for valid nick change + float flood_nextkill; // next time for suicide + + playerinfo_t playerinfo; +} gclient_t; + +#include "g_BoundingForm.h" +#include "g_Edict.h" +#ifdef __cplusplus //this is for ds.cpp +#include "Vector.h" +#endif +qboolean FindTarget (edict_t *self); +void MG_PostDeathThink (edict_t *self); +qboolean movable (edict_t *ent); +qboolean EntReflecting(edict_t *ent, qboolean checkmonster, qboolean checkplayer); +void SkyFly (edict_t *self); + +//For simplicity of use.. take it out later + +#define BUOY_DEBUG showbuoys->value +#define BUOY_DEBUG_LITE showlitebuoys->value +#define MGAI_DEBUG mgai_debug->value +#define DEACTIVATE_BUOYS deactivate_buoys->value +#define ANARCHY anarchy->value +#define IMPACT_DAMAGE impact_damage->value +#define CHEATING_MONSTERS cheating_monsters->value + +// Scripts ds.cpp +#ifndef __cplusplus + void ProcessScripts(void); + void ShutdownScripts(qboolean Complete); + void SaveScripts(FILE *FH, qboolean DoGlobals); + void LoadScripts(FILE *FH, qboolean DoGlobals); +#endif + +#endif // G_LOCAL_H + diff --git a/Toolkit/Programming/GameCode/game/g_main.c b/Toolkit/Programming/GameCode/game/g_main.c new file mode 100644 index 0000000..62a5425 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_main.c @@ -0,0 +1,735 @@ +#include "g_local.h" +#include "g_Skeletons.h" +#include "ArrayedList.h" +#include "vector.h" +#include "g_Physics.h" +#include "g_volume_effect.h" +#include "PrimitiveDisplayHack.h" +#include "q_shared.h" +#include "timing.h" +#include "fx.h" +#include "Utilities.h" +#include "random.h" +#include "g_playstats.h" +#include "p_anims2.h" +#include "cl_strings.h" + +//Used for monster_speeds timing stuff +#ifdef _DEVEL +__int64 begin_monster_time, end_monster_time; +__int64 begin_ent_time, end_ent_time; +__int64 next_update, all, mt, cur_all, cur_mt; +int num_monsters, num_ents; +#endif //_DEVEL + +game_locals_t game; +level_locals_t level; +game_import_t gi; +game_export_t globals; +spawn_temp_t st; + +int sm_meat_index; +qboolean MonsterAdvanceFrame=false; + +//int snd_fry; + +edict_t *g_edicts; + +cvar_t *deathmatch; +cvar_t *coop; +cvar_t *dmflags; +cvar_t *skill; +cvar_t *fraglimit; +cvar_t *timelimit; +cvar_t *password; +cvar_t *maxclients; +cvar_t *maxentities; +cvar_t *sv_maplist; +cvar_t *g_select_empty; + +cvar_t *dedicated; +cvar_t *filterban; + +cvar_t *sv_maxvelocity; +cvar_t *sv_gravity; +cvar_t *sv_friction; + +cvar_t *sv_rollspeed; +cvar_t *sv_rollangle; +cvar_t *gun_x; +cvar_t *gun_y; +cvar_t *gun_z; + +cvar_t *run_pitch; +cvar_t *run_roll; +cvar_t *bob_up; +cvar_t *bob_pitch; +cvar_t *bob_roll; + +cvar_t *sv_cheats; +cvar_t *sv_nomonsters=NULL; +cvar_t *sv_freezemonsters; + +cvar_t *autorotate; +cvar_t *blood; + +cvar_t *checkanim; + +cvar_t *pvs_cull; + +cvar_t *showbuoys; +cvar_t *showlitebuoys; +cvar_t *mgai_debug; +cvar_t *deactivate_buoys; +cvar_t *anarchy; +cvar_t *impact_damage; +cvar_t *cheating_monsters; +cvar_t *singing_ogles; + +cvar_t *flood_msgs; +cvar_t *flood_persecond; +cvar_t *flood_waitdelay; +cvar_t *flood_killdelay; + +cvar_t *game_test; + +cvar_t *player_dll; + +cvar_t *sv_cinematicfreeze; +cvar_t *sv_jumpcinematic; +cvar_t *blood_level; + +void SpawnEntities (char *mapname, char *entities, char *spawnpoint, qboolean loadgame); +void ClientThink (edict_t *ent, usercmd_t *cmd); +qboolean ClientConnect (edict_t *ent, char *userinfo); +void ClientUserinfoChanged (edict_t *ent, char *userinfo); +void ClientDisconnect (edict_t *ent); +void ClientBegin (edict_t *ent); +void ClientCommand (edict_t *ent); +void RunEntity (edict_t *ent); +void WriteGame (char *filename, qboolean autosave); +void ReadGame (char *filename); +void WriteLevel (char *filename); +void ReadLevel (char *filename); +void InitGame (void); +void G_RunFrame (void); +void ConstructEntities(void); +void CheckCoopTimeout(qboolean BeenHereBefore); +void ClearMessageQueues(); + +//=================================================================== + +/* +================= +ShutdownGame +================= +*/ +void ShutdownGame (void) +{ + void G_ReleaseResourceManagers(); + + edict_t *ent; + int i; + + gi.dprintf ("==== ShutdownGame ====\n"); + + ShutdownScripts(true); + + if(game.entitiesSpawned) + { + ClearMessageQueues(); + + for(i = 0, ent = g_edicts; i < game.maxentities ; ++i, ++ent) + { + SLList_Des(&ent->msgQ.msgs); + G_FreeEdict(ent); + } + + G_ReleaseResourceManagers(); + } + game.entitiesSpawned = false; + + gi.FS_FreeFile(messagebuf); + + gi.FreeTags(TAG_LEVEL); + gi.FreeTags(TAG_GAME); + + P_Freelib(); // free the player lib +} + + + +game_export_t *GetGameAPI (game_import_t *import) +{ + gi = *import; + + globals.apiversion = GAME_API_VERSION; + + globals.numSkeletalJoints = MAX_ARRAYED_SKELETAL_JOINTS; + globals.skeletalJoints = skeletalJoints; + globals.jointNodes = jointNodes; + + globals.Init = InitGame; + globals.Shutdown = ShutdownGame; + globals.SpawnEntities = SpawnEntities; + globals.ConstructEntities = ConstructEntities; + globals.CheckCoopTimeout= CheckCoopTimeout; + + globals.WriteGame = WriteGame; + globals.ReadGame = ReadGame; + globals.WriteLevel = WriteLevel; + globals.ReadLevel = ReadLevel; + + globals.ClientThink = ClientThink; + globals.ClientConnect = ClientConnect; + globals.ClientUserinfoChanged = ClientUserinfoChanged; + globals.ClientDisconnect = ClientDisconnect; + globals.ClientBegin = ClientBegin; + globals.ClientCommand = ClientCommand; + + globals.RunFrame = G_RunFrame; + + globals.ServerCommand = ServerCommand; + + globals.edict_size = sizeof(edict_t); + + memset(&game, 0, sizeof(game)); + + return &globals; +} + +//====================================================================== + + +/* +================= +ClientEndServerFrames +================= +*/ +void ClientEndServerFrames (void) +{ + int i; + edict_t *ent; + + // calc the player views now that all pushing + // and damage has been added + for (i=0 ; ivalue ; i++) + { + ent = g_edicts + 1 + i; + if (!ent->inuse || !ent->client) + continue; + ClientEndServerFrame (ent); + } + +} + +/* +================= +CreateTargetChangeLevel + +Returns the created target changelevel +================= +*/ +edict_t *CreateTargetChangeLevel(char *map) +{ + edict_t *ent; + + ent = G_Spawn (); + ent->classname = "target_changelevel"; + Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map); + ent->map = level.nextmap; + return ent; +} + +/* +================= +EndDMLevel + +The timelimit or fraglimit has been exceeded +================= +*/ +void EndDMLevel (void) +{ + edict_t *ent; + char *s, *t, *f; + static const char *seps = " ,\n\r"; + + // stay on same level flag + if ((int)dmflags->value & DF_SAME_LEVEL) + { + BeginIntermission (CreateTargetChangeLevel (level.mapname) ); + return; + } + + // see if it's in the map list + if (*sv_maplist->string) + { + s = strdup(sv_maplist->string); + f = NULL; + t = strtok(s, seps); + while (t != NULL) + { + if (Q_stricmp(t, level.mapname) == 0) + { + // it's in the list, go to the next one + t = strtok(NULL, seps); + if (t == NULL) + { // end of list, go to first one + if (f == NULL) // there isn't a first one, same level + BeginIntermission (CreateTargetChangeLevel (level.mapname) ); + else + BeginIntermission (CreateTargetChangeLevel (f) ); + } + else + { + BeginIntermission (CreateTargetChangeLevel (t) ); + } + free(s); + return; + } + if (!f) + { + f = t; + } + t = strtok(NULL, seps); + } + free(s); + } + + if (level.nextmap[0]) // go to a specific map + BeginIntermission (CreateTargetChangeLevel (level.nextmap) ); + else + { // search for a changelevel + ent = G_Find (NULL, FOFS(classname), "target_changelevel"); + if (!ent) + { // the map designer didn't include a changelevel, + // so create a fake ent that goes back to the same level + BeginIntermission (CreateTargetChangeLevel (level.mapname) ); + return; + } + BeginIntermission (ent); + } +} + +/* +================= +CheckDMRules +================= +*/ +void CheckDMRules (void) +{ + int i; + gclient_t *cl; + + if (level.intermissiontime) + return; + + if (!deathmatch->value) + return; + + if (timelimit->value) + { + if (level.time >= timelimit->value*60) + { + gi.Obituary (PRINT_HIGH, GM_TIMELIMIT, 0, 0); + EndDMLevel (); + return; + } + } + + if (fraglimit->value) + { + for (i=0 ; ivalue ; i++) + { + cl = game.clients + i; + if (!g_edicts[i+1].inuse) + continue; + + if (cl->resp.score >= fraglimit->value) + { + gi.Obituary (PRINT_HIGH, GM_FRAGLIMIT, 0, 0); + EndDMLevel (); + return; + } + } + } +} + + +/* +============= +ExitLevel +============= +*/ +void ExitLevel (void) +{ + char command [256]; + + Com_sprintf (command, sizeof(command), "gamemap \"%s\"\n", level.changemap); + gi.AddCommandString (command); + level.changemap = NULL; + level.exitintermission = 0; + level.intermissiontime = 0; + + ClientEndServerFrames (); + + ClearMessageQueues(); +} + +void CheckContinuousAutomaticEffects(edict_t *self) +{//only used for fire damage for now + edict_t *damager; + vec3_t checkpoint; + + if(self->fire_damage_time > level.time) + { + VectorCopy(self->s.origin, checkpoint); + checkpoint[2] += self->mins[2]; + checkpoint[2] += self->size[2] * 0.5; + if(gi.pointcontents(checkpoint) & (CONTENTS_WATER|CONTENTS_SLIME)) // Not lava + {//FIXME: make hiss and smoke too + gi.dprintf("%s fire doused\n", self->classname); + self->fire_damage_time = 0; + gi.RemoveEffects(&self->s, FX_FIRE_ON_ENTITY);//turn off CFX too + self->s.effects |= EF_MARCUS_FLAG1; // Use this to instead notify the fire to stop. + gi.CreateEffect(NULL, + FX_ENVSMOKE, + CEF_FLAG6, + checkpoint, + ""); + return; + } + + if(self->health <= 0) + return; + + if(self->fire_damage_enemy) + damager = self->fire_damage_enemy; + else + damager = world; + + if (self->client) + { // Take less damage than a monster. + if (!(((byte)(level.time*10))&0x07)) + { + T_Damage(self, damager, damager, vec3_origin, self->s.origin, vec3_origin, + 1, 0, DAMAGE_BURNING,MOD_BURNT); + } + } + else // For monsters + { // Only account for damage every .4 second. + if (!(((byte)(level.time*10))&0x03)) + { + T_Damage(self, damager, damager, vec3_origin, self->s.origin, vec3_origin, + irand(FIRE_LINGER_DMG_MIN, FIRE_LINGER_DMG_MAX), 0, DAMAGE_BURNING,MOD_BURNT); + } + //tint it darker brown as goes on? How to get back? no, scorched art would look better + } + + if(self->client) + { + if(self->client->playerinfo.lowerseq == ASEQ_ROLLDIVEF_W || self->client->playerinfo.lowerseq == ASEQ_ROLLDIVEF_R || self->client->playerinfo.lowerseq == ASEQ_ROLL_FROM_FFLIP || + self->client->playerinfo.upperseq == ASEQ_ROLLDIVEF_W || self->client->playerinfo.upperseq == ASEQ_ROLLDIVEF_R || self->client->playerinfo.upperseq == ASEQ_ROLL_FROM_FFLIP || + self->client->playerinfo.lowerseq == ASEQ_ROLL_L || self->client->playerinfo.lowerseq == ASEQ_ROLL_R || self->client->playerinfo.lowerseq == ASEQ_ROLL_B || + self->client->playerinfo.upperseq == ASEQ_ROLL_L || self->client->playerinfo.upperseq == ASEQ_ROLL_R || self->client->playerinfo.upperseq == ASEQ_ROLL_B) + { + float waterlevel; + + waterlevel = self->waterlevel/5.0; + if (self->watertype & CONTENTS_LAVA) + waterlevel = 0; + self->fire_damage_time -= (0.15 + (waterlevel*0.5));//stop, drop and roll! + } + } + } + else if(self->fire_damage_time>0) + { + self->fire_damage_time = 0; + gi.RemoveEffects(&self->s, FX_FIRE_ON_ENTITY);//turn off CFX too + self->s.effects |= EF_MARCUS_FLAG1; // Use this to instead notify the fire to stop. + return; + } + +} + +static void EntityThink(edict_t *self) +{ + float thinktime; + + //see if anything is happening to us we need to update... + CheckContinuousAutomaticEffects(self); + + thinktime = self->nextthink; + + if(self->pre_think && self->next_pre_think > 0.0f && self->next_pre_think < level.time) + {//not used for guides anymore, but nice for effects + //like tinting/fading, etc that should continue + //while the entity is doing other stuff + self->pre_think(self); + } + if(!ThinkTime(self)) + { + return; + } + self->think(self); + + assert(!self->inuse || !self->think || thinktime != self->nextthink); + //NOTENOTE: This is a Quake oldy... it's common practice to do this! + /*assert(self->nextthink == -1);*/ +} + +static void EntityPostThink(edict_t *self) +{ + if(self->post_think && self->next_post_think > 0.0f && self->next_post_think < level.time) + {//for effects that rely on accurate physics info + self->post_think (self); + } +} + +static void SetNumPlayers (void) +{ + int i; + edict_t *ent; + + ent = g_edicts; + game.num_clients = 0; + for(i = 0; i < MAX_CLIENTS; i++, ent++) + {//If player hasn't moved, don't clear this + if(ent) + { + if(ent->client) + { + game.num_clients++; + } + } + } +} + +static void UpdatePlayerBuoys (void) +{ + qboolean dont_null; + int i, j; + edict_t *ent; + vec3_t v; + + for(i = 0; i NULL_BUOY) + { + ent = g_edicts; + for(j = 0; j < globals.num_edicts; j++, ent++) + {//If player hasn't moved, don't clear this + if(ent->s.number - 1 == i) + { + VectorSubtract(level.buoy_list[level.player_buoy[i]].origin, ent->s.origin, v); + if(VectorLengthSquared(v) > 576)//24 squared + dont_null = false; + else + dont_null = true; + break; + } + } + } + + if(!dont_null) + { + level.player_last_buoy[i] = level.player_buoy[i];//save it so monsters can check this first- FIXME: should this expire? + level.player_buoy[i] = NULL_BUOY;//this is for monsters following buoys- only the first monster who's searching for the player has to do a buoy connection to him this frame, the rest can use this- reset each frame + } + } +} + +/* +================ +G_RunFrame + +Advances the world by 0.1 seconds +================ +*/ +void G_RunFrame (void) +{ + void UpdateSkeletons(); + int i; + edict_t *ent; + +// void (*update)(edict_t *self); //old crap causing buoy crash + + qboolean SV_RunThink(edict_t *ent); + + if(deathmatch->value || coop->value) + Clamp(blood_level->value, VIOLENCE_NONE, VIOLENCE_NORMAL); + + // Update server ticks + level.framenum++; + level.time = level.framenum * FRAMETIME; + + // choose a client for monsters to target this frame + // Only targets one client for all monsters + AI_SetSightClient (); + + // exit intermissions + if (level.exitintermission) + { + ExitLevel (); + return; + } + + // Update any joints that need to be + UpdateSkeletons(); + + //Keep track of player buoys + if(!deathmatch->value) + UpdatePlayerBuoys(); + else + SetNumPlayers();//for shrines and pick-ups + + // + // treat each object in turn + // even the world gets a chance to think + // + ent = g_edicts; + for(i = 0; i < globals.num_edicts; i++, ent++) + { + + if (sv_cinematicfreeze->value) + { + if ((ent->svflags & SVF_MONSTER) && (!ent->monsterinfo.c_mode)) + continue; + } + + // If entity not in use - don`t process + if(!ent->inuse) + { +#ifdef BBOX_DISPLAY_HACK + DisableBBoxDisplay(i); +#endif + continue; + } + + // + // Don`t let monster think or move if its not in the PVS and not hunting + // + + // If the ent is a monster (but not a cinematic monster) and the culling is active... + + if ((ent->svflags & SVF_MONSTER) && (!ent->monsterinfo.c_mode) && pvs_cull->value) + { + // Ent cannot be hunting an enemy or moving to a goalentity. + + if (!ent->enemy && !ent->goalentity && level.sight_client) + { + int j; + edict_t *client_ent; + + // If not in our PVS, we don't care. + + for(j=0;jvalue;j++) + { + client_ent=g_edicts+1+j; + + if(client_ent->inuse) + { +// if (!gi.inPVS(ent->s.origin, level.sight_client->s.origin)) + if (!gi.inPVS(ent->s.origin, client_ent->s.origin)) + { + continue; + } + } + } + } + } + +#ifdef BBOX_DISPLAY_HACK + EnableBBoxDisplay(i); +#endif + level.current_entity = ent; + +#ifndef G_TRANSITION + assert(ent->msgHandler); +#else + if(ent->msgHandler) // eventually this check wont be needed +#endif // G_TRANSITION + { + ProcessMessages(ent); + } + + if(ent->flags & FL_SUSPENDED) + { + continue; + } + + // Remember original origin + VectorCopy(ent->s.origin, ent->s.old_origin); + + // Make sure the entity still has something to stand on + if(ent->groundentity) + { + // check for the groundentity being freed + if(!ent->groundentity->inuse) + { + ent->groundentity = NULL; + } + else if(ent->groundentity->linkcount != ent->groundentity_linkcount) + { // if the ground entity moved, make sure we are still on it + ent->groundentity = NULL; + + if(ent->svflags & SVF_MONSTER) + { + CheckEntityOn(ent); + } + } + } + + if (i > 0 && i <= maxclients->value) + { + ClientBeginServerFrame (ent); + // ok, we need to hack in some bits here - the players think function never appears to get called. Why, I don't know + // kinda defies the point of having a think based system if your not going to use it. Still, never mind. + // we need the think function for when the player is a chicken, in order to keep track of how long he should remain a chicken + + if (ent->flags & FL_CHICKEN) // We're set as a chicken + EntityThink(ent); + + continue; + } + + // Use new physics for everything except flymissile (and movetype none) + // The scripts work using the new physics now + if(ent->movetype != MOVETYPE_FLYMISSILE) + { + EntityThink(ent); + + assert(ent->movetype < NUM_PHYSICSTYPES); + + if(!ent->inuse) + { + continue; + } + + EntityPhysics(ent); + EntityPostThink(ent); + } + else + // Use old physics for missiles (for compatibility) + { + G_RunEntity(ent); + } + } + + // If the monsters are frozen, we wanted a single frame advance. + if (MonsterAdvanceFrame) + { + MonsterAdvanceFrame = false; + } + + ProcessScripts (); + + // see if it is time to end a deathmatch + CheckDMRules (); + + // build the playerstate_t structures for all players + ClientEndServerFrames (); + + assert(Vec3IsZero(vec3_origin)); +} + diff --git a/Toolkit/Programming/GameCode/game/g_misc.c b/Toolkit/Programming/GameCode/game/g_misc.c new file mode 100644 index 0000000..f61853f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_misc.c @@ -0,0 +1,2323 @@ +// g_misc.c + +#include "q_shared.h" +#include "g_DefaultMessageHandler.h" +#include "g_misc.h" +#include "g_local.h" +#include "FX.h" +#include "random.h" +#include "g_monster.h" +#include "vector.h" +#include "g_teleport.h" +#include "g_HitLocation.h" +#include "m_stats.h" +#include "g_playstats.h" + +void ED_CallSpawn (edict_t *ent); + +extern vec3_t mins; + +#define CAMERA_SCRIPTED 2 + +int AndoriaSoundID[AS_MAX] = +{ + AS_NOTHING, + AS_SMALLFOUNTAIN, + AS_LARGEFOUNTAIN, + AS_SEWERWATER, + AS_OUTSIDEWATERWAY, + AS_WINDCHIME, +}; + + + +int CloudSoundID[AS_MAX] = +{ + AS_NOTHING, + AS_CAULDRONBUBBLE, + AS_WINDEERIE, + AS_WINDNOISY, + AS_WINDSOFTHI, + AS_WINDSOFTLO, + AS_WINDSTRONG1, + AS_WINDSTRONG2, + AS_WINDWHISTLE, +}; + +int HiveSoundID[AS_MAX] = +{ + AS_NOTHING, + AS_GONG, + AS_WINDEERIE, + AS_WINDNOISY, + AS_WINDSOFTHI, + AS_WINDSOFTLO, + AS_WINDSTRONG1, + AS_WINDSTRONG2, + AS_WINDWHISTLE, +}; + +int MineSoundID[AS_MAX] = +{ + AS_NOTHING, + AS_MUDPOOL, + AS_ROCKS, + AS_WINDEERIE, + AS_WINDSOFTLO, + AS_CONVEYOR, + AS_BUCKETCONVEYOR, + AS_CAVECREAK, +}; + +int SilverSpringSoundID[AS_MAX] = +{ + AS_NOTHING, + AS_FIRE, + AS_WATERLAPPING, + AS_SEAGULLS, + AS_OCEAN, + AS_BIRDS, + AS_CRICKETS, + AS_FROGS, + AS_CRYING, + AS_MOSQUITOES, + AS_BUBBLES, + AS_BELL, + AS_FOOTSTEPS, + AS_MOANS, + AS_SEWERDRIPS, + AS_WATERDRIPS, + AS_HEAVYDRIPS, + AS_CAULDRONBUBBLE, + AS_SPIT, +}; + +int SwampCanyonSoundID[AS_MAX] = +{ + AS_NOTHING, + AS_BIRD1, + AS_BIRD2, + AS_HUGEWATERFALL, + AS_MUDPOOL, + AS_WINDEERIE, + AS_WINDNOISY, + AS_WINDSOFTHI, + AS_WINDSOFTLO, + AS_WINDSTRONG1, + AS_WINDSTRONG2, + AS_WINDWHISTLE, +}; + + +typedef struct DebrisSound +{ + char *Name; +} DebrisSound_t; + +DebrisSound_t DebrisSound [NUM_MAT]= +{ + "misc/breakstone.wav", // MAT_STONE + "misc/breakstone.wav", // MAT_GREYSTONE + "misc/tearcloth.wav", // MAT_CLOTH + "misc/metalbreak.wav", // MAT_METAL + "misc/fleshbreak.wav", // MAT_FLESH + "misc/potbreak.wav", // MAT_POTTERY + "misc/glassbreak2.wav", // MAT_GLASS + "misc/breakstone.wav", // MAT_LEAF FIXME + "misc/breakwood.wav", // MAT_WOOD + "misc/breakstone.wav", // MAT_BROWNSTONE + "misc/bushbreak.wav", // MAT_NONE + NULL, // MAT_INSECT +}; + + +/*QUAKED func_group (0 0 0) ? + + Used to group brushes together just for editor convenience. +*/ + +//===================================================== + +void Use_Areaportal (edict_t *ent, edict_t *other, edict_t *activator) +{ + ent->count ^= 1; // toggle state +// gi.dprintf ("portalstate: %i = %i\n", ent->style, ent->count); + gi.SetAreaPortalState (ent->style, ent->count); +} + +/*QUAKED func_areaportal (0 0 0) ? + + This is a non-visible object that divides the world into + areas that are seperated when this portal is not activated. + Usually enclosed in the middle of a door. +*/ +void SP_func_areaportal (edict_t *ent) +{ + ent->use = Use_Areaportal; + ent->count = 0; // allways start closed; +} + +//===================================================== + +/* +================= +Misc functions +================= +*/ + +void VelocityForDamage (int damage, vec3_t v) +{ + v[0] = flrand(-100.0F, 100.0F); + v[1] = flrand(-100.0F, 100.0F); + v[2] = flrand(200.0F, 300.0F); + + if (damage < 50) + VectorScale (v, 0.7, v); + else + VectorScale (v, 1.2, v); +} + +void ClipGibVelocity (edict_t *ent) +{ + if (ent->velocity[0] < -300) + ent->velocity[0] = -300; + else if (ent->velocity[0] > 300) + ent->velocity[0] = 300; + if (ent->velocity[1] < -300) + ent->velocity[1] = -300; + else if (ent->velocity[1] > 300) + ent->velocity[1] = 300; + if (ent->velocity[2] < 200) + ent->velocity[2] = 200; // always some upwards + else if (ent->velocity[2] > 500) + ent->velocity[2] = 500; +} + +/* +================= +gibs +================= +*/ + +void gib_think (edict_t *self) +{ + self->s.frame++; + self->nextthink = level.time + FRAMETIME; + + if (self->s.frame == 10) + { + self->think = G_FreeEdict; + self->nextthink = level.time + flrand(8.0F, 18.0F); + } +} + +void gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + vec3_t normal_angles, right; + + if (!self->groundentity) + return; + + self->touch = NULL; + + if (plane) + { +// gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0); + + vectoangles (plane->normal, normal_angles); + AngleVectors (normal_angles, NULL, right, NULL); + vectoangles (right, self->s.angles); + + if (self->s.modelindex == sm_meat_index) + { + self->s.frame++; + self->think = gib_think; + self->nextthink = level.time + FRAMETIME; + } + } +} + +int gib_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ + G_FreeEdict(self); + + return(0); +} + +void ThrowGib (edict_t *self, char *gibname, int damage, int type) +{ + edict_t *gib; + vec3_t vd; + vec3_t origin; + vec3_t size; + float vscale; + + gib=G_Spawn(); + + VectorScale (self->size, 0.5, size); + VectorAdd (self->absmin, size, origin); + VectorRandomAdd(origin, size, gib->s.origin); + + gi.setmodel (gib, gibname); + gib->solid = SOLID_NOT; + + gi.CreateEffect(&gib->s,FX_GIB_TRAIL,CEF_OWNERS_ORIGIN,gib->s.origin,NULL); + + gib->flags |= FL_NO_KNOCKBACK; + gib->takedamage = DAMAGE_YES; + gib->die = gib_die; + + if (type == GIB_ORGANIC) + { + gib->movetype = PHYSICSTYPE_STEP; + gib->touch = gib_touch; + vscale = 0.5; + } + else + { + gib->movetype = PHYSICSTYPE_STEP; + vscale = 1.0; + } + + VelocityForDamage (damage, vd); + VectorMA (self->velocity, vscale, vd, gib->velocity); + ClipGibVelocity (gib); + gib->avelocity[0] = flrand(-600, 600); + gib->avelocity[1] = flrand(-600, 600); + gib->avelocity[2] = flrand(-600, 600); + + gib->think = G_FreeEdict; + gib->nextthink = level.time + flrand(10.0, 20.0); + + gi.linkentity (gib); +} + +void BecomeExplosion1 (edict_t *self) +{ + gi.CreateEffect(NULL, FX_EXPLOSION1, 0, self->s.origin, NULL); + + G_FreeEdict (self); +} + +void BecomeExplosion2 (edict_t *self) +{ + gi.CreateEffect(NULL, FX_EXPLOSION2, 0, self->s.origin, NULL); + + G_FreeEdict (self); +} + +void SpawnDebris(edict_t *self, float size, vec3_t origin) +{ + byte sizeb, magb; + vec3_t halfsize; + float mag; + int flags = 0; + int violence=VIOLENCE_DEFAULT; + + size /=10; + sizeb = Clamp(size, 1.0, 255.0); + VectorScale(self->size, 0.5, halfsize); + mag = VectorLength(halfsize); + magb = Clamp(mag, 1.0, 255.0); + + if(self->fire_damage_time > level.time || self->svflags&SVF_ONFIRE) + flags |= CEF_FLAG6; + + if (self->materialtype == MAT_FLESH || self->materialtype == MAT_INSECT) + { + if (blood_level) + violence = blood_level->value; + + if(violence < VIOLENCE_NORMAL) + { + size /= 10; + sizeb = Clamp(size, 1.0, 255.0); + gi.CreateEffect(NULL, + FX_DEBRIS, + flags, origin, + "bbdb", + sizeb, + MAT_STONE, + halfsize, magb); + } + else + { + if(violence > VIOLENCE_NORMAL) + { + sizeb *= (violence - VIOLENCE_NORMAL); + if(sizeb > 255) + sizeb = 255; + } + + if(self->materialtype == MAT_INSECT) + flags |= CEF_FLAG8; + + if(!stricmp(self->classname, "monster_tcheckrik_male")) + flags |= CEF_FLAG7;//use male insect skin on chunks + + gi.CreateEffect(NULL, + FX_FLESH_DEBRIS, + flags, origin, + "bdb", + sizeb, + halfsize, magb); + } + } + else + { + if(self->s.renderfx & RF_REFLECTION) + flags |= CEF_FLAG8; + + gi.CreateEffect(NULL, + FX_DEBRIS, + flags, origin, + "bbdb", + sizeb, + (byte)self->materialtype, + halfsize, magb); + } + + if(self->classID == CID_OBJECT) + if(!strcmp(self->classname, "obj_larvabrokenegg") || !strcmp(self->classname, "obj_larvaegg")) + self->materialtype = MAT_POTTERY; + + if (DebrisSound[self->materialtype].Name) + gi.sound (self, CHAN_VOICE, gi.soundindex(DebrisSound[self->materialtype].Name) , + 2, ATTN_NORM, 0); +} + +void BecomeDebris2(edict_t *self, float damage) +{ + float size; + int violence=VIOLENCE_DEFAULT; + + if (blood_level) + violence = blood_level->value; + + if (violence > VIOLENCE_BLOOD) + { + if(!(self->svflags & SVF_PARTS_GIBBED)) + {//haven't yet thrown parts + if(self->monsterinfo.dismember) + {//FIXME:have a generic GibParts effect that throws flesh and several body parts- much cheaper? + int i, num_limbs; + + num_limbs = irand(3, 10); + + if(violence > VIOLENCE_NORMAL) + num_limbs *= (violence - VIOLENCE_NORMAL); + + for(i = 0; i < num_limbs; i++) + { + if(self->svflags&SVF_MONSTER) + self->monsterinfo.dismember(self, flrand(80, 160), irand(hl_Head, hl_LegLowerRight) | hl_MeleeHit); + } + self->svflags |= SVF_PARTS_GIBBED; + self->think = BecomeDebris; + self->nextthink = level.time + 0.1; + return; + } + } + } + // Set my message handler to the special message handler for dead entities. + self->msgHandler=DeadMsgHandler; + + //What the hell is this??? + if (self->spawnflags & 4 && !(self->svflags&SVF_MONSTER)) + { // Need to create an explosion effect for this + if(self->owner) + { + T_DamageRadius(self, self->owner, self, 60.0, + self->dmg, self->dmg/2, DAMAGE_NORMAL|DAMAGE_AVOID_ARMOR,MOD_DIED); + } + else + { + T_DamageRadius(self, self, self, 60.0, + self->dmg, self->dmg/2, DAMAGE_NORMAL|DAMAGE_AVOID_ARMOR,MOD_DIED); + } + } + + // A zero mass is well and truly illegal! + if (self->mass<0) + gi.dprintf("ERROR: %s needs a mass to generate debris",self->classname); + + // Create a chunk-spitting client effect and remove me now that I've been chunked. + + // This only yields 4, 8, 12, or 16 chunks, generally seems to yield 16 + if(self->svflags&SVF_MONSTER && self->classID != CID_MOTHER) + { + size = VectorLength(self->size); + size *= 100; + assert(size >= 0); + } + else + { + if (Vec3IsZero(self->s.origin)) + {// Set this brush up as if it were an object so the debris will be thrown properly + // If I'm a BModel (and therefore don't have an origin), calculate one to use instead and + // slap that into my origin. +// self->solid = SOLID_NOT; // This causes the breakable brushes to generate a sound + VectorMA(self->absmin,0.5,self->size,self->s.origin); + } + + size = VectorLength(self->size) * 3; + + if(self->solid == SOLID_BSP) + size *= 3; + else if(self->classID == CID_MOTHER) + size *= 10; + + if (!self->mass) + self->mass = size / 10; + } + + SpawnDebris(self, size, self->s.origin); + + self->s.modelindex = 0; + self->solid = SOLID_NOT; + self->deadflag = DEAD_DEAD; + + G_SetToFree(self); + self->nextthink = level.time + 2; +} + +void BecomeDebris(edict_t *self) +{ + if(self->health<0) + BecomeDebris2(self, abs(self->health)+10.0f); + else + BecomeDebris2(self, 10.0f); +} + +void SprayDebris(edict_t *self, vec3_t spot, byte NoOfChunks, float damage) +{ + byte magb, mat; + float mag, size; + int flags = 0; + int violence=VIOLENCE_DEFAULT; + + mag = VectorLength(self->mins); + + mat = (byte)(self->materialtype); + magb = Clamp(mag, 1.0, 255.0); + + if(mat == MAT_FLESH || mat == MAT_INSECT) + { + if (blood_level) + violence = blood_level->value; + + if (violence < VIOLENCE_NORMAL) + { + mat = MAT_STONE; + } + else if(violence > VIOLENCE_NORMAL) + { + NoOfChunks *= (violence - VIOLENCE_NORMAL); + if(NoOfChunks > 255) + NoOfChunks = 255; + } + } + + + if(mat == MAT_FLESH || mat == MAT_INSECT) + { + if(self->materialtype == MAT_INSECT) + { + flags |= CEF_FLAG8; + if(!stricmp(self->classname, "monster_tcheckrik_male")) + flags |= CEF_FLAG7;//use male insect skin on chunks + } + + if(self->fire_damage_time > level.time || self->svflags&SVF_ONFIRE) + flags |= CEF_FLAG6; + + gi.CreateEffect(NULL, + FX_FLESH_DEBRIS, + flags, + spot, + "bdb", + NoOfChunks, self->mins, magb); + } + else + { + size = (float)(NoOfChunks/100); + NoOfChunks = Clamp(size, 1.0, 255.0); + + gi.CreateEffect(NULL, + FX_DEBRIS, + flags, spot, + "bbdb", + NoOfChunks, + MAT_STONE, + self->mins, magb); + } +} + +void DefaultObjectDieHandler(edict_t *self, G_Message_t *msg) +{ + edict_t *inflictor; + + ParseMsgParms(msg, "ee", &inflictor, &inflictor); + + G_UseTargets(self, inflictor); + + if (self->target_ent) + BecomeDebris(self->target_ent); + + BecomeDebris(self); +} + +void harpy_take_head(edict_t *self, edict_t *victim, int BodyPart, int frame, int flags); +void ThrowBodyPart(edict_t *self, vec3_t *spot, int BodyPart, float damage, int frame) +{//add blood spew to sever loc and blood trail on flying part + float ke = 0; + vec3_t spot2; + int flags; + + if (damage) + { + if (damage>255) + { + damage = 255; + } + gi.sound (self, CHAN_VOICE, gi.soundindex("misc/fleshbreak.wav") , 1, ATTN_NORM, 0); + } + + VectorAdd(self->s.origin, *spot, spot2); + + if(self->fire_damage_time > level.time || self->svflags&SVF_ONFIRE) + flags = CEF_FLAG6; + else + flags = 0; + + if(self->materialtype == MAT_INSECT) + flags |= CEF_FLAG8; + + if(give_head_to_harpy && take_head_from == self) + { + harpy_take_head(give_head_to_harpy, self, BodyPart, frame, flags); + SprayDebris(self, *spot, 5, damage); + return; + } + + gi.CreateEffect(NULL,//owner + FX_BODYPART,//type + flags,//can't mess with this, sends only 1st byte and effects message + spot2,//spot, + "ssbbb",//int int float byte + (short)frame,//only 1 frame, sorry no anim + (short)BodyPart,//bitwise - node(s) to leave on + (byte)damage,//speed + self->s.modelindex,//my modelindex + self->s.number);//my number +} + +void ThrowWeapon(edict_t *self, vec3_t *spot, int BodyPart, float damage, int frame) +{//same but no blood and metal sound when hits ground + vec3_t spot2; + + if (damage>255) + { + damage = 255; + } + + VectorAdd(self->s.origin, *spot, spot2); + gi.CreateEffect(NULL,//owner + FX_THROWWEAPON,//type + 0,//can't mess with this, sends only 1st byte and effects message + spot2,//spot, + "ssbbb",// int int float byte + (short)frame,//only 1 frame, sorry no anim + (short)BodyPart,//bitwise - node(s) to leave on + (byte)damage,//speed + self->s.modelindex,//my modelindex + self->s.number);//my number +} + +/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT +---------KEYS--------------- +target - target name of next path corner +pathtarget - used when an entity that has this path_corner targeted touches it +angles - used to make the brush rotate. The brush MUST have an origin brush in it. It is an + accumulative value so if the value is 0 40 0 the brush rotate an additional 40 degrees along + the y axis before it reaches this path corner. +wait - -1 makes trains stop until retriggered + -3 trains explode upon reaching this path corner + +noise - file to play when corner is hit (trains only) +-objects/bucket.wav +*/ + +void path_corner_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + vec3_t v; + edict_t *next; + + if (other->movetarget != self) + return; + + if (other->enemy) + return; + + + if (self->pathtarget) + { + char *savetarget; + + savetarget = self->target; + self->target = self->pathtarget; + G_UseTargets (self, other); + self->target = savetarget; + } + + if (self->target) + next = G_PickTarget(self->target); + else + next = NULL; + + if ((next) && (next->spawnflags & MSF_AMBUSH)) + { + VectorCopy (next->s.origin, v); + v[2] += next->mins[2]; + v[2] -= other->mins[2]; + VectorCopy (v, other->s.origin); + next = G_PickTarget(next->target); + } + + other->goalentity = other->movetarget = next; + + if (self->wait) + { + other->monsterinfo.pausetime = level.time + self->wait; + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +// M_GiveOrder(ORD_STAND,other,other,PR_LOW, 0,0,0,0,0,0); +// other->monsterinfo.stand (other); + return; + } + + + if (!other->movetarget) + { + other->monsterinfo.pausetime = level.time + 100000000; + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +// M_GiveOrder(ORD_STAND,other,other,PR_LOW, 0,0,0,0,0,0); +// other->monsterinfo.stand (other); + } + else + { + VectorSubtract (other->goalentity->s.origin, other->s.origin, v); + other->ideal_yaw = vectoyaw (v); + } + + +} + +void SP_path_corner (edict_t *self) +{ + if (!self->targetname) + { + gi.dprintf ("path_corner with no targetname at %s\n", vtos(self->s.origin)); + G_FreeEdict (self); + return; + } + + if (st.noise) + self->moveinfo.sound_middle = gi.soundindex (st.noise); + + self->solid = SOLID_TRIGGER; + self->movetype = PHYSICSTYPE_NONE; + self->touch = path_corner_touch; + VectorSet (self->mins, -8, -8, -8); + VectorSet (self->maxs, 8, 8, 8); + self->svflags |= SVF_NOCLIENT; + gi.linkentity (self); +} + +/*QUAKED point_combat (0.5 0.3 0) (-8 -8 -8) (8 8 8) Hold + + Makes this the target of a monster and it will head here + when first activated before going after the activator. If + hold is selected, it will stay here. + + NOTE FROM MG: Probably still works... will test +*/ +void point_combat_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + edict_t *activator; + + if (other->movetarget != self) + return;//wasn't purposely heading for me + + if (self->target) + { + other->target = self->target; + other->goalentity = other->movetarget = G_PickTarget(other->target); + if (!other->goalentity) + { + gi.dprintf("%s at %s target %s does not exist\n", self->classname, vtos(self->s.origin), self->target); + other->movetarget = self; + } + self->target = NULL; + } + else if ((self->spawnflags & 1) && !(other->flags & (FL_SWIM|FL_FLY))) + {//HOLD + other->spawnflags |= MSF_FIXED;//stay here forever now + QPostMessage(other, MSG_STAND, PRI_DIRECTIVE, NULL); + } + + if (other->movetarget == self) + { + other->target = NULL; + other->movetarget = NULL; + other->goalentity = other->enemy; + other->monsterinfo.aiflags &= ~AI_COMBAT_POINT; + } + + if (self->pathtarget) + { + char *savetarget; + + savetarget = self->target; + self->target = self->pathtarget; + if (other->enemy && other->enemy->client) + activator = other->enemy; + else if (other->oldenemy && other->oldenemy->client) + activator = other->oldenemy; + else if (other->activator && other->activator->client) + activator = other->activator; + else + activator = other; + G_UseTargets (self, activator); + self->target = savetarget; + } +} + +void SP_point_combat (edict_t *self) +{ + self->solid = SOLID_TRIGGER; + self->touch = point_combat_touch; + VectorSet (self->mins, -8, -8, -16); + VectorSet (self->maxs, 8, 8, 16); + self->svflags = SVF_NOCLIENT; + gi.linkentity (self); +}; + + +/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4) + + Used as a positional target for spotlights, etc. +*/ +void SP_info_null (edict_t *self) +{ + G_FreeEdict (self); +}; + + +/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4) + + Used as a positional target for lightning. +*/ +void SP_info_notnull (edict_t *self) +{ + VectorCopy (self->s.origin, self->absmin); + VectorCopy (self->s.origin, self->absmax); + + self->solid = SOLID_TRIGGER; + self->movetype = PHYSICSTYPE_NONE; + +}; + + +/*QUAKED func_wall (0 .5 .8) ? TRIGGER_SPAWN TOGGLE START_ON ANIMATED ANIMATED_FAST + + This is just a solid wall if not inhibited + + TRIGGER_SPAWN the wall will not be present until triggered + it will then blink in to existance; it will + kill anything that was in it's way + + TOGGLE only valid for TRIGGER_SPAWN walls + this allows the wall to be turned on and off + + START_ON only valid for TRIGGER_SPAWN walls + the wall will initially be present +*/ +void func_wall_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->solid == SOLID_NOT) + { + self->solid = SOLID_BSP; + self->svflags &= ~SVF_NOCLIENT; + KillBox (self); + } + else + { + self->solid = SOLID_NOT; + self->svflags |= SVF_NOCLIENT; + } + gi.linkentity (self); + + if (!(self->spawnflags & 2)) + self->use = NULL; +} + +void SP_func_wall (edict_t *self) +{ + self->movetype = PHYSICSTYPE_PUSH; + gi.setmodel (self, self->model); + + if (self->spawnflags & 8) + self->s.effects |= EF_ANIM_ALL; + if (self->spawnflags & 16) + self->s.effects |= EF_ANIM_ALLFAST; + + // just a wall + if ((self->spawnflags & 7) == 0) + { + self->solid = SOLID_BSP; + gi.linkentity (self); + return; + } + + // it must be TRIGGER_SPAWN + if (!(self->spawnflags & 1)) + { +// gi.dprintf("func_wall missing TRIGGER_SPAWN\n"); + self->spawnflags |= 1; + } + + // yell if the spawnflags are odd + if (self->spawnflags & 4) + { + if (!(self->spawnflags & 2)) + { + gi.dprintf("func_wall START_ON without TOGGLE\n"); + self->spawnflags |= 2; + } + } + + self->use = func_wall_use; + if (self->spawnflags & 4) + { + self->solid = SOLID_BSP; + } + else + { + self->solid = SOLID_NOT; + self->svflags |= SVF_NOCLIENT; + } + gi.linkentity (self); +} + + +/*QUAKED func_object (0 .5 .8) ? TRIGGER_SPAWN ANIMATED ANIMATED_FAST + + This is solid bmodel that will fall if it's support it removed. +*/ + +void func_object_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // only squash thing we fall on top of + if (!plane) + return; + if (plane->normal[2] < 1.0) + return; + if (other->takedamage == DAMAGE_NO) + return; + T_Damage (other, self, self, vec3_origin, self->s.origin, vec3_origin, self->dmg, 1, DAMAGE_AVOID_ARMOR,MOD_DIED); +} + +void func_object_release (edict_t *self) +{ + self->movetype = PHYSICSTYPE_STEP; + self->touch = func_object_touch; +} + +void func_object_use (edict_t *self, edict_t *other, edict_t *activator) +{ + self->solid = SOLID_BSP; + self->svflags &= ~SVF_NOCLIENT; + self->use = NULL; + KillBox (self); + func_object_release (self); +} + +void SP_func_object (edict_t *self) +{ + gi.setmodel (self, self->model); + + self->mins[0] += 1; + self->mins[1] += 1; + self->mins[2] += 1; + self->maxs[0] -= 1; + self->maxs[1] -= 1; + self->maxs[2] -= 1; + + if (!self->dmg) + self->dmg = 100; + + if (self->spawnflags == 0) + { + self->solid = SOLID_BSP; + self->movetype = PHYSICSTYPE_PUSH; + self->think = func_object_release; + self->nextthink = level.time + 2 * FRAMETIME; + } + else + { + self->solid = SOLID_NOT; + self->movetype = PHYSICSTYPE_PUSH; + self->use = func_object_use; + self->svflags |= SVF_NOCLIENT; + } + + if (self->spawnflags & 2) + self->s.effects |= EF_ANIM_ALL; + if (self->spawnflags & 4) + self->s.effects |= EF_ANIM_ALLFAST; + + self->clipmask = MASK_MONSTERSOLID; + + gi.linkentity (self); +} + + +void ItemSpitterSpit(edict_t *self,edict_t *owner,edict_t *attacker) +{ + int i1; + gitem_t *item; + edict_t *newitem; + vec3_t forward, holdangles,holdorigin; + float delta; + + if ((!self->target) || (!self->style)) + { + return; + } + + self->style = 0; // Show spitter has been used + + delta =(float) 360 / self->count; + VectorCopy(owner->s.angles,holdangles); + holdangles[YAW]= 0; + + for (i1 = 0;i1 < self->count;++i1) + { + item = FindItemByClassname(self->target); + + if (!item) // Must be an object not an item + { + newitem = G_Spawn(); + newitem->classname = ED_NewString(self->target); + + AngleVectors(holdangles,forward,NULL,NULL); + + VectorCopy(self->s.origin,newitem->s.origin); + VectorMA(newitem->s.origin, self->dmg_radius, forward, newitem->s.origin); + + if (self->mass) + newitem->spawnflags |= self->mass; + + ED_CallSpawn(newitem); + + VectorCopy(newitem->s.origin,holdorigin); + if (!(self->spawnflags & 1)) + gi.CreateEffect(NULL, FX_PICKUP, 0, holdorigin, ""); + + } + else + { + newitem = G_Spawn(); + newitem->movetype = PHYSICSTYPE_STEP; + AngleVectors(holdangles,forward,NULL,NULL); + + VectorCopy(self->s.origin,newitem->s.origin); + VectorMA(newitem->s.origin, self->dmg_radius, forward, newitem->s.origin); + + if (self->mass) + newitem->spawnflags |= self->mass; + + SpawnItem(newitem, item); + + VectorCopy(newitem->s.origin,holdorigin); + if (!(self->spawnflags & 1)) + gi.CreateEffect(NULL, FX_PICKUP, 0, holdorigin, ""); + } + + holdangles[YAW] += delta; + } + +} + +/*QUAKED item_spitter (0 .5 .8) (-4 -4 -4) (4 4 4) NOFLASH +When targeted it will spit out an number of items in various directions +-------SPAWN FLAGS ----------- +NOFLASH - no flash is created when item is 'spit out' +---------KEYS----------------- +target - classname of item or object being spit out +count - number of items being spit out (default 1) +radius - distance from item_spitter origin that items will be spawned +spawnflags2 - the spawnflags for the item being created. +*/ +void SP_item_spitter(edict_t *self) +{ + self->style = 1; // To show it hasn't been used yet + + self->movetype = PHYSICSTYPE_NONE; + + VectorSet(self->mins,-4,-4,-4); + VectorSet(self->maxs,4,4,4); + + self->use = ItemSpitterSpit; + + self->solid = SOLID_NOT; + + if (!self->count) + self->count = 1; + + self->dmg_radius = st.radius; + if (st.spawnflags2) + self->mass = st.spawnflags2; + else + self->mass = 0; + + gi.linkentity (self); +} + +//================================================================================= + +// update the spawner so that we will rematerialise in a different position +void respawner_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + edict_t *spot = NULL; + + // if we aren't a player, forget it + if (!other->client) + return; + + while ((spot = G_Find (spot, FOFS(classname), "info_player_start")) != NULL) + { + if (!game.spawnpoint[0] && !spot->targetname) + break; + + if (!game.spawnpoint[0] || !spot->targetname) + continue; + + if (Q_stricmp(game.spawnpoint, spot->targetname) == 0) + break; + } + + if (!spot) + { + if (!game.spawnpoint[0]) + { // there wasn't a spawnpoint without a target, so use any + spot = G_Find (spot, FOFS(classname), "info_player_start"); + } + if (!spot) + gi.error ("Couldn't find spawn point %s\n", game.spawnpoint); + } + + VectorSet(spot->s.origin, self->mins[0]+((self->size[0]) /2), self->mins[1]+((self->size[1]) /2) ,self->mins[2]+self->size[2]); + VectorCopy (self->s.angles, spot->s.angles); + + G_FreeEdict (self); +} + +/*QUAKED misc_update_spawner (.5 .5 .5) ? + This creates the spawner update entity, which upates the spawner position when triggered +*/ +void misc_update_spawner (edict_t *ent) +{ + + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->touch = respawner_touch; + + gi.setmodel(ent,ent->model); + gi.linkentity (ent); + +} + +void Teleporter_Deactivate(edict_t *self, G_Message_t *msg) +{ + self->touch = NULL; + // if there's an effect out there, kill it + if (self->enemy) + { + gi.RemoveEffects(&self->enemy->s, FX_TELEPORT_PAD); + gi.RemovePersistantEffect(self->enemy->PersistantCFX); + self->PersistantCFX = 0; + self->enemy = NULL; + } +} + +void Teleporter_Activate(edict_t *self, G_Message_t *msg) +{ + vec3_t real_origin; + edict_t *effect; + + self->touch = teleporter_touch; + + // if there's no effect already, create a new one + if (!self->enemy) + { + effect = G_Spawn(); + VectorCopy(self->maxs, effect->maxs); + VectorCopy(self->mins, effect->mins); + effect->solid = SOLID_NOT; + effect->s.effects |= EF_NODRAW_ALWAYS_SEND|EF_ALWAYS_ADD_EFFECTS; + self->enemy = effect; + gi.linkentity (effect); + + real_origin[0] = ((self->maxs[0] - self->mins[0]) / 2.0) + self->mins[0]; + real_origin[1] = ((self->maxs[1] - self->mins[1]) / 2.0) + self->mins[1]; + real_origin[2] = ((self->maxs[2] - self->mins[2]) / 2.0) + self->mins[2]; + + if (!(self->spawnflags & 1)) + effect->PersistantCFX = gi.CreatePersistantEffect(&effect->s, FX_TELEPORT_PAD, CEF_BROADCAST, real_origin, ""); + } +} + +void TeleporterStaticsInit() +{ + classStatics[CID_TELEPORTER].msgReceivers[G_MSG_SUSPEND] = Teleporter_Deactivate; + classStatics[CID_TELEPORTER].msgReceivers[G_MSG_UNSUSPEND] = Teleporter_Activate; +} + +/*QUAKED misc_teleporter (1 0 0) ? NO_MODEL DEATHMATCH_RANDOM START_OFF MULT_DEST +This creates the teleporter disc that will send us places +Stepping onto this disc will teleport players to the targeted misc_teleporter_dest object. +------- FIELDS ------------------ +NO_MODEL - makes teleporter invisible +DEATHMATCH_RANDOM - makes the teleporter dump you at random spawn points in deathmatch +START_OFF - Pad has no effect, and won't teleport you anywhere till its activated +MULT_DEST - pad is targeted at more than one destination +---------- KEYS ----------------- +style - number of destinations this pad has. + +*/ +void SP_misc_teleporter (edict_t *ent) +{ + vec3_t real_origin; + edict_t *effect; + + if (!ent->target && (!ent->spawnflags&DEATHMATCH_RANDOM || !deathmatch->value)) + { + gi.dprintf ("teleporter without a target.\n"); + G_FreeEdict (ent); + return; + } + + ent->msgHandler = DefaultMsgHandler; + ent->classID = CID_TELEPORTER; + + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); + + // if we don't have mult dests - probably redundant + if (!(ent->spawnflags & 8)) + ent->style = 0; + + // if we want an effect on spawn, create it. + if (!(ent->spawnflags & 4)) + { + ent->touch = teleporter_touch; + + effect = G_Spawn(); + VectorCopy(ent->maxs, effect->maxs); + VectorCopy(ent->mins, effect->mins); + effect->solid = SOLID_NOT; + effect->s.effects |= EF_NODRAW_ALWAYS_SEND|EF_ALWAYS_ADD_EFFECTS; + ent->enemy = effect; + gi.linkentity (effect); + + real_origin[0] = ((ent->maxs[0] - ent->mins[0]) / 2.0) + ent->mins[0]; + real_origin[1] = ((ent->maxs[1] - ent->mins[1]) / 2.0) + ent->mins[1]; + real_origin[2] = ((ent->maxs[2] - ent->mins[2]) / 2.0) + ent->mins[2]; + + if (!(ent->spawnflags & 1)) + effect->PersistantCFX = gi.CreatePersistantEffect(&effect->s, FX_TELEPORT_PAD, CEF_BROADCAST, real_origin, ""); + } + +} + +/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16) + + Point teleporters at these. +*/ +void SP_misc_teleporter_dest (edict_t *ent) +{ + trace_t tr; + vec3_t endpos; + + ent->s.skinnum = 0; + ent->solid = SOLID_NOT; + VectorSet (ent->mins, -32, -32, -24); + VectorSet (ent->maxs, 32, 32, -16); + gi.linkentity (ent); + + VectorCopy(ent->s.origin, endpos); + endpos[2] -= 500; + gi.trace (ent->s.origin, vec3_origin, vec3_origin, endpos, NULL, CONTENTS_WORLD_ONLY|MASK_PLAYERSOLID,&tr); + + VectorCopy(tr.endpos,ent->last_org); + ent->last_org[2] -= mins[2]; + +} + + + +extern void use_target_changelevel (edict_t *self, edict_t *other, edict_t *activator); +void misc_magic_portal_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + edict_t *ent=NULL; + + if (level.time < self->touch_debounce_time) + return; + + if (!other->client) // Not a player + return; + + ent = G_Find (ent, FOFS(targetname), self->target); + if (!ent) + { // No target. Don't do anything. +// Com_Printf("Portal has no target.\n"); + } + else + { + use_target_changelevel(ent, self, other); + } + + self->touch_debounce_time = level.time + 4.0; + + return; +} + + +void misc_magic_portal_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (level.time < self->impact_debounce_time) + return; + + if (self->solid == SOLID_NOT) + { // We aren't engaged yet. Make solid and start the effect. + self->solid = SOLID_TRIGGER; + self->touch = misc_magic_portal_touch; + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, FX_MAGIC_PORTAL, CEF_BROADCAST, self->s.origin, + "vbb", self->s.angles, (byte)self->style, (byte)self->count); + self->s.effects &= ~EF_DISABLE_EXTRA_FX; + } + else + { // We were on, now turn it off. + self->solid = SOLID_NOT; + self->touch = NULL; + // remove the persistant effect + gi.RemovePersistantEffect(self->PersistantCFX); + self->PersistantCFX = 0; +// gi.RemoveEffects(&self->s, FX_MAGIC_PORTAL); + + self->s.effects |= EF_DISABLE_EXTRA_FX; + } + + gi.linkentity(self); + + self->impact_debounce_time = level.time + 4.0; +} + + + +#define START_OFF 1 + +/*QUAKED misc_magic_portal (1 .5 0) (-16 -16 -32) (16 16 32) START_OFF +A magical glowing portal. Triggerable. +------- FIELDS ------------------ +START_OFF - portal will start off +----------------------------------- +angles - manipulates the facing of the effect as normal. +style - 0-blue, 1-red, 2-green +count - Close after 1-255 seconds. 0 means stay until triggered. + +In order to be functional as a world teleport, + it must target a target_changelevel + +*/ +void SP_misc_magic_portal (edict_t *self) +{ + // Set up the basics. + VectorSet(self->mins, -16, -16, -32); + VectorSet(self->maxs, 16, 16, 32); + self->s.scale = 1; + self->mass = 250; + self->friction = 0; + self->gravity = 0; + self->s.effects |= EF_ALWAYS_ADD_EFFECTS; + self->svflags |= SVF_ALWAYS_SEND; + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_NOT; + self->touch = NULL; + + self->use = misc_magic_portal_use; + + if (!self->spawnflags & START_OFF) + { // Set up the touch function, since this baby is live. + misc_magic_portal_use(self, NULL, NULL); + } + + gi.linkentity(self); +} + + + +void flame_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (other->damage_debounce_time < level.time) + { + other->damage_debounce_time = level.time + 0.2; + + T_Damage (other, world, world, other->s.origin, vec3_origin, vec3_origin, 10, 0, DAMAGE_SPELL|DAMAGE_AVOID_ARMOR,MOD_DIED);//Fixme: propper params. + } +} + +void flame_think (edict_t *self) +{ +// self->s.frame++; +// if (self->s.frame > 5) +// self->s.frame = 0; + +// self->nextthink = level.time + FRAMETIME; + self->nextthink = level.time + 200; +} + + +void soundambient_think(edict_t *self) +{ + byte style,wait,attenuation,volume; + + attenuation = Q_ftol(self->attenuation); + volume = Q_ftol(self->volume * 255); + + self->s.sound_data = (volume & ENT_VOL_MASK) | attenuation; + + // if its a looping sound, create it on this entity + switch((int)(self->style)) + { + case AS_FIRE: + self->s.sound = gi.soundindex("ambient/fireplace.wav"); + break; + case AS_WATERLAPPING: + self->s.sound = gi.soundindex("ambient/waterlap.wav"); + break; + case AS_OCEAN: + self->s.sound = gi.soundindex("ambient/ocean.wav"); + break; + case AS_SMALLFOUNTAIN: + self->s.sound = gi.soundindex("ambient/smallfountain.wav"); + break; + case AS_LARGEFOUNTAIN: + self->s.sound = gi.soundindex("ambient/fountainloop.wav"); + break; + case AS_SEWERWATER: + self->s.sound = gi.soundindex("ambient/sewerflow.wav"); + break; + case AS_OUTSIDEWATERWAY: + self->s.sound = gi.soundindex("ambient/river.wav"); + break; + case AS_CAULDRONBUBBLE: + self->s.sound = gi.soundindex("ambient/cauldronbubble.wav"); + break; + case AS_HUGEWATERFALL: + self->s.sound = gi.soundindex("ambient/hugewaterfall.wav"); + break; + case AS_MUDPOOL: + self->s.sound = gi.soundindex("ambient/mudpool.wav"); + break; + case AS_WINDEERIE: + self->s.sound = gi.soundindex("ambient/windeerie.wav"); + break; + case AS_WINDNOISY: + self->s.sound = gi.soundindex("ambient/windnoisy.wav"); + break; + case AS_WINDSOFTHI: + self->s.sound = gi.soundindex("ambient/windsofthi.wav"); + break; + case AS_WINDSOFTLO: + self->s.sound = gi.soundindex("ambient/windsoftlow.wav"); + break; + case AS_WINDSTRONG1: + self->s.sound = gi.soundindex("ambient/windstrong1.wav"); + break; + case AS_WINDSTRONG2: + self->s.sound = gi.soundindex("ambient/windstrong2.wav"); + break; + case AS_WINDWHISTLE: + self->s.sound = gi.soundindex("ambient/windwhistle.wav"); + break; + case AS_CONVEYOR: + self->s.sound = gi.soundindex("objects/conveyor.wav"); + break; + case AS_BUCKETCONVEYOR: + self->s.sound = gi.soundindex("objects/bucketconveyor.wav"); + break; + case AS_SPIT: + self->s.sound = gi.soundindex("objects/spit.wav"); + break; + default: + style = Q_ftol(self->style); + wait = Q_ftol(self->wait); + gi.CreatePersistantEffect(&self->s, + FX_SOUND, + CEF_BROADCAST | CEF_OWNERS_ORIGIN, + self->s.origin, + "bbbb", + style,attenuation,volume,wait); + break; + } + self->count = 1; // This is just a flag to show it's on + + self->think = NULL; +} + + +void sound_ambient_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->count) // This is just a flag to show it's on + { + self->count = 0; + gi.RemoveEffects(&self->s,0); + } + else + soundambient_think(self); +} + + +void sound_ambient_init(edict_t *self) +{ + VectorSet(self->mins,-4,-4,-4); + VectorSet(self->maxs,4,4,4); + + self->movetype = PHYSICSTYPE_NONE; + + if (self->attenuation <= 0.01) + self->attenuation = 1; + + if (self->volume <= 0.01) + self->volume = .5; + + if (self->wait<1) + self->wait = 10; + + self->s.effects |= EF_NODRAW_ALWAYS_SEND; + + if (!(self->spawnflags & 2)) + { + self->nextthink = level.time + 2.5; + self->think = soundambient_think; + } + + // if we are asked to do a sound of type zero, free this edict, since its obviously bogus + if (!self->style) + { + gi.dprintf("Bogus ambient sound at x:%f y:%f z:%f\n",self->s.origin[0], self->s.origin[1],self->s.origin[2]); + G_SetToFree(self); + return; + } + + // if we are non local, clear the origin of this object + if (self->spawnflags & 1) + { + VectorClear(self->s.origin); + } + else + // if we are here, then this ambient sound should have an origin + assert(Vec3NotZero(self->s.origin)); + + self->use = sound_ambient_use; + + gi.linkentity(self); +} + + + + +/*QUAKED sound_ambient_cloudfortress (1 0 0) (-4 -4 0) (4 4 4) NON_LOCAL START_OFF +Generates an ambient sound for cloud fortress levels +------- FLAGS ------------------ +NON_LOCAL - sound occurs everywhere in the level - attenuation is not operative with this type of sound +wait amount of seconds to wait + or - 50% before spawning sound again (default is 10 seconds) +START_OFF - starts off, can be triggered on +------- KEYS ------------------ +style +1 - Cauldron bubbling (looping sound) +2 - wind, low, eerie (looping) +3 - wind, low, noisy (looping) +4 - wind, high, soft (looping) +5 - wind, low, soft (looping) +6 - wind, low, strong (looping) +7 - wind, high, strong (looping) +8 - wind, whistling, strong (looping) + +attenuation (how quickly sound drops off from origin) + 0 - heard over entire level (default) + 1 - + 2 - + 3 - diminish very rapidly with distance + +volume range of .1 to 1 (default .5) + 0 - silent + 1 - full volume +----------------------------------- +*/ +void SP_sound_ambient_cloudfortress (edict_t *self) +{ + sound_ambient_init(self); + + self->style = CloudSoundID[self->style]; +} + + +/*QUAKED sound_ambient_mine (1 0 0) (-4 -4 0) (4 4 4) NON_LOCAL START_OFF +Generates an ambient sound for mine levels +------- FLAGS ------------------ +NON_LOCAL - sound occurs everywhere in the level - attenuation is not operative with this type of sound +wait amount of seconds to wait + or - 50% before spawning sound again (default is 10 seconds) +START_OFF - starts off, can be triggered on +------- KEYS ------------------ +style +1 - Mud pool bubbling (looping) +2 - Rocks falling (3 sounds) +3 - wind, low, eerie (looping) +4 - wind, low, soft (looping) +5 - conveyor belt (looping) +6 - bucket conveyor belt (looping) +7 - three different creaks of heavy timbers + +attenuation (how quickly sound drops off from origin) + 0 - heard over entire level (default) + 1 - + 2 - + 3 - diminish very rapidly with distance + +volume range of .1 to 1 (default .5) + 0 - silent + 1 - full volume +----------------------------------- +*/ +void SP_sound_ambient_mine (edict_t *self) +{ + sound_ambient_init(self); + + self->style = MineSoundID[self->style]; +} + + +/*QUAKED sound_ambient_hive (1 0 0) (-4 -4 0) (4 4 4) NON_LOCAL START_OFF +Generates an ambient sound for hive levels +------- FLAGS ------------------ +NON_LOCAL - sound occurs everywhere in the level - attenuation is not operative with this type of sound +wait amount of seconds to wait + or - 50% before spawning sound again (default is 10 seconds) +START_OFF - starts off, can be triggered on +------- KEYS ------------------ +style +1 - gong +2 - wind, low, eerie (looping) +3 - wind, low, noisy (looping) +4 - wind, high, soft (looping) +5 - wind, low, soft (looping) +6 - wind, low, strong (looping) +7 - wind, high, strong (looping) +8 - wind, whistling, strong (looping) + +attenuation (how quickly sound drops off from origin) + 0 - heard over entire level (default) + 1 - + 2 - + 3 - diminish very rapidly with distance + +volume range of .1 to 1 (default .5) + 0 - silent + 1 - full volume +----------------------------------- +*/ +void SP_sound_ambient_hive (edict_t *self) +{ + sound_ambient_init(self); + + self->style = HiveSoundID[self->style]; +} + + +/*QUAKED sound_ambient_andoria (1 0 0) (-4 -4 0) (4 4 4) NON_LOCAL START_OFF +Generates an ambient sound for andoria levels +------- FLAGS ------------------ +NON_LOCAL - sound occurs everywhere in the level - attenuation is not operative with this type of sound +wait amount of seconds to wait + or - 50% before spawning sound again (default is 10 seconds) +START_OFF - starts off, can be triggered on +------- KEYS ------------------ +style +1 - small fountain (constant loop) +2 - large fountain (constant loop) +3 - water running out of sewer (constant loop) +4 - rushing waterway outside (constant loop) +5 - wind chime + +attenuation (how quickly sound drops off from origin) + 0 - heard over entire level (default) + 1 - + 2 - + 3 - diminish very rapidly with distance + +volume range of .1 to 1 (default .5) + 0 - silent + 1 - full volume +----------------------------------- +*/ +void SP_sound_ambient_andoria (edict_t *self) +{ + sound_ambient_init(self); + + self->style = AndoriaSoundID[self->style]; +} + +/*QUAKED sound_ambient_swampcanyon (1 0 0) (-4 -4 0) (4 4 4) NON_LOCAL START_OFF +Generates an ambient sound for swamp or canyon levels +------- FLAGS ------------------ +NON_LOCAL - sound occurs everywhere in the level - attenuation is not operative with this type of sound +wait amount of seconds to wait + or - 50% before spawning sound again (default is 10 seconds) +START_OFF - starts off, can be triggered on +------- KEYS ------------------ +style +1 - bird, quick, high pitch +2 - bird, low, medium pitch +3 - huge waterfall +4 - mud pool bubbling (looping) +5 - wind, low, eerie (looping) +6 - wind, low, noisy (looping) +7 - wind, high, soft (looping) +8 - wind, low, soft (looping) +9 - wind, low, strong (looping) +10 - wind, high, strong (looping) +11 - wind, whistling, strong (looping) + + +attenuation (how quickly sound drops off from origin) + 0 - heard over entire level (default) + 1 - + 2 - + 3 - diminish very rapidly with distance + +volume range of .1 to 1 (default .5) + 0 - silent + 1 - full volume +----------------------------------- +*/ +void SP_sound_ambient_swampcanyon (edict_t *self) +{ + self->style = SwampCanyonSoundID[self->style]; + sound_ambient_init(self); +} + +/*QUAKED sound_ambient_silverspring (1 0 0) (-4 -4 -4) (4 4 4) NON_LOCAL START_OFF +Generates an ambient sound for silverspring levels +------- FLAGS ------------------ +NON_LOCAL - sound occurs everywhere in the level - attenuation is not operative with this type of sound +wait amount of seconds to wait + or - 50% before spawning sound again (default is 10 seconds) +START_OFF - starts off, can be triggered on +------- KEYS ------------------ +style : +1 - fire (looping) +2 - water lapping (looping) +3 - seagulls (2 random calls) +4 - ocean +5 - birds (10 random bird calls) +6 - crickets (3 random chirps) +7 - frogs (2 random ribbets) +8 - distant women/children crying (4 total) +9 - mosquitoes (2 random sounds) +10 - bubbles +11 - bell tolling +12 - footsteps (3 random sounds) +13 - moans/screams/coughing (5 random sounds) +14 - Sewer drips (3 random sounds) +15 - Water drips (3 random sounds) +16 - Solid drips - heavy liquid (3 random sounds) +17 - Cauldron bubbling (looping sound) +18 - Creaking for the spit that's holding the elf over a fire + +attenuation (how quickly sound drops off from origin) +0 - heard over entire level (default) +1 - +2 - +3 - diminish very rapidly with distance + +volume range of .1 to 1 (default .5) + 0 - silent + 1 - full volume +----------------------------------- +*/ +void SP_sound_ambient_silverspring (edict_t *self) +{ + self->style = SilverSpringSoundID[self->style]; + sound_ambient_init(self); +} + +/*QUAKED misc_remote_camera (0 0.5 0.8) (-4 -4 -4) (4 4 4) ACTIVATING SCRIPTED NO_DELETE + + pathtarget - holds the name of the camera's owner entity (if any). + target - holds the name of the entity to be looked at. + spawnflags - 1 only the activating client will see the remote camera view. + - 2 this is a scripted camera + - 4 don't delete camera +*/ + +void remove_camera(edict_t *Self) +{ + if(Self->spawnflags&1) + { + // Just for the activator. + + Self->activator->client->RemoteCameraLockCount--; + } + else + { + // For all clients. + + int i; + edict_t *cl_ent; + + for(i=0;iinuse) + continue; + + cl_ent->client->RemoteCameraLockCount--; + } + } + + if(!(Self->spawnflags&4)) + { + G_FreeEdict(Self); + } +} + +void misc_remote_camera_think(edict_t *Self) +{ + // ******************************************************************************************** + // Attempt to find my owner entity (i.e. what I'm fixed to). If nothing is found, then my + // position will remain unchanged. + // ******************************************************************************************** + + if(Self->pathtarget) + Self->enemy=G_Find(NULL,FOFS(targetname),Self->pathtarget); + + if(Self->enemy||(Self->spawnflags&2)) + { + // I am attatched to another (possibly moving) entity, so update my position. + + if(Self->enemy) + { + VectorCopy(Self->enemy->s.origin,Self->s.origin); + } + + // Update the position on client(s). + + if(Self->spawnflags&1) + { + // Just for the activator. + + if(Self->activator->client->RemoteCameraNumber==Self->s.number) + { + int i; + + for(i=0;i<3;i++) + Self->activator->client->ps.remote_vieworigin[i]=Self->s.origin[i]*8.0; + } + } + else + { + // For all clients. + + int i; + edict_t *cl_ent; + + for(i=0;iinuse) + continue; + + if(cl_ent->client->RemoteCameraNumber==Self->s.number) + { + int j; + + for(j=0;j<3;j++) + cl_ent->client->ps.remote_vieworigin[j]=Self->s.origin[j]*8.0; + } + } + } + } + + // ******************************************************************************************** + // Find my target entity and then orientate myself to look at it. + // ******************************************************************************************** + + if(Self->targetEnt=G_Find(NULL,FOFS(targetname),Self->target)) + { + // Calculate the angles from myself to my target. + + vec3_t Forward; + + VectorSubtract(Self->targetEnt->s.origin,Self->s.origin,Forward); + VectorNormalize(Forward); + vectoangles(Forward,Self->s.angles); + Self->s.angles[PITCH]=-Self->s.angles[PITCH]; + + // Update the angles on client(s). + + if(Self->spawnflags&1) + { + // Just for the activator. + + if(Self->activator->client->RemoteCameraNumber==Self->s.number) + { + int i; + + for(i=0;i<3;i++) + Self->activator->client->ps.remote_viewangles[i]=Self->s.angles[i]; + } + } + else + { + // For all clients. + + int i; + edict_t *cl_ent; + + for(i=0;iinuse) + continue; + + if(cl_ent->client->RemoteCameraNumber==Self->s.number) + { + int j; + + for(j=0;j<3;j++) + cl_ent->client->ps.remote_viewangles[j]=Self->s.angles[j]; + } + } + } + } + + // Think again or remove myself? + + if (Self->spawnflags & 2) + { + Self->nextthink = level.time+FRAMETIME; + } + else + { + Self->delay-=0.1; + + if (Self->delay >= 0.0) + { + Self->nextthink=level.time+0.1; + } + else + { + remove_camera(Self); + } + } +} + +void Use_misc_remote_camera(edict_t *Self,edict_t *Other,edict_t *Activator) +{ + vec3_t Forward; + + // ******************************************************************************************** + // If I am already active, just return, else flag that I am active. + // ******************************************************************************************** + + if(Self->count) + { + if(Self->spawnflags&2) + { + // I am a scripted camera, so free myself before returning. + + remove_camera(Self); + } + + return; + } + + Self->count=1; + + // ******************************************************************************************** + // Signal to client(s) that a remote camera view is active, + // ******************************************************************************************** + + if(Self->spawnflags&1) + { + // Signal to just the activator (i.e. person who was ultimately responsible for triggering the + // remote camera) that their camera view has changed to a remote camera view.. + + Self->activator=Activator; + + Self->activator->client->RemoteCameraLockCount++; + + Self->activator->client->RemoteCameraNumber=Self->s.number; + } + else + { + // Signal to all clients that their camera view has changed to a remote camera view.. + + int i; + edict_t *cl_ent; + + for(i=0;iinuse) + continue; + + cl_ent->client->RemoteCameraLockCount++; + + cl_ent->client->RemoteCameraNumber=Self->s.number; + } + } + + // ******************************************************************************************** + // Attempt to find my owner entity (i.e. what I'm fixed to). If nothing is found, then I am a + // static camera so set up my position here (it will remain unchanged hereafter). + // ******************************************************************************************** + + if(!Self->pathtarget) + { + // I am static, so set up my position (which will not change hereafter). + + if(Self->spawnflags&1) + { + // Just for the activator. + + int i; + + Self->enemy=NULL; + + for(i=0;i<3;i++) + Self->activator->client->ps.remote_vieworigin[i]=Self->s.origin[i]*8.0; + } + else + { + // For all clients. + + int i,j; + edict_t *cl_ent; + + Self->enemy=NULL; + + for(i=0;iinuse) + continue; + + for(j=0;j<3;j++) + cl_ent->client->ps.remote_vieworigin[j]=Self->s.origin[j]*8.0; + } + } + } + else + { + Self->enemy=G_Find(NULL,FOFS(targetname),Self->pathtarget); + + if(Self->enemy||(Self->spawnflags&2)) + { + // I am attatched to another (possibly moving) entity, so update my position. + + if(Self->enemy) + { + VectorCopy(Self->enemy->s.origin,Self->s.origin); + } + + // Update the position on client(s). + + if(Self->spawnflags&1) + { + // Just for the activator. + + if(Self->activator->client->RemoteCameraNumber==Self->s.number) + { + int i; + + for(i=0;i<3;i++) + Self->activator->client->ps.remote_vieworigin[i]=Self->s.origin[i]*8.0; + } + } + else + { + // For all clients. + + int i; + edict_t *cl_ent; + + for(i=0;iinuse) + continue; + + if(cl_ent->client->RemoteCameraNumber==Self->s.number) + { + int j; + + for(j=0;j<3;j++) + cl_ent->client->ps.remote_vieworigin[j]=Self->s.origin[j]*8.0; + } + } + } + } + } + // ******************************************************************************************** + // Find my target entity and then orientate myself to look at it. + // ******************************************************************************************** + + Self->targetEnt=G_Find(NULL,FOFS(targetname),Self->target); + VectorSubtract(Self->targetEnt->s.origin,Self->s.origin,Forward); + VectorNormalize(Forward); + vectoangles(Forward,Self->s.angles); + Self->s.angles[PITCH]=-Self->s.angles[PITCH]; + + // Update the angles on client(s). + + if(Self->spawnflags&1) + { + // Just for the activator. + + if(Self->activator->client->RemoteCameraNumber==Self->s.number) + { + int i; + + for(i=0;i<3;i++) + Self->activator->client->ps.remote_viewangles[i]=Self->s.angles[i]; + } + } + else + { + // For all clients. + + int i; + edict_t *cl_ent; + + for(i=0;iinuse) + continue; + + if(cl_ent->client->RemoteCameraNumber==Self->s.number) + { + int j; + + for(j=0;j<3;j++) + cl_ent->client->ps.remote_viewangles[j]=Self->s.angles[j]; + } + } + } + + // ******************************************************************************************** + // Setup next think stuff. + // ******************************************************************************************** + + Self->think=misc_remote_camera_think; + Self->nextthink=level.time + FRAMETIME; +} + +void SP_misc_remote_camera(edict_t *Self) +{ + Self->enemy=Self->targetEnt=NULL; + + if(!Self->target) + { + gi.dprintf("Object 'misc_remote_camera' without a target.\n"); + + G_FreeEdict(Self); + + return; + } + + Self->movetype = PHYSICSTYPE_NONE; + Self->solid=SOLID_NOT; + VectorSet(Self->mins,-4,-4,-4); + VectorSet(Self->maxs,4,4,4); + Self->count=0; + + Self->use=Use_misc_remote_camera; + + gi.linkentity(Self); +} + +// Spawns a client model animation +// spawnflags & 2 is a designer flag whether to animate or not +// If the model is supposed to animate, the hi bit of the type is set +// If the model is static, then the default frame stored on the client is used +// Valid scale ranges from 1/50th to 5 + +void SpawnClientAnim(edict_t *self, byte type, char *sound) +{ + int scale, skin; + + if (self->spawnflags & 2) // Animate it + { + type |= 0x80; + if(sound) + { + self->s.sound = gi.soundindex(sound); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; + } + } + scale = (byte)(self->s.scale * 50); + assert((scale > 0) && (scale < 255)); + skin = (byte)self->s.skinnum; + +// self->svflags |= SVF_ALWAYS_SEND; + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, + FX_ANIMATE, + CEF_BROADCAST, + self->s.origin, + "bbbv", type, scale, skin, self->s.angles); + + self->s.effects |= EF_ALWAYS_ADD_EFFECTS; +} + +//A check to see if ent should reflect +qboolean EntReflecting(edict_t *ent, qboolean checkmonster, qboolean checkplayer) +{ + if(!ent) + { + return false; + } + + if(checkmonster) + { + if(ent->svflags & SVF_MONSTER && ent->svflags & SVF_REFLECT) + { + return true; + } + } + + if(checkplayer) + { + if(ent->client) + { + if(ent->client->playerinfo.reflect_timer > level.time) + { + return true; + } + // possibly, we might want to reflect this if the player has gold armor + else + if((ent->client->playerinfo.pers.armortype == ARMOR_TYPE_GOLD) && (ent->client->playerinfo.armor_count) && (irand(0,100) < 30)) + return true; + + } + } + + return false; +} + +void SkyFlyCheck(edict_t *self) +{ + if(self->s.origin[2]>3900) + G_FreeEdict(self); + else + self->nextthink = level.time + 0.1; +} + +void SkyFly (edict_t *self) +{ +/* if(deathmatch->value) + {*/ + G_SetToFree(self); + return; +/* } +//They're not being drawn, even after this is set- why not? Did they stop? + self->svflags |= SVF_ALWAYS_SEND; + self->movetype = PHYSICSTYPE_NOCLIP; + self->solid = SOLID_NOT; + + self->touch = NULL; + self->isBlocked = NULL; + self->isBlocking = NULL; + self->bounced = NULL; +//or just remove self after a time + self->think = SkyFlyCheck; + self->nextthink = level.time + 0.1; +*/ +} + +void fire_spark_think (edict_t *self) +{ + if(self->delay && self->delay < level.time) + { + G_FreeEdict(self); + return; + } + + self->think = fire_spark_think; + self->nextthink = level.time + 0.1;//self->wait; +} + +void fire_spark_gone (edict_t *self, edict_t *other, edict_t *activator) +{ + self->use = NULL; + gi.RemoveEffects(&self->s, FX_SPARKS); + G_FreeEdict(self); +} + +void fire_spark_use (edict_t *self, edict_t *other, edict_t *activator) +{ + gi.CreateEffect(&self->s, FX_SPARKS, CEF_FLAG6|CEF_FLAG7|CEF_FLAG8, self->s.origin, "d", vec3_up); + + self->use = fire_spark_gone; + + self->think = fire_spark_think; + self->nextthink = level.time + 0.1; +} + +/*QUAKED misc_fire_sparker (0 0 0) (-4 -4 0) (4 4 8) FIREBALL + + FIREBALL - more of a poofy fireball trail + + Fires of sparks when used... + used a second time removes it + + "delay" - how long to live for... (default is forever) +*/ + +void SP_misc_fire_sparker (edict_t *self) +{ + + if(self->spawnflags & 1) + self->s.effects |= EF_MARCUS_FLAG1; + + self->svflags |= SVF_ALWAYS_SEND; + self->solid = SOLID_NOT; + self->movetype = PHYSICSTYPE_NOCLIP; + self->clipmask = 0; + + self->use = fire_spark_use; +} + +// end diff --git a/Toolkit/Programming/GameCode/game/g_misc.h b/Toolkit/Programming/GameCode/game/g_misc.h new file mode 100644 index 0000000..24d74bb --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_misc.h @@ -0,0 +1,20 @@ +// +// g_misc.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef G_MISC_H +#define G_MISC_H + +#include "q_Typedef.h" + +void BecomeDebris(edict_t *Self); +void SprayDebris(edict_t *self, vec3_t spot, byte NoOfChunks, float damage); +void ThrowBodyPart(edict_t *self, vec3_t *spot, int BodyPart, float damage, int frame); +void ThrowWeapon(edict_t *self, vec3_t *spot, int BodyPart, float damage, int frame); +void DefaultObjectDieHandler(edict_t *self, struct G_Message_s *msg); +void BboxYawAndScale(edict_t *self); + +#endif diff --git a/Toolkit/Programming/GameCode/game/g_monster.c b/Toolkit/Programming/GameCode/game/g_monster.c new file mode 100644 index 0000000..415a3bc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_monster.c @@ -0,0 +1,1968 @@ +#include "g_monster.h" +#include "m_stats.h" +#include "g_local.h" +#include "FX.h" +#include "g_DefaultMessageHandler.h" +#include "vector.h" +#include "g_playstats.h" + +#include "random.h" + +//JWEIER START INCLUDES +#include "g_misc.h" +#include "utilities.h" +//JWEIER END INCLUDES +#include "g_HitLocation.h" +#include "mg_guide.h" + +#define FALLDAMAGE_MODIFIER 8 + +qboolean defaultMonsterAlerted (edict_t *self, alertent_t *alerter, edict_t *enemy); +// ************************************************************************************************ +// MonsterHealth +// ------------- +// Returns the modified health for a monster based on the number of players who will be in a game. +// ************************************************************************************************ + +int MonsterHealth(int health) +{ + return(health+(health*((game.maxclients-1)*0.25))); // 175% with 4 players. +} + +/*------------------------------------------------------------------------- + DeadMsgHandler +-------------------------------------------------------------------------*/ +void DeadMsgHandler(edict_t *self, G_Message_t *msg) +{ + G_MsgReceiver_t receiver; + + if(msg->ID!=MSG_DEATH_PAIN) + return; + + receiver = classStatics[self->classID].msgReceivers[msg->ID]; + + if(receiver) + { + receiver(self, msg); + } + else + { + // if and when there are a good number of defaults, change the NULL to be an Empty + // function, overall that should be faster to just always call the function then + // do the check + receiver = DefaultMessageReceivers[msg->ID]; + + if(receiver) + { + DefaultMessageReceivers[msg->ID](self, msg); + } + } +} + +/*------------------------------------------------------------------------- + DyingMsgHandler + + Allows only dimemberment to still be called +-------------------------------------------------------------------------*/ + +void DyingMsgHandler(edict_t *self, G_Message_t *msg) +{ + G_MsgReceiver_t receiver; + + if(msg->ID!=MSG_DISMEMBER) + return; + + receiver = classStatics[self->classID].msgReceivers[msg->ID]; + + if(receiver) + { + receiver(self, msg); + } + else + { + // if and when there are a good number of defaults, change the NULL to be an Empty + // function, overall that should be faster to just always call the function then + // do the check + receiver = DefaultMessageReceivers[msg->ID]; + + if(receiver) + { + DefaultMessageReceivers[msg->ID](self, msg); + } + } +} + +/*------------------------------------------------------------------------- + PauseTime +-------------------------------------------------------------------------*/ +void PauseTime(edict_t *self, float time) +{ + self->monsterinfo.pausetime = level.time + time; +} + +/*------------------------------------------------------------------------- + AttackFinished +-------------------------------------------------------------------------*/ +void AttackFinished (edict_t *self, float time) +{ + self->monsterinfo.attack_finished = level.time + time; +} + + +/*------------------------------------------------------------------------- + M_CheckGround +-------------------------------------------------------------------------*/ +void M_CheckGround (edict_t *ent) +{ + vec3_t point; + trace_t trace; + + if (ent->flags & (FL_SWIM|FL_FLY)) + return; + + if (ent->velocity[2] >= 50) + { +// ent->groundentity = NULL; + return; + } + +// if the hull point one-quarter unit down is solid the entity is on ground + point[0] = ent->s.origin[0]; + point[1] = ent->s.origin[1]; + point[2] = ent->s.origin[2] - 0.25; + + gi.trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID,&trace); + + // check steepness + if ( trace.plane.normal[2] < 0.7 && !trace.startsolid) + { +// ent->groundentity = NULL; + return; + } + +// ent->groundentity = trace.ent; +// ent->groundentity_linkcount = trace.ent->linkcount; +// if (!trace.startsolid && !trace.allsolid) +// VectorCopy (trace.endpos, ent->s.origin); + if (!trace.startsolid && !trace.allsolid) + { + VectorCopy (trace.endpos, ent->s.origin); + ent->groundentity = trace.ent; + ent->groundentity_linkcount = trace.ent->linkcount; + ent->velocity[2] = 0; + } +} + + +/*------------------------------------------------------------------------- + M_CatagorizePosition +-------------------------------------------------------------------------*/ +void M_MonsterCatPos (edict_t *ent) +{ + vec3_t point; + int cont; + +// +// get waterlevel +// + point[0] = ent->s.origin[0]; + point[1] = ent->s.origin[1]; + point[2] = ent->s.origin[2] + ent->mins[2] + 1; + cont = gi.pointcontents (point); + + if (!(cont & MASK_WATER)) + { + ent->waterlevel = 0; + ent->watertype = 0; + return; + } + + point[2] -= 1; + ent->watertype = cont; + ent->waterlevel = 1;//below knees + point[2] += ent->size[2] * 0.25;// quarter of way up + cont = gi.pointcontents (point); + if (!(cont & MASK_WATER)) + return; + + ent->waterlevel = 2;//between knees and head + point[2] = ent->absmax[2];//over head + cont = gi.pointcontents (point); + if (cont & MASK_WATER) + ent->waterlevel = 3;//all the way in +} + +void M_CatagorizePosition (edict_t *ent) +{ + vec3_t point; + int cont; + + if(!ent->client) + { + M_MonsterCatPos(ent); + return; + } +// +// get waterlevel +// + point[0] = ent->s.origin[0]; + point[1] = ent->s.origin[1]; + point[2] = ent->s.origin[2] + ent->mins[2] + 1; + cont = gi.pointcontents (point); + + if (!(cont & MASK_WATER)) + { + ent->waterlevel = 0; + ent->watertype = 0; + return; + } + + ent->watertype = cont; + ent->waterlevel = 1; + point[2] += 26; + cont = gi.pointcontents (point); + if (!(cont & MASK_WATER)) + return; + + ent->waterlevel = 2; + point[2] += 22; + cont = gi.pointcontents (point); + if (cont & MASK_WATER) + ent->waterlevel = 3; +} + + +/*------------------------------------------------------------------------- + M_WorldEffects +-------------------------------------------------------------------------*/ +void M_WorldEffects (edict_t *ent) +{ + int dmg; + + if (ent->health > 0) + { + if (!(ent->flags & FL_SWIM)) + { + if (ent->waterlevel < 3 || (ent->monsterinfo.aiflags&AI_SWIM_OK)) + { + ent->air_finished = level.time + M_HOLD_BREATH_TIME; + } + else if (ent->air_finished < level.time && !(ent->flags & FL_AMPHIBIAN)) + { // drown! + if (ent->pain_debounce_time < level.time) + { + dmg = 2 + 2 * floor(level.time - ent->air_finished); + if (dmg > 15) + dmg = 15; + T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_SUFFOCATION,MOD_WATER); + ent->pain_debounce_time = level.time + 1; + } + } + } + else + { + if (ent->waterlevel > 0 || (ent->monsterinfo.aiflags&AI_SWIM_OK)) + { + ent->air_finished = level.time + 9; + } + else if (ent->air_finished < level.time && !(ent->flags & FL_AMPHIBIAN)) + { // suffocate! + if (ent->pain_debounce_time < level.time) + { + dmg = 2 + 2 * floor(level.time - ent->air_finished); + if (dmg > 15) + dmg = 15; + T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_SUFFOCATION,MOD_WATER); + ent->pain_debounce_time = level.time + 1; + } + } + } + } + + if (ent->waterlevel == 0) + { + // INWATER is set whether in lava, slime or water. + if (ent->flags & FL_INWATER) + { + if (ent->flags & FL_INLAVA) + { + gi.sound (ent, CHAN_BODY, gi.soundindex("player/inlava.wav"), 1, ATTN_NORM, 0); + ent->flags &= ~FL_INLAVA; + } + else if (ent->flags & FL_INSLIME) + { + gi.sound (ent, CHAN_BODY, gi.soundindex("player/muckexit.wav"), 1, ATTN_NORM, 0); + ent->flags &= ~FL_INSLIME; + } + else + { + gi.sound (ent, CHAN_BODY, gi.soundindex("player/Water Exit.wav"), 1, ATTN_NORM, 0); + } + + ent->flags &= ~FL_INWATER; + } + return; + } + + if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags & FL_IMMUNE_LAVA)) + { + if (ent->damage_debounce_time < level.time) + { + ent->damage_debounce_time = level.time + 0.2; + T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 10*ent->waterlevel, 0, DAMAGE_LAVA,MOD_LAVA); + } + } + if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags & FL_IMMUNE_SLIME)) + { + if (ent->damage_debounce_time < level.time) + { + ent->damage_debounce_time = level.time + 1; + T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 4*ent->waterlevel, 0, DAMAGE_SLIME,MOD_SLIME); + } + } + + if ( !(ent->flags & FL_INWATER) ) + { + if (ent->watertype & CONTENTS_LAVA) + { + gi.sound (ent, CHAN_BODY, gi.soundindex("player/inlava.wav"), 1, ATTN_NORM, 0); + ent->flags |= FL_INLAVA; + } + else + if (ent->watertype & CONTENTS_SLIME) + { + gi.sound (ent, CHAN_BODY, gi.soundindex("player/muckin.wav"), 1, ATTN_NORM, 0); + ent->flags |= FL_INSLIME; + } + else + { + gi.sound (ent, CHAN_BODY, gi.soundindex("player/Water Enter.wav"), 1, ATTN_NORM, 0); + } + + // INWATER is set whether in lava, slime or water. + ent->flags |= FL_INWATER; + ent->damage_debounce_time = 0; + } +} + + +/*------------------------------------------------------------------------- + M_droptofloor +-------------------------------------------------------------------------*/ +void M_droptofloor (edict_t *ent) +{ + vec3_t end; + trace_t trace; + + if(Vec3IsZero(ent->mins)&&Vec3IsZero(ent->maxs)) + { + gi.dprintf("ERROR : %s at %s called drop to floor before having size set\n", ent->classname, vtos(ent->s.origin)); + if(ent->think == M_droptofloor) + ent->think = NULL;//don't try again + return; + } + + ent->nextthink = level.time + FRAMETIME; + + ent->s.origin[2] += 1.0; + VectorCopy (ent->s.origin, end); + end[2] -= 256; + + gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID,&trace); + + if(trace.allsolid||trace.startsolid) + { + gi.dprintf("ERROR : Object (%s) at %s started in solid\n", ent->classname, vtos(ent->s.origin)); + if(ent->think == M_droptofloor) + { + ent->think = NULL;//don't try again + gi.linkentity (ent); + M_CatagorizePosition (ent); + } + return; + } + + if(trace.fraction == 1.0) + { + gi.dprintf("ERROR : Object (%s) more than 256 off ground, waiting to fall\n", ent->classname); + return; + } + + if(MGAI_DEBUG) + gi.dprintf("%s at %s dropped to floor at %s\n", ent->classname, vtos(ent->s.origin), vtos(trace.endpos)); + + VectorCopy (trace.endpos, ent->s.origin); + + gi.linkentity (ent); + M_CheckGround (ent); + M_CatagorizePosition (ent); + + // No need to think anymore if on the ground + ent->think = NULL; +} + +/* ------------------------------------------------------------------------------ + M_MoveFrame - unless a nextframe is specified, advance to the next frame listed in + the Animation Frame Array. Execute any aifunction or think function specified + with the given frame. + --------------------------------------------------------------------------------*/ +extern qboolean MonsterAdvanceFrame; +void M_MoveFrame (edict_t *self) +{ + animmove_t *move; + int index; + qboolean wasnewphys = false; + + + if(self->movetype < NUM_PHYSICSTYPES) + wasnewphys = true; + + move = self->monsterinfo.currentmove; + if (move == NULL) + { // if move is NULL, then this monster needs to have an anim set on it or all is lost. +#ifdef _DEVEL + gi.dprintf("MONSTER: '%s', at %s has no move pointer. Setting to move zero.\n", self->classname, self->s.origin); +#endif + self->think = NULL; + self->nextthink = -1; + return; + } + + self->nextthink = level.time + self->monsterinfo.thinkinc; + + //There is a voice sound waiting to play + if (self->monsterinfo.sound_pending && self->monsterinfo.sound_start <= level.time) + { + //Post a message and make the monster speak + QPostMessage(self, MSG_VOICE_PUPPET, PRI_DIRECTIVE, "i", self->monsterinfo.sound_pending); + + //Sound queue is free + self->monsterinfo.sound_pending = 0; + } + + // If this is set, the monster runs absolutely no animations or ai + if (sv_freezemonsters->value != 0 && !MonsterAdvanceFrame) + return; + + // Forcing the next frame index - usually the start of an animation + if (self->monsterinfo.nextframeindex > -1) + { + self->monsterinfo.currframeindex = self->monsterinfo.nextframeindex; + self->monsterinfo.nextframeindex = -1; + } + else + { + if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME)) + { + ++self->monsterinfo.currframeindex; + if (self->monsterinfo.currframeindex >= move->numframes) + self->monsterinfo.currframeindex = 0; + } + + // + if (self->monsterinfo.currframeindex == (move->numframes - 1)) + { + if (move->endfunc) + { + move->endfunc (self); + + // regrab move, endfunc is very likely to change it + move = self->monsterinfo.currentmove; + + // check for death + if (self->svflags & SVF_DEADMONSTER) + return; + } + } + } + + index = self->monsterinfo.currframeindex; + self->s.frame = move->frame[index].framenum; + + //this is consistent with the animmove_t in the monster anims. + //currently all of the *real* movement happens in the + //"actionfunc" instead of the move func + if(!(self->monsterinfo.aiflags & AI_DONT_THINK)) + { + if(move->frame[index].movefunc) + { + move->frame[index].movefunc(self, move->frame[index].var1, move->frame[index].var2, + move->frame[index].var3); + } + + if (move->frame[index].actionfunc) + { + if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME)) + {//Put scaling into SV_Movestep since this isn't ALWAYS the movement function + move->frame[index].actionfunc (self, move->frame[index].var4);//* self->monsterinfo.scale); + } + else + move->frame[index].actionfunc (self, 0); + } + + if (move->frame[index].thinkfunc) + move->frame[index].thinkfunc (self); + } + + if(wasnewphys) + { + assert(self->movetype < NUM_PHYSICSTYPES); + } +} + + +/*------------------------------------------------------------------------- + monster_think +-------------------------------------------------------------------------*/ +void monster_think (edict_t *self) +{ + M_MoveFrame (self); +/* + if (self->linkcount != self->monsterinfo.linkcount) + { + self->monsterinfo.linkcount = self->linkcount; + M_CheckGround (self); + } +*/ + M_CatagorizePosition (self); + M_WorldEffects (self); +} + + +/* +================ +monster_use + +Using a monster makes it angry at the current activator +================ +*/ +void monster_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->enemy) + return; + if (self->health <= 0) + return; + if (activator->flags & FL_NOTARGET) + return; + if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY)) + return; + +// delay reaction so if the monster is teleported, its sound is still heard + //self->targetname = "";//so can only be used once...??? + self->enemy = activator; + FoundTarget (self, true); +} + + +void monster_start_go (edict_t *self); + + +/*------------------------------------------------------------------------- + monster_triggered_spawn +-------------------------------------------------------------------------*/ +void monster_triggered_spawn (edict_t *self) +{ + vec3_t pos; + + self->s.origin[2] += 1; + KillBox (self); + + self->solid = SOLID_BBOX; + self->movetype = PHYSICSTYPE_STEP; + self->svflags &= ~SVF_NOCLIENT; + self->air_finished = level.time + M_HOLD_BREATH_TIME; + gi.linkentity (self); + + monster_start_go (self); + + if((self->classID==CID_ASSASSIN) && (self->spawnflags & MSF_ASS_TPORTAMBUSH)) + { + FoundTarget (self, true); + VectorCopy(self->s.origin, pos); + pos[2]+=self->mins[2]; + gi.CreateEffect(NULL, FX_TPORTSMOKE, 0, pos, ""); + } + else if (self->enemy && !(self->spawnflags & MSF_AMBUSH) && !(self->enemy->flags & FL_NOTARGET)) + { + FoundTarget (self, true); + } + else + { + self->enemy = NULL; + } +} + +/*------------------------------------------------------------------------- + monster_triggered_spawn_use +-------------------------------------------------------------------------*/ +void monster_triggered_spawn_use (edict_t *self, edict_t *other, edict_t *activator) +{ + // we have a one frame delay here so we don't telefrag the guy who activated us + self->spawnflags &= ~MSF_ASLEEP; + self->think = monster_triggered_spawn; + self->nextthink = level.time + FRAMETIME; + if (activator->client) + self->enemy = activator; + self->use = monster_use; +} + +/*------------------------------------------------------------------------- + monster_triggered_start +-------------------------------------------------------------------------*/ +void monster_triggered_start (edict_t *self) +{ + self->solid = SOLID_NOT; + self->movetype = PHYSICSTYPE_NONE; + self->svflags |= SVF_NOCLIENT; + self->nextthink = 0; + self->use = monster_triggered_spawn_use; +} + + +/* +================ +monster_death_use + +When a monster dies, it fires all of its targets with the current +enemy as activator. +================ +*/ +void monster_death_use (edict_t *self) +{ + self->flags &= ~(FL_FLY|FL_SWIM); +// self->monsterinfo.aiflags &= AI_GOOD_GUY;//WHY mask out everything above this flag??? + + if (self->item) + { + Drop_Item (self, self->item); + self->item = NULL; + } + + if (self->target) + G_UseTargets (self, self->enemy); + + if (self->deathtarget) + { + self->target = self->deathtarget; + G_UseTargets (self, self->enemy); + } +} + + +//============================================================================ + +void MG_CheckInGround (edict_t *self) +{ + if(gi.pointcontents(self->s.origin)&CONTENTS_SOLID) + { + gi.dprintf("G.D.E. FAULT: %s's origin at %s in solid!!!\n", self->classname, vtos(self->s.origin)); + } + else + {//check down against world- does not check against entities! Does not check up against cieling (why would they put one close to a cieling???) + vec3_t top, bottom, mins, maxs; + trace_t trace; + + VectorCopy(self->s.origin, top); + VectorCopy(self->s.origin, bottom); + top[2] += self->maxs[2] - 1; + bottom[2] += self->mins[2]; + + VectorSet(mins, self->mins[0], self->mins[1], 0); + VectorSet(maxs, self->maxs[0], self->maxs[1], 1); + + gi.trace(top, mins, maxs, bottom, self, MASK_SOLID,&trace); + if(trace.allsolid || trace.startsolid)//monster in solid, can't be fixed + { + gi.dprintf("G.D.E. FAULT: top of %s at %s in solid architecture(%s)!!!\n", self->classname, vtos(self->s.origin), trace.ent->classname); + } + else if(trace.fraction < 1.0f) + {//buoy is in the ground + VectorCopy(trace.endpos, bottom); + bottom[2] -= self->mins[2]; + if((int)(trace.endpos[2]) != (int)(self->s.origin[2])) + gi.dprintf("G.D.E. FAULT: %s at %s was in ground(%s), moved to %s...!!!\n", self->classname, vtos(self->s.origin), trace.ent->classname, vtos(bottom)); + VectorCopy(bottom, self->s.origin); + } + //fixme- check against other ents too? same trace or second one? + } +} + +/*------------------------------------------------------------------------- + monster_start +-------------------------------------------------------------------------*/ +qboolean monster_start (edict_t *self) +{ + if (deathmatch->value == 1) + { + G_FreeEdict (self); + return false; + } + + if (!(self->monsterinfo.aiflags & AI_GOOD_GUY)) + level.total_monsters++; + + self->monsterinfo.awake = false; + self->nextthink = level.time + FRAMETIME; + self->svflags |= SVF_MONSTER; + self->s.renderfx |= RF_FRAMELERP; + self->takedamage = DAMAGE_AIM; + self->air_finished = level.time + M_HOLD_BREATH_TIME; + + self->use = monster_use; + self->touch = M_Touch; + self->monsterinfo.alert = defaultMonsterAlerted;//I don't understand why I get a warning here... + + self->max_health = self->health; + self->clipmask = MASK_MONSTERSOLID; + if(!self->materialtype) + self->materialtype = MAT_FLESH; + + // Stop the camera clipping with monsters, except the trial beast. + + if(self->classID!=CID_TBEAST) + self->s.effects|=EF_CAMERA_NO_CLIP; + + if (G_MonsterShadow[self->classID].useShadow) + { + gi.CreateEffect(&self->s, + FX_SHADOW, + CEF_OWNERS_ORIGIN, + self->s.origin, + "f", + G_MonsterShadow[self->classID].scale); + } + + + self->s.skinnum = 0; + self->deadflag = DEAD_NO; + self->svflags &= ~SVF_DEADMONSTER; + self->monsterinfo.thinkinc = MONSTER_THINK_INC;//FRAMETIME; + self->monsterinfo.nextframeindex = -1; + + if (!self->monsterinfo.checkattack) + self->monsterinfo.checkattack = M_CheckAttack; + VectorCopy (self->s.origin, self->s.old_origin); + + if (st.item) + { + self->item = FindItemByClassname (st.item); + if (!self->item) + gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item); + } + + // randomize what frame they start on +// if (self->monsterinfo.currentmove) +// self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1)); + + if (!self->mass) + self->mass = 200; + + self->s.frame = 1; + + self->oldenemy_debounce_time = -1; + + return true; +} + +void MG_BBoxAndOriginAdjustForScale (edict_t *self) +{ + float o_mins2; + + if(!self->s.scale) + { + if(!self->monsterinfo.scale) + self->s.scale = self->monsterinfo.scale = 1.0f; + } + else if(!self->monsterinfo.scale) + self->monsterinfo.scale = self->s.scale; + + o_mins2 = self->mins[2]; + + Vec3ScaleAssign(self->s.scale, self->mins); + Vec3ScaleAssign(self->s.scale, self->maxs); + + self->s.origin[2] += o_mins2 - self->mins[2]; + + gi.linkentity(self); +} + +/*------------------------------------------------------------------------- + monster_start_go +-------------------------------------------------------------------------*/ +void monster_start_go (edict_t *self) +{ + vec3_t v; + float volume; + + self->nextthink = level.time + FRAMETIME; + + if (self->health <= 0) + return; + + MG_BBoxAndOriginAdjustForScale(self); + MG_CheckInGround(self); + + if(!self->mass) + self->mass = 100; + + if(self->s.scale) + self->mass *= self->s.scale; + + if(self->spawnflags & MSF_COWARD)//start off running away- FIXME: let them specify a flee_time and use AI_FLEE if one is set? Would anyone ever use this?!?!? + self->monsterinfo.aiflags |= AI_COWARD; + + if(self->spawnflags&MSF_STALK)//stalks enemies- only approaches and attacks from behind + self->ai_mood_flags |= AI_MOOD_FLAG_BACKSTAB; + + if(self->spawnflags&MSF_MELEE_LEAD)//lead enemies in melee and tries to cut them off + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + + if(!self->wakeup_distance) + self->wakeup_distance = MAX_SIGHT_PLAYER_DIST; + + volume = VectorLength(self->size); + if(volume < 32) + self->svflags |= SVF_DO_NO_IMPACT_DMG; + + self->jump_time = level.time + 2;//so they don't take damage from the fall after spawning... + + // check for target to combat_point and change to combattarget + self->monsterinfo.coop_check_debounce_time = 0; + self->monsterinfo.pausetime = -1; + if(self->enemy) + {//spawned mad + FoundTarget(self, false); + } + else + { + if (self->target) + { + qboolean notcombat; + qboolean fixup; + edict_t *target; + + target = NULL; + notcombat = false; + fixup = false; + while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL) + { + if (strcmp(target->classname, "point_combat") == 0) + { + self->combattarget = self->target; + fixup = true; + } + else + { + notcombat = true; + } + } + if (notcombat && self->combattarget) + gi.dprintf("%s at %s has target with mixed types\n", self->classname, vtos(self->s.origin)); + if (fixup) + self->target = NULL; + } + + // validate combattarget + if (self->combattarget) + { + edict_t *target; + + target = NULL; + while ((target = G_Find (target, FOFS(targetname), self->combattarget)) != NULL) + { + if (strcmp(target->classname, "point_combat") != 0) + { + gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n", + self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2], + self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1], + (int)target->s.origin[2]); + } + } + } + + if (self->target) + { + self->goalentity = self->movetarget = G_PickTarget(self->target); + if (!self->movetarget) + { + gi.dprintf ("%s can't find target %s at %s\n", self->classname, self->target, vtos(self->s.origin)); + self->target = NULL; + self->monsterinfo.pausetime = 100000000; + + if (!self->monsterinfo.c_mode) // Not in cinematic mode + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_C_IDLE1, PRI_DIRECTIVE, "iiige",0,0,0,NULL,NULL); + } + else if (strcmp (self->movetarget->classname, "path_corner") == 0) + { + if(self->classID != CID_SERAPH_OVERLORD) + { + VectorSubtract (self->goalentity->s.origin, self->s.origin, v); + self->ideal_yaw = self->s.angles[YAW] = vectoyaw(v); + gi.dprintf("Monster start go to walk\n"); + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + self->monsterinfo.pausetime = 0; + } + else + { + self->goalentity = self->movetarget = NULL; + self->monsterinfo.pausetime = 100000000; + if (!self->monsterinfo.c_mode) // Not in cinematic mode + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_C_IDLE1, PRI_DIRECTIVE, "iiige",0,0,0,NULL,NULL); + } + self->target = NULL; + } + else + { + self->goalentity = self->movetarget = NULL; + self->monsterinfo.pausetime = 100000000; + if (!self->monsterinfo.c_mode) // Not in cinematic mode + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_C_IDLE1, PRI_DIRECTIVE, "iiige",0,0,0,NULL,NULL); + } + } + else + { + self->monsterinfo.pausetime = 100000000; + if (self->monsterinfo.aiflags & AI_EATING) + { + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + } + else + { + if (!self->monsterinfo.c_mode) // Not in cinematic mode + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_C_IDLE1, PRI_DIRECTIVE, "iiige",0,0,0,NULL,NULL); + } + } + } + + self->think = monster_think; +} + + +/*------------------------------------------------------------------------- + walkmonster_start_go +-------------------------------------------------------------------------*/ +void walkmonster_start_go (edict_t *self) +{ + if (!(self->spawnflags & MSF_ASLEEP) && level.time < 1) + { + M_droptofloor (self); + + if (self->groundentity) + if (!M_walkmove (self, 0, 0)) + gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin)); + } + + if (!self->yaw_speed) + self->yaw_speed = 20; + self->viewheight = 25; + + monster_start_go (self); + + if (self->spawnflags & MSF_ASLEEP) + monster_triggered_start (self); +} + +/*------------------------------------------------------------------------- + walkmonster_start +-------------------------------------------------------------------------*/ +qboolean walkmonster_start (edict_t *self) +{ + self->think = walkmonster_start_go; + + if (!monster_start(self)) + return false; // Failed initialization + else + return true; +} + + +/*------------------------------------------------------------------------- + flymonster_start_go +-------------------------------------------------------------------------*/ +void flymonster_start_go (edict_t *self) +{ + if (!M_walkmove (self, 0, 0)) + gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin)); + + if (!self->yaw_speed) + self->yaw_speed = 10; + + if(!self->viewheight) + self->viewheight = 25; + + monster_start_go (self); + + if (self->spawnflags & MSF_ASLEEP) + monster_triggered_start (self); +} + + +/*------------------------------------------------------------------------- + flymonster_start +-------------------------------------------------------------------------*/ +qboolean flymonster_start (edict_t *self) +{ + self->flags |= FL_FLY; + self->think = flymonster_start_go; + + if (!monster_start(self)) + return false; // Failed initialization + else + return true; +} + + +/*------------------------------------------------------------------------- + swimmonster_start_go +-------------------------------------------------------------------------*/ +void swimmonster_start_go (edict_t *self) +{ + if (!self->yaw_speed) + self->yaw_speed = 10; + self->viewheight = 10; + + monster_start_go (self); + + if (self->spawnflags & MSF_ASLEEP) + monster_triggered_start (self); +} + +/*------------------------------------------------------------------------- + swimmonster_start +-------------------------------------------------------------------------*/ +qboolean swimmonster_start (edict_t *self) +{ + self->flags |= FL_SWIM; + self->think = swimmonster_start_go; + M_CatagorizePosition (self); + + if (!monster_start(self)) + return false; // Failed initialization + else + return true; +} + +/* +==================================================================== +void pitch_roll_for_slope (edict_t *forwhom, vec3_t *slope) + +MG + +This will adjust the pitch and roll of a monster to match +a given slope - if a non-'0 0 0' slope is passed, it will +use that value, otherwise it will use the ground underneath +the monster. If it doesn't find a surface, it does nothinh\g +and returns. +==================================================================== +*/ +void pitch_roll_for_slope (edict_t *forwhom, vec3_t pass_slope) +{ + vec3_t slope; + vec3_t nvf, ovf, ovr, startspot, endspot, new_angles = { 0, 0, 0 }; + float pitch, mod, dot; + + if(!pass_slope) + { + trace_t trace; + + VectorCopy(forwhom->s.origin, startspot); + startspot[2] += forwhom->mins[2]; + VectorCopy(startspot, endspot); + endspot[2] -= 300; + gi.trace(forwhom->s.origin, vec3_origin, vec3_origin, endspot, forwhom, MASK_SOLID,&trace); +// if(trace_fraction>0.05&&forwhom.movetype==MOVETYPE_STEP) +// forwhom.flags(-)FL_ONGROUND; + + if(trace.fraction==1.0) + return; + + if(!(&trace.plane)) + return; + + if(Vec3IsZero(trace.plane.normal)) + return; + + VectorCopy(trace.plane.normal, slope); + } + else + VectorCopy(pass_slope, slope); + + +//C stuff + + AngleVectors(forwhom->s.angles, ovf, ovr, NULL); + + vectoangles(slope, new_angles); + pitch = new_angles[PITCH] - 90; + new_angles[ROLL] = new_angles[PITCH] = 0; + + AngleVectors(new_angles, nvf, NULL, NULL); + + mod = DotProduct(nvf, ovr); + + if(mod<0) + mod = -1; + else + mod = 1; + + dot = DotProduct(nvf, ovf); + + forwhom->s.angles[PITCH] = dot * pitch; + forwhom->s.angles[ROLL] = (1-Q_fabs(dot)) * pitch * mod; +} + +//JWEIER START HELPER BLOCK + +/*---------------------------------------------------------------------------------------------------------------- + + Monster Helper Functions + +----------------------------------------------------------------------------------------------------------------*/ + +/*==================================================================================================================== + + void M_Touch + + Tests to see whether the thing touching it is on its head, and if so, it tries to correct that situation. + + Returns: + + All parameters are passed to the function from the touch callback + +======================================================================================================================*/ + +void M_Touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + vec3_t pos1, pos2, dir; + float zdiff, dropmag; + + if ((other->svflags & SVF_MONSTER) || (!stricmp(other->classname, "player"))) + { + VectorCopy(other->s.origin, pos1); + pos1[2] += other->mins[2]; + + VectorCopy(self->s.origin, pos2); + pos2[2] += self->maxs[2]; + + zdiff = pos1[2] - pos2[2]; + + // On top + if (zdiff >= 0 ) + { + //We want the full magnitude of the vector, not just drop magnitude + VectorCopy(other->velocity, dir); + dropmag = VectorNormalize(dir); + + //Do damage to the thing getting hit based on how hard the collision was +// T_Damage (self, other, other, dir, pos2, vec3_origin, 1 + (dropmag/FALLDAMAGE_MODIFIER), 0, DAMAGE_NO_BLOOD | DAMAGE_NO_KNOCKBACK); + if(!irand(0, 9))//10% chance + { + int damage; + + damage = irand(1, 3); +#ifdef _DEVEL + gi.dprintf("%s doing %d damage to %s by standing on it\n", other->classname, damage, self->classname); +#endif + T_Damage (self, other, other, dir, pos2, vec3_origin, damage, 0, DAMAGE_NO_KNOCKBACK|DAMAGE_AVOID_ARMOR,MOD_DIED); + } + + //Setup a random velocity for the first entity + other->velocity[0] = flrand(100.0, 150.0); + other->velocity[1] = flrand(100.0, 150.0); + other->velocity[2] += 110; + + //Randomly reverse those random numbers + if (irand(0,1)) + VectorScale(other->velocity, -1, other->velocity); + + //Let the other entity move at its velocity +// other->groundentity = NULL; + } + } +} + +/*==================================================================================================================== + + edict_t *M_CheckMeleeHit + + Test a melee strike to see if it has hit its target. + + Returns: "trace.ent" if a valid entity is struck (may not be intended target) + "NULL" if nothing hit + "attacker" if hit a wall, but no entity (used for spark effects) + + attacker - the entity attacking + max_dist - the distance it checks forward + trace - passed parameter filled with the trace information (can be overkill, or very useful) + +======================================================================================================================*/ + +edict_t *M_CheckMeleeHit( edict_t *attacker, float max_dist, trace_t *trace ) +{ + vec3_t targPos, vf; + + //Trace forward the maximum amount of the melee distance + AngleVectors(attacker->s.angles, vf, NULL, NULL); + VectorMA(attacker->s.origin, max_dist, vf, targPos); + + gi.trace(attacker->s.origin, attacker->mins, attacker->maxs, targPos, attacker, MASK_MONSTERSOLID,trace); + + //Check to see if the trace was successful (miss) + if (trace->fraction < 1) + { + //Check an entity collision + if (trace->ent) + { + //Can take damage, so pass it back + if (trace->ent->takedamage) + { + //VectorCopy(trace.endpos, hitPos); + return trace->ent; + } + } + + //Wasn't an entity, but we were blocked (world brush) + return attacker; + } + + //Nothing found (missed) + return NULL; +} + +/*==================================================================================================================== + + edict_t *M_CheckMeleeLineHit + + Test a melee attack along a directed line. + + Returns: "trace.ent" if a valid entity is struck (may not be intended target) + "NULL" if nothing hit + "attacker" if hit a wall, but no entity (used for spark effects) + + attacker - what's attacking + start - starting position of the attack (offsets from the character (f,r,u) + end - ending position of the attack (offsets from the character (f,r,u) + mins, maxs - the size of the box to trace by + trace - passed parameter filled with the trace information (can be overkill, or very useful) + +======================================================================================================================*/ + +edict_t *M_CheckMeleeLineHit( edict_t *attacker, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace, vec3_t direction) +{ + vec3_t startv, endv, midv, swipedir, + vf, vr, vu; + + //Apply the offsets to the positions passed + AngleVectors(attacker->s.angles, vf, vr, vu); + + VectorMA(attacker->s.origin, start[0], vf, startv); + VectorMA(startv, start[1], vr, startv); + VectorMA(startv, start[2], vu, startv); + + VectorMA(attacker->s.origin, end[0], vf, endv); + VectorMA(endv, end[1], vr, endv); + VectorMA(endv, end[2], vu, endv); + + VectorSubtract(endv, startv, swipedir); + //make sure line to start of swipe is clear + gi.trace(attacker->s.origin, mins, maxs, startv, attacker, MASK_SHOT,trace); + + if(trace->fraction == 1.0)//line to start of trace not blocked + gi.trace(startv, mins, maxs, endv, attacker, MASK_SHOT,trace);//MASK_MONSTERSOLID); + + if(trace->fraction == 1.0) + {//hit nothing, trace to middle of line from origin to see if reached too far + VectorMA(startv, 0.5, swipedir, midv); + gi.trace(attacker->s.origin, mins, maxs, midv, attacker, MASK_SHOT,trace); + } + + if(trace->fraction == 1.0) + {//Last Chance: trace to end of swipe from origin to see if reached too far + gi.trace(attacker->s.origin, mins, maxs, endv, attacker, MASK_SHOT,trace); + } + + VectorNormalize(swipedir); + if(direction) + VectorCopy(swipedir, direction); + + //Check to see if the trace was successful (miss) + if (trace->fraction < 1 || trace->startsolid || trace->allsolid) + { + //Check an entity collision + if (trace->ent) + { + //Can take damage, so pass it back + if (trace->ent->takedamage) + return trace->ent; + } + + //Wasn't an entity, but we were blocked (world brush) + return attacker; + } + + //Nothing found (missed) + return NULL; +} + +/*==================================================================================================================== + + float M_DistanceToTarget + + Make sure we have a live enemy, and then return a distance to him. + + Returns: distance to target + + self - what's attacking + target - what were looking for + +======================================================================================================================*/ + +float M_DistanceToTarget ( edict_t *self, edict_t *target ) +{ + vec3_t vec; + + assert (target); + + VectorSubtract(target->s.origin, self->s.origin, vec); + + return VectorLength(vec); +} + +/*==================================================================================================================== + + qboolean M_ValidTarget + + Make sure we have a live enemy, and then return a distance to it. + + Returns: true if the enemy is valid, false if it is dead. + + self - what's attacking + target - what were looking for + +======================================================================================================================*/ + +qboolean M_ValidOldEnemy (edict_t *self) +{ + if (!self->oldenemy) + return false; + + if (self->oldenemy->health <= 0 || self->oldenemy == self) + return false; + + if(self->monsterinfo.last_successful_enemy_tracking_time + MONSTER_SEARCH_TIME < level.time) + if(!visible(self, self->oldenemy)) + return false; + + self->monsterinfo.aiflags &= ~AI_STRAIGHT_TO_ENEMY; + self->enemy = self->goalentity = self->oldenemy; + self->oldenemy = NULL; + return true; +} + +qboolean M_ValidTarget( edict_t *self, edict_t *target ) +{ + qboolean checkold = false; + + if(self->oldenemy_debounce_time > 0) + { + if(self->oldenemy_debounce_time < level.time) + { + self->oldenemy_debounce_time = -1; + if(M_ValidOldEnemy(self)) + return true; + } + } + + if(target == self->enemy) + checkold = true; + + if (!target) + { + self->monsterinfo.aiflags &= ~AI_STRAIGHT_TO_ENEMY; + + if(checkold) + if(M_ValidOldEnemy(self)) + return true; + + if (!FindTarget(self)) + return false; + + target = self->enemy; + } + + if(!target) + return false; + + //See if the target has died + if (target->health <= 0 || target == self) + { + self->monsterinfo.aiflags &= ~AI_STRAIGHT_TO_ENEMY; + //See if there is another valid target to go after + if(checkold) + if(M_ValidOldEnemy(self)) + return true; + + if (!FindTarget(self)) + { + if(self->enemy) + self->oldenemy = self->enemy; + self->enemy = NULL; + return false; + } + } + + if(coop->value) + { + if(self->monsterinfo.awake) + { + if(self->enemy && self->monsterinfo.coop_check_debounce_time < level.time) + { + int c_dist[MAX_CLIENTS]; + float e_dist; + int i; + edict_t *newenemy = NULL; + edict_t *client = NULL; + + //only do this check once a second per monster + self->monsterinfo.coop_check_debounce_time = level.time + 1; + + e_dist = M_DistanceToTarget(self, self->enemy); + + for(i = 0; i <= game.maxclients; i++) + { + c_dist[i] = 9999999999; + + client = &g_edicts[i]; + if(client->client && client->health > 0) + { + c_dist[i] = M_DistanceToTarget(self, client); + } + } + + for(i = 0; i <= game.maxclients; i++) + { + if(c_dist[i] < e_dist) + { + client = &g_edicts[i]; + if(visible(self, client)) + { + newenemy = client; + e_dist = c_dist[i]; + } + } + } + + if(newenemy) + { + if(self->enemy->client && self->enemy->health > 0) + self->oldenemy = self->enemy; + + self->enemy = newenemy; + FoundTarget(self, false); + self->monsterinfo.searchType = SEARCH_COMMON; + } + } + } + } + + return true; +} + +/*==================================================================================================================== + + int M_PredictTargetEvasion + + Predicts where the target will be a few frames later based on current velocity and facing, and predicts where + the attacker will be at that same time. It then decides whether or not it will be able to melee from there. + This is necessary for melee striking creatures who tend to run up to the player, swing, then stand for a few + frames while the player backs up. + + NOTE: Does not detect whether or not a target and attacker will collide during the course of movement, but ai_run will + find this for us. + + Returns: 0 - target will be out of range at end of movements (suggest: run after) + 1 - target will be within range at the end of the movements at current velocities (suggest: continue motion) + + attacker - the entity pursuing the target + target - what's being pursued + pursue_vel - attacker's desired movement velocity (passed as parameter so an average velocity for frames can be used) + evade_vel - target's estimated evade velocity (again, passed as parameter in case you have special knowledge of a movement) + strike_dist - maximum distance a melee attack can occur at, this is the range checked at the end of prediction + pred_frames - number of frames (1/10th second) to predict over (prediction accuracy decreases over large amounts of time) + +======================================================================================================================*/ + +int M_PredictTargetEvasion( edict_t *attacker, edict_t *target, vec3_t pursue_vel, vec3_t evade_vel, float strike_dist, float pred_frames ) +{ + vec3_t pTargetPos, pAttackPos, targetMove, attackMove, vec; + float dist, targetDist, attackDist; + + //Setup the movement directions + VectorCopy(pursue_vel, attackMove); + VectorCopy(evade_vel, targetMove); + + //Setup the distances of attack + attackDist = VectorNormalize(attackMove); + targetDist = VectorNormalize(targetMove); + + //Obtain movement per frame, then apply it over the number of predicted frames + attackDist = pred_frames * (attackDist * FRAMETIME); + targetDist = pred_frames * (targetDist * FRAMETIME); + + VectorMA(attacker->s.origin, attackDist, attackMove, pAttackPos); + VectorMA(target->s.origin, targetDist, targetMove, pTargetPos); + + //Find the distance between them + VectorSubtract(pAttackPos, pTargetPos, vec); + dist = VectorLength(vec); + + //If dist is too far, we won't hit + if (dist > strike_dist) + return 0; + + return 1; +} + +/*==================================================================================================================== + + vec3_t M_PredictTargetPosition + + Predicts where the target will be a few frames later based on current velocity and facing. + + NOTE: Does not detect whether or not a target and attacker will collide during the course of movement, but ai_run will + find this for us. + + Returns: Position the target may be at in the predicted period + + target - what's being pursued + evade_vel - target's estimated evade velocity (again, passed as parameter in case you have special knowledge of a movement) + pred_frames - number of frames (1/10th second) to predict over (prediction accuracy decreases over large amounts of time) + pTargetPos - where the enemy will be + +======================================================================================================================*/ + +void M_PredictTargetPosition( edict_t *target, vec3_t evade_vel, float pred_frames, vec3_t pTargetPos) +{ + vec3_t targetMove; + float targetDist; + + //Setup the movement directions + VectorCopy(evade_vel, targetMove); + + //Setup the distances of attack + targetDist = VectorNormalize(targetMove); + + //Obtain movement per frame, then apply it over the number of predicted frames + targetDist = pred_frames * (targetDist * FRAMETIME); + + VectorMA(target->s.origin, targetDist, targetMove, pTargetPos); +} + +/*==================================================================================================================== + + void M_StartDeath + + Sets various states and sets up the monster to play his death frames. Passing -1 in the sound field will + skip the sound playing + + Returns: + + self - the entity dying + sound - the sound ID to play, -1 if no sound + +======================================================================================================================*/ + +void M_StartDeath( edict_t *self, int animID) +{ + self->msgHandler = DeadMsgHandler; + + /*if(self->monsterinfo.aiflags & AI_DONT_THINK) + { + SetAnim(self, animID); + return; + }*/ + + //Dead but still being hit + if(self->deadflag == DEAD_DEAD) + return; + + self->deadflag = DEAD_DEAD; + + //gib death + if(self->health <= -80) + { + //The monster much check and play its own sound if a gib occured + self->think = BecomeDebris; + self->nextthink = level.time + FRAMETIME; + return; + } +} + +/*==================================================================================================================== + + void M_EndDeath + + The monster is dead completely. Set all information to reflect this. + + Returns: + + self - the entity that is dead + +======================================================================================================================*/ + +void M_EndDeath( edict_t *self) +{ + self->mood_nextthink = -1;//never mood_think again + self->maxs[2] = self->mins[2] + 16; + + self->think = NULL; + self->nextthink = -1;//stop thinkin' + + gi.RemoveEffects(&self->s, 0); + + gi.linkentity (self); +} + + +/*==================================================================================================================== + + int M_FindSupport + + Look for monsters of a similar race around the current position of this monster. + + Returns: Number of monsters around the current monster + + range - The radius to check inside + +======================================================================================================================*/ + +int M_FindSupport( edict_t *self, int range ) +{ + edict_t *ent = NULL; + int numSupport = 0; + + while((ent = findradius(ent, self->s.origin, range)) != NULL) + { + if (ent==self) + continue; + + if (ent->classID != self->classID) + continue; + + if (ent->health <= 0) + continue; + + numSupport++; + } + + return numSupport; +} + +/*==================================================================================================================== + + qboolean M_FindSupport + + Look for monsters of a similar race and if they are already trying to alert others + + Returns: Whether or not to alert other monsters + + range - The radius to check inside + +======================================================================================================================*/ + +qboolean M_CheckAlert( edict_t *self, int range ) +{ + edict_t *ent = NULL; + int numSupport = 0; + + while((ent = findradius(ent, self->s.origin, range)) != NULL) + { + if (ent==self) + continue; + + if (ent->classID != self->classID) + continue; + + if (ent->enemy != self->enemy) + continue; + + if (ent->health <= 0) + continue; + + if (ent->monsterinfo.sound_finished < level.time || ent->monsterinfo.sound_pending) + continue; + + return false; + } + + return true; +} + +/*---------------------------------------------------------------------- + Generic Jump +-----------------------------------------------------------------------*/ + +void M_jump(edict_t *self, G_Message_t *msg) +{ + vec3_t jvec, fwd; + float dist; + + if (!self->goalentity) + return; + + if(self->spawnflags&MSF_FIXED) + return; + + dist = M_DistanceToTarget(self, self->goalentity); + + if (dist > 256) + return; + + self->jump_time = level.time + 0.5; + + AngleVectors(self->s.angles, fwd, NULL, NULL); + VectorScale(fwd, 256, jvec); + jvec[2] += 101; + + if(classStatics[self->classID].msgReceivers[MSG_CHECK_MOOD]) + { + VectorCopy(jvec, self->movedir); + self->ai_mood = AI_MOOD_JUMP;//don't technically need this line + self->mood_nextthink = level.time + 0.5; + //as an alternative, call self->forced_jump(self); + QPostMessage(self, MSG_CHECK_MOOD, PRI_DIRECTIVE, "i", AI_MOOD_JUMP); + } + else + VectorCopy(jvec, self->velocity); +} + +// get the dismember message and send it to my dismember code + +void MG_parse_dismember_msg(edict_t *self, G_Message_t *msg) +{ + HitLocation_t HitLocation; + int damage; + + if(!self->monsterinfo.dismember) + { +#ifdef _DEVEL + gi.dprintf("ERROR: %s with dismember message handler but no dismember function\n", self->classname); +#endif + return; + } + + ParseMsgParms(msg, "ii", &damage, &HitLocation); + + self->monsterinfo.dismember(self, damage, HitLocation); +} + +/*---------------------------------------------------------------------- + Generic Monster Reaction to being alerted +-----------------------------------------------------------------------*/ +qboolean defaultMonsterAlerted (edict_t *self, alertent_t *alerter, edict_t *enemy)//I don't understand why I get a warning here... +{ + if(self->alert_time < level.time) + {//not already alerted + if(!(alerter->alert_svflags&SVF_ALERT_NO_SHADE) && skill->value < 3.0 && !(self->monsterinfo.aiflags & AI_NIGHTVISION)) + { + if(enemy->light_level < flrand(6, 77)) + { + return false; + } + } + } + + if(alerter->lifetime < level.time + 2) + self->alert_time = level.time + 2;//be ready for 2 seconds to wake up if alerted again + else + self->alert_time = alerter->lifetime;//be alert as long as the alert sticks around + + if(enemy->svflags&SVF_MONSTER) + self->enemy = alerter->enemy; + else + self->enemy = enemy; + + FoundTarget(self, true); + return true; +} + + +/* +=============== +MG_ChangePitchForZVel + +=============== +*/ +float MG_ChangePitch(edict_t *self, float ideal, float speed) +{ + float current; + float move; + + current = anglemod(self->s.angles[PITCH]); + ideal = anglemod(ideal); + + if (current == ideal) + return false; + + move = ideal - current; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + self->s.angles[PITCH] = anglemod (current + move); + return move; +} + +float MG_ChangePitchForZVel(edict_t *self, float speed, float cap_vel, float max_angle) +{ + float ideal; + + ideal = self->velocity[PITCH]; + + if(fabs(ideal) > cap_vel) + { + if(ideal > 0) + ideal = max_angle; + else + ideal = -max_angle; + } + else + ideal = ideal/cap_vel * max_angle; + + return MG_ChangePitch(self, ideal, 10); +} + + +/* +=============== +MG_SetNormalizeVelToGoal + +=============== +*/ +void MG_SetNormalizeVelToGoal(edict_t *self, vec3_t vec) +{ + vec3_t targVec; + qboolean charge_enemy = false; + + if(self->monsterinfo.aiflags&AI_STRAIGHT_TO_ENEMY && self->enemy) + charge_enemy = true; + + if (self->monsterinfo.searchType == SEARCH_BUOY && !charge_enemy) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Vec to navgoal!\n"); +#endif + if(self->buoy_index < 0 || self->buoy_index > level.active_buoys) + { +#ifdef _DEVEL + gi.dprintf("Error: SEARCH_BUOY but invalid index!!!\n"); +#endif + VectorClear(vec); + return; + } + + VectorCopy(level.buoy_list[self->buoy_index].origin, self->monsterinfo.nav_goal); + VectorSubtract(self->monsterinfo.nav_goal, self->s.origin, vec); + } + else if(self->goalentity && !charge_enemy) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Vec to goalentity!\n"); +#endif + + if(self->goalentity == self->enemy && self->ai_mood_flags & AI_MOOD_FLAG_PREDICT) + {//predict where he's goin + M_PredictTargetPosition( self->enemy, self->enemy->velocity, 8, targVec); + } + else + { + VectorCopy(self->goalentity->s.origin, targVec); + } + + VectorSubtract(targVec, self->s.origin, vec); + } + else if(self->enemy) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Vec to enemy!\n"); +#endif + if (self->ai_mood_flags & AI_MOOD_FLAG_PREDICT) + {//predict where he's goin + M_PredictTargetPosition( self->enemy, self->enemy->velocity, 8, targVec); + } + else + { + VectorCopy(self->enemy->s.origin, targVec); + } + + VectorSubtract(targVec, self->s.origin, vec); + } + else + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("No goal to face!\n"); +#endif + VectorClear(vec); + return; + } + + VectorNormalize(vec); +} + +/*==================================================================================================================== + + void M_ShowLifeMeter + + Overides the lung meter and displays the creature's life meter to all clients + + Returns: Nothing + +======================================================================================================================*/ + +#define LIFEBAR_SCALE 16 + +void M_ShowLifeMeter( edict_t *self, int value, int max_value ) +{ + player_state_t *ps; + int i; + + //Update all clients + for (i = 0 ; i < maxclients->value ; i++) + { + ps = &game.clients[i].ps; + + ps->stats[STAT_LIFEBAR_VALUE] = (value / LIFEBAR_SCALE); + ps->stats[STAT_LIFEBAR_SIZE] = (max_value / LIFEBAR_SCALE); + ps->stats[STAT_LIFEBAR_BACK] = gi.imageindex("icons/lifebar_back.m8"); + } +} + diff --git a/Toolkit/Programming/GameCode/game/g_monster.h b/Toolkit/Programming/GameCode/game/g_monster.h new file mode 100644 index 0000000..9f4f9db --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_monster.h @@ -0,0 +1,58 @@ +// +// g_monster.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef G_MONSTER_H +#define G_MONSTER_H + +#include "g_local.h" +#include "Message.h" +#include "g_ClassStatics.h" + +extern void M_WorldEffects (struct edict_s *ent); +extern void PM_CatagorizePosition (void); + +extern void monster_use (struct edict_s *self, struct edict_s *other, struct edict_s *activator); + +int MonsterHealth(int health); + +qboolean monster_start (edict_t *self); +void walkmonster_start_go (edict_t *self); + +void DeadMsgHandler(edict_t *self, G_Message_t *msg); + +void MG_InitMoods(edict_t *self); +void MG_NoBlocking (edict_t *self); + +//JWEIER START HELPER PROTO + +qboolean MG_GetTargOrg (edict_t *self, vec3_t targ_org); +qboolean visible_pos (edict_t *self, vec3_t spot2); +qboolean clear_visible_pos (edict_t *self, vec3_t spot2); +qboolean infront_pos (edict_t *self, vec3_t pos); +qboolean M_ValidTarget( edict_t *self, edict_t *target ); +qboolean M_CheckAlert( edict_t *self, int range ); + +edict_t *M_CheckMeleeLineHit( edict_t *attacker, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace, vec3_t direction); +edict_t *M_CheckMeleeHit( edict_t *attacker, float max_dist, trace_t *trace ); + +float M_DistanceToTarget ( edict_t *self, edict_t *target ); + +void M_Touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); +void M_StartDeath( edict_t *self, int animID); +void M_EndDeath( edict_t *self); +void M_PredictTargetPosition( edict_t *target, vec3_t evade_vel, float pred_frames, vec3_t pTargetPos); +void M_jump(edict_t *self, G_Message_t *msg); +void MG_parse_dismember_msg(edict_t *self, G_Message_t *msg); +void M_ShowLifeMeter( edict_t *self, int value, int max_value ); + +int M_PredictTargetEvasion( edict_t *attacker, edict_t *target, vec3_t pursue_vel, vec3_t evade_vel, float strike_dist, float pred_frames ); +int M_FindSupport( edict_t *self, int range ); +float MG_FaceGoal (edict_t *self, qboolean doturn); + +//JWEIER END HELPER PROTO + +#endif // G_MONSTER_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_newsystem.h b/Toolkit/Programming/GameCode/game/g_newsystem.h new file mode 100644 index 0000000..71e393e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_newsystem.h @@ -0,0 +1,7 @@ +#ifndef G_NEW_SYSTEM_H +#define G_NEW_SYSTEM_H + +#define G_NEW_PHYSICS +#define G_TRANSITION + +#endif // G_NEW_SYSTEM_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_obj.c b/Toolkit/Programming/GameCode/game/g_obj.c new file mode 100644 index 0000000..d5b31f4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_obj.c @@ -0,0 +1,4808 @@ +// +// g_obj.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "fx.h" +#include "g_local.h" +#include "g_misc.h" +#include "g_DefaultMessageHandler.h" +#include "vector.h" +#include "m_plagueElf_anim.h" +//#include "m_plaguessithra_anim.h" // Can't do this because NUM_MESH_NODES is in all tris headers +#include "Random.h" +#include "angles.h" +#include "g_playstats.h" +#include "m_stats.h" + + +void SpawnFlame(edict_t *self,vec3_t origin); +void SpawnClientAnim(edict_t *self, byte type, char *sound); + + +void ObjectStaticsInit(void) +{ + classStatics[CID_OBJECT].msgReceivers[MSG_DEATH] = DefaultObjectDieHandler; +} + +void objpush_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{//FIXME: make player push? + float ratio; + + if ((!other->groundentity) || (other->groundentity == self)) + return; + + ratio = (float)other->mass / (float)self->mass; + if (M_walkmove (self, other->s.angles[YAW], 20 * ratio * FRAMETIME)) + { + if (self->pain_debounce_time < level.time) + { + // there are going to be more sounds to choose from, dependant on the mass of the object + gi.sound (self, CHAN_BODY, gi.soundindex("misc/barrelmove.wav"), 1, ATTN_STATIC, 0); + self->pain_debounce_time = level.time + 1.2; + } + } +} + +/*-------------------------------------- + It is assumed all bounding boxes for objects were initially implimented as if the objects + yaw was 0 +----------------------------------------*/ +void BboxYawAndScale(edict_t *self) +{ + vec3_t holdmins,holdmaxs; + vec3_t forward, right; + vec3_t point[4],minpoint,maxpoint; + int i; + float scale; + + VectorCopy(self->mins,holdmins); + VectorCopy(self->maxs,holdmaxs); + + AngleVectors (self->s.angles,forward, right,NULL); + + VectorMA (self->s.origin, holdmins[0],forward, point[0]); + VectorMA (point[0], holdmins[1],right, point[0]); + + VectorMA (self->s.origin, holdmaxs[0],forward, point[1]); + VectorMA (point[1], holdmaxs[1],right, point[1]); + + VectorMA (self->s.origin, holdmins[0],forward, point[2]); + VectorMA (point[2], holdmaxs[1],right, point[2]); + + VectorMA (self->s.origin, holdmaxs[0],forward, point[3]); + VectorMA (point[3], holdmins[1],right, point[3]); + + minpoint[0] = point[0][0]; + minpoint[1] = point[0][1]; + + maxpoint[0] = point[0][0]; + maxpoint[1] = point[0][1]; + + // Find max and min point + for (i=0;i<4;++i) + { + if (point[i][0] < minpoint[0]) + minpoint[0] = point[i][0]; + + if (point[i][1] < minpoint[1]) + minpoint[1] = point[i][1]; + + + if (point[i][0] > maxpoint[0]) + maxpoint[0] = point[i][0]; + + if (point[i][1] > maxpoint[1]) + maxpoint[1] = point[i][1]; + + } + + scale = self->s.scale; + if (scale == 0) + scale = 1; + + self->mins[0] = (minpoint[0] - self->s.origin[0]) * scale; + self->mins[1] = (minpoint[1] - self->s.origin[1]) * scale; + self->mins[2] = self->mins[2] * scale; + + self->maxs[0] = (maxpoint[0] - self->s.origin[0]) * scale; + self->maxs[1] = (maxpoint[1] - self->s.origin[1]) * scale; + self->maxs[2] = self->maxs[2] * scale; + +} + +/*-------------------------------------- + It is assumed all bounding boxes for objects were initially implimented as if the objects + yaw was 0 +----------------------------------------*/ +void BboxYawAndScaleAndMoveUp(edict_t *self) +{ + vec3_t holdmins,holdmaxs; + vec3_t forward, right; + vec3_t point[4],minpoint,maxpoint; + int i; + float scale; + + VectorCopy(self->mins,holdmins); + VectorCopy(self->maxs,holdmaxs); + + AngleVectors (self->s.angles,forward, right,NULL); + + VectorMA (self->s.origin, holdmins[0],forward, point[0]); + VectorMA (point[0], holdmins[1],right, point[0]); + + VectorMA (self->s.origin, holdmaxs[0],forward, point[1]); + VectorMA (point[1], holdmaxs[1],right, point[1]); + + VectorMA (self->s.origin, holdmins[0],forward, point[2]); + VectorMA (point[2], holdmaxs[1],right, point[2]); + + VectorMA (self->s.origin, holdmaxs[0],forward, point[3]); + VectorMA (point[3], holdmins[1],right, point[3]); + + minpoint[0] = point[0][0]; + minpoint[1] = point[0][1]; + + maxpoint[0] = point[0][0]; + maxpoint[1] = point[0][1]; + + // Find max and min point + for (i=0;i<4;++i) + { + if (point[i][0] < minpoint[0]) + minpoint[0] = point[i][0]; + + if (point[i][1] < minpoint[1]) + minpoint[1] = point[i][1]; + + + if (point[i][0] > maxpoint[0]) + maxpoint[0] = point[i][0]; + + if (point[i][1] > maxpoint[1]) + maxpoint[1] = point[i][1]; + + } + + scale = self->s.scale; + if (scale == 0) + scale = 1; + + self->mins[0] = (minpoint[0] - self->s.origin[0]) * scale; + self->mins[1] = (minpoint[1] - self->s.origin[1]) * scale; + self->mins[2] = self->mins[2] * scale; + + self->maxs[0] = (maxpoint[0] - self->s.origin[0]) * scale; + self->maxs[1] = (maxpoint[1] - self->s.origin[1]) * scale; + self->maxs[2] = self->maxs[2] * scale; + +} + +void ObjectInit(edict_t *self,int health,int mass, int materialtype,int solid) +{ + self->movetype = PHYSICSTYPE_NONE; + self->solid = solid; + self->msgHandler = DefaultMsgHandler; + self->takedamage = DAMAGE_YES; + self->clipmask = MASK_MONSTERSOLID; + + if (!self->health) + self->health = health; + + if (!self->mass) + { + self->mass = mass; + if (!mass) // Needs a mass if it breaks up + self->mass = 10; + } + + if (!self->materialtype) + self->materialtype = materialtype; + + if (self->spawnflags & OBJ_INVULNERABLE) // Invulnerable + { + self->takedamage = DAMAGE_NO; + } + else + { + self->takedamage = DAMAGE_YES; + } + + BboxYawAndScale(self); + + if (!(self->spawnflags & OBJ_NOPUSH)) // PUSHABLE + { + self->movetype = PHYSICSTYPE_STOP; + self->monsterinfo.aiflags = AI_NOSTEP; + self->touch = objpush_touch; + + self->think = M_droptofloor; + self->nextthink = level.time + (2 * FRAMETIME); + } + else + { + gi.linkentity (self); + } +} + + + +//============================================================================ +// +// OBJECTS +// +//============================================================================ + + +/*QUAKED obj_banner (1 .5 0) (-8 -44 -296) (8 44 0) INVULNERABLE ANIMATE EXPLODING NOPUSH +A really big banner. +------- FIELDS ------------------ +INVULNERABLE - N/A (it can't ever be hurt) +ANIMATE - makes it flutter in the breeze, just like a...banner +EXPLODING - N/A +NOPUSH - N/A (banner can't be pushed) +------- KEYS ------------------ +skinnum = 0 : blue + 1 : red +----------------------------------- +*/ +void SP_obj_banner (edict_t *self) +{ + +// G_FreeEdict(self); +// return; + + VectorSet(self->mins, -8, -44, -296); + VectorSet(self->maxs, 8, 44, 0); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + SpawnClientAnim(self, FX_ANIM_BANNER, "ambient/bannerflap.wav"); + ObjectInit(self,40,200,MAT_CLOTH,SOLID_BBOX); +} + +/*QUAKED obj_banneronpole (1 .5 0) (-8 -28 -30) (8 28 30) INVULNERABLE ANIMATE EXPLODING NOPUSH +A banner on a pole sticking out of a wall. +------- FIELDS ------------------ +INVULNERABLE - can it be hurt +ANIMATE - makes it flutter in the breeze +EXPLODING - N/A +NOPUSH - N/A (banner can't be pushed) +----------------------------------- +*/ +void SP_obj_banneronpole (edict_t *self) +{ + VectorSet(self->mins, -8, -28, -30); + VectorSet(self->maxs, 8, 28, 30); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + SpawnClientAnim(self, FX_ANIM_BANNERONPOLE, "ambient/bannerflap.wav"); + ObjectInit(self,40,200,MAT_WOOD,SOLID_BBOX); +} + + + +/*----------------------------------------------- + exploding barrel +-----------------------------------------------*/ +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); +void barrel_explode_think(edict_t *self) +{ + vec3_t loc; + + VectorCopy(self->s.origin, loc); + AlertMonsters (self, self->owner, 3, false); + + self->fire_damage_time = level.time + 1.0; + self->svflags |= SVF_ONFIRE; + BecomeDebris(self); + + T_DamageRadiusFromLoc(loc, self->owner, self->owner, NULL, BARREL_EXPLODE_RADIUS, + BARREL_EXPLODE_DMG_MAX, BARREL_EXPLODE_DMG_MIN, + DAMAGE_NORMAL|DAMAGE_FIRE|DAMAGE_EXTRA_KNOCKBACK,MOD_BARREL); + + // Start the explosion + gi.CreateEffect(NULL, FX_BARREL_EXPLODE, CEF_BROADCAST, loc, ""); + + G_SetToFree(self); +} + + + +int barrel_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ + self->think = barrel_explode_think; + self->nextthink = level.time + FRAMETIME; + self->owner = attacker; // The one to get credit for this should be the one destroying the barrel. + + self->takedamage = DAMAGE_NO; + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_NOT; + self->touch = NULL; + self->blocked = NULL; + self->isBlocked = NULL; + self->isBlocking = NULL; + self->bounced = NULL; + + gi.linkentity(self); + + return 1; +} + + + +/*QUAKED obj_barrel (1 .5 0) (-12 -12 -19) (12 12 19) INVULNERABLE ANIMATE EXPLODING NOPUSH +A barrel. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - the barrel will explode and cause radius damage +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_barrel (edict_t *self) +{ + + self->s.modelindex = gi.modelindex("models/objects/barrel/normal/tris.fm"); + + VectorSet(self->mins, -12, -12, -19); + VectorSet(self->maxs, 12, 12, 19); + + self->dmg = 10; + + ObjectInit(self,10,60,MAT_WOOD,SOLID_BBOX); + + if (self->spawnflags & OBJ_EXPLODING) + { + // Set this up so we go through die rather than the message. + self->classID = CID_NONE; + self->die = barrel_die; + self->s.skinnum = 1; + } +} + +/*QUAKED obj_broom (1 .5 0) (-2 -2 -25) (2 2 25) INVULNERABLE ANIMATE EXPLODING NOPUSH +A broom. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_broom (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/broom/tris.fm"); + + VectorSet(self->mins, -2, -2, -25); + VectorSet(self->maxs, 2, 2, 25); + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,10,40,MAT_WOOD,SOLID_BBOX); +} + + +/*QUAKED obj_chair1 (1 .5 0) (-12 -8 -26) (12 8 26) INVULNERABLE ANIMATE EXPLODING NOPUSH +A highback wooden chair with a triangle at the top. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_chair1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chairs/chair1/tris.fm"); + + VectorSet(self->mins, -12, -8, -26); + VectorSet(self->maxs, 12, 8, 26); + + ObjectInit(self,20,50,MAT_WOOD,SOLID_BBOX); +} + + +/*QUAKED obj_chair2 (1 .5 0) (-18 -29 -30) (18 29 30) INVULNERABLE ANIMATE EXPLODING NOPUSH +A thick chair with slanted sides +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_chair2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chairs/chair2/tris.fm"); + + VectorSet(self->mins, -18, -29, -30); + VectorSet(self->maxs, 18, 29, 30); + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,20,50,MAT_WOOD,SOLID_BBOX); +} + + +/*QUAKED obj_chair3 (1 .5 0) (-14 -21 -28) (14 21 28) INVULNERABLE ANIMATE EXPLODING NOPUSH +A big stone throne. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_chair3 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chairs/chair3/tris.fm"); + + VectorSet(self->mins, -14, -21, -28); + VectorSet(self->maxs, 14, 21, 28); + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,20,50,MAT_GREYSTONE,SOLID_BBOX); +} + + +void chest1_anim (edict_t *self) +{ + if (self->s.frame < 10) + { + ++self->s.frame; + self->think = chest1_anim; + self->nextthink = level.time + FRAMETIME; + } + else + self->think = NULL; +} + +void chest1_use (edict_t *self, edict_t *other, edict_t *activator) +{ + gi.sound (self, CHAN_VOICE, gi.soundindex("objects/chest.wav"), 1, ATTN_NORM, 0); + + chest1_anim(self); +} + +/*QUAKED obj_chest1 (1 .5 0) (-10 -18 -19) (10 18 19) INVULNERABLE ANIMATE EXPLODING NOPUSH +A large chest with a snake carving on top. When used it opens its lid. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_chest1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chests/chest1/tris.fm"); + + VectorSet(self->mins, -10, -18, -19); + VectorSet(self->maxs, 10, 18, 19); + + ObjectInit(self,60,150,MAT_WOOD,SOLID_BBOX); + + self->use = chest1_use; +} + +/*QUAKED obj_chest2 (1 .5 0) (-14 -17 -9) (14 17 9) INVULNERABLE ANIMATE EXPLODING NOPUSH +A medium sized chest with the top open - for use in the mines +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_chest2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chests/chest2/tris.fm"); + + VectorSet(self->mins, -14, -17, -9); + VectorSet(self->maxs, 14, 17, 9); + + self->spawnflags &= ~OBJ_NOPUSH; + + ObjectInit(self,60,150,MAT_WOOD,SOLID_BBOX); + +} + +/*QUAKED obj_chest3 (1 .5 0) (-10 -17 -6) (10 17 6) INVULNERABLE ANIMATE EXPLODING NOPUSH +A medium sized chest with the top closed - for use in the mines +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_chest3 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chests/chest3/tris.fm"); + + VectorSet(self->mins, -10, -17, -6); + VectorSet(self->maxs, 10, 17, 6); + + self->spawnflags &= ~OBJ_NOPUSH; + + ObjectInit(self,60,150,MAT_WOOD,SOLID_BBOX); + +} + +void cog1_anim (edict_t *self) +{ + + if (self->s.frame < 11) + ++self->s.frame; + else + self->s.frame=1; + + if (self->touch_debounce_time > level.time) // First time through reach anim + { + self->think = cog1_anim; + self->nextthink = level.time + FRAMETIME * 2; + } + else + { + gi.sound (self, CHAN_VOICE, gi.soundindex("misc/null.wav"), 1, ATTN_NORM, 0); + self->think = NULL; + } +} + +void cog1_use (edict_t *self, edict_t *other, edict_t *activator) +{ + gi.sound (self, CHAN_VOICE, gi.soundindex("items/cogsturn.wav"), 1, ATTN_NORM, 0); + + self->touch_debounce_time = level.time + (FRAMETIME * 30); + + self->s.frame=1; + cog1_anim(self); +} + +/*QUAKED obj_cog1 (1 .5 0) (-8 -4 0) (8 4 20) INVULNERABLE ANIMATE EXPLODING NOPUSH +A cog with spokes coming out the front of it. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (cog can't be pushed) +----------------------------------- +*/ +void SP_obj_cog1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/cogs/cog1/tris.fm"); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + VectorSet(self->mins, -8, -4, 0); + VectorSet(self->maxs, 8, 4, 20); + + ObjectInit(self,40,20,MAT_WOOD,SOLID_BBOX); + + self->use = cog1_use; + + +} + + +void SpawnCorpse(edict_t *self) +{ + int chance; + + self->s.modelindex = gi.modelindex("models/monsters/plaguelf/tris.fm"); + + if ((self->style > 4) || (self->style < 0)) + self->style = 0; + + if (self->style == 0) + self->s.frame = FRAME_death13end; + else if (self->style == 1) + self->s.frame = FRAME_deathb13end; + else if (self->style == 2) + self->s.frame = FRAME_deathc13end; + else if (self->style == 3) + self->s.frame = FRAME_deathd13end; + else if (self->style == 4) + { + self->s.frame = FRAME_skewered; + self->s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + } + + chance = irand(0, 3); + if(chance < 1) + { + //show the hammer + self->s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + } + else if(chance < 2) + { + //show the hoe + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + } + else + { + //show the gaff (that hook thingie) + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + } + + VectorSet(self->mins,-30,-12,-2); + VectorSet(self->maxs,30,12,2); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->svflags |= SVF_DEADMONSTER;//doesn't block walking + + ObjectInit(self,40,60,MAT_FLESH,SOLID_BBOX); +} + +/*QUAKED obj_corpse1 (1 .5 0) (-30 -12 0) (30 12 5) INVULNERABLE ANIMATE EXPLODING NOPUSH +Plague elf dead. +---------- KEYS ----------------- +style - (default 0) + 0 - both arms above head + 1 - on side + 2 - arm over face + 3 - arms out to side + 4 - skewered +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (corpse can't be pushed) +----------------------------------- +*/ +void SP_obj_corpse1(edict_t *self) +{ + SpawnCorpse(self); + + self->s.skinnum = 0; +} + + +/*QUAKED obj_corpse2 (1 .5 0) (-30 -12 0) (30 12 5) INVULNERABLE ANIMATE EXPLODING NOPUSH +Plague elf dead with a different skin +---------- KEYS ----------------- +style - (default 0) + 0 - both arms above head + 1 - on side + 2 - arm over face + 3 - arms out to side + 4 - skewered +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (corpse can't be pushed) +----------------------------------- +*/ +void SP_obj_corpse2(edict_t *self) +{ + SpawnCorpse(self); + + self->s.skinnum = 1; +} + +#define PELF_NUM_PAIN_VOICES 4 +#define PELF_NUM_IDLE_VOICES 4 +#define PELF_NUM_TOUCH_VOICES 7 + +static const char *dying_pelf_touch_voices[PELF_NUM_TOUCH_VOICES] = +{ + "voices/helpe.wav", + "voices/helpk.wav", + "voices/helpm.wav", + "voices/getawayb.wav", + "voices/leavemeb.wav", + "voices/mercyp.wav", + "voices/nomrj.wav", +}; + +static const char *dying_pelf_pain_voices[PELF_NUM_PAIN_VOICES] = +{ + "voices/getawayb.wav", + "voices/leavemeb.wav", + "voices/mercyp.wav", + "voices/nomrj.wav", +}; + +static const char *dying_pelf_idle_voices[PELF_NUM_IDLE_VOICES] = +{ + "pelfgasp.wav", + "pelfpant.wav", + "pelfshiv.wav", + "pelfsigh.wav", +}; + +void dying_elf_sounds (edict_t *self, int type) +{ + char sound_string[1024]; + + strcpy(sound_string, "monsters/plagueElf/"); + + switch(type) + { + case DYING_ELF_PAIN_VOICE: + strcat(sound_string, dying_pelf_pain_voices[irand(0, PELF_NUM_PAIN_VOICES - 1)]); + gi.sound (self, CHAN_VOICE, gi.soundindex(sound_string), 1, ATTN_NORM, 0); + break; + case DYING_ELF_IDLE_VOICE: + strcat(sound_string, dying_pelf_idle_voices[irand(0, PELF_NUM_IDLE_VOICES - 1)]); + gi.sound (self, CHAN_VOICE, gi.soundindex(sound_string), 1, ATTN_IDLE, 0); + break; + case DYING_ELF_TOUCH_VOICE: + strcat(sound_string, dying_pelf_touch_voices[irand(0, PELF_NUM_TOUCH_VOICES - 1)]); + gi.sound (self, CHAN_VOICE, gi.soundindex(sound_string), 1, ATTN_NORM, 0); + break; + } +} + +void dying_elf_idle(edict_t *self) +{ + ++self->s.frame; + if (self->s.frame > FRAME_fetal26) + { + self->s.frame=FRAME_fetal1; + self->nextthink = level.time + FRAMETIME; + } + + if(!irand(0, 50)) + dying_elf_sounds(self, DYING_ELF_IDLE_VOICE); + + self->think = dying_elf_idle; + self->nextthink = level.time + FRAMETIME; +} + +void dying_elf_reach_anim(edict_t *self) +{ + if (self->touch_debounce_time < level.time) // First time through reach anim + { + self->s.frame = FRAME_reach1; + self->touch_debounce_time = level.time + (FRAMETIME * 60); + } + else if (!self->count) // Reaching + { + ++self->s.frame; + + self->think = dying_elf_idle; + self->nextthink = level.time + FRAMETIME; + } + + if (self->s.frame > FRAME_reach38) // All done, stay down for a bit + { + self->s.frame = FRAME_fetal1; + self->think = dying_elf_idle; + } + else + { + self->think = dying_elf_reach_anim; + } + + self->nextthink = level.time + FRAMETIME; +} + +void dying_elf_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (self->touch_debounce_time < level.time) // First time through reach anim + { + if (irand(1,3) == 1 || self->touch_debounce_time == -1) + { + self->enemy = other; + dying_elf_reach_anim(self); + if (self->enemy->client || self->enemy->svflags & SVF_MONSTER) + dying_elf_sounds(self, DYING_ELF_TOUCH_VOICE); + } + else + self->touch_debounce_time = level.time + (FRAMETIME * 20); + } +} + +int dying_elf_pain (edict_t *self, edict_t *other, float kick, int damage) +{ + self->enemy = other; + dying_elf_reach_anim(self); + if (self->enemy->client || self->enemy->svflags & SVF_MONSTER) + dying_elf_sounds(self, DYING_ELF_PAIN_VOICE); + + return true; +} + +int dying_elf_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ + int chance; + + chance = irand(0, 2); + switch(chance) + { + case 0: + gi.sound(self, CHAN_VOICE, gi.soundindex("monsters/plagueElf/death1.wav"), 1, ATTN_NORM, 0); + break; + + case 1: + gi.sound(self, CHAN_VOICE, gi.soundindex("monsters/plagueElf/death2.wav"), 1, ATTN_NORM, 0); + break; + + case 2: + gi.sound(self, CHAN_VOICE, gi.soundindex("monsters/plagueElf/death3.wav"), 1, ATTN_NORM, 0); + break; + } + + BecomeDebris(self); + return (false); +} + +/*QUAKED obj_dying_elf (1 .5 0) (-30 -12 0) (30 12 5) INVULNERABLE ANIMATE EXPLODING NOPUSH +Plague elf lying on the ground shaking. +---------- KEYS ----------------- +style - skin to use +0 - +1 - +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (corpse can't be pushed) +----------------------------------- +*/ +void SP_obj_dying_elf(edict_t *self) +{ + + VectorSet(self->mins,-32,-32,-2); + VectorSet(self->maxs,32,32,6); + + self->s.modelindex = gi.modelindex("models/monsters/plaguelf/tris.fm"); + + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->movetype = PHYSICSTYPE_STEP; + + self->touch_debounce_time = -1; + self->touch = dying_elf_touch; + self->pain = dying_elf_pain; + self->die = dying_elf_die; + + ObjectInit(self, 40, 60, MAT_FLESH, SOLID_BBOX); + + // No weapons + self->s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + + self->s.frame = FRAME_fetal1; + self->think = dying_elf_idle; + self->nextthink = level.time + FRAMETIME; +} + + +/*QUAKED obj_sign1 (1 .5 0) (-29 -4 -16) (29 4 16) INVULNERABLE ANIMATE EXPLODING NOPUSH +A square sign coming out of a wall. +--------KEYS------------------- +style - +0 - sign with a dragon +1 - sign with two steins +2 - sign with a fish +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (sign1 can't be pushed) +----------------------------------- +*/ +void SP_obj_sign1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/signs/sign1/tris.fm"); + + VectorSet(self->mins, -29, -4,-16); + VectorSet(self->maxs, 29, 4, 16); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,40,150,MAT_WOOD,SOLID_BBOX); + + if (self->style==0) + self->s.skinnum = 0; + else if (self->style==1) + self->s.skinnum = 1; + else if (self->style==2) + self->s.skinnum = 2; + else + self->s.skinnum = 0; + + self->s.frame = 3; + +} + + +/*QUAKED obj_sign4 (1 .5 0) (-8 -18 -29) (8 18 29) INVULNERABLE ANIMATE EXPLODING NOPUSH +A square sign that is on top of a post. It is leaning badly. +For the MINE or DESERT areas. +style - +0 for the Andorian skin +1 for the Tchecktrik skin + +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (sign4 can't be pushed) +----------------------------------- +*/ +void SP_obj_sign4 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/signs/sign4/tris.fm"); + + VectorSet(self->mins, -8, -18, -29); + VectorSet(self->maxs, 8, 18, 29); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + if (self->style==0) + self->s.skinnum = 0; + else if (self->style==1) + self->s.skinnum = 1; + + + ObjectInit(self,40,150,MAT_WOOD,SOLID_BBOX); +} + +/*QUAK-ED obj_stalagmite1 (1 .5 0) (-32 -32 -200) (32 32 0) INVULNERABLE ANIMATE EXPLODING DARKSKIN +A big long thick stalagmite.These point up. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +DARKSKIN - if checked it uses the dark skin +----------------------------------- +*/ +void SP_obj_stalagmite1(edict_t *self) +{ + self->s.modelindex=gi.modelindex("models/objects/stalagmite/smite1/tris.fm"); + + VectorSet(self->mins,-32,-32,-200); + VectorSet(self->maxs,32,32,0); + + if (self->spawnflags & 8) + self->s.skinnum = 1; + + ObjectInit(self,200,300,MAT_BROWNSTONE,SOLID_BBOX); + +} + + +/*QUAK-ED obj_stalagmite2 (1 .5 0) (-32 -32 -128) (32 32 0) DARKSKIN +A big squat stalagmite.These point up. +------- FIELDS ------------------ +DARKSKIN - if checked it uses the dark skin +----------------------------------- +*/ +void SP_obj_stalagmite2(edict_t *self) +{ + self->s.modelindex=gi.modelindex("models/objects/stalagmite/smite2/tris.fm"); + + VectorSet(self->mins,-32,-32,-128); + VectorSet(self->maxs,32,32,0); + + if (self->spawnflags & 1) + self->s.skinnum = 1; + + ObjectInit(self,200,300,MAT_BROWNSTONE,SOLID_BBOX); +} + +/*QUAK-ED obj_stalagmite3 (1 .5 0) (-32 -32 -200) (32 32 0) DARKSKIN +A long pointy stalagmite. These point up +------- FIELDS ------------------ +DARKSKIN - if checked it uses the dark skin +----------------------------------- +-*/ +void SP_obj_stalagmite3(edict_t *self) +{ + self->s.modelindex=gi.modelindex("models/objects/stalagmite/smite3/tris.fm"); + + VectorSet(self->mins,-16,-16,-200); + VectorSet(self->maxs,16,16,0); + + if (self->spawnflags & 1) + self->s.skinnum = 1; + + ObjectInit(self,200,200,MAT_BROWNSTONE,SOLID_BBOX); +} + +/*QUAKED obj_statue_corvus (1 .5 0) (-16 -16 0) (16 16 32) INVULNERABLE ANIMATE EXPLODING NOPUSH +A statue of Corvus. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_statue_corvus (edict_t *self) +{ + VectorSet(self->mins, -16, -16, 0); + VectorSet(self->maxs, 16, 16, 128); + + self->s.modelindex = gi.modelindex("models/objects/statue/corvus/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_statue_dolphin1 (1 .5 0) (-68 -22 -30) (68 22 30) VULNERABLE ANIMATE EXPLODING NOPUSH +The dolphin on all fours +------- FIELDS ------------------ +VULNERABLE - it can be hurt - default it can't be +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_dolphin1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/dolphin/tris.fm"); + + VectorSet(self->mins, -68, -22, -30); + VectorSet(self->maxs, 68, 22, 30); + + self->spawnflags |= OBJ_NOPUSH; + if (self->spawnflags & OBJ_INVULNERABLE) + self->spawnflags &= ~OBJ_INVULNERABLE; // can be destroyed + else + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,300,200,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_statue_dolphin2 (1 .5 0) (-17 -20 -70) (17 20 70) INVULNERABLE ANIMATE EXPLODING NOPUSH +The dolphin on a wall. Head turned to the right +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_dolphin2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/dolphin/tris.fm"); + + VectorSet(self->mins, -17, -20, -70); + VectorSet(self->maxs, 17, 20, 70); + + self->s.frame = 1; + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,300,200,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_statue_dolphin3 (1 .5 0) (-17 -20 -70) (17 20 70) INVULNERABLE ANIMATE EXPLODING NOPUSH +The dolphin on a wall. Head turned to the left +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_dolphin3 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/dolphin/tris.fm"); + + VectorSet(self->mins, -17, -20, -70); + VectorSet(self->maxs, 17, 20, 70); + + self->s.frame = 3; + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,300,200,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_statue_dolphin4 (1 .5 0) (-63 -22 -37) (63 22 37) INVULNERABLE ANIMATE EXPLODING NOPUSH +The dolphin up on two legs +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_dolphin4 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/dolphin/tris.fm"); + + VectorSet(self->mins, -63, -22, -37); + VectorSet(self->maxs, 63, 22, 37); + self->s.frame = 2; + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,300,200,MAT_GREYSTONE,SOLID_BBOX); +} + + +/*QUAKED obj_statue_guardian (1 .5 0) (-100 -64 0) (64 64 128) INVULNERABLE ANIMATE EXPLODING NOPUSH +A big statue of a fish guy on his haunches holding a spear. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_guardian (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/guardian/tris.fm"); + + VectorSet(self->mins, -100, -64, 0); + VectorSet(self->maxs, 64, 64, 128); + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,400,300,MAT_METAL,SOLID_BBOX); +} + +/*QUAKED obj_table1 (1 .5 0) (-28 -54 -18) (28 54 18) INVULNERABLE ANIMATE EXPLODING NOPUSH +A large wooden dining table with two legs. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_table1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/tables/table1/tris.fm"); + + VectorSet(self->mins, -28, -54, -18); + VectorSet(self->maxs, 28, 54, 18); + + ObjectInit(self,40,100,MAT_WOOD,SOLID_BBOX); + +} + +/*QUAKED obj_table2 (1 .5 0) (-28 -54 -17) (28 54 17) INVULNERABLE ANIMATE EXPLODING NOPUSH +A grey stone table. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_table2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/tables/table2/tris.fm"); + + VectorSet(self->mins, -28, -54, -17); + VectorSet(self->maxs, 28, 54, 17); + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,80,150,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_throne (1 .5 0) (-20 -22 -44) (20 22 44) INVULNERABLE ANIMATE EXPLODING NOPUSH +A highbacked throne. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_throne (edict_t *self) +{ + VectorSet(self->mins, -20, -22, -44); + VectorSet(self->maxs, 20,22, 44); + + self->s.modelindex = gi.modelindex("models/objects/chairs/throne/tris.fm"); + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,150,200,MAT_WOOD,SOLID_BBOX); +} + + +/*QUAKED obj_kettle (1 .5 0) (-8 -8 0) (8 8 10) INVULNERABLE ANIMATE EXPLODING NOPUSH +A kettle. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_kettle (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pots/kettle/tris.fm"); + + VectorSet(self->mins, -8, -8, 0); + VectorSet(self->maxs, 8, 8, 10); + + ObjectInit(self,40,100,MAT_METAL,SOLID_BBOX); +} + +/*QUAKED obj_cauldron (1 .5 0) (-22 -22 -10) (22 22 10) INVULNERABLE ANIMATE EXPLODING NOPUSH +A metal cauldron filled with green liquid +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_cauldron (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pots/caldrn/tris.fm"); + + VectorSet(self->mins, -22, -22, -10); + VectorSet(self->maxs, 22, 22, 10); + + if (self->spawnflags & OBJ_ANIMATE) // Animate it + { + self->s.sound = gi.soundindex("ambient/cauldronbubble.wav"); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; + } + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,60,100,MAT_METAL,SOLID_BBOX); +} + + +/*QUAKED obj_firepot (1 .5 0) (-18 -18 -12) (18 18 12) INVULNERABLE ANIMATE EXPLODING NOPUSH +A grey stone firepot +------- FIELDS ------------------ +INVULNERABLE - always invulnerable +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't ever be moved by player) +----------------------------------- +*/ +void SP_obj_firepot (edict_t *self) +{ + vec3_t holdorigin; + + self->s.modelindex = gi.modelindex("models/objects/pots/firepot/tris.fm"); + self->s.sound = gi.soundindex("ambient/fireplace.wav"); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; + + VectorSet(self->mins, -18, -18, -12); + VectorSet(self->maxs, 18, 18, 12); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Cant' be moved + + ObjectInit(self,140,100,MAT_GREYSTONE,SOLID_BBOX); + + if (self->spawnflags & OBJ_ANIMATE) // Animate it + { + VectorCopy(self->s.origin,holdorigin); + holdorigin[2] += 30; + SpawnFlame(self,holdorigin); + } +} + +/*QUAKED obj_statue_duckbill1 (1 .5 0) (-67 -24 -51) (67 24 51) INVULNERABLE ANIMATE EXPLODING NOPUSH +The duckbilled thing - tail to the right +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_duckbill1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/duckbill/tris.fm"); + + VectorSet(self->mins, -67, -24, -51); + VectorSet(self->maxs, 67, 24, 51); + + self->s.frame = 0; + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + + ObjectInit(self,150,100,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_statue_duckbill2 (1 .5 0) (-67 -24 -50) (67 24 50) INVULNERABLE ANIMATE EXPLODING NOPUSH +The duckbilled thing - tail to the left +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_duckbill2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/duckbill/tris.fm"); + + VectorSet(self->mins, -67, -24, -50); + VectorSet(self->maxs, 67, 24, 50); + + self->s.frame = 1; + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + + ObjectInit(self,150,100,MAT_GREYSTONE,SOLID_BBOX); +} + + +void globebottom_turn (edict_t *self) +{ + float current, ideal, move; + + M_ChangeYaw(self); + + current = anglemod(self->s.angles[YAW]); + ideal = self->ideal_yaw; + move = ideal - current; + + if (current == ideal || abs(move) < 0.1) + { + self->s.angles[YAW] = ceil(ideal); + + if (self->s.angles[YAW] == 225 && self->enemy->s.angles[YAW] == 45) + { + G_UseTargets(self, self); + } + self->monsterinfo.idle_time = 0; + self->think = NULL; + } + else + { + self->think = globebottom_turn; + self->nextthink = level.time + FRAMETIME; + } +} + +void globetop_turn (edict_t *self) +{ + float current, ideal, move; + + M_ChangeYaw(self); + + current = anglemod(self->s.angles[YAW]); + ideal = self->ideal_yaw; + move = ideal - current; + + if (current == ideal || abs(move) < 0.1) + { + self->s.angles[YAW] = ceil(ideal); + + if (self->s.angles[YAW] == 270) // Because they want it to swing all the way around + { + self->ideal_yaw = 45; + self->think = globetop_turn; + self->nextthink = level.time + FRAMETIME; + } + else + { + if (self->s.angles[YAW] == 45 && self->enemy->s.angles[YAW] == 225) + { + G_UseTargets(self, self); + } + self->monsterinfo.idle_time = 0; + self->think = NULL; + } + } + else + { + self->think = globetop_turn; + self->nextthink = level.time + FRAMETIME; + } +} + +void globetop_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->monsterinfo.idle_time) + return; + + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/globetop.wav"), 1, ATTN_NORM, 0); + + self->monsterinfo.idle_time = 1; + + self->ideal_yaw = 270; + + self->think = globetop_turn; + self->nextthink = level.time + FRAMETIME; +} + +void globebottom_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->monsterinfo.idle_time) + return; + + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/globebottomstart.wav"), 1, ATTN_NORM, 0); + + self->monsterinfo.idle_time = 1; + + self->ideal_yaw = 225; + + self->think = globebottom_turn; + self->nextthink = level.time + FRAMETIME; +} + +/*QUAKED obj_seasonglobe (1 .5 0) (-80 -80 0) (80 80 100) INVULNERABLE ANIMATE EXPLODING NOPUSH +The globe thingy +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (globe can't be moved) +----------------------------------- +*/ +void SP_obj_seasonglobe (edict_t *bottom) +{ + edict_t *top; + + bottom->spawnflags |= OBJ_NOPUSH; // Can't be pushed + bottom->movetype = PHYSICSTYPE_NONE; + bottom->solid = SOLID_BBOX; + VectorSet(bottom->mins, -80, -80, 0); + VectorSet(bottom->maxs, 80, 80, 320); + bottom->s.modelindex = gi.modelindex("models/objects/globe/globebottom/tris.fm"); + bottom->s.frame = 1; + bottom->s.scale = 1.75; + BboxYawAndScale(bottom); + bottom->targetname = "globebottom"; + bottom->use = globebottom_use; + bottom->yaw_speed = 2.5; + VectorSet(bottom->s.angles, 0, 90, 0); + gi.linkentity (bottom); + + top = G_Spawn(); + + VectorCopy(bottom->s.origin,top->s.origin); + top->s.origin[2] += 36; + top->movetype = PHYSICSTYPE_NONE; + top->solid = SOLID_BBOX; + VectorSet(top->mins, -80, -80, 0); + VectorSet(top->maxs, 80, 80, 100); + top->s.modelindex = gi.modelindex("models/objects/globe/globetop/tris.fm"); + top->s.frame = 1; + top->s.scale = 1.75; + BboxYawAndScale(top); + + bottom->spawnflags |= OBJ_NOPUSH; // Can't be pushed + top->targetname = "globetop"; + top->use = globetop_use; + top->yaw_speed = 2.5; + top->target = bottom->target; + VectorSet(top->s.angles, 0, 120, 0); + gi.linkentity (top); + + bottom->enemy = top; + top->enemy = bottom; +} + + + +/*QUAKED obj_stein (1 .5 0) (-2 -2 -3) (2 2 3) INVULNERABLE ANIMATE EXPLODING NOPUSH +A beer stein. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_stein (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/stein/tris.fm"); + + VectorSet(self->mins, -2, -2, -3); + VectorSet(self->maxs, 2, 2, 3); + + ObjectInit(self,15,10,MAT_METAL,SOLID_BBOX); +} + +/*QUAKED obj_scroll (1 .5 0) (-2 -18 -3) (2 18 3) INVULNERABLE ANIMATE EXPLODING NOPUSH +A paper scroll +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_scroll (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/scroll/tris.fm"); + + VectorSet(self->mins, -2, -18, -3); + VectorSet(self->maxs, 2, 18, 3); + + ObjectInit(self,10,50,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_fountain_fish (1 .5 0) (-52 -34 -48) (52 34 48) INVULNERABLE ANIMATE EXPLODING NOPUSH +A two headed fish fountain +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_fountain_fish (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/fountainfish/tris.fm"); + + VectorSet(self->mins, -52, -34, -48); + VectorSet(self->maxs, 52, 34, 48); + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,40,50,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_statue_boulderfish (1 .5 0) (-26 -16 -27) (26 16 27) INVULNERABLE ANIMATE EXPLODING NOPUSH +A statue of a fish. The one which raises up a boulder. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_boulderfish (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/boulderfish/tris.fm"); + + VectorSet(self->mins, -26, -16, -27); + VectorSet(self->maxs, 26, 16, 27); + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,200,150,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_pottedplant (1 .5 0) (-20 -20 -30) (20 20 30) INVULNERABLE ANIMATE EXPLODING NOPUSH +A potted plant with ferns +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_pottedplant (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pots/plant/tris.fm"); + + VectorSet(self->mins, -20, -20, -30); + VectorSet(self->maxs, 20, 20, 30); + + ObjectInit(self,20,50,MAT_POTTERY,SOLID_BBOX); +} + +/*QUAKED obj_plant1 (1 .5 0) (-8 -8 -24) (8 8 24) INVULNERABLE ANIMATE EXPLODING NOPUSH +A clump of tall, thin, plants +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (plant1 can't be moved) +----------------------------------- +*/ +void SP_obj_plant1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/plant1/tris.fm"); + + // The bbox in QUAKED comment is bigger than code bbox to show designers how big model is + VectorSet(self->mins, -8, -8, -24); + VectorSet(self->maxs, 8, 8, 24); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + self->s.effects|=EF_CAMERA_NO_CLIP; + + ObjectInit(self,20,50,MAT_LEAF,SOLID_NOT); + +} + +/*QUAKED obj_plant2 (1 .5 0) (-20 -20 -10) (20 20 20) INVULNERABLE ANIMATE EXPLODING NOPUSH +A plant with broad leaves. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (plant2 can't be moved) +----------------------------------- +*/ +void SP_obj_plant2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/plant2/tris.fm"); + + // The bbox in QUAKED comment is bigger than code bbox to show designers how big model is + VectorSet(self->mins, -20, -20, -10); + VectorSet(self->maxs, 20, 20, 20); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + self->s.effects|=EF_CAMERA_NO_CLIP; + + ObjectInit(self,20,50,MAT_LEAF,SOLID_NOT); + +} + +/*QUAKED obj_plant3 (1 .5 0) (-8 -8 -12) (8 8 12) INVULNERABLE ANIMATE EXPLODING NOPUSH +A group of ferns +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (plant3 can't be moved) +----------------------------------- +*/ +void SP_obj_plant3 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/plant3/tris.fm"); + + VectorSet(self->mins, -8, -8, -12); + VectorSet(self->maxs, 8, 8, 12); + + if (self->style==0) + self->s.skinnum = 0; + else if (self->style==1) + self->s.skinnum = 1; + else if (self->style==2) + self->s.skinnum = 2; + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + self->s.effects|=EF_CAMERA_NO_CLIP; + + ObjectInit(self,20,50,MAT_LEAF,SOLID_NOT); + +} + +/*QUAKED obj_treetop (1 .5 0) (-176 -176 -125) (176 176 125) INVULNERABLE ANIMATE EXPLODING NOPUSH +A canopy for a tree. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (treetop can't be moved) +----------------------------------- +*/ +void SP_obj_treetop (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/treetop/tris.fm"); + + VectorSet(self->mins, -176, -176, -125); + VectorSet(self->maxs, 176, 176, 125); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,40,50,MAT_WOOD,SOLID_NOT); +} + +/*QUAKED obj_tree (1 .5 0) (-100 -100 -120) (100 100 120) INVULNERABLE ANIMATE EXPLODING NOPUSH +A tree for Matt's level +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (tree can't be moved) +----------------------------------- +*/ +void SP_obj_tree (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/tree/tris.fm"); + + VectorSet(self->mins, -100, -100, -120); + VectorSet(self->maxs, 100, 100, 120); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,40,50,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_tree2 (1 .5 0) (-50 -50 -286) (50 50 286) INVULNERABLE ANIMATE EXPLODING NOPUSH +A tall spikey tree for the swamps +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (tree2 can't be moved) +----------------------------------- +*/ +void SP_obj_tree2 (edict_t *self) +{ + edict_t *moss; + + self->s.modelindex = gi.modelindex("models/objects/plants/tree2/trunk2/tris.fm"); + + VectorSet(self->mins, -50, -50, -286); + VectorSet(self->maxs, 50, 50, 286); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,40,50,MAT_WOOD,SOLID_BBOX); + + + moss = G_Spawn(); + VectorCopy(self->s.origin,moss->s.origin); + VectorCopy(self->s.angles,moss->s.angles); + moss->s.modelindex = gi.modelindex("models/objects/plants/tree2/moss2/tris.fm"); + moss->movetype = PHYSICSTYPE_NONE; + moss->solid = SOLID_NOT; + moss->s.scale = self->s.scale; + moss->s.renderfx |= RF_TRANSLUCENT; + + + BboxYawAndScale(moss); + gi.linkentity (moss); + + self->target_ent = moss; +} + +/*QUAKED obj_tree3 (1 .5 0) (-50 -50 -286) (50 50 286) INVULNERABLE ANIMATE EXPLODING NOPUSH +A tall spikey tree with big roots on the bottom. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (tree3 can't be moved) +----------------------------------- +*/ +void SP_obj_tree3 (edict_t *self) +{ + edict_t *moss; + + self->s.modelindex = gi.modelindex("models/objects/plants/tree3/trunk3/tris.fm"); + + VectorSet(self->mins, -50, -50, -286); + VectorSet(self->maxs, 50, 50, 286); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,40,50,MAT_WOOD,SOLID_BBOX); + + moss = G_Spawn(); + VectorCopy(self->s.origin,moss->s.origin); + VectorCopy(self->s.angles,moss->s.angles); + moss->s.modelindex = gi.modelindex("models/objects/plants/tree3/moss3/tris.fm"); + moss->movetype = PHYSICSTYPE_NONE; + moss->solid = SOLID_NOT; + moss->s.scale = self->s.scale; + moss->s.renderfx |= RF_TRANSLUCENT; + + BboxYawAndScale(moss); + gi.linkentity (moss); + + self->target_ent = moss; +} + +/*QUAKED obj_treetall (1 .5 0) (-46 -46 -340) (46 46 340) INVULNERABLE ANIMATE EXPLODING NOPUSH +A very tall tree +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (tree3 can't be moved) +----------------------------------- +*/ +void SP_obj_treetall (edict_t *self) +{ + edict_t *moss; + + self->s.modelindex = gi.modelindex("models/objects/plants/talltree/trunk1/tris.fm"); + + VectorSet(self->mins, -46, -46, -340); + VectorSet(self->maxs, 46, 46, 340); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,40,50,MAT_WOOD,SOLID_BBOX); + + moss = G_Spawn(); + VectorCopy(self->s.origin,moss->s.origin); + VectorCopy(self->s.angles,moss->s.angles); + moss->s.modelindex = gi.modelindex("models/objects/plants/talltree/moss1/tris.fm"); + moss->movetype = PHYSICSTYPE_NONE; + moss->solid = SOLID_NOT; + moss->s.renderfx |= RF_TRANSLUCENT; + moss->s.scale = self->s.scale; + BboxYawAndScale(moss); + gi.linkentity (moss); + + self->target_ent = moss; +} + +/*QUAKED obj_treefallen (1 .5 0) (-24 -62 -35) (24 62 35) INVULNERABLE ANIMATE EXPLODING NOPUSH +A tree that is leaning as if it had over. Meant to be partially submerged in water or muck. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (treefallen can't be moved) +----------------------------------- +*/ +void SP_obj_treefallen (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/cactus/tris.fm"); + + VectorSet(self->mins, -24, -62, -35); + VectorSet(self->maxs, 24, 62, 35); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,40,50,MAT_WOOD,SOLID_BBOX); + + self->s.frame = 1; +} + + +/*QUAKED obj_shovel (1 .5 0) (-8 -8 -20) (8 8 20) INVULNERABLE ANIMATE EXPLODING NOPUSH +A shovel +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_shovel (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/shovel/tris.fm"); + + VectorSet(self->mins, -8, -8, -20); + VectorSet(self->maxs, 8, 8, 20); + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,20,40,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_woodpile (1 .5 0) (-12 -20 -7) (12 20 7) INVULNERABLE ANIMATE EXPLODING NOPUSH +A pile of chopped wood. +------- FIELDS ------------------ +INVULNERABLE - Can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_woodpile (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/wood/tris.fm"); + + self->spawnflags |= OBJ_NOPUSH; // Can't move + + VectorSet(self->mins, -12, -20, -7); + VectorSet(self->maxs, 12, 20, 7); + self->s.scale = 2; + + ObjectInit(self,100,150,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_fishtrap (1 .5 0) (-14 -28 -13) (14 28 13) INVULNERABLE ANIMATE EXPLODING NOPUSH +A fishtrap +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_fishtrap (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/fishtrap/tris.fm"); + + VectorSet(self->mins, -14, -28, -13); + VectorSet(self->maxs, 14, 28, 13); + + ObjectInit(self,30,100,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_bench (1 .5 0) (-10 -21 -10) (10 21 10) INVULNERABLE ANIMATE EXPLODING NOPUSH +A stone bench to sit on +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_bench (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chairs/bench/tris.fm"); + + VectorSet(self->mins, -10, -22, -10); + VectorSet(self->maxs, 10, 22, 10); + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,3,4,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_bucket (1 .5 0) (-8 -8 -9) (8 8 10) INVULNERABLE ANIMATE EXPLODING NOPUSH +A bucket +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_bucket (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/bucket/tris.fm"); + + VectorSet(self->mins, -8, -8, -9); + VectorSet(self->maxs, 8, 8, 10); + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,3,4,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_ropechain (1 .5 0) (-20 -20 -14) (20 20 14) INVULNERABLE ANIMATE EXPLODING NOPUSH +A pile of rope or chain +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (ropechain can't be moved) + +Variables: +skinnum = 0 : rope + 1 : chain +----------------------------------- +*/ +void SP_obj_ropechain (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/rope/tris.fm"); + + VectorSet(self->mins, -20, -20, -14); + VectorSet(self->maxs, 20, 20, 14); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + if (self->s.skinnum == 0) + ObjectInit(self,80,100,MAT_WOOD,SOLID_BBOX); + else + ObjectInit(self,160,100,MAT_METAL,SOLID_BBOX); +} + + +/*QUAKED obj_wheelbarrow (1 .5 0) (-37 -20 -21) (37 20 21) INVULNERABLE ANIMATE EXPLODING NOPUSH +A wheelbarrow +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_wheelbarrow (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/wheelbarrow/tris.fm"); + + VectorSet(self->mins, -37, -20, -21); + VectorSet(self->maxs, 37, 20, 21); + + ObjectInit(self,60,100,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_wheelbarrowdamaged (1 .5 0) (-38 -26 -20) (38 26 20) INVULNERABLE ANIMATE EXPLODING NOPUSH +A wheelbarrow on it's side missing a wheel +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (wheelbarrowdamaged can't be moved) +----------------------------------- +*/ +void SP_obj_wheelbarrowdamaged (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/wheelbarrow/tris.fm"); + + VectorSet(self->mins, -38, -26, -20); + VectorSet(self->maxs, 38, 26, 20); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->s.frame = 1; + + ObjectInit(self,60,100,MAT_WOOD,SOLID_BBOX); +} + + +/*QUAKED obj_urn (1 .5 0) (-8 -8 -27) (8 8 30) INVULNERABLE ANIMATE EXPLODING NOPUSH +An urn +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_urn (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pots/urn/tris.fm"); + + VectorSet(self->mins, -8, -8, -27); + VectorSet(self->maxs, 8, 8, 30); + + ObjectInit(self,50,100,MAT_POTTERY,SOLID_BBOX); +} + + + +/*QUAKED obj_bigcrystal (1 .5 0) (-35 -35 -50) (35 35 50) INVULNERABLE ANIMATE EXPLODING NOPUSH +A big circular crystal which rotates. +------- KEYS ------------------ +speed - rate of rotation +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_bigcrystal(edict_t *self) +{ + self->s.modelindex=gi.modelindex("models/objects/crystals/bigcrystal/tris.fm"); + + VectorSet(self->mins,-35,-35,-50); + VectorSet(self->maxs,35,35,50); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + ObjectInit(self,350,200,MAT_GREYSTONE,SOLID_BBOX); + + self->avelocity[1] = self->speed; + + self->movetype = PHYSICSTYPE_FLY; + self->gravity = 0; +} + + +/*QUAKED obj_moss1 (1 .5 0) (-4 -10 -40) (4 10 40) INVULNERABLE ANIMATE EXPLODING NOPUSH + +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (moss1 can't be moved) +----------------------------------- +*/ +void SP_obj_moss1(edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/moss/tris.fm"); + + VectorSet(self->mins, -1, -10, -40); + VectorSet(self->maxs, 1, 10, 40); + self->s.skinnum = 0; + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->s.renderfx |= RF_TRANSLUCENT; + ObjectInit(self,10,10,MAT_LEAF,SOLID_NOT); +} + +/*QUAKED obj_moss2 (1 .5 0) (-4 -9 -40) (4 9 40) INVULNERABLE ANIMATE EXPLODING NOPUSH +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (moss2 can't be moved) +----------------------------------- +*/ +void SP_obj_moss2(edict_t *self) +{ + self->s.modelindex=gi.modelindex("models/objects/moss/tris.fm"); + + VectorSet(self->mins,-1,-9,-40); + VectorSet(self->maxs,1,9,40); + self->s.skinnum = 1; + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->s.renderfx |= RF_TRANSLUCENT; + ObjectInit(self,10,10,MAT_LEAF,SOLID_NOT); +} + +/*QUAKED obj_moss3 (1 .5 0) (-4 -15 -40) (4 15 40) INVULNERABLE ANIMATE EXPLODING NOPUSH +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (moss3 can't be moved) +----------------------------------- +*/ +void SP_obj_moss3(edict_t *self) +{ + self->s.modelindex=gi.modelindex("models/objects/moss/tris.fm"); + + VectorSet(self->mins,-1,-15,-40); + VectorSet(self->maxs,1,15,40); + self->s.skinnum = 2; + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->s.renderfx |= RF_TRANSLUCENT; + + ObjectInit(self,10,10,MAT_LEAF,SOLID_NOT); +} + +/*QUAKED obj_moss4 (1 .5 0) (-4 -12 -40) (4 12 40) INVULNERABLE ANIMATE EXPLODING NOPUSH +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (moss4 can't be moved) +----------------------------------- +*/ +void SP_obj_moss4(edict_t *self) +{ + self->s.modelindex=gi.modelindex("models/objects/moss/tris.fm"); + + VectorSet(self->mins,-1,-12,-40); + VectorSet(self->maxs,1,12,40); + self->s.skinnum = 3; + self->s.renderfx |= RF_TRANSLUCENT; + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + ObjectInit(self,10,10,MAT_LEAF,SOLID_NOT); +} + +/*QUAKED obj_moss5 (1 .5 0) (-4 -10 -40) (4 10 40) INVULNERABLE ANIMATE EXPLODING NOPUSH +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (moss5 can't be moved) +----------------------------------- +*/ +void SP_obj_moss5(edict_t *self) +{ + self->s.modelindex=gi.modelindex("models/objects/moss/tris.fm"); + + VectorSet(self->mins,-1,-10,-40); + VectorSet(self->maxs,1,10,40); + self->s.skinnum = 4; + self->s.renderfx |= RF_TRANSLUCENT; + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + ObjectInit(self,10,10,MAT_LEAF,SOLID_NOT); +} + +/*QUAKED obj_floor_candelabrum (1 .5 0) (-8 -8 -35) (8 8 35) INVULNERABLE ANIMATE EXPLODING NOPUSH +A floor candelabrum. +------- FIELDS ------------------ +INVULNERABLE - it can't be destroyed +ANIMATE - makes flickering flames appear +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_floor_candelabrum (edict_t *self) +{ + VectorSet(self->mins, -8, -8, -35); + VectorSet(self->maxs, 8, 8, 35); + + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + SpawnClientAnim(self, FX_ANIM_CANDELABRUM, NULL); + ObjectInit(self,40,60,MAT_METAL,SOLID_BBOX); +} + +/*QUAKED obj_statue_dragonhead (1 .5 0) (-76 -28 -46) (76 28 46) INVULNERABLE ANIMATE EXPLODING NOPUSH +A statue of a dragon head +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_dragonhead (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/dragonhead/tris.fm"); + + VectorSet(self->mins, -76, -28, -46); + VectorSet(self->maxs, 76, 28, 46); + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,200,200,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_statue_dragon (1 .5 0) (-53 -33 -72) (53 33 72) INVULNERABLE ANIMATE EXPLODING NOPUSH +A statue of a dragon +---------- KEYS ----------------- +style - (default 0) + 0 - dragon looking left + 1 - dragon looking right +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_statue_dragon (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/dragon/tris.fm"); + + VectorSet(self->mins, -53, -33, -72); + VectorSet(self->maxs, 53, 33, 72); + + self->spawnflags |= OBJ_NOPUSH; + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,200,400,MAT_GREYSTONE,SOLID_BBOX); + + if (self->style == 0) + self->s.frame = 0; + else if (self->style == 1) + self->s.frame = 1; + else + self->s.frame = 0; + +} + +/*QUAKED obj_flagonpole (1 .5 0) (-8 -8 0) (8 8 60) INVULNERABLE ANIMATE EXPLODING NOPUSH +A flag on a pole +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (flagonpole can't be moved) +----------------------------------- +*/ +void SP_obj_flagonpole (edict_t *self) +{ + VectorSet(self->mins, -8, -28, -30); + VectorSet(self->maxs, 8, 28, 30); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + SpawnClientAnim(self, FX_ANIM_FLAGONPOLE, "ambient/bannerflap.wav"); + ObjectInit(self,40,200,MAT_WOOD,SOLID_BBOX); +} + +void lever1downthink(edict_t *self) +{ + if (self->s.frame < 5) + { + ++self->s.frame; + self->nextthink = level.time + FRAMETIME; + } + else + { + self->think = NULL; + } +} + +void lever1upthink(edict_t *self) +{ + if (self->s.frame > 0) + { + --self->s.frame; + self->nextthink = level.time + FRAMETIME; + } + else + { + self->think = NULL; + } +} + +void lever1_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (!self->s.frame) + { + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/lever1.wav"), 1, ATTN_NORM, 0); + self->think = lever1downthink; + self->nextthink = level.time + FRAMETIME; + } + else if (self->s.frame == 5) + { + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/lever1.wav"), 1, ATTN_NORM, 0); + self->think = lever1upthink; + self->nextthink = level.time + FRAMETIME; + } + G_UseTargets(self, activator); + +} + +/*QUAKED obj_lever1 (1 .5 0) (-6 -14 -17) (6 14 17) INVULNERABLE ANIMATE EXPLODING NOPUSH +A wooden floor lever that is triggerable. +------- FIELDS ------------------ +INVULNERABLE - always invulnerable +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_lever1 can't be moved) +----------------------------------- +*/ +void SP_obj_lever1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/levers/lever1/tris.fm"); + + VectorSet(self->mins, -6, -14, -17); + VectorSet(self->maxs, 6, 14, 17); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,150,125,MAT_WOOD,SOLID_BBOX); + + self->use = lever1_use; +} + + + +void lever2downthink(edict_t *self) +{ + if (self->s.frame < 4) + { + ++self->s.frame; + self->nextthink = level.time + FRAMETIME; + } + else + { + self->think = NULL; + } +} + +void lever2upthink(edict_t *self) +{ + if (self->s.frame > 0) + { + --self->s.frame; + self->nextthink = level.time + FRAMETIME; + } + else + { + self->think = NULL; + } +} + +void lever2_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (!self->s.frame) + { + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/lever2.wav"), 1, ATTN_NORM, 0); + self->think = lever2downthink; + } + else if (self->s.frame == 4) + { + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/lever2.wav"), 1, ATTN_NORM, 0); + self->think = lever2upthink; + } + self->nextthink = level.time + FRAMETIME; + G_UseTargets(self, activator); +} + +/*QUAKED obj_lever2 (1 .5 0) (-14 -14 -9) (14 14 9) INVULNERABLE ANIMATE EXPLODING NOPUSH +A wooden wheel lever that is triggerable. +------- FIELDS ------------------ +INVULNERABLE - always invulnerable +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_lever2 can't be moved) +----------------------------------- +*/ +void SP_obj_lever2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/levers/lever2/tris.fm"); + + VectorSet(self->mins, -14, -14, -9); + VectorSet(self->maxs, 14, 14, 9); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,150,125,MAT_WOOD,SOLID_BBOX); + + self->use = lever2_use; +} + +void lever3downthink(edict_t *self) +{ + if (self->s.frame < 5) + { + ++self->s.frame; + self->nextthink = level.time + FRAMETIME; + } + else + { + self->think = NULL; + } +} + +void lever3upthink(edict_t *self) +{ + if (self->s.frame > 0) + { + --self->s.frame; + self->nextthink = level.time + FRAMETIME; + } + else + { + self->think = NULL; + } +} + +void lever3_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (!self->s.frame) + { + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/lever3.wav"), 1, ATTN_NORM, 0); + self->think = lever3downthink; + } + else if (self->s.frame == 5) + { + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/lever3.wav"), 1, ATTN_NORM, 0); + self->think = lever3upthink; + } + self->nextthink = level.time + FRAMETIME; + G_UseTargets(self, activator); +} + +/*QUAKED obj_lever3 (1 .5 0) (-4 -6 -16) (4 6 16) INVULNERABLE ANIMATE EXPLODING NOPUSH +A lever for the wall...and it's triggerable. +------- FIELDS ------------------ +INVULNERABLE - always invulnerable +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_lever3 can't be moved) +----------------------------------- +*/ +void SP_obj_lever3 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/levers/lever3/tris.fm"); + + VectorSet(self->mins, -6, -4, -16); + VectorSet(self->maxs, 6, 4, 16); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,150,125,MAT_WOOD,SOLID_BBOX); + + self->use = lever3_use; +} +void lever_used(edict_t *self, G_Message_t *msg) +{ + self->activator = self->enemy; +// button_fire (self); +} + +void LeverStaticsInit() +{ + classStatics[CID_LEVER].msgReceivers[MSG_DEATH] = lever_used; +} + + + + + +void bush_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (self->touch_debounce_time > level.time) + return; + + //gi.sound (self, CHAN_BODY, gi.soundindex ("objects/bush.wav"), 1, ATTN_NORM, 0); + self->touch_debounce_time = level.time + 1; +} + +/*QUAKED obj_bush1 (1 .5 0) (-34 -34 -19) (34 34 19) INVULNERABLE ANIMATE EXPLODING NOPUSH +A dome shaped bush +------- FIELDS ------------------ +INVULNERABLE - N/A +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_bush1 can't be moved) +----------------------------------- +*/ +void SP_obj_bush1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/bush1/tris.fm"); + + // The bounding box in the QUAKED comment is bigger to show the designers the true size of the objects + VectorSet(self->mins, -16, -16, -19); + VectorSet(self->maxs, 16, 16, 19); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,25,25,MAT_WOOD,SOLID_NOT); + + self->touch_debounce_time = level.time; + self->touch = bush_touch; + +} + +/*QUAKED obj_bush2 (1 .5 0) (-56 -56 -40) (56 56 40) INVULNERABLE ANIMATE EXPLODING NOPUSH +A larger dome shaped bush +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_bush2 can't be moved) +----------------------------------- +*/ +void SP_obj_bush2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/bush2/tris.fm"); + + // The bounding box in the QUAKED comment is bigger to show the designers the true size of the objects + VectorSet(self->mins, -16, -16, -40); + VectorSet(self->maxs, 16, 16, 40); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,25,50,MAT_WOOD,SOLID_BBOX); + + self->touch_debounce_time = level.time; + self->touch = bush_touch; + +} + +// Cactus will hurt player +void cactus_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (!other->client) + return; + + if (self->touch_debounce_time > level.time) + return; + + self->touch_debounce_time = level.time + 5; + + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 1, 0, DAMAGE_AVOID_ARMOR,MOD_DIED); +} + +/*QUAKED obj_cactus (1 .5 0) (-18 -18 -44) (18 18 44) INVULNERABLE ANIMATE EXPLODING NOPUSH +A cactus. Hurts the player 1 pt every five seconds he is pushes against it. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_cactus can't be moved) +----------------------------------- +*/ +void SP_obj_cactus (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/cactus/tris.fm"); + + VectorSet(self->mins, -18, -18, -44); + VectorSet(self->maxs, 18, 18, 44); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,50,125,MAT_NONE,SOLID_BBOX); + + self->touch_debounce_time = level.time; + self->touch = cactus_touch; +} + +/*QUAKED obj_cactus3 (1 .5 0) (-14 -14 -32) (14 14 32) INVULNERABLE ANIMATE EXPLODING NOPUSH +A cactus. Hurts the player 1 pt every five seconds he is pushes against it. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_cactus3 can't be moved) +----------------------------------- +*/ +void SP_obj_cactus3 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/cactus3/tris.fm"); + + VectorSet(self->mins, -14, -14, -32); + VectorSet(self->maxs, 14, 14, 32); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,50,125,MAT_NONE,SOLID_BBOX); + + self->touch_debounce_time = level.time; + self->touch = cactus_touch; +} + +void cactus_close(edict_t *self) +{ + if (self->s.frame > 0) + { + self->s.frame--; + self->think=cactus_close; + } + self->nextthink=level.time + FRAMETIME; +} + +void cactus_open(edict_t *self) +{ + self->s.frame+=4; + if (self->s.frame < 16) + { + self->think=cactus_open; + } + else + self->s.frame = 16; + + self->nextthink=level.time + FRAMETIME; +} + +void cactus4_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (!self->s.frame) + { + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/lever1.wav"), 1, ATTN_NORM, 0); + self->think = cactus_open; + } + else if (self->s.frame == 16) + { + gi.sound (self, CHAN_BODY, gi.soundindex ("objects/lever1.wav"), 1, ATTN_NORM, 0); + self->think = cactus_close; + } + self->nextthink = level.time + FRAMETIME; +} + +/*QUAKED obj_cactus4 (1 .5 0) (-11 -11 -11) (11 11 11) INVULNERABLE ANIMATE EXPLODING NOPUSH +A small cactus that open up or closes. Is triggerable. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_cactus4 can't be moved) +----------------------------------- +*/ +void SP_obj_cactus4 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/cactus4/tris.fm"); + + VectorSet(self->mins, -11, -11, -11); + VectorSet(self->maxs, 11, 11, 11); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_NONE,SOLID_BBOX); + self->use = cactus4_use; + + self->touch_debounce_time = level.time; + self->touch = cactus_touch; +} + +/*QUAKED obj_basket (1 .5 0) (-13 -13 -21) (13 13 21) INVULNERABLE ANIMATE EXPLODING NOPUSH +A tall basket with a lid on it. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_basket (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pots/basket/tris.fm"); + + VectorSet(self->mins, -13, -13, -21); + VectorSet(self->maxs, 13, 13, 21); + + ObjectInit(self,50,70,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_claybowl (1 .5 0) (-6 -6 -2) (6 6 2) INVULNERABLE ANIMATE EXPLODING NOPUSH +A bowl made of clay +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_claybowl (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pots/claybowl/tris.fm"); + + VectorSet(self->mins, -6, -6, -2); + VectorSet(self->maxs, 6, 6, 2); + + ObjectInit(self,5,5,MAT_POTTERY,SOLID_BBOX); +} + +/*QUAKED obj_clayjar (1 .5 0) (-15 -15 -24) (15 15 24) INVULNERABLE ANIMATE EXPLODING NOPUSH +A big honking urn made of clay +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_clayjar (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pots/clayjar/tris.fm"); + + VectorSet(self->mins, -15, -15, -24); + VectorSet(self->maxs, 15, 15, 24); + + ObjectInit(self,25,125,MAT_POTTERY,SOLID_BBOX); +} + +/*QUAKED obj_gorgonbones (1 .5 0) (-18 -38 -9) (18 38 1) INVULNERABLE ANIMATE EXPLODING NOPUSH +The bones of a dead gorgon. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_gorgonbones can't be moved) +----------------------------------- +*/ +void SP_obj_gorgonbones (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/bones/gorgon/tris.fm"); + + VectorSet(self->mins, -18, -38, -9); + VectorSet(self->maxs, 18, 38, 1); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,50,125,MAT_NONE,SOLID_BBOX); +} + +/*QUAKED obj_grass (1 .5 0) (-8 -8 -10) (8 8 10) INVULNERABLE ANIMATE EXPLODING NOPUSH +A clump of grass +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (obj_grass can't be moved) +----------------------------------- +*/ +void SP_obj_grass (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/grass/tris.fm"); + + VectorSet(self->mins, -8, -8, -10); + VectorSet(self->maxs, 8, 8, 10); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,50,125,MAT_WOOD,SOLID_NOT); + + self->s.effects|=EF_CAMERA_NO_CLIP; +} + +/*QUAKED obj_swampflat_top (1 .5 0) (0 -100 -48) (2 100 48) INVULNERABLE ANIMATE EXPLODING NOPUSH +A flat poly to be used on the outer edge of swamp levels. Vegetation growing up. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_swampflat_top (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/swampflat/tris.fm"); + + VectorSet(self->mins, 0, -100, -48); + VectorSet(self->maxs, 2, 100, 48); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_swampflat_bottom (1 .5 0) (0 -100 -48) (2 100 48) INVULNERABLE ANIMATE EXPLODING NOPUSH +A flat poly to be used on the outer edge of swamp levels. Vegetation hanging down. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_swampflat_bottom (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/swampflat/tris.fm"); + + VectorSet(self->mins, 0, -100, -48); + VectorSet(self->maxs, 2, 100, 48); + + self->s.skinnum = 1; + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); + +} + +/*QUAKED obj_treestump (1 .5 0) (-18 -18 -16) (18 18 16) INVULNERABLE ANIMATE EXPLODING NOPUSH +A short tree stump +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_treestump (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/plants/treestump/tris.fm"); + + VectorSet(self->mins, -18, -18, -16); + VectorSet(self->maxs, 18, 18, 16); + + self->s.skinnum = 1; + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_jawbone (1 .5 0) (-11 -11 -12) (11 11 12) INVULNERABLE ANIMATE EXPLODING NOPUSH +The jaws of a fish. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_jawbone (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/bones/jaws/tris.fm"); + + VectorSet(self->mins, -11, -11, -12); + VectorSet(self->maxs, 11, 11, 12); + + self->s.effects|=EF_CAMERA_NO_CLIP; + + ObjectInit(self,25,125,MAT_NONE,SOLID_BBOX); + + self->s.skinnum = 1; + +} + +/*QUAKED obj_barrel_metal (1 .5 0) (-11 -12 -18) (11 12 18) INVULNERABLE ANIMATE EXPLODING NOPUSH +A metal barrel. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_barrel_metal (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/barrel/metal/tris.fm"); + + VectorSet(self->mins, -11, -12, -18); + VectorSet(self->maxs, 11, 12, 18); + + ObjectInit(self,75,125,MAT_METAL,SOLID_BBOX); + self->s.skinnum = 1; +} + +/*QUAKED obj_barrel_explosive (1 .5 0) (-11 -12 -18) (11 12 18) INVULNERABLE ANIMATE EXPLODING NOPUSH +A barrel that explodes and does damage. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_barrel_explosive (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/barrel/normal/tris.fm"); + + VectorSet(self->mins, -11, -12, -18); + VectorSet(self->maxs, 11, 12, 18); + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); + self->s.skinnum = 1; + +} +/*QUAKED obj_gascan (1 .5 0) (-8 -9 -13) (8 9 13) INVULNERABLE ANIMATE EXPLODING NOPUSH +A metal gas can. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_gascan (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/barrel/gascan/tris.fm"); + + VectorSet(self->mins, -8, -9, -13); + VectorSet(self->maxs, 8, 9, 13); + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); + self->s.skinnum = 1; + +} + +/*QUAKED obj_pipe1 (1 .5 0) (-11 -24 -7) (11 24 7) INVULNERABLE ANIMATE EXPLODING NOPUSH +A section of pipe with 90 degree bend in it. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_pipe1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pipes/pipe1/tris.fm"); + + VectorSet(self->mins, -11, -24, -7); + VectorSet(self->maxs, 11, 24, 7); + + ObjectInit(self,50,125,MAT_WOOD,SOLID_BBOX); + self->s.skinnum = 1; + +} + +/*QUAKED obj_pipe2 (1 .5 0) (-6 -25 -4) (6 25 4) INVULNERABLE ANIMATE EXPLODING NOPUSH +A straight section of pipe. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_pipe2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pipes/pipe2/tris.fm"); + + VectorSet(self->mins, -6, -25, -4); + VectorSet(self->maxs, 6, 25, 4); + + ObjectInit(self,50,125,MAT_WOOD,SOLID_BBOX); + self->s.skinnum = 1; + +} + +/*QUAKED obj_pipewheel (1 .5 0) (-14 -14 -12) (14 14 12) INVULNERABLE ANIMATE EXPLODING NOPUSH +A shutoff valve for pipe. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_pipewheel (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pipes/pipewheel/tris.fm"); + + VectorSet(self->mins, -14, -14, -12); + VectorSet(self->maxs, 14, 14, 12); + + self->spawnflags |= OBJ_NOPUSH; + + ObjectInit(self,50,125,MAT_WOOD,SOLID_BBOX); + self->s.skinnum = 1; + +} + +/*QUAKED obj_minecart (1 .5 0) (-18 -29 -20) (18 29 20) INVULNERABLE ANIMATE EXPLODING NOPUSH +A full mine cart used on the mine levels. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_minecart (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/carts/mine/tris.fm"); + + VectorSet(self->mins, -18, -29, -20); + VectorSet(self->maxs, 18, 29, 20); + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); + self->s.frame = 0; + +} + +/*QUAKED obj_minecart2 (1 .5 0) (-18 -29 -20) (18 29 20) INVULNERABLE ANIMATE EXPLODING NOPUSH +An empty mine cart used on the mine levels. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_minecart2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/carts/mine/tris.fm"); + + VectorSet(self->mins, -18, -29, -20); + VectorSet(self->maxs, 18, 29, 20); + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); + self->s.frame = 20; + +} + + +/*QUAKED obj_minecart3 (1 .5 0) (-18 -29 -15) (18 29 20) INVULNERABLE ANIMATE EXPLODING NOPUSH +A busted mine cart used on the mine levels. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_minecart3 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/carts/mine/tris.fm"); + + VectorSet(self->mins, -18, -29, -15); + VectorSet(self->maxs, 18, 29, 20); + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); + self->s.frame = 40; + +} + +/*QUAKED obj_andwallhanging (1 .5 0) ( 0 -19 -24) (4 19 24) INVULNERABLE ANIMATE EXPLODING NOPUSH +A circular Andorian wall hanging. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_andwallhanging (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/andwallhang/tris.fm"); + + VectorSet(self->mins, 0, -19, -24); + VectorSet(self->maxs, 4, 19, 24); + + ObjectInit(self,75,100,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_pick (1 .5 0) ( -12 -13 -2) (12 13 2) INVULNERABLE ANIMATE EXPLODING NOPUSH +A tool that is a pick. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_pick (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/tools/pick/tris.fm"); + + VectorSet(self->mins, -12, -13, -2); + VectorSet(self->maxs, 12, 13, 2); + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); +} + +/*QUAKED obj_metalchunk1 (1 .5 0) ( -10 -26 -4) (10 26 4) INVULNERABLE ANIMATE EXPLODING NOPUSH +A chunk of twisted metal. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_metalchunk1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pipes/metalchunks/tris.fm"); + + VectorSet(self->mins, -10, -26, -4); + VectorSet(self->maxs, 10, 26, 4); + + ObjectInit(self,75,125,MAT_METAL,SOLID_BBOX); +} + +/*QUAKED obj_metalchunk2 (1 .5 0) ( -10 -26 -7) (10 26 7) INVULNERABLE ANIMATE EXPLODING NOPUSH +Another chunk of twisted metal. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_metalchunk2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pipes/metalchunks/tris.fm"); + + VectorSet(self->mins, -10, -26, -7); + VectorSet(self->maxs, 10, 26, 7); + + ObjectInit(self,75,125,MAT_METAL,SOLID_BBOX); + + self->s.frame = 1; +} + + +/*QUAKED obj_metalchunk3 (1 .5 0) ( -9 -30 -4) (9 30 4) INVULNERABLE ANIMATE EXPLODING NOPUSH +Another chunk of twisted metal. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_metalchunk3 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pipes/metalchunks/tris.fm"); + + VectorSet(self->mins, -9, -30, -4); + VectorSet(self->maxs, 9, 30, 4); + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); + + self->s.frame = 2; +} + +/*QUAKED obj_rocks1 (1 .5 0) ( -12 -13 -4) (12 13 4) INVULNERABLE ANIMATE EXPLODING NOPUSH +A bunch of rocks together +For the MINE levels +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_rocks1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/rocks/rock1/tris.fm"); + + VectorSet(self->mins, -12, -13, -4); + VectorSet(self->maxs, 12, 13, 4); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_BBOX); + +} + +/*QUAKED obj_rocks2 (1 .5 0) ( -9 -30 -4) (9 30 4) INVULNERABLE ANIMATE EXPLODING NOPUSH +A big rock +For the MINE levels +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_rocks2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/rocks/rock2/tris.fm"); + + VectorSet(self->mins, -34, -40, -19); + VectorSet(self->maxs, 34, 40, 19); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_BBOX); + +} + +void symbolthink(edict_t *self) +{ + M_droptofloor(self); + + self->think = symbolthink; + self->nextthink = level.time + FRAMETIME; + + if (self->touch_debounce_time < level.time) + { + self->think = NULL; + self->nextthink = -1; + } +} + +void hivepriestesssymbol_use (edict_t *self, edict_t *other, edict_t *activator) +{ + self->s.modelindex = gi.modelindex("models/items/puzzles/hiveidol/tris.fm"); + + VectorSet(self->mins, -4, -4, -13); + VectorSet(self->maxs, 4, 4, 13); + + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_BBOX); + + self->velocity[2] = -1; + + self->touch_debounce_time = level.time + 5; + + self->think = symbolthink; + self->nextthink = level.time + FRAMETIME; + +} + +/*QUAKED obj_hivepriestessssymbol (1 .5 0) ( -4 -4 -13) (4 4 13) INVULNERABLE ANIMATE EXPLODING NOPUSH +The Hive Priestess Symbol was created originally by T'jektaluck back in 14567 AH (After Hive). It was stolen by Matt Pinkston in 20054. He was promptly captured and fed Zots until he died from sugar overload. +It starts off invisible. When used it appears. +For the HIVE level +------- FIELDS ------------------ +INVULNERABLE - N/A it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_hivepriestessssymbol (edict_t *self) +{ + self->s.modelindex = 0; + + VectorSet(self->mins, -4, -4, -13); + VectorSet(self->maxs, 4, 4, 13); + self->use = hivepriestesssymbol_use; + + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_NOT); + +} + +/*QUAKED obj_queenthrone (1 .5 0) ( -40 -56 -49) (40 56 49) INVULNERABLE ANIMATE EXPLODING NOPUSH +A throne for the queen +For the HIVE levels +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_queenthrone (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chairs/queen/tris.fm"); + + VectorSet(self->mins, -40, -56, -49); + VectorSet(self->maxs, 40, 56, 49); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_BBOX); + +} + +/*QUAKED obj_queenchair (1 .5 0) ( -30 -28 -31) (30 28 31) INVULNERABLE ANIMATE EXPLODING NOPUSH +A chair to go by the queen throne +For the HIVE levels +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_queenchair (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/chairs/smallchair/tris.fm"); + + VectorSet(self->mins, -30, -28, -31); + VectorSet(self->maxs, 30, 28, 31); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_BBOX); + +} + +/*QUAKED obj_shrine (1 .5 0) ( -26 -38 -38) (26 38 38) INVULNERABLE ANIMATE EXPLODING NOPUSH +Its a shrine +For all levels +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +---------- KEYS ----------------- +style - (default 0) type of shrine + 0 - heal + 1 - mana + 2 - lungs + 3 - light + 4 - power up + 5 - armor + 6 - armor gold + 7 - random + 8 - reflection + 9 - staff + 10 - ghost + 11 - speed +----------------------------------- + +*/ +void SP_obj_shrine (edict_t *self) +{ + vec3_t offset2; + vec3_t offset; + + if (deathmatch->value && ((int)dmflags->value & DF_NO_SHRINE)) + { + G_SetToFree(self); + return; + } + + self->s.modelindex = gi.modelindex("models/objects/shrine/tris.fm"); + + VectorSet(self->mins, -26, -38, -38); + VectorSet(self->maxs, 26, 38, 38); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_BBOX); + + if (deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS)) + { self->style = 7; + } + + if ((self->style >= 0) && (self->style <= 11)) + { + ++self->style; + self->s.skinnum = self->style; + } + else + self->s.skinnum = 0; + + // make the ball appear in the middle + VectorScale(self->s.angles, ANGLE_TO_RAD, offset); + DirFromAngles(offset, offset2); + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, FX_SHRINE_BALL, CEF_BROADCAST, self->s.origin, + "db", offset2, (byte)(self->style-1)); + +} + +/*QUAKED obj_larvaegg (1 .5 0) ( -6 -14 -6) (6 14 6) INVULNERABLE ANIMATE EXPLODING NOPUSH +An egg for the larva +For the HIVE levels +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_larvaegg (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/eggs/eggs/tris.fm"); + + VectorSet(self->mins, -6, -14, -6); + VectorSet(self->maxs, 6, 14, 6); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_GLASS,SOLID_BBOX); + +} + +/*QUAKED obj_larvabrokenegg (1 .5 0) ( -6 -7 -5) (6 7 5) INVULNERABLE ANIMATE EXPLODING NOPUSH +A broken egg for the larva +For the HIVE levels +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_larvabrokenegg (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/eggs/brokenegg/tris.fm"); + + VectorSet(self->mins, -6, -7, -5); + VectorSet(self->maxs, 6, 7, 5); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_GLASS,SOLID_BBOX); + +} + +/*QUAKED obj_cocoon (1 .5 0) ( -20 -20 -36) (20 20 36) INVULNERABLE ANIMATE EXPLODING NOPUSH +A cocoon which hangs from the ceiling +For the HIVE levels +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A (always animates) +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_cocoon (edict_t *self) +{ + + VectorSet(self->mins, -20, -20, -36); + VectorSet(self->maxs, 20, 20, 36); + + // Always animate and can't be pushed + self->spawnflags |= OBJ_NOPUSH | OBJ_ANIMATE; + SpawnClientAnim(self, FX_ANIM_COCOON, NULL); + + ObjectInit(self,75,125,MAT_INSECT,SOLID_BBOX); +} + +/*QUAKED obj_cocoonopen (1 .5 0) ( -20 -20 -34) (20 20 34) INVULNERABLE ANIMATE EXPLODING NOPUSH +An open cocoon which hangs from the ceiling +For the HIVE levels +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_cocoonopen (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/eggs/cocoon/tris.fm"); + + VectorSet(self->mins, -20, -20, -34); + VectorSet(self->maxs, 20, 20, 34); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + self->s.frame = 20; + + ObjectInit(self,75,125,MAT_INSECT,SOLID_BBOX); + +} + +/*QUAKED obj_venusflytrap (1 .5 0) ( -20 -20 -24) (20 20 24) INVULNERABLE ANIMATE EXPLODING NOPUSH +The venus flytrap - a viscous beast of a plant +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_venusflytrap (edict_t *self) +{ + edict_t *leaves; + + self->s.modelindex = gi.modelindex("models/objects/plants/venus/tris.fm"); + + VectorSet(self->mins, -20, -20, -24); + VectorSet(self->maxs, 20, 20, 24); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_LEAF,SOLID_BBOX); + + leaves = G_Spawn(); + + VectorCopy(self->s.origin,leaves->s.origin); + leaves->s.origin[2] -= 16; + leaves->movetype = PHYSICSTYPE_NONE; + leaves->solid = SOLID_NOT; + leaves->s.modelindex = gi.modelindex("models/objects/plants/v-plant/tris.fm"); + BboxYawAndScale(leaves); + leaves->s.angles[YAW] = self->s.angles[YAW]; + gi.linkentity (leaves); + + self->target_ent = leaves; + + +} + +void tomb_use (edict_t *self, edict_t *other, edict_t *activator) +{ + --self->s.frame; + if (self->s.frame < 0) + self->s.frame=1; +} +/*QUAKED obj_statue_techeckriktomb (1 .5 0) ( -41 -11 -14) (41 11 14) INVULNERABLE ANIMATE EXPLODING NOPUSH +The statue of the techeckrik laying down. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_statue_techeckriktomb (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/tomb/tris.fm"); + + VectorSet(self->mins, -41, -11, -14); + VectorSet(self->maxs, 41, 11, 14); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_BBOX); + + self->s.frame = 1; + + self->use = tomb_use; +} + + +void tcheckrik_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->s.frame > 0) + --self->s.frame; +} + +/*QUAKED obj_statue_techeckrikright (1 .5 0) ( -26 -40 -50) (26 40 50) INVULNERABLE ANIMATE EXPLODING NOPUSH NOGEM +The statue of the techeckrik with his arms raised up to the right. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +NOGEM - No gem in the chest (puzzle) +----------------------------------- +*/ +void SP_obj_statue_techeckrikright (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/tcheckrik/tris.fm"); + + VectorSet(self->mins, -26, -40, -50); + VectorSet(self->maxs, 26, 40, 50); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_BBOX); + + self->s.frame = 2; + if (self->spawnflags & 16) // NOGEM + self->s.frame = 3; + + self->use = tcheckrik_use; + +} + + + +/*QUAKED obj_statue_techeckrikleft (1 .5 0) ( -26 -40 -50) (26 40 50) INVULNERABLE ANIMATE EXPLODING NOPUSH NOGEM +The statue of the techeckrik with his arms raised up to the left. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +NOGEM - No gem in the chest (puzzle) +----------------------------------- +*/ +void SP_obj_statue_techeckrikleft (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/statue/tcheckrik/tris.fm"); + + VectorSet(self->mins, -26, -40, -50); + VectorSet(self->maxs, 26, 40, 50); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_GREYSTONE,SOLID_BBOX); + + self->s.frame = 0; + + if (self->spawnflags & 16) // NOGEM + self->s.frame = 1; + + self->use = tcheckrik_use; + +} + + +void spellbook_anim (edict_t *self) +{ + if (self->s.frame > 0) + { + --self->s.frame; + + self->think = spellbook_anim; + self->nextthink = level.time + FRAMETIME; + } + else + { + gi.sound (self, CHAN_BODY, gi.soundindex ("misc/spbkcls.wav"), 1, ATTN_NORM, 0); + self->think = NULL; + } + +} + +void spellbook_use (edict_t *self, edict_t *other, edict_t *activator) +{ + spellbook_anim(self); + + G_FreeEdict(self->target_ent); + + gi.sound (self, CHAN_BODY, gi.soundindex ("misc/spbook.wav"), 1, ATTN_NORM, 0); + +} + +/*QUAKED obj_spellbook (1 .5 0) ( -14 -14 -35) (14 14 40) INVULNERABLE ANIMATE EXPLODING NOPUSH +A spell book that closes when triggered. +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_spellbook (edict_t *self) +{ + edict_t *beam; + + self->s.modelindex = gi.modelindex("models/objects/spellbook/book/tris.fm"); + + VectorSet(self->mins, -14, -14, -35); + VectorSet(self->maxs, 14, 14, 40); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + self->use = spellbook_use; + ObjectInit(self,75,125,MAT_NONE,SOLID_BBOX); + self->s.frame = 20; + + beam = G_Spawn(); + + VectorCopy(self->s.origin,beam->s.origin); + beam->s.origin[2] += 2; + beam->movetype = PHYSICSTYPE_NONE; + beam->solid = SOLID_NOT; + beam->s.modelindex = gi.modelindex("models/objects/spellbook/beam/tris.fm"); + BboxYawAndScale(beam); + beam->s.angles[YAW] = self->s.angles[YAW]; + gi.linkentity (beam); + + self->target_ent = beam; +} + +/*QUAKED obj_skullpole (1 .5 0) ( -10 -10 -47) (10 10 47) INVULNERABLE ANIMATE EXPLODING NOPUSH +A pole with skulls on it +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_skullpole (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/flags/totempole/tris.fm"); + + VectorSet(self->mins, -10, -10, -47); + VectorSet(self->maxs, 10, 10, 47); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,75,125,MAT_POTTERY,SOLID_BBOX); + +} + +/*QUAKED obj_pot1 (1 .5 0) ( -3 -8 -8) (3 8 8) INVULNERABLE ANIMATE EXPLODING NOPUSH +A cooking pot which hangs from a wall +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_pot1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pots/pot/tris.fm"); + + VectorSet(self->mins, -3, -8, -8); + VectorSet(self->maxs, 3, 8, 8); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_POTTERY,SOLID_BBOX); + +} + +/*QUAKED obj_pot2 (1 .5 0) ( -7 -7 -3) (7 7 3) INVULNERABLE ANIMATE EXPLODING NOPUSH +A cooking pot which lays flat on a table +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_pot2 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/pots/pot2/tris.fm"); + + VectorSet(self->mins, -7, -7, -3); + VectorSet(self->maxs, 7, 7, 3); + + ObjectInit(self,75,125,MAT_POTTERY,SOLID_BBOX); + +} + +/*QUAKED obj_bottle1 (1 .5 0) ( -3 -3 -7) (3 3 7) INVULNERABLE ANIMATE EXPLODING NOPUSH +A bottle that looks like the one Jennie came out of in I Dream of Jennie +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_bottle1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/jars/bottle/tris.fm"); + + VectorSet(self->mins, -3, -3, -7); + VectorSet(self->maxs, 3, 3, 7); + + ObjectInit(self,75,125,MAT_POTTERY,SOLID_BBOX); + +} + +/*QUAKED obj_jug1 (1 .5 0) ( -6 -6 -6) (6 6 6) INVULNERABLE ANIMATE EXPLODING NOPUSH +A wine jug +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can't be moved by player +----------------------------------- +*/ +void SP_obj_jug1 (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/jars/jug/tris.fm"); + + VectorSet(self->mins, -6, -6, -6); + VectorSet(self->maxs, 6, 6, 6); + + ObjectInit(self,75,125,MAT_POTTERY,SOLID_BBOX); + +} + + +/*QUAKED obj_torture_table (1 .5 0) ( -46 -14 -14) (46 14 14) INVULNERABLE ANIMATE EXPLODING NOPUSH +A table useful for wringing confessions from your broken and pitiful enemies. +style - the frame of animation for model + 0 -table is down + 1 - table is in upright position +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't ever be moved by player) +----------------------------------- +*/ +void SP_obj_torture_table (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/torture/table/tris.fm"); + + VectorSet(self->mins, -46, -14, -14); + VectorSet(self->maxs, 46, 14, 14); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + if (self->style < 2) + self->s.frame = self->style; + else + self->s.frame = 0; + + ObjectInit(self,75,125,MAT_WOOD,SOLID_BBOX); + +} + + +/*QUAKED obj_torture_wallring (1 .5 0) ( -2 -4 -6) (2 4 6) INVULNERABLE ANIMATE EXPLODING NOPUSH +A ring that hangs from a wall +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't ever be moved by player) +----------------------------------- +*/ +void SP_obj_torture_wallring (edict_t *self) +{ + self->s.modelindex = gi.modelindex("models/objects/torture/wallring/tris.fm"); + + VectorSet(self->mins, -2, -4, -6); + VectorSet(self->maxs, 2, 4, 6); + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,75,125,MAT_METAL,SOLID_BBOX); + +} + +void statue_tchecktrik_bust_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->s.frame) + self->s.frame = 0; + else + self->s.frame = 1; +} + +/*QUAKED obj_statue_tchecktrik_bust (1 .5 0) (-8 -12 -15) (8 12 15) INVULNERABLE ANIMATE EXPLODING NOPUSH +A bust of a tchecktrik. When used a necklace appears aroundit's neck. +style - +0 - no necklace until used then necklace appears +1 - necklace until used then necklace disappears +------- FIELDS ------------------ +INVULNERABLE - N/A (can't be hurt) +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_statue_tchecktrik_bust (edict_t *self) +{ + VectorSet(self->mins, -8, -12, -15); + VectorSet(self->maxs, 8, 12, 15); + + self->s.modelindex = gi.modelindex("models/items/puzzles/tchecktrikbust/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + if (!self->style) + self->s.frame = 1; + else + self->s.frame = 0; + + self->use = statue_tchecktrik_bust_use; + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_BBOX); + +} + +void statue_sithraguard_think (edict_t *self) +{ + if (self->s.frame < 20) + { + ++self->s.frame; + self->think = statue_sithraguard_think; + self->nextthink = level.time + FRAMETIME; + } + else + self->think = NULL; +} + +void statue_sithraguard_use (edict_t *self, edict_t *other, edict_t *activator) +{ + edict_t *shield; + + statue_sithraguard_think(self); + gi.sound (self, CHAN_BODY, gi.soundindex ("items/statuearm.wav"), 1, ATTN_NORM, 0); + + shield = G_Spawn(); + VectorCopy(self->s.origin,shield->s.origin); + VectorCopy(self->s.angles,shield->s.angles); + shield->s.modelindex = gi.modelindex("models/objects/statue/sithshield/tris.fm"); + shield->s.scale = self->s.scale; + shield->spawnflags |= OBJ_NOPUSH; // Can't be pushed + shield->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + shield->movetype = PHYSICSTYPE_NONE; + shield->solid = SOLID_NOT; + + BboxYawAndScale(shield); + gi.linkentity (shield); + + + +} + +/*QUAKED obj_statue_sithraguard (1 .5 0) (-22 -20 -57) (22 20 57) INVULNERABLE ANIMATE EXPLODING NOPUSH +A statue of a sithra guard with spear extended. When used the guard pulls his arm back. +style - type of statue +------- FIELDS ------------------ +INVULNERABLE - N/A (can't be hurt) +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_statue_sithraguard (edict_t *self) +{ + VectorSet(self->mins, -22, -20, -57); + VectorSet(self->maxs, 22, 20, 57); + + self->s.modelindex = gi.modelindex("models/objects/statue/sithraguard/tris.fm"); + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + self->s.frame = 0; + + self->use = statue_sithraguard_use; + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_BBOX); + +} + +void ironmaiden_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); + +void ironmaiden_open (edict_t *self) +{ + + if (self->s.frame == 9) + gi.sound (self, CHAN_BODY, gi.soundindex ("items/ironmaiden.wav"), 1, ATTN_NORM, 0); + + if (self->s.frame > 0) + { + --self->s.frame; + self->think = ironmaiden_open; + self->nextthink = level.time + FRAMETIME; + } + else + { + self->s.frame = 0; + self->think = NULL; + self->touch = ironmaiden_touch; + } +} + +void ironmaiden_close (edict_t *self) +{ + if (self->s.frame < 10) + { + ++self->s.frame; + self->think = ironmaiden_close; + self->nextthink = level.time + FRAMETIME; + } + else + { + self->think = ironmaiden_open; + self->nextthink = level.time + FRAMETIME * 30; // Open up in 30 seconds + } +} + +void ironmaiden_use (edict_t *self, edict_t *other, edict_t *activator) +{ + VectorSet(self->mins, -18, -18, -49); + VectorSet(self->maxs, 18, 18, 49); + + self->touch = NULL; + + ironmaiden_close(self); + gi.sound (self, CHAN_BODY, gi.soundindex ("items/ironmaiden.wav"), 1, ATTN_NORM, 0); + +} + + +// Cactus will hurt player +void ironmaiden_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + vec3_t source, vf; + trace_t trace; + + if (!other->client) + return; + + if (self->touch_debounce_time > level.time) + return; + + self->touch_debounce_time = level.time + 5; + + VectorCopy(self->s.origin, source); + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(source, 44, vf, source); + + gi.trace (self->s.origin, self->mins, self->maxs, source, self, MASK_PLAYERSOLID,&trace); + if (trace.ent == other) + T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 5, 0, DAMAGE_AVOID_ARMOR,MOD_DIED); + + ironmaiden_use(self,NULL,NULL); +} + + +/*QUAKED obj_torture_ironmaiden (1 .5 0) (-18 -18 -49) (18 18 49) INVULNERABLE ANIMATE EXPLODING NOPUSH +An iron maiden that closes when used +------- FIELDS ------------------ +INVULNERABLE - N/A (can't be hurt) +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_torture_ironmaiden (edict_t *self) +{ + VectorSet(self->mins, -28, -48, -49); + VectorSet(self->maxs, 28, 48, 49); + + self->s.modelindex = gi.modelindex("models/objects/torture/ironmaiden/tris.fm"); + self->spawnflags |= OBJ_INVULNERABLE; + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + self->s.frame = 0; + self->use = ironmaiden_use; + self->touch = ironmaiden_touch; + + ObjectInit(self,250,200,MAT_METAL,SOLID_BBOX); + +} + + +/*QUAKED obj_torture_rack (1 .5 0) (-22 -46 -19) (22 46 19) INVULNERABLE ANIMATE EXPLODING NOPUSH +A rack +------- FIELDS ------------------ +INVULNERABLE - N/A (can't be hurt) +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_torture_rack (edict_t *self) +{ + VectorSet(self->mins, -22, -46, -19); + VectorSet(self->maxs, 22, 46, 19); + + self->s.modelindex = gi.modelindex("models/objects/torture/rack/tris.fm"); + self->spawnflags |= OBJ_INVULNERABLE; + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,250,200,MAT_WOOD,SOLID_BBOX); + +} + +/*QUAKED obj_torture_bed (1 .5 0) (-21 -43 -94) (21 43 94) INVULNERABLE ANIMATE EXPLODING NOPUSH +A bed of spikes that falls from the ceiling. +------- FIELDS ------------------ +INVULNERABLE - N/A (can't be hurt) +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_torture_bed (edict_t *self) +{ + VectorSet(self->mins, -21, -43, -94); + VectorSet(self->maxs, 21, 43, 94); + + self->s.modelindex = gi.modelindex("models/objects/torture/bed/tris.fm"); + self->spawnflags |= OBJ_INVULNERABLE; + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,250,200,MAT_WOOD,SOLID_BBOX); + +} + + +/*QUAKED obj_statue_saraphbust (1 .5 0) (-10 -20 -24) (10 20 24) INVULNERABLE ANIMATE EXPLODING NOPUSH +A bust of a saraph +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_statue_saraphbust (edict_t *self) +{ + VectorSet(self->mins, -10, -20, -24); + VectorSet(self->maxs, 10, 20, 24); + + self->s.modelindex = gi.modelindex("models/objects/statue/saraphbust/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_BBOX); + +} + +#define FISHBOB_HEIGHT .1 +#define FISHBOB_SPEED ANGLE_10 + +void fish_anim (edict_t *self) +{ + + M_ChangeYaw(self); + + self->s.origin[2] += (cos(self->moveinfo.current_speed) * FISHBOB_HEIGHT); + self->moveinfo.current_speed += FISHBOB_SPEED; + + if (self->s.frame < self->count) + { + ++self->s.frame; + } + else + self->s.frame=0; + + self->think = fish_anim; + self->nextthink = level.time + FRAMETIME; +} + +void biotank_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + self->target_ent->ideal_yaw = anglemod(other->s.angles[YAW] + 180); +} + +/*QUAKED obj_biotank (1 .5 0) (-20 -33 -52) (20 33 52) INVULNERABLE ANIMATE EXPLODING NOPUSH +A biotank +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +------- KEYS ------------------ +style - what's in the biotank +0 - empty +1 - ET's head +2 - hairless Critter +3 - three fish +4 - wasp +*/ +void SP_obj_biotank (edict_t *self) +{ + edict_t *fish,*glass; + vec3_t forward,right; + + VectorSet(self->mins, -21, -34, -52); + VectorSet(self->maxs, 21, 34, 52); + + self->s.modelindex = gi.modelindex("models/objects/labs/biotank/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_BBOX); + + glass = G_Spawn(); + VectorSet(glass->mins, -1, -1, -1); + VectorSet(glass->maxs, 1, 1, 1); + + VectorCopy(self->s.origin,glass->s.origin); + AngleVectors(self->s.angles, forward, right, NULL); + VectorMA(glass->s.origin, -8, right, glass->s.origin); + VectorCopy(self->s.angles,glass->s.angles); + glass->s.angles[1] += 90.0f; + glass->s.renderfx |= RF_TRANSLUCENT; + glass->s.modelindex = gi.modelindex("models/objects/labs/bioglass2/tris.fm"); + glass->spawnflags |= OBJ_NOPUSH; // Can't be pushed + glass->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(glass,250,200,MAT_GLASS,SOLID_NOT); + + + glass = G_Spawn(); + VectorSet(glass->mins, -1, -1, -1); + VectorSet(glass->maxs, 1, 1, 1); + + VectorCopy(self->s.origin,glass->s.origin); + AngleVectors(self->s.angles, forward, right, NULL); + VectorMA(glass->s.origin, 26, right, glass->s.origin); + VectorCopy(self->s.angles,glass->s.angles); + glass->s.angles[1] += 270.0f; + glass->s.renderfx |= RF_TRANSLUCENT; + glass->s.modelindex = gi.modelindex("models/objects/labs/bioglass2/tris.fm"); + glass->spawnflags |= OBJ_NOPUSH; // Can't be pushed + glass->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(glass,250,200,MAT_GLASS,SOLID_NOT); + + glass = G_Spawn(); + VectorSet(glass->mins, -1, -1, -1); + VectorSet(glass->maxs, 1, 1, 1); + + VectorCopy(self->s.origin,glass->s.origin); + AngleVectors(self->s.angles, forward, right, NULL); + VectorMA(glass->s.origin, 9, right, glass->s.origin); + VectorMA(glass->s.origin, -17, forward, glass->s.origin); + VectorCopy(self->s.angles,glass->s.angles); + glass->s.renderfx |= RF_TRANSLUCENT; + glass->s.modelindex = gi.modelindex("models/objects/labs/bioglass2/tris.fm"); + glass->spawnflags |= OBJ_NOPUSH; // Can't be pushed + glass->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(glass,250,200,MAT_GLASS,SOLID_NOT); + + glass = G_Spawn(); + VectorSet(glass->mins, -1, -1, -1); + VectorSet(glass->maxs, 1, 1, 1); + + VectorCopy(self->s.origin,glass->s.origin); + AngleVectors(self->s.angles, forward, right, NULL); + VectorMA(glass->s.origin, 9, right, glass->s.origin); + VectorMA(glass->s.origin, 17, forward, glass->s.origin); + VectorCopy(self->s.angles,glass->s.angles); + glass->s.angles[1] += 180.0f; + glass->s.renderfx |= RF_TRANSLUCENT; + glass->s.modelindex = gi.modelindex("models/objects/labs/bioglass2/tris.fm"); + glass->spawnflags |= OBJ_NOPUSH; // Can't be pushed + glass->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(glass,250,200,MAT_GLASS,SOLID_NOT); + + if (!self->style) + return; + + fish = G_Spawn(); + + VectorCopy(self->s.origin,fish->s.origin); + fish->s.origin[2] -= 8; + fish->movetype = PHYSICSTYPE_FLY; + fish->solid = SOLID_NOT; + fish->gravity = 0; + + fish->yaw_speed = 4; + fish->ideal_yaw = self->s.angles[YAW]; + + AngleVectors(self->s.angles, forward, right, NULL); + VectorMA(fish->s.origin, 9, right, fish->s.origin); + + if (self->style==1) + { + fish->s.modelindex = gi.modelindex("models/objects/labs/labfish/tris.fm"); + fish->count = 30; + self->s.sound = gi.soundindex("objects/slowbubbles.wav"); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; + } + else if (self->style==2) + { + fish->s.modelindex = gi.modelindex("models/objects/labs/labfish2/tris.fm"); + fish->count = 60; + self->s.sound = gi.soundindex("objects/slowbubbles.wav"); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; + } + else if (self->style==3) + { + fish->s.modelindex = gi.modelindex("models/objects/labs/labfish3/tris.fm"); + fish->count = 100; + self->s.sound = gi.soundindex("objects/fastbubbles.wav"); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; + } + else + { + fish->s.modelindex = gi.modelindex("models/monsters/bee/tris.fm"); + fish->count = 60; + fish->s.scale = 2; + self->s.sound = gi.soundindex("objects/fastbubbles.wav"); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; + } + + BboxYawAndScale(fish); + fish->s.angles[YAW] = self->s.angles[YAW]; + + gi.linkentity (fish); + + fish->think = fish_anim; + fish->nextthink = level.time + FRAMETIME; + + self->target_ent = fish; + self->touch = biotank_touch; +} + + +/*QUAKED obj_tapper (1 .5 0) (-2 -5 -2) (2 5 2) INVULNERABLE ANIMATE EXPLODING NOPUSH +A tapper for a keg +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_tapper (edict_t *self) +{ + VectorSet(self->mins, -2, -5, -2); + VectorSet(self->maxs, 2, 5, 2); + + self->s.modelindex = gi.modelindex("models/objects/tapper/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_NOT); + +} + + +/*QUAKED obj_wallringplaque (1 .5 0) (-3 -20 -55) (3 20 55) INVULNERABLE ANIMATE EXPLODING NOPUSH +An iron plaque with rings hanging from it. Great for hanging half corpses from +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_wallringplaque (edict_t *self) +{ + VectorSet(self->mins, -3, -20, -55); + VectorSet(self->maxs, 3, 20, 55); + + self->s.modelindex = gi.modelindex("models/objects/torture/plaque/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_hangingdude (1 .5 0) (-3 -20 -55) (3 20 55) INVULNERABLE ANIMATE EXPLODING NOPUSH +A half a dude hanging from a wall ring plaque +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_hangingdude (edict_t *self) +{ + edict_t *ring; + + + VectorSet(self->mins, -3, -20, -55); + VectorSet(self->maxs, 3, 20, 55); + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_BBOX; + self->s.modelindex = gi.modelindex("models/objects/torture/guy1/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->s.frame = 0; + BboxYawAndScale(self); + self->targetname = "guy1"; + gi.linkentity (self); + + + ring = G_Spawn(); + VectorCopy(self->s.origin,ring->s.origin); + VectorCopy(self->s.angles,ring->s.angles); + ring->s.modelindex = gi.modelindex("models/objects/torture/plaque/tris.fm"); + ring->spawnflags |= OBJ_NOPUSH; // Can't be pushed + ring->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + ring->movetype = PHYSICSTYPE_NONE; + ring->solid = SOLID_BBOX; + VectorSet(ring->mins, -3, -20, -55); + VectorSet(ring->maxs, 3, 20, 55); + + BboxYawAndScale(ring); + gi.linkentity (ring); + +} + +/*QUAKED obj_frypan (1 .5 0) (-1 -3 -10) (1 3 10) INVULNERABLE ANIMATE EXPLODING NOPUSH +A pan which is hanging on a nail +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_frypan (edict_t *self) +{ + VectorSet(self->mins, -1, -3, -10); + VectorSet(self->maxs, 1, 3, 10); + + self->s.modelindex = gi.modelindex("models/objects/pots/frypan/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_eggpan (1 .5 0) (-4 -10 -1) (4 10 1) INVULNERABLE ANIMATE EXPLODING NOPUSH +A pan which is laying flat like it was on a stove +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_eggpan (edict_t *self) +{ + VectorSet(self->mins, -4, -10, -1); + VectorSet(self->maxs, 4, 10, 1); + + self->s.modelindex = gi.modelindex("models/objects/pots/eggpan/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_nest (1 .5 0) (-25 -25 -4) (25 25 4) INVULNERABLE ANIMATE EXPLODING NOPUSH +A big bird nest +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_nest (edict_t *self) +{ + VectorSet(self->mins, -25, -25, -4); + VectorSet(self->maxs, 25, 25, 4); + + self->s.modelindex = gi.modelindex("models/objects/nest/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,250,200,MAT_GREYSTONE,SOLID_BBOX); +} + + +/*QUAKED obj_choppeddude (1 .5 0) (-15 -40 -8) (15 40 8) INVULNERABLE ANIMATE EXPLODING NOPUSH +A guy who's all chopped up and laying on a table +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be moved) +----------------------------------- +*/ +void SP_obj_choppeddude (edict_t *self) +{ + VectorSet(self->mins, -15, -40, -8); + VectorSet(self->maxs, 15, 40, 8); + + self->s.modelindex = gi.modelindex("models/objects/torture/guy2/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,250,200,MAT_FLESH,SOLID_BBOX); +} + +/*QUAKED obj_lab_parts_container (1 .5 0) (-8 -8 -11) (8 8 11) INVULNERABLE ANIMATE EXPLODING NOPUSH +A container of moving body parts +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A (thing always animates) +EXPLODING - N/A +NOPUSH - can't be pushed +----------------------------------- +*/ +void SP_obj_lab_parts_container (edict_t *self) +{ + VectorSet(self->mins, -8, -8, -11); + VectorSet(self->maxs, 8, 8, 11); + + self->spawnflags |= OBJ_ANIMATE; + SpawnClientAnim(self, FX_ANIM_LABPARTSCONTAINER, NULL); + ObjectInit(self,40,200,MAT_GLASS,SOLID_BBOX); +} + +/*QUAKED obj_eyeball_jar (1 .5 0) (-13 -13 -18) (13 13 18) INVULNERABLE ANIMATE EXPLODING NOPUSH +A jar full of eyeballs +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A (thing always animates) +EXPLODING - N/A +NOPUSH - can't be moved +----------------------------------- +*/ +void SP_obj_eyeball_jar (edict_t *self) +{ + VectorSet(self->mins, -13, -13, -18); + VectorSet(self->maxs, 13, 13, 18); + + self->spawnflags |= OBJ_NOPUSH | OBJ_ANIMATE; + + SpawnClientAnim(self, FX_ANIM_EYEBALLJAR, NULL); + ObjectInit(self,50,200,MAT_GLASS,SOLID_BBOX); +} + +/*QUAKED obj_lab_tray (1 .5 0) (-8 -8 -5) (8 8 5) INVULNERABLE ANIMATE EXPLODING NOPUSH +A tray with a beating heart and some tools on it. +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A (thing always animates) +EXPLODING - N/A +NOPUSH - N/A (can't be pushed) +----------------------------------- +*/ +void SP_obj_lab_tray (edict_t *self) +{ + VectorSet(self->mins, -8, -8, -5); + VectorSet(self->maxs, 8, 8, 5); + + self->spawnflags |= OBJ_NOPUSH | OBJ_ANIMATE; + SpawnClientAnim(self, FX_ANIM_LABTRAY, NULL); + ObjectInit(self,40,200,MAT_FLESH,SOLID_BBOX); +} + + +void ogle_moan (edict_t *self) +{ + gi.sound(self, CHAN_VOICE, gi.soundindex(va("monsters/ogle/oglemoan%c.wav", irand('1', '2'))), 1, ATTN_IDLE, 0); + self->think = ogle_moan; + self->nextthink = level.time + irand (3, 10); +} + +/*QUAKED obj_hanging_ogle (1 .5 0) (-8 -16 -34) (8 16 34) INVULNERABLE ANIMATE EXPLODING NOPUSH +Poor little hanging ogle +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A (thing always animates) +EXPLODING - N/A +NOPUSH - N/A (can't be pushed) +----------------------------------- +*/ +void SP_obj_hanging_ogle (edict_t *self) +{ + edict_t *ring; + vec3_t forward; + + VectorSet(self->mins, -8, -16, -34); + VectorSet(self->maxs, 8, 16, 34); + + self->spawnflags |= OBJ_NOPUSH | OBJ_ANIMATE; + + SpawnClientAnim(self, FX_ANIM_HANGING_OGLE, NULL); + ObjectInit(self,100,200,MAT_FLESH,SOLID_BBOX); + + + ring = G_Spawn(); + VectorCopy(self->s.origin,ring->s.origin); + ring->s.origin[2] += 27; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(ring->s.origin, -9, forward, ring->s.origin); + + VectorCopy(self->s.angles,ring->s.angles); + ring->s.modelindex = gi.modelindex("models/objects/torture/plaque2/tris.fm"); + ring->movetype = PHYSICSTYPE_NONE; + ring->solid = SOLID_NOT; + ring->spawnflags |= OBJ_NOPUSH; // Can't be pushed + ring->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + BboxYawAndScale(ring); + gi.linkentity (ring); + + self->target_ent = ring; + + self->think = ogle_moan; + self->nextthink = level.time + irand (3, 10); +} + + +/*QUAKED obj_ring_plaque2 (1 .5 0) (-2 -24 -20) (2 24 20) INVULNERABLE ANIMATE EXPLODING NOPUSH +More rings mounted into a wall plate +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be pushed) +----------------------------------- +*/ +void SP_obj_ring_plaque2 (edict_t *self) +{ + VectorSet(self->mins, -2, -24, -20); + VectorSet(self->maxs, 2, 24, 20); + + self->s.modelindex = gi.modelindex("models/objects/torture/plaque2/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->spawnflags |= OBJ_INVULNERABLE; // can't be destroyed + + ObjectInit(self,250,200,MAT_FLESH,SOLID_BBOX); +} + + +/*QUAKED obj_statue_sariph (1 .5 0) (-13 -16 -41) (13 16 41) INVULNERABLE ANIMATE EXPLODING NOPUSH +Big statue in armor carrying an axe +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (can't be pushed) +----------------------------------- +*/ +void SP_obj_statue_sariph (edict_t *self) +{ + VectorSet(self->mins, -13, -16, -41); + VectorSet(self->maxs, 13, 16, 41); + + self->s.modelindex = gi.modelindex("models/objects/statue/sariph/tris.fm"); + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + + ObjectInit(self,250,200,MAT_STONE,SOLID_BBOX); +} + +/*QUAKED obj_pushcart (1 .5 0) (-13 -16 -41) (13 16 41) INVULNERABLE ANIMATE EXPLODING NOPUSH +A push cart for the ogles to push around +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can be pushed +----------------------------------- +*/ +void SP_obj_pushcart (edict_t *self) +{ + VectorSet(self->mins, -14, -30, -17); + VectorSet(self->maxs, 14, 30, 17); + + self->s.modelindex = gi.modelindex("models/objects/carts/pushcart/tris.fm"); + + ObjectInit(self,250,200,MAT_WOOD,SOLID_BBOX); +} + + + +/*QUAKED obj_bookopen (1 .5 0) (-8 -16 -2) (8 16 2) INVULNERABLE ANIMATE EXPLODING NOPUSH +An open book +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can be pushed +----------------------------------- +*/ +void SP_obj_bookopen (edict_t *self) +{ + VectorSet(self->mins, -8, -16, -2); + VectorSet(self->maxs, 8, 16, 2); + + self->s.modelindex = gi.modelindex("models/objects/books/bookopen/tris.fm"); + + ObjectInit(self,250,200,MAT_WOOD,SOLID_BBOX); +} + + +/*QUAKED obj_bookclosed (1 .5 0) (-8 -8 -2) (8 8 2) INVULNERABLE ANIMATE EXPLODING NOPUSH +A closed book standing up +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can be pushed +----------------------------------- +*/ +void SP_obj_bookclosed (edict_t *self) +{ + VectorSet(self->mins, -8, -8, -2); + VectorSet(self->maxs, 8, 8, 2); + + self->s.modelindex = gi.modelindex("models/objects/books/bookclosed/tris.fm"); + + ObjectInit(self,250,200,MAT_WOOD,SOLID_BBOX); +} + + +/*QUAKED obj_web (1 .5 0) (-2 -18 -20) (2 18 20) INVULNERABLE ANIMATE EXPLODING NOPUSH +A cobweb +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can be pushed +----------------------------------- +*/ +void SP_obj_web (edict_t *self) +{ + VectorSet(self->mins, -2, -18, -20); + VectorSet(self->maxs, 2, 18, 20); + + self->s.modelindex = gi.modelindex("models/objects/web/web/tris.fm"); + self->s.renderfx |= RF_TRANSLUCENT; + + ObjectInit(self,250,200,MAT_WOOD,SOLID_NOT); +} + +#define FAST_TWITCH 16 + +void larva_anim (edict_t *self) +{ + + if (self->s.frame < self->count) + { + ++self->s.frame; + + if (self->spawnflags & FAST_TWITCH) // Some squirm faster + ++self->s.frame; + } + else + { + self->s.frame=0; + } + + self->think = larva_anim; + self->nextthink = level.time + FRAMETIME; +} + +void larva_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if (!other->client) + return; + + T_Damage (self, other, other, vec3_origin, self->s.origin, vec3_origin, 10, 0, DAMAGE_AVOID_ARMOR,MOD_DIED); +} + +/*QUAKED obj_larva (1 .5 0) (-8 -8 -2) (8 8 2) INVULNERABLE ANIMATE EXPLODING NOPUSH +A squirming larva +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can be pushed +----------------------------------- +*/ +void SP_obj_larva (edict_t *self) +{ + VectorSet(self->mins, -8, -12, -2); + VectorSet(self->maxs, 8, 12, 2); + + self->s.modelindex = gi.modelindex("models/objects/eggs/larva/tris.fm"); + + ObjectInit(self,2,100,MAT_INSECT,SOLID_BBOX); + + self->movetype = PHYSICSTYPE_STEP; + self->count = 19; + + self->think = larva_anim; + self->nextthink = level.time + FRAMETIME; + self->nextthink += FRAMETIME * flrand(1, 6); // Don't all start at the same time + + self->s.sound = gi.soundindex("misc/larva.wav"); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; + + self->svflags = SVF_ALLOW_AUTO_TARGET; + + if (irand(0, 1)) + self->spawnflags |= FAST_TWITCH; + + self->touch = larva_touch; + + +} + +/*QUAKED obj_bloodsplat (1 .5 0) (-8 -8 -2) (8 8 2) INVULNERABLE ANIMATE EXPLODING NOPUSH +A red blood splat +------- FIELDS ------------------ +INVULNERABLE - can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - can be pushed +----------------------------------- +*/ +void SP_obj_bloodsplat (edict_t *self) +{ + VectorSet(self->mins, -8, -8, -2); + VectorSet(self->maxs, 8, 8, 2); + + self->s.modelindex = gi.modelindex("sprites/fx/bsplat.sp2"); + self->flags |= RF_FIXED | RF_ALPHA_TEXTURE; + + ObjectInit(self,2,100,MAT_FLESH,SOLID_NOT); + +} diff --git a/Toolkit/Programming/GameCode/game/g_phys.c b/Toolkit/Programming/GameCode/game/g_phys.c new file mode 100644 index 0000000..cd375d7 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_phys.c @@ -0,0 +1,1083 @@ +// g_phys.c + +#include "g_local.h" +#include "Message.h" +#include "vector.h" + + +#define KNOCKBACK_SCALING 0.5 +#define KNOCKBACK_THRESH .5 + +/* + + +pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move. + +onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects + +doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH +bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS +corpses are SOLID_NOT and MOVETYPE_TOSS +crates are SOLID_BBOX and MOVETYPE_TOSS +walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP +flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY + +solid_edge items only clip against bsp models. + +*/ + + +/* +============ +SV_TestEntityPosition + +============ +*/ +edict_t *SV_TestEntityPosition (edict_t *ent) +{ + trace_t trace; + + gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, MASK_SOLID,&trace); + + if (trace.startsolid) + return g_edicts; + + return NULL; +} + + +/* +================ +SV_CheckVelocity +================ +*/ +void SV_CheckVelocity (edict_t *ent) +{ + int i; + +// +// bound velocity +// + for (i=0 ; i<3 ; i++) + { + if (ent->velocity[i] > sv_maxvelocity->value) + ent->velocity[i] = sv_maxvelocity->value; + else if (ent->velocity[i] < -sv_maxvelocity->value) + ent->velocity[i] = -sv_maxvelocity->value; + } +} + +/* +============= +SV_RunThink + +Runs thinking code for this frame if necessary +============= +*/ +qboolean SV_RunThink (edict_t *ent) +{ + float thinktime; + + thinktime = ent->nextthink; + + assert(ent->inuse); + + if(ent->msgHandler) + { + ProcessMessages(ent); + } + + assert(ent->inuse); + + if(!ent->think || thinktime<=0 || thinktime>level.time+0.001) + { + return(true); + } + +#if 1 + ent->nextthink = 0; + + ent->think(ent); +#else + { +#ifndef NDEBUG + void *think; + think = ent->think; +#endif + + ent->think(ent); + + assert(!ent->think || think != ent->think || thinktime != ent->nextthink); // think should be nulled if nextthink is not set + } +#endif + + // NOTENOTE Is this what we want to return if it gets this far? + return(true); +} + +/* +================== +SV_Impact + +Two entities have touched, so run their touch functions +================== +*/ +void SV_Impact (edict_t *e1, trace_t *trace) +{ + edict_t *e2; +// cplane_t backplane; + + e2 = trace->ent; + + if (e1->touch && e1->solid != SOLID_NOT) + e1->touch (e1, e2, &trace->plane, trace->surface); + + if (e2->touch && e2->solid != SOLID_NOT) + e2->touch (e2, e1, NULL, NULL); +} + + +/* +================== +ClipVelocity + +Slide off of the impacting object +returns the blocked flags (1 = floor, 2 = step / wall) +================== +*/ +#define STOP_EPSILON 0.1 + +int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) +{ + float backoff; + float change; + int i, blocked; + + blocked = 0; + if (normal[2] > 0) + blocked |= 1; // floor + if (!normal[2]) + blocked |= 2; // step + + backoff = DotProduct (in, normal) * overbounce; + + for (i=0 ; i<3 ; i++) + { + change = normal[i]*backoff; + out[i] = in[i] - change; + if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) + out[i] = 0; + } + + return blocked; +} + + +/* +============ +SV_FlyMove (only called by Physics_Step) + +The basic solid body movement clip that slides along multiple planes +Returns the clipflags if the velocity was modified (hit something solid) +1 = floor +2 = wall / step +4 = dead stop +============ +*/ +#define MAX_CLIP_PLANES 5 +static int SV_FlyMove (edict_t *ent, float time, int mask) +{ + edict_t *hit; + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity, original_velocity, new_velocity; + int i, j; + trace_t trace; + vec3_t end; + float time_left; + int blocked; + + numbumps = 4; + + blocked = 0; + VectorCopy (ent->velocity, original_velocity); + VectorCopy (ent->velocity, primal_velocity); + numplanes = 0; + + time_left = time; + + ent->groundentity = NULL; + for (bumpcount=0 ; bumpcounts.origin[i] + time_left * ent->velocity[i]; + + gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask,&trace); + + if (trace.allsolid) + { // entity is trapped in another solid + VectorCopy (vec3_origin, ent->velocity); + return 3; + } + + if (trace.fraction > 0) + { // actually covered some distance + VectorCopy (trace.endpos, ent->s.origin); + VectorCopy (ent->velocity, original_velocity); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + hit = trace.ent; + + if (trace.plane.normal[2] > 0.7) + { + blocked |= 1; // floor + if ( hit->solid == SOLID_BSP) + { + ent->groundentity = hit; + ent->groundentity_linkcount = hit->linkcount; + } + } + if (!trace.plane.normal[2]) + { + blocked |= 2; // step + } + +// +// run the impact function +// + SV_Impact (ent, &trace); + if (!ent->inuse) + break; // removed by the impact function + + + time_left -= time_left * trace.fraction; + + // cliped to another plane + if (numplanes >= MAX_CLIP_PLANES) + { // this shouldn't really happen + VectorCopy (vec3_origin, ent->velocity); + return 3; + } + + VectorCopy (trace.plane.normal, planes[numplanes]); + numplanes++; + +// +// modify original_velocity so it parallels all of the clip planes +// + for (i=0 ; ivelocity); + } + else + { // go along the crease + if (numplanes != 2) + { +// gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); + VectorCopy (vec3_origin, ent->velocity); + return 7; + } + CrossProduct (planes[0], planes[1], dir); + d = DotProduct (dir, ent->velocity); + VectorScale (dir, d, ent->velocity); + } + +// +// if original velocity is against the original velocity, stop dead +// to avoid tiny occilations in sloping corners +// + if (DotProduct (ent->velocity, primal_velocity) <= 0) + { + VectorCopy (vec3_origin, ent->velocity); + return blocked; + } + } + + return blocked; +} + + +/* +============ +SV_AddGravity + +============ +*/ +void SV_AddGravity (edict_t *ent) +{ + ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME; +} + +/* +=============================================================================== + +PUSHMOVE + +=============================================================================== +*/ + +/* +============ +SV_PushEntity + +Does not change the entities velocity at all +============ +*/ +trace_t SV_PushEntity (edict_t *ent, vec3_t push) +{ + trace_t trace; + vec3_t start; + vec3_t end; + int mask; + + VectorCopy (ent->s.origin, start); + VectorAdd (start, push, end); + +retry: + if (ent->clipmask) + mask = ent->clipmask; + else + mask = MASK_SOLID; + + gi.trace (start, ent->mins, ent->maxs, end, ent, mask,&trace); + + VectorCopy (trace.endpos, ent->s.origin); + + if (ent->movetype == MOVETYPE_FLYMISSILE) + { + G_LinkMissile(ent); + } + else + { + gi.linkentity (ent); + } + + if (trace.fraction != 1.0) + { + SV_Impact (ent, &trace); + + // if the pushed entity went away and the pusher is still there + if (!trace.ent->inuse && ent->inuse) + { + // move the pusher back and try again + VectorCopy (start, ent->s.origin); + gi.linkentity (ent); + goto retry; + } + } + + if (ent->inuse) + G_TouchTriggers (ent); + + return trace; +} + + +typedef struct +{ + edict_t *ent; + vec3_t origin; + vec3_t angles; + float deltayaw; +} pushed_t; +pushed_t pushed[MAX_EDICTS], *pushed_p; + +edict_t *obstacle; + +/* +============ +SV_Push + +Objects need to be moved back on a failed push, +otherwise riders would continue to slide. +============ +*/ +qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) +{ + int i, e; + edict_t *check, *block; + vec3_t mins, maxs; + pushed_t *p; + vec3_t org, org2, move2, forward, right, up; + + // clamp the move to 1/8 units, so the position will + // be accurate for client side prediction + for (i=0 ; i<3 ; i++) + { + float temp; + temp = move[i]*8.0; + if (temp > 0.0) + temp += 0.5; + else + temp -= 0.5; + move[i] = 0.125 * (int)temp; + } + + // find the bounding box + for (i=0 ; i<3 ; i++) + { + mins[i] = pusher->absmin[i] + move[i]; + maxs[i] = pusher->absmax[i] + move[i]; + } + +// we need this for pushing things later + VectorSubtract (vec3_origin, amove, org); + AngleVectors (org, forward, right, up); + +// save the pusher's original position + pushed_p->ent = pusher; + VectorCopy (pusher->s.origin, pushed_p->origin); + VectorCopy (pusher->s.angles, pushed_p->angles); + if (pusher->client) + pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW]; + pushed_p++; + +// move the pusher to it's final position + VectorAdd (pusher->s.origin, move, pusher->s.origin); + VectorAdd (pusher->s.angles, amove, pusher->s.angles); + gi.linkentity (pusher); + +// see if any solid entities are inside the final position + check = g_edicts+1; + for (e = 1; e < globals.num_edicts; e++, check++) + { + if (!check->inuse) + continue; + if (check->movetype == MOVETYPE_PUSH + || check->movetype == MOVETYPE_STOP +// || check->movetype == MOVETYPE_NOCLIP + || check->movetype == MOVETYPE_SCRIPT_ANGULAR) + continue; + + // if the entity is standing on the pusher, it will definitely be moved + if (check->groundentity != pusher) + { + // see if the ent needs to be tested + if ( check->absmin[0] >= maxs[0] + || check->absmin[1] >= maxs[1] + || check->absmin[2] >= maxs[2] + || check->absmax[0] <= mins[0] + || check->absmax[1] <= mins[1] + || check->absmax[2] <= mins[2] ) + continue; + + // see if the ent's bbox is inside the pusher's final position + if (!SV_TestEntityPosition (check)) + continue; + } + + if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher)) + { + // move this entity + pushed_p->ent = check; + VectorCopy (check->s.origin, pushed_p->origin); + VectorCopy (check->s.angles, pushed_p->angles); + pushed_p++; + + // try moving the contacted entity + VectorAdd (check->s.origin, move, check->s.origin); + if (check->client) + { // FIXME: doesn't rotate monsters? + check->client->ps.pmove.delta_angles[YAW] += amove[YAW]; + } + + // figure movement due to the pusher's amove + VectorSubtract (check->s.origin, pusher->s.origin, org); + org2[0] = DotProduct (org, forward); + org2[1] = -DotProduct (org, right); + org2[2] = DotProduct (org, up); + VectorSubtract (org2, org, move2); + VectorAdd (check->s.origin, move2, check->s.origin); + + // may have pushed them off an edge + if (check->groundentity != pusher) + check->groundentity = NULL; + + block = SV_TestEntityPosition (check); + if (!block) + { // pushed ok + gi.linkentity (check); + // impact? + continue; + } + + // if it is ok to leave in the old position, do it + // this is only relevent for riding entities, not pushed + // FIXME: this doesn't acount for rotation + VectorSubtract (check->s.origin, move, check->s.origin); + block = SV_TestEntityPosition (check); + if (!block) + { + pushed_p--; + continue; + } + } + + // save off the obstacle so we can call the block function + obstacle = check; + + // move back any entities we already moved + // go backwards, so if the same entity was pushed + // twice, it goes back to the original position + for (p=pushed_p-1 ; p>=pushed ; p--) + { + VectorCopy (p->origin, p->ent->s.origin); + VectorCopy (p->angles, p->ent->s.angles); + if (p->ent->client) + { + p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw; + } + gi.linkentity (p->ent); + } + return false; + } + +//FIXME: is there a better way to handle this? + // see if anything we moved has touched a trigger + for (p=pushed_p-1 ; p>=pushed ; p--) + G_TouchTriggers (p->ent); + + return true; +} + +/* +================ +SV_Physics_Pusher + +Bmodel objects don't interact with each other, but +push all box objects +================ +*/ +void SV_Physics_Pusher (edict_t *ent) +{ + vec3_t move, amove; + edict_t *part, *mv; + + // if not a team captain, so movement will be handled elsewhere + if ( ent->flags & FL_TEAMSLAVE) + return; + + // make sure all team slaves can move before commiting + // any moves or calling any think functions + // if the move is blocked, all moved objects will be backed out +//retry: + pushed_p = pushed; + for (part = ent ; part ; part=part->teamchain) + { + if (part->velocity[0] || part->velocity[1] || part->velocity[2] || + part->avelocity[0] || part->avelocity[1] || part->avelocity[2] + ) + { // object is moving + VectorScale (part->velocity, FRAMETIME, move); + VectorScale (part->avelocity, FRAMETIME, amove); + + if (!SV_Push (part, move, amove)) + break; // move was blocked + } + } + if (pushed_p > &pushed[MAX_EDICTS]) + gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted"); + + if (part) + { + // the move failed, bump all nextthink times and back out moves + for (mv = ent ; mv ; mv=mv->teamchain) + { + if (mv->nextthink > 0) + mv->nextthink += FRAMETIME; + } + + // if the pusher has a "blocked" function, call it + // otherwise, just stay in place until the obstacle is gone + if (part->blocked) + part->blocked (part, obstacle); +#if 0 + // if the pushed entity went away and the pusher is still there + if (!obstacle->inuse && part->inuse) + goto retry; +#endif + } + else + { + // the move succeeded, so call all think functions + for (part = ent ; part ; part=part->teamchain) + { + SV_RunThink (part); + } + } +} + +//================================================================== + +/* +============= +SV_Physics_None + +Non moving objects can only think +============= +*/ +void SV_Physics_None (edict_t *ent) +{ +// regular thinking + assert(ent->inuse); + + SV_RunThink (ent); +} + +/* +============= +SV_Physics_Noclip + +A moving object that doesn't obey physics +============= +*/ +void SV_Physics_Noclip (edict_t *ent) +{ +// regular thinking + if (!SV_RunThink (ent)) + return; + + VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); + VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin); + + gi.linkentity (ent); +} + +/* +============================================================================== + +TOSS / BOUNCE + +============================================================================== +*/ + +/* +============= +SV_Physics_Toss + +Toss, bounce, and fly movement. When onground, do nothing. +============= +*/ +void PhysicsCheckWaterTransition(edict_t *self); +void SV_Physics_Toss (edict_t *ent) +{ + trace_t trace; + vec3_t move; + float backoff; + edict_t *slave; +// qboolean wasinwater; +// qboolean isinwater; + vec3_t old_origin; + +// regular thinking + SV_RunThink (ent); + + // if not a team captain, so movement will be handled elsewhere + if ( ent->flags & FL_TEAMSLAVE) + return; + + if (ent->velocity[2] > 0) + ent->groundentity = NULL; + +// check for the groundentity going away + if (ent->groundentity) + if (!ent->groundentity->inuse) + ent->groundentity = NULL; + +// if onground, return without moving + if ( ent->groundentity ) + return; + + VectorCopy (ent->s.origin, old_origin); + + SV_CheckVelocity (ent); + +// add gravity + if (ent->movetype != MOVETYPE_FLY + && ent->movetype != MOVETYPE_FLYMISSILE) + SV_AddGravity (ent); + +// move angles + VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); + +// move origin + VectorScale (ent->velocity, FRAMETIME, move); + trace = SV_PushEntity (ent, move); + if (!ent->inuse) + return; + + if (trace.fraction < 1) + { + if (ent->movetype == MOVETYPE_BOUNCE) + backoff = 1.5; + else + backoff = 1; + + ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); + + // stop if on ground + if (trace.plane.normal[2] > 0.7) + { + if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE ) + { + ent->groundentity = trace.ent; + ent->groundentity_linkcount = trace.ent->linkcount; + VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->avelocity); + } + } + +// if (ent->touch) +// ent->touch (ent, trace.ent, &trace.plane, trace.surface); + } + +// check for water transition + PhysicsCheckWaterTransition(ent); + +/* + wasinwater = (ent->watertype & MASK_WATER); + ent->watertype = gi.pointcontents (ent->s.origin); + isinwater = ent->watertype & MASK_WATER; + + if (isinwater) + ent->waterlevel = 1; + else + ent->waterlevel = 0; + + if (!wasinwater && isinwater) + gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); + else if (wasinwater && !isinwater) + gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); +*/ +// move teamslaves + for (slave = ent->teamchain; slave; slave = slave->teamchain) + { + VectorCopy (ent->s.origin, slave->s.origin); + gi.linkentity (slave); + } +} + +/* +=============================================================================== + +STEPPING MOVEMENT + +=============================================================================== +*/ + +/* +============= +SV_Physics_Step + +Monsters freefall when they don't have a ground entity, otherwise +all movement is done with discrete steps. + +This is also used for objects that have become still on the ground, but +will fall if the floor is pulled out from under them. +FIXME: is this true? +============= +*/ + +//FIXME: hacked in for E3 demo +#define sv_stopspeed 100 +#define sv_friction 6 +#define sv_waterfriction 1 + +void SV_AddRotationalFriction (edict_t *ent) +{ + int n; + float adjustment; + + VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); + adjustment = FRAMETIME * sv_stopspeed * sv_friction; + for (n = 0; n < 3; n++) + { + if (ent->avelocity[n] > 0) + { + ent->avelocity[n] -= adjustment; + if (ent->avelocity[n] < 0) + ent->avelocity[n] = 0; + } + else + { + ent->avelocity[n] += adjustment; + if (ent->avelocity[n] > 0) + ent->avelocity[n] = 0; + } + } +} + +void SV_Physics_Step (edict_t *ent) +{ + qboolean wasonground; + qboolean hitsound = false; + float *vel; + float speed, newspeed, control; + float friction; + edict_t *groundentity; + int mask; + vec3_t origvel; + + int i, threshhit=0; + + // airborn monsters should always check for ground + if (!ent->groundentity) + M_CheckGround (ent); + + groundentity = ent->groundentity; + + SV_CheckVelocity (ent); + + if (groundentity) + wasonground = true; + else + wasonground = false; + + if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) + SV_AddRotationalFriction (ent); + + // add gravity except: + // flying monsters + // swimming monsters who are in the water + if (! wasonground) + if (!(ent->flags & FL_FLY)) + if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) + { + if (ent->velocity[2] < sv_gravity->value*-0.1) + hitsound = true; + if (ent->waterlevel == 0) + SV_AddGravity (ent); + } + + // friction for flying monsters that have been given vertical velocity + if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) + { + speed = Q_fabs(ent->velocity[2]); + control = speed < sv_stopspeed ? sv_stopspeed : speed; + friction = sv_friction/3; + newspeed = speed - (FRAMETIME * control * friction); + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + ent->velocity[2] *= newspeed; + } + + // friction for flying monsters that have been given vertical velocity + if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) + { + speed = Q_fabs(ent->velocity[2]); + control = speed < sv_stopspeed ? sv_stopspeed : speed; + newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + ent->velocity[2] *= newspeed; + } + + if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0] || ent->knockbackvel[0] || ent->knockbackvel[1] || ent->knockbackvel[2]) + { + // apply friction + // let dead monsters who aren't completely onground slide + if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) + if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) + { + vel = ent->velocity; + speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); + if (speed) + { + friction = sv_friction; + + control = speed < sv_stopspeed ? sv_stopspeed : speed; + newspeed = speed - FRAMETIME*control*friction; + + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + vel[0] *= newspeed; + vel[1] *= newspeed; + } + } + + if (ent->svflags & SVF_MONSTER) + mask = MASK_MONSTERSOLID; + else + mask = MASK_SOLID; + + // Try to add velocity + VectorAdd(ent->velocity, ent->knockbackvel, ent->velocity); + VectorCopy(ent->velocity, origvel); + // Returns value if velocity was clipped + SV_FlyMove (ent, FRAMETIME, mask); + + for (i=0; i<3; i++) + { + if (ent->knockbackvel != 0) + { + if (ent->velocity[i] != origvel[i]) + { + ent->knockbackvel[i] = 0; + } + else + { + ent->velocity[i] -= ent->knockbackvel[i]; + ent->knockbackvel[i] *= KNOCKBACK_SCALING; + if (Q_fabs(ent->knockbackvel[i]) < KNOCKBACK_THRESH) + threshhit++; + } + } + } + if (threshhit >= 3) + VectorClear(ent->knockbackvel); + + /* + // If clipped, Take the amount the velocity was clipped and apply it to the knockback first, then to the regular velocity. + gi.dprintf("Velocity clip from %s, %s: ",vtos(origvel), vtos(ent->knockbackvel)); + + for (i=0; i<3; i++) + { + d = ent->velocity[i] - (origvel[i] + ent->knockbackvel[i]); + newkb = ent->knockbackvel[i]; + + if (newkb > 0) + { + if (d > 0) + ent->velocity[i] -= newkb; + else + { + newkb += d; + if (newkb < 0) + { + ent->knockbackvel[i] = 0; + ent->velocity[i] = origvel[i] + newkb; + } + else + { + ent->knockbackvel[i] = newkb; + ent->velocity[i] = origvel[i]; + } + } + } + else if (newkb < 0) + { + if (d < 0) + ent->velocity[i] -= newkb; + else + { + newkb += d; + if (newkb > 0) + { + ent->velocity[i] = origvel[i] + newkb; + ent->knockbackvel[i] = 0; + } + else + { + ent->knockbackvel[i] = newkb; + ent->velocity[i] = origvel[i]; + } + } + } + } + + gi.dprintf("now %s, %s\n",vtos(ent->velocity), vtos(ent->knockbackvel)); + */ + + + gi.linkentity (ent); + G_TouchTriggers (ent); + +/* if (ent->groundentity) + if (!wasonground) + if (hitsound) + gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); */ + } + +// regular thinking + SV_RunThink (ent); +} + +void SV_Physics_Script_Angular(edict_t *ent) +{ + vec3_t Forward; + + if (ent->owner) + { + AngleVectors(ent->owner->s.angles, NULL, NULL, Forward); + + Forward[0] = -Forward[0]; + Forward[1] = -Forward[1]; + Forward[2] = -Forward[2]; + + VectorMA(ent->moveinfo.start_origin, ent->moveinfo.distance, Forward, ent->s.origin); + + gi.linkentity (ent); + } + + SV_RunThink (ent); +} + +//============================================================================ +/* +================ +G_RunEntity + +================ +*/ +void G_RunEntity (edict_t *ent) +{ + assert(ent->inuse); + + if (ent->prethink) + ent->prethink (ent); + + switch ( (int)ent->movetype) + { + case MOVETYPE_PUSH: + case MOVETYPE_STOP: + SV_Physics_Pusher (ent); + break; + case 0: + case MOVETYPE_NONE: + SV_Physics_None (ent); + break; + case MOVETYPE_NOCLIP: + SV_Physics_Noclip (ent); + break; + case MOVETYPE_STEP: + SV_Physics_Step (ent); + break; + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + case MOVETYPE_FLY: + case MOVETYPE_FLYMISSILE: + SV_Physics_Toss (ent); + break; + + case MOVETYPE_SCRIPT_ANGULAR: + SV_Physics_Script_Angular(ent); + break; + + default: + gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype); + } +} diff --git a/Toolkit/Programming/GameCode/game/g_playstats.h b/Toolkit/Programming/GameCode/game/g_playstats.h new file mode 100644 index 0000000..d7e6f70 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_playstats.h @@ -0,0 +1,288 @@ +// +// g_playstats.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef _G_PLAYSTATS_H_ +#define _G_PLAYSTATS_H_ + + +// *************************************** +// ** GENERAL +// *************************************** +#define DAMAGE_DM_FACTOR 0.67 + + +// *************************************** +// ** WEAPON STATS +// *************************************** +#define MAX_REFLECT 8 + + +// Sword staff +#define SWORD_DMG_MIN 15 +#define SWORD_DMG_MAX 25 +#define SWORD_POWER1_DMG_MIN 30 +#define SWORD_POWER1_DMG_MAX 40 +#define SWORD_POWER2_DMG_MIN 45 +#define SWORD_POWER2_DMG_MAX 55 + +#define SWORD_SPIN_DMG_MOD 1.75 + +// Flying Fist +#define FIREBALL_MIN_FIZZLE_DAMAGE 5 // Least amount of damage it will do after flying +#define FIREBALL_DAMAGE_MIN 20 +#define FIREBALL_DAMAGE_MAX 25 +#define FIREBALL_DAMAGE_MIN_POWER 30 +#define FIREBALL_DAMAGE_MAX_POWER 40 +#define FIREBALL_RADIUS 64.0 // Radius of damage for the powered up version. +#define FLYING_FIST_SPEED 1000.0 + +// Hellstaff +#define HELLBOLT_DAMAGE_MIN 7 +#define HELLBOLT_DAMAGE_MAX 10 +#define HELLLASER_DIST 1024.0 +#define HELLLASER_DAMAGE_MIN 11 +#define HELLLASER_DAMAGE_MAX 14 +#define HELLBOLT_SPEED 1000.0 + +// Blast (Arc of Thunder) +#define BLAST_DISTANCE 1000.0 // Max range of the blast +#define BLAST_DMG_MIN 10 +#define BLAST_DMG_MAX 15 +#define BLAST_ANGLE_INC 3.5 +#define BLAST_NUM_SHOTS 5 + + +// Magic Missile array (powered up Arc) +#define MAGICMISSILE_DAMAGE_MIN 30 +#define MAGICMISSILE_DAMAGE_MAX 40 +#define MAGICMISSILE_DAMAGE_RAD 20 +#define MAGICMISSILE_RADIUS 48 +#define MAGICMISSILE_SPEED 1500.0 +// #define MAGICMISSILE_DAMAGE_RADIUS 64 + +// Red Rain Arrows +#define RED_RAIN_DMG_ARROW_MIN 35 +#define RED_RAIN_DMG_ARROW_MAX 45 +#define RED_RAIN_DURATION 8.0F +#define RED_RAIN_DAMAGE_INTERVAL 0.25 +#define RED_RAIN_DAMAGE 10 // 10 points every .25 seconds. +#define RED_RAIN_RADIUS 60.0F +#define MAX_REDRAINHEIGHT 200.0F +#define MAX_REDRAINFALLDIST 1000.0F +#define RED_RAIN_LIGHTNING_DURATION (RED_RAIN_DURATION - 1.5) +#define RED_RAIN_LIGHTNING_CHANCE 6 // 1 in 6 chance per target every .25 seconds +#define RED_RAIN_LIGHTNING_RADIUS 100.0 +#define RED_RAIN_LIGHTNING_WIDTH 6.0 +#define RED_RAIN_DMG_LIGHTNING_MIN 20 +#define RED_RAIN_DMG_LIGHTNING_MAX 30 +#define NUM_STORMS_PER_PLAYER 3//maybe 5, esp in DM? + +#define RED_ARROW_SPEED 1000.0F + +// Powered up red rain arrows +#define POWER_RAIN_DMG_ARROW_MIN 45 +#define POWER_RAIN_DMG_ARROW_MAX 55 +#define POWER_RAIN_DAMAGE 15 // 15 points every .25 seconds +#define POWER_RAIN_RADIUS 80.0F +#define POWER_RAIN_LIGHTNING_RADIUS 120.0 +#define POWER_RAIN_LIGHTNING_WIDTH 40.0 +#define POWER_RAIN_DMG_LIGHTNING_MIN 30 // Big nasty beam of thick lightning with radius damage +#define POWER_RAIN_DMG_LIGHTNING_MAX 45 +#define POWER_RAIN_DMG_LIGHTNING_RADIUS 100 + +// Fireblast (unpowered firewall) +#define FIREBLAST_LIFETIME 5 +#define FIREBLAST_SPEED 480.0 +#define FIREBLAST_RADIUS 48.0 +#define FIREBLAST_PROJ_RADIUS 8.0 +#define FIREBLAST_DRADIUS (1.0) +#define FIREBLAST_VRADIUS 16 +#define FIREBLAST_DAMAGE 48 +#define FIREBLAST_DAMAGE_MIN 32 + +// Firewall (powered fireblast!) +#define FIREWAVE_UP 80 +#define FIREWAVE_DOWN 48 +#define FIREWAVE_SPEED 320.0F // Speed of the firewall +#define FIREWAVE_DM_SPEED 450.0F // Speed of the firewall in deathmatch +#define FIREWAVE_PROJ_RADIUS 8.0 +#define FIREWAVE_RADIUS 20.0F // Size of each element of the firewall +#define FIREWAVE_DRADIUS (FIREWAVE_RADIUS) +#define FIREWAVE_DAMAGE 75 // How much damage the wall does every think. +#define FIREWAVE_DAMAGE_MIN 50 +#define FIREWAVE_WORM_DAMAGE 30 +#define FIREWAVE_WORM_RADIUS 64.0 + +// Phoenix Arrows +#define PHOENIX_EXPLODE_DAMAGE 175 // Silver armor + 100 health ends with 13 health. Demo: 225 +#define PHOENIX_EXPLODE_RADIUS 128 +#define PHOENIX_EXPLODE_DAMAGE_POWER 300 // Gold armor + 100 health ends with 25 health. Demo: 350 +#define PHOENIX_EXPLODE_RADIUS_POWER 144 +#define PHOENIX_ARROW_SPEED 640.0F + +// Sphere of Annihilation +#define SPHERE_DAMAGE 100 +#define SPHERE_RADIUS_MIN 48 +#define SPHERE_RADIUS_MAX 256 +#define SPHERE_BASE_MANA 6 +#define SPHERE_MANA_PER_CHARGE 1 +#define SPHERE_MAX_MANA_CHARGE 7 // For a total of 20 mana in a shot. +#define SPHERE_MAX_CHARGES (SPHERE_MAX_MANA_CHARGE * 2) // 2 frames per charge. +#define SPHERE_FLY_SPEED 600.0 +#define SPHERE_LASER_SPEED 320.0 + +// Ripper (Iron Doom) +#define RIPPER_DAMAGE_MIN 40 +#define RIPPER_DAMAGE_MAX 50 +#define RIPPER_BALLS 8 +#define RIPPER_BALL_ANGLE (M_PI*2.0/RIPPER_BALLS) +#define RIPPER_BALL_BANGLE (256/RIPPER_BALLS) // NOTE: Only works if the number of balls is evenly dividable! +#define RIPPER_EXPLODE_DAMAGE 20 +#define RIPPER_SPEED 2000.0 +#define RIPPER_EXPLODE_SPEED 500 + +// Mace balls (powered up Iron Doom) +#define MACEBALL_GRAVITY 0.5F +#define MACEBALL_LIFE 5.0 +#define MACEBALL_EXTRALIFE 5 +#define MACEBALL_DAMAGE 1000 +#define MACEBALL_BOSS_DAMAGE 100 + + +#define FIRE_LINGER_PLAYER_DMG_MIN 0 +#define FIRE_LINGER_PLAYER_DMG_MAX 1 + +#define FIRE_LINGER_DMG_MIN 2 +#define FIRE_LINGER_DMG_MAX 3 + + +// *************************************** +// ** DEFENSIVE SPELL STATS +// *************************************** + +// Delay before you can use a defensive spell again. +#define DEFENSE_DEBOUNCE 0.5 + +// Blue Ring of repulsion +#define RING_EFFECT_RADIUS 200.0 +#define RING_MASS_FACTOR 200.0 +#define RING_KNOCKBACK_BASE 150 +#define RING_KNOCKBACK_SCALE 200 + +// Meteor Barrier +#define METEOR_DAMAGE_MIN 35 +#define METEOR_DAMAGE_MAX 40 +#define METEOR_SEARCH_CHANCE 12 +#define METEOR_SEARCH_RADIUS 800 + +// Morph ovum +#define NUM_OF_OVUMS 6 +#define MORPH_DUR 30 // how long players / bad guys remain chickens - in seconds + +// Lightning Shield +#define SHIELD_DAMAGE_MIN 15 +#define SHIELD_DAMAGE_MAX 20 +#define SHIELD_DURATION 23 +#define SHIELD_DAMAGE_RADIUS 96 +#define SHIELD_LIGHTNING_WIDTH 8 +#define SHIELD_ATTACK_CHANCE 3 // This is the chance of searching at all, and the chance of being zapped if found. + + + +// *************************************** +// ** OTHER EFFECT STATS +// *************************************** + +/////////////////////////////////////////// +// ITEM STUFF +/////////////////////////////////////////// +#define BARREL_EXPLODE_DMG_MIN 10 +#define BARREL_EXPLODE_DMG_MAX 100 +#define BARREL_EXPLODE_RADIUS 128 + +/////////////////////////////////////////// +// FLAME THROWER STUFF - SERVER SIDE +/////////////////////////////////////////// + +// time to move from min to max grav values - server side +#define GRAV_MOV 1.0 +// gravity flamethrower starts with - server side +#define MAX_GRAV 1.2 +// gravity flamethrower maxes out at - server side +#define MIN_GRAV 0.12 +// time for flamethrower to be at its max - server side - seconds +#define ZEN_TIME 3.0 +// damage flamethrower does at one hit +#define FLAME_THROW_DAMAGE 10.0 + +// frame update speed - server side +#define FLAME_UPDATE_PER_SEC 0.2 +// count of number of updates per second - server side +#define FLAME_NUM_UPDATE_PER_SEC (GRAV_MOV / FLAME_UPDATE_PER_SEC) +// given the update speed, and the distance we have to go, and the time move from one to another, +// get us a value to update gravity with each frame +#define TOTAL_GRAV_MOV (MAX_GRAV - MIN_GRAV) / ((float)FLAME_NUM_UPDATE_PER_SEC) + +/////////////////////////////////////////// +// FLAME THROWER STUFF - CLIENT EFFECTS SIDE +/////////////////////////////////////////// + +// inital gravity value - client effects side. Should match cl_gravity->value +#define FLAME_GRAV -675.0 +// gravity flamethrower starts out with - client effects side +#define MAX_GRAV_FX FLAME_GRAV * MAX_GRAV +// gravity flamethrower maxes out at - client effects side +#define MIN_GRAV_FX FLAME_GRAV * MIN_GRAV +// time for flamethrower to be at its max - client effects side - milliseconds +#define ZEN_TIME_FX ZEN_TIME * 1000.0 +// time to move from min to max grav values - client effects side - milliseconds +#define GRAV_MOV_FX GRAV_MOV * 1000.0 +// total distance from min to max grav +#define TOTAL_DIST_FX ((float)MAX_GRAV_FX - (float)MIN_GRAV_FX) + + +/////////////////////////////////////////// +// SCREEN SHAKE DEFINES +/////////////////////////////////////////// + +#define SHAKE_LATERAL 1 +#define SHAKE_VERTICAL 2 +#define SHAKE_DEPTH 4 +#define SHAKE_ALL_DIR 7 + +/////////////////////////////////////////// +// DISTANCE DEFINES +/////////////////////////////////////////// + +#define FAR_CLIP_DIST "4096.0" +#define FAR_CLIP_DIST_VAL 4096.0 +#define NEAR_CLIP_DIST "64.0" +#define NEAR_CLIP_DIST_VAL 64.0 + +#define DETAIL_LOW 0 +#define DETAIL_NORMAL 1 +#define DETAIL_HIGH 2 +#define DETAIL_UBERHIGH 3 + +#define DETAIL_DEFAULT "2.0" + +#define VIOLENCE_NONE 0 +#define VIOLENCE_BLOOD 1 +#define VIOLENCE_NORMAL 2 +#define VIOLENCE_ULTRA 3 + +#define VIOLENCE_DEFAULT VIOLENCE_NORMAL +#define VIOLENCE_DEFAULT_STR "2" + +/////////////////////////////////////////// +// BREATH HOLDING DURATIONS (IN SECONDS) +/////////////////////////////////////////// +#define HOLD_BREATH_TIME 20.0 +#define M_HOLD_BREATH_TIME 12.0 + + +#endif // _G_PLAYSTATS_H_ diff --git a/Toolkit/Programming/GameCode/game/g_rope.c b/Toolkit/Programming/GameCode/game/g_rope.c new file mode 100644 index 0000000..3d3c0b3 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_rope.c @@ -0,0 +1,891 @@ +//g_rope.c +// +// In game, animating rope + +#include "g_local.h" +#include "vector.h" +#include "random.h" +#include "timing.h" // for time based sway +#include "p_main2.h" +#include "p_anims2.h" +#include "fx.h" +#include "p_anim_branch2.h" +#include "utilities.h" +#include "p_animactor.h" +#include "m_chicken_anim.h" +#include "cl_strings.h" + +#define CHICKEN_KNOCKBACK 1 + +#define ROPE_SEGMENT_LENGTH 16 +#define ROPE_MAX_SEGMENTS 256 + +#define ROPEFLAG_VINE 1 +#define ROPEFLAG_CHAIN 2 +#define ROPEFLAG_TENDRIL 4 +#define ROPEFLAG_HANGING_CHICKEN 8 + +//Correspondes with the model index on the client side DIRECTLY, ie DON'T CHANGE! +enum { + RM_ROPE = 0, + RM_CHAIN, + RM_VINE, + RM_TENDRIL +}; + +/*QUAKED obj_rope (.3 .2 .8) ? VINE CHAIN TENDRIL HANGING_CHICKEN + +A rope to climb or swing (default to rope model) + +Place the top of the entity at the top of the rope, and drag +the bottom of the box to the end of the rope + +THE ENTITY MUST HAVE AN ORIGIN BRUSH + +------------ FIELDS ------------- +ROPE (default) +VINE - use a vine model +CHAIN - use a chain model +TENDRIL - use a tendril model +------------- KEYS -------------- +----------------------------------- +*/ + +//============================================ + +//SIR NATE + +//============================================ + +#define NATE_HEALTH 10000 + +enum//instructions +{ + NATE_INSTRUCTION_SWIPE = 0, + NATE_INSTRUCTION_SPIN, + NATE_INSTRUCTION_JUMP_KICK, + NATE_INSTRUCTION_FIREBALL, + NUM_INSTRUCTIONS +}; + +enum//sayings +{ + NATE_SAYING_GREETING = 0, + NATE_SAYING_INTRO, + NATE_SAYING_FAILURE, + NATE_SAYING_SUCCESS, + NATE_SAYING_FINISHED, + NATE_SAYING_HITME_AGAIN1,//5 + NATE_SAYING_HITME_AGAIN2, + NATE_SAYING_HITME_AGAIN3, + NATE_SAYING_HITME_AGAIN4, + NATE_SAYING_HITME_AGAIN5, + NATE_SAYING_HITME_AGAIN6, + NATE_SAYING_HITME_AGAIN7, + NATE_SAYING_HITME_AGAIN8, + NATE_SAYING_HITME_AGAIN9, + NATE_SAYING_HITME_AGAIN10, + NATE_SAYING_END_LEVEL, + NUM_SAYINGS +}; + +qboolean UsedRightAttack(int instruction, edict_t *attacker, edict_t *projectile) +{ + int sequence; + + if (attacker->client) + { + if (attacker->client->playerinfo.upperseq == ASEQ_NONE) + sequence = attacker->client->playerinfo.lowerseq; + else + sequence = attacker->client->playerinfo.upperseq; + } + + switch(instruction) + { + case NATE_INSTRUCTION_SWIPE: + if(sequence == ASEQ_WSWORD_STD1|| + sequence == ASEQ_WSWORD_STD2|| + sequence == ASEQ_WSWORD_STEP2|| + sequence == ASEQ_WSWORD_STEP) + return (true); + break; + + case NATE_INSTRUCTION_SPIN: + if(sequence == ASEQ_WSWORD_SPIN || sequence == ASEQ_WSWORD_SPIN2) + return (true); + break; + + case NATE_INSTRUCTION_JUMP_KICK: + if(sequence == ASEQ_POLEVAULT2) + return (true); + break; + + case NATE_INSTRUCTION_FIREBALL: + if(!stricmp(projectile->classname, "Spell_FlyingFist")) + return (true); + break; + } + return (false); +} + +int sir_nate_of_the_embarassingly_shortshanks_pain (edict_t *self, edict_t *attacker, float kick, int damage) +{ + short msg; + + self->health = NATE_HEALTH; + + VectorClear(self->velocity); + + if(self->enemy->use)//still waiting to be triggered + return false; + + if(!attacker->client) + return false; + + if(self->count == NUM_INSTRUCTIONS) + { + gi.gamemsg_centerprintf(attacker, GM_SIR_NATE_END); + self->count++; + } + else if(self->count > NUM_INSTRUCTIONS) + { + msg = (short)(irand(NATE_SAYING_HITME_AGAIN1, NATE_SAYING_HITME_AGAIN10) - 5 + GM_SIR_NATE_HIT_AGAIN0); + gi.msgvar_centerprintf(attacker, msg, damage); + } + else if(UsedRightAttack(self->count, attacker, self->activator)) + { + if(self->damage_debounce_time>level.time) + return false; + + self->count++; + if(self->count == NUM_INSTRUCTIONS) + { + gi.gamemsg_centerprintf(attacker, GM_SIR_NATE_FINISH); + } + else + { + gi.msgdual_centerprintf(attacker, GM_SIR_NATE_SUCCESS, (short)(self->count + GM_SIR_NATE_INSTRUCTIONS0)); + self->damage_debounce_time = level.time + 1.0; + } + } + else + { + gi.msgdual_centerprintf(attacker, GM_SIR_NATE_FAILURE, (short)(self->count + GM_SIR_NATE_INSTRUCTIONS0)); + } + return false; +} + +void sir_nate_of_the_embarassingly_shortshanks_use(edict_t *self, edict_t *other, edict_t *activator) +{ + + if(!activator->client) + return; + + gi.gamemsg_centerprintf(activator, (short)(self->dmg_radius+GM_SIR_NATE_GREETING)); + + self->dmg_radius++; + + if(self->dmg_radius == 2)//last opening message + self->use = NULL; +} + +void rope_use (edict_t *self, edict_t *other, edict_t *activator) +{ + sir_nate_of_the_embarassingly_shortshanks_use(self, other, activator); +} + +void rope_think(edict_t *self) +{//FIXME!!!! Do a trace down rope to make sure the ropse does not clip through stuff! + trace_t trace; + vec3_t rope_top; + + if (!self->enemy) + return; + + //See if the player has chosen this rope as the one to grab + if (self->enemy->targetEnt == self) + { + //If he's already grabbed it... + if ( (self->enemy->client->playerinfo.flags & PLAYER_FLAG_ONROPE) && (!(self->enemy->client->playerinfo.flags & PLAYER_FLAG_RELEASEROPE)) ) + { + if (!self->count) + { + self->count = 1; + + VectorCopy(self->s.origin, rope_top); + rope_top[2] += self->maxs[2]; + + //Create the new rope that's attached to the player + self->rope_grab->s.effects |= EF_ALTCLIENTFX; + + gi.CreateEffect(&self->enemy->s, + FX_ROPE, CEF_BROADCAST | CEF_OWNERS_ORIGIN | CEF_FLAG6, + rope_top, + "ssbvvv", + self->rope_grab->s.number, //ID for the grab entity + self->rope_end->s.number, //ID for the end entity + self->bloodType, //Model type + rope_top, //Top of the rope + self->rope_grab->s.origin, //Grab's current origin (???) + self->rope_end->s.origin); //End's current origin (???) + } + + gi.trace(self->rope_grab->s.origin, vec3_origin, vec3_origin, self->s.origin, self->enemy, MASK_SOLID,&trace); + + if ( (trace.fraction == 1) && (!trace.startsolid && !trace.allsolid) ) + gi.trace(self->enemy->s.origin, self->enemy->mins, self->enemy->maxs, self->rope_grab->s.origin, self->enemy, MASK_PLAYERSOLID,&trace); + + //If the rope's movement is clear, move the player and the rope + if ( (trace.fraction == 1) && (!trace.startsolid && !trace.allsolid) ) + { + VectorCopy(self->rope_grab->s.origin, self->enemy->s.origin); + } + else + { + //Otherwise stop the player and the rope from entering a solid brush + VectorScale(self->rope_grab->velocity, -0.5, self->rope_grab->velocity); + VectorCopy(self->enemy->s.origin, self->rope_grab->s.origin); + } + } + else + { + self->count = 0; + self->rope_grab->s.effects &= ~EF_ALTCLIENTFX; + } + } + else + { + //This grabber is invalid, clear it + self->enemy = NULL; + } +} + +/*----------------------------------------------- + rope_end_think2 +-----------------------------------------------*/ + +void rope_end_think2( edict_t *self ) +{ + edict_t *grab = self->rope_end; + trace_t trace; + vec3_t rope_end, rope_top, end_rest, end_vel, end_vec, end_dest; + float grab_len, mag, end_len; + + vec3_t end_pos; + + VectorCopy(grab->velocity, end_pos); + mag = VectorNormalize(end_pos); + VectorMA(grab->s.origin, (mag*FRAMETIME), end_pos, end_pos); + + if(!CHICKEN_KNOCKBACK) + {//otherwise, done in hanging_chicken_think + gi.trace(grab->s.origin, self->targetEnt->mins, self->targetEnt->maxs, end_pos, self->targetEnt, MASK_MONSTERSOLID,&trace); + + if ((trace.fraction < 1 || trace.startsolid || trace.allsolid) && trace.ent != self) + { + if ( (trace.ent) && (stricmp(trace.ent->classname, "worldspawn")) ) + { + VectorScale(grab->velocity, -0.5, grab->velocity); + } + else + { + VectorScale(grab->velocity, -0.5, grab->velocity); + } + } + } + + //Setup the top of the rope entity (the rope's attach point) + VectorCopy(self->s.origin, rope_top); + + //Find the length of the end segment + grab_len = Q_fabs(self->maxs[2]+self->mins[2]); + + //Find the vector to the rope's point of rest + VectorCopy(rope_top, end_rest); + end_rest[2] -= grab_len; + + //Find the vector towards the middle, and that distance (disregarding height) + VectorSubtract(end_rest, grab->s.origin, end_vec); + VectorNormalize(end_vec); + end_len = vhlen(end_rest, grab->s.origin); + + //Subtract away from the rope's velocity based on that distance + VectorScale(end_vec, -end_len*0.75, end_vec); + VectorSubtract(grab->velocity, end_vec, grab->velocity); + VectorScale(grab->velocity, 0.99, grab->velocity); + + //Move the rope based on the new velocity + VectorCopy(grab->velocity, end_vel); + + mag = VectorNormalize(end_vel); + VectorMA(grab->s.origin, FRAMETIME * mag, end_vel, end_dest); + + //Find the angle between the top of the rope and the bottom + VectorSubtract(end_dest, rope_top, end_vel); + VectorNormalize(end_vel); + + //Move the length of the rope in that direction from the top + VectorMA(rope_top, grab_len, end_vel, rope_end); + + //You're done + VectorCopy(rope_end, grab->s.origin); + + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + rope_end_think +-----------------------------------------------*/ + +void rope_end_think( edict_t *self ) +{ + edict_t *grab = self->rope_end; + vec3_t rope_end, rope_top, end_rest, end_vel, end_vec, end_dest; + float grab_len, mag, end_len; + + //Setup the top of the rope entity (the rope's attach point) + VectorCopy(self->rope_grab->s.origin, rope_top); + + //Find the length of the end segment + grab_len = Q_fabs(self->maxs[2]+self->mins[2]) - self->rope_grab->viewheight; + + //Find the vector to the rope's point of rest + VectorCopy(rope_top, end_rest); + end_rest[2] -= grab_len; + + //Find the vector towards the middle, and that distance (disregarding height) + VectorSubtract(end_rest, grab->s.origin, end_vec); + VectorNormalize(end_vec); + end_len = vhlen(end_rest, grab->s.origin); + + //Subtract away from the rope's velocity based on that distance + VectorScale(end_vec, -end_len, end_vec); + VectorSubtract(grab->velocity, end_vec, grab->velocity); + VectorScale(grab->velocity, 0.95, grab->velocity); + + //Move the rope based on the new velocity + VectorCopy(grab->velocity, end_vel); + + mag = VectorNormalize(end_vel); + VectorMA(grab->s.origin, FRAMETIME * mag, end_vel, end_dest); + + //Find the angle between the top of the rope and the bottom + VectorSubtract(end_dest, rope_top, end_vel); + VectorNormalize(end_vel); + + //Move the length of the rope in that direction from the top + VectorMA(rope_top, grab_len, end_vel, rope_end); + + //You're done + VectorCopy(rope_end, grab->s.origin); +} + +/*----------------------------------------------- + rope_sway +-----------------------------------------------*/ + +void rope_sway(edict_t *self) +{ + //edict_t *end = self->slave; + edict_t *grab = self->rope_grab; + vec3_t rope_end, rope_top, grab_end; + vec3_t v_rope, v_grab, v_dest, rope_rest, v_dir; + float rope_len, grab_len, dist, mag; + + if ( ((Q_fabs(grab->velocity[0])) < 0.13) && ((Q_fabs(grab->velocity[1])) < 0.13) ) + { + //The rope isn't moving enough to run all the math, so just make it sway a little + VectorCopy(self->s.origin, rope_rest); + rope_rest[2] += self->mins[2]; + + rope_rest[0] += (sin((float) level.time * 2)) * 1.25; + rope_rest[1] += (cos((float) level.time * 2)) * 1.75; + + VectorCopy(rope_rest, self->pos1); + VectorCopy(rope_rest, self->slave->s.origin); + + VectorCopy(self->s.origin, rope_top); + rope_top[2] += self->maxs[2]; + + VectorSubtract(rope_rest, rope_top, v_rope); + VectorNormalize(v_rope); + VectorMA(rope_top, grab->viewheight, v_rope, grab_end); + + VectorCopy(grab_end, grab->s.origin); + + rope_think(self); + + self->think = rope_sway; + self->nextthink = level.time + FRAMETIME; + + return; + } + + //Setup the top of the rope entity (the rope's attach point) + VectorCopy(self->s.origin, rope_top); + rope_top[2] += self->maxs[2]; + + //Find the length of the grab + VectorSubtract(rope_top, grab->s.origin, v_grab); + grab_len = VectorLength(v_grab); + + //Find the vector to the rope's point of rest + VectorCopy(self->s.origin, rope_rest); + rope_rest[2] -= grab_len; + + //Find the length of the rope + VectorSubtract(rope_top, rope_rest, v_rope); + rope_len = VectorLength(v_rope); + + //Find the vector towards the middle, and that distance (disregarding height) + VectorSubtract(rope_rest, grab->s.origin, v_rope); + VectorNormalize(v_rope); + dist = vhlen(rope_rest, grab->s.origin); + + //NOTENOTE: There's a fine line between a real pendulum motion here that comes to rest, + // and a chaotic one that builds too much and runs amuck.. so don't monkey with + // the values in here... ok? --jweier + + //Subtract away from the rope's velocity based on that distance + VectorScale(v_rope, -dist, v_rope); + VectorSubtract(grab->velocity, v_rope, grab->velocity); + VectorScale(grab->velocity, 0.95, grab->velocity); + + //Move the rope based on the new velocity + VectorCopy(grab->velocity, v_dir); + + mag = VectorNormalize(v_dir); + VectorMA(grab->s.origin, FRAMETIME * mag, v_dir, v_dest); + + //Find the angle between the top of the rope and the bottom + VectorSubtract(v_dest, rope_top, v_rope); + VectorNormalize(v_rope); + + //Move the length of the rope in that direction from the top + VectorMA(rope_top, rope_len, v_rope, rope_end); + + VectorSubtract(v_dest, rope_top, v_rope); + VectorNormalize(v_rope); + VectorMA(rope_top, grab->viewheight, v_rope, grab_end); + + //You're done + VectorCopy(grab_end, grab->s.origin); + + //VectorCopy(rope_end, grab->s.origin); + VectorCopy(grab_end, self->pos1); + + //Make the end of the rope come to the end + rope_end_think(self); + + rope_think(self); + + self->think = rope_sway; + self->nextthink = level.time + FRAMETIME; +} + +void rope_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if ( !stricmp(other->classname, "player") ) + { + //If the player is already on a rope, forget him as a valid grabber + if ( (other->targetEnt) && (other->client->playerinfo.flags & PLAYER_FLAG_ONROPE) ) + return; + + //If we've got a player on the rope, and this guy isn't it, then don't let him grab + if (self->enemy && other != self->enemy) + return; + + self->enemy = other; + self->viewheight = other->s.origin[2]; + other->targetEnt = self; + } +} + +void grab_think(edict_t *self) +{ + +} + +void end_think(edict_t *self) +{ + +} + +int hanging_chicken_pain(edict_t *self, edict_t *other, float kick, int damage) +{ + self->health = 10000; + VectorCopy(self->targetEnt->s.origin, self->s.origin); + self->velocity[2] = 0; + + VectorCopy(self->velocity, self->targetEnt->velocity); + VectorClear(self->velocity); + VectorClear(self->knockbackvel); + + self->svflags &= ~SVF_ONFIRE; + + sir_nate_of_the_embarassingly_shortshanks_pain(self, other, kick, damage); + + if (damage < 100) + gi.CreateEffect(&self->s, FX_CHICKEN_EXPLODE, CEF_OWNERS_ORIGIN|CEF_FLAG6, NULL, "" ); + else + gi.CreateEffect(&self->s, FX_CHICKEN_EXPLODE, CEF_OWNERS_ORIGIN, NULL, "" ); + + if (irand(0,1)) + gi.sound (self, CHAN_AUTO, gi.soundindex("monsters/chicken/pain1.wav"), 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_AUTO, gi.soundindex("monsters/chicken/pain2.wav"), 1, ATTN_NORM, 0); + + return true; +} + +void hanging_chicken_think(edict_t *self) +{ + vec3_t vec, angles; + float d_ang, knockbacktime; + int i, mag; + qboolean knockback = true; + trace_t trace; + + VectorCopy(self->targetEnt->velocity, vec); + vec[2] = 0; + mag = VectorLength(vec); + + if (mag > 100) + { + self->dmg++; + self->dmg = self->dmg & ((FRAME_cluck18-FRAME_cluck14)-1); + self->s.frame = FRAME_cluck14 + self->dmg; + } + else + { + if (++self->dmg > (FRAME_wait6-FRAME_wait1)) + self->dmg = 0; + + self->s.frame = FRAME_wait1 + self->dmg; + } + + //knockback + if(CHICKEN_KNOCKBACK) + { + gi.trace(self->s.origin, self->mins, self->maxs, self->targetEnt->s.origin, self, self->clipmask,&trace); + if(trace.ent) + { + if(movable(trace.ent)) + { + vec3_t kvel; + float mass, force, upvel; + + VectorSubtract(self->targetEnt->s.origin, self->s.origin, vec); + + force = VectorNormalize(vec); + mass = VectorLength(trace.ent->size) * 3; + + force = 600.0 * force / mass; + + // Players are not as affected by velocities when they are on the ground, so increase what players experience. + if (trace.ent->client && trace.ent->groundentity) + force *= 4.0; + else if (trace.ent->client) // && !(targ->groundentity) + force *= 0.25; // Too much knockback + + if (force > 512) // Cap this speed so it doesn't get insane + force=512; + VectorScale (vec, force, kvel); + + if (trace.ent->client) // Don't force players up quite so much as monsters. + upvel=30; + else + upvel=120; + // Now if the player isn't being forced DOWN very far, let's force them UP a bit. + if ((vec[2] > -0.5 || trace.ent->groundentity) && kvel[2] < upvel && force > 30) + { // Don't knock UP the player more than we do across... + if (force < upvel) + kvel[2] = force; + else + kvel[2] = upvel; + } + + VectorAdd (trace.ent->velocity, kvel, trace.ent->velocity); + + if (trace.ent->client) // If player, then set the player flag that will affect this. + { + trace.ent->client->playerinfo.flags |= PLAYER_FLAG_USE_ENT_POS; + // The knockbacktime indicates how long this knockback affects the player. + if (force>200 && trace.ent->health>0 && trace.ent->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN && infront(trace.ent, self)) + { + if(self->evade_debounce_timeevade_debounce_time = level.time + 3.0; + } + PlayerAnimSetLowerSeq(&trace.ent->client->playerinfo,ASEQ_KNOCKDOWN); + PlayerAnimSetUpperSeq(&trace.ent->client->playerinfo,ASEQ_NONE); + TurnOffPlayerEffects(&trace.ent->client->playerinfo); + VectorMA (trace.ent->velocity, 3, kvel, trace.ent->velocity); + knockbacktime = level.time + 3.0; + } + else if(force > 500) + knockbacktime = level.time + 1.25; + else + knockbacktime = level.time + (force/400.0); + + if (knockbacktime > trace.ent->client->playerinfo.knockbacktime) + trace.ent->client->playerinfo.knockbacktime = knockbacktime; + } + + if(force>100) + { + VectorMA(trace.endpos, -force/5, vec, self->targetEnt->s.origin); + VectorScale(self->enemy->rope_end->velocity, -0.5 * force/400 , self->enemy->rope_end->velocity); + } + else + VectorScale(self->enemy->rope_end->velocity, -0.5, self->enemy->rope_end->velocity); + } + } + } + VectorCopy(self->targetEnt->s.origin, self->s.origin); + VectorSubtract(self->targetEnt->owner->s.origin, self->s.origin, vec); + VectorNormalize(vec); + vectoangles(vec, angles); + + //interpolate the angles + for (i=0;i<2;i++) + { + d_ang = (angles[i]-self->s.angles[i]); + + if (i==PITCH) + continue; + + if (d_ang == 0) + continue; + + if (d_ang > 0) + { + if (Q_fabs(d_ang) > 8) + self->s.angles[i] -= 8; + else + self->s.angles[i] = angles[i]; + } + else + { + if (Q_fabs(d_ang) > 8) + self->s.angles[i] += 8; + else + self->s.angles[i] = angles[i]; + } + } + + if (!irand(0,100)) + { + if (irand(0,1)) + gi.sound (self, CHAN_AUTO, gi.soundindex("monsters/chicken/cluck1.wav"), 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_AUTO, gi.soundindex("monsters/chicken/cluck2.wav"), 1, ATTN_NORM, 0); + } + + VectorClear(self->velocity); + + gi.linkentity(self); + self->nextthink = level.time + 0.1; +} + +void spawn_hanging_chicken(edict_t *self) +{ + edict_t *end_ent; + edict_t *chicken; + vec3_t rope_end; + short end_id; + byte model_type; + + gi.setmodel(self, self->model); + self->svflags |= SVF_NOCLIENT; + + //We only need the vertical size from the designer + self->maxs[0] = 32; + self->maxs[1] = 32; + + self->mins[0] = -32; + self->mins[1] = -32; + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_NOT; + + VectorClear(self->velocity); + + end_ent = G_Spawn(); + end_ent->movetype = PHYSICSTYPE_NONE; + end_ent->solid = SOLID_NOT; + end_ent->svflags |= SVF_ALWAYS_SEND; + end_ent->owner = self; + end_id = end_ent->s.number; + + VectorCopy(self->s.origin, end_ent->s.origin); + end_ent->s.origin[2] += self->mins[2]; + + VectorClear(end_ent->velocity); + + gi.linkentity(end_ent); + + //gi.setmodel(end_ent, "models/objects/barrel/normal/tris.fm"); + + self->rope_end = end_ent; + + VectorCopy(self->s.origin, rope_end); + rope_end[2] += self->mins[2]; + + model_type = RM_ROPE; + + self->bloodType = end_ent->bloodType = model_type; + + VectorCopy(self->s.origin, rope_end); + rope_end[2] += self->mins[2]; + + gi.CreatePersistantEffect(&self->s, FX_ROPE, CEF_BROADCAST, self->s.origin, "ssbvvv", end_id, end_id, model_type, end_ent->s.origin, end_ent->s.origin, end_ent->s.origin ); + + self->think = rope_end_think2; + self->nextthink = level.time + 0.1; + + gi.linkentity(self); + + ///////////////////////////////////////////// + //Now spawn the poor chicken + + chicken = G_Spawn(); + + gi.setmodel(chicken, "models/monsters/chicken2/tris.fm"); + chicken->enemy = self; + + //Hanging by feet + chicken->s.angles[PITCH] += 180; + chicken->pain = hanging_chicken_pain; + chicken->classID = 0; + chicken->client = NULL; + + chicken->health = 10000; + VectorSet(chicken->mins, -16, -16, -8); + VectorSet(chicken->maxs, 16, 16, 16); + + chicken->movetype = PHYSICSTYPE_STEP; + chicken->gravity = 0; + chicken->solid = SOLID_BBOX; + chicken->takedamage = DAMAGE_YES; + chicken->clipmask = MASK_MONSTERSOLID; + chicken->svflags = SVF_DO_NO_IMPACT_DMG | SVF_ALLOW_AUTO_TARGET; + chicken->s.effects = EF_CAMERA_NO_CLIP; + + VectorCopy(self->rope_end->s.origin, chicken->s.origin); + + chicken->targetEnt = self->rope_end; + + chicken->s.scale = 1; + chicken->classname = "NATE"; + chicken->think = hanging_chicken_think; + chicken->nextthink = level.time + 0.1; + chicken->materialtype = MAT_FLESH; + + self->targetEnt = chicken; + + gi.linkentity(chicken); +} + +void SP_obj_rope(edict_t *self) +{ + edict_t *grab_ent, *end_ent; + vec3_t rope_end; + short grab_id, end_id; + byte model_type; + + if (self->spawnflags & ROPEFLAG_HANGING_CHICKEN) + { + if(self->targetname) + self->use = rope_use; + else + gi.dprintf("Chicken on a Rope with no targetname...\n"); + spawn_hanging_chicken(self); + return; + } + + gi.setmodel(self, self->model); + self->svflags |= SVF_NOCLIENT; + + //We only need the vertical size from the designer + self->maxs[0] = 32; + self->maxs[1] = 32; + + self->mins[0] = -32; + self->mins[1] = -32; + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_TRIGGER; + self->touch = rope_touch; + + VectorClear(self->velocity); + + end_ent = G_Spawn(); + end_ent->movetype = PHYSICSTYPE_NONE; + end_ent->solid = SOLID_NOT; + end_ent->svflags |= SVF_ALWAYS_SEND; + end_id = end_ent->s.number; + + VectorCopy(self->s.origin, end_ent->s.origin); + end_ent->s.origin[2] += self->mins[2]; + + VectorClear(end_ent->velocity); + + gi.linkentity(end_ent); + + //gi.setmodel(end_ent, "models/objects/barrel/normal/tris.fm"); + + self->rope_end = end_ent; + + grab_ent = G_Spawn(); + grab_ent->movetype = PHYSICSTYPE_NONE; + grab_ent->solid = SOLID_NOT; + grab_ent->svflags |= SVF_ALWAYS_SEND; + grab_id = grab_ent->s.number; + VectorClear(grab_ent->velocity); + + gi.linkentity(grab_ent); + + //gi.setmodel(grab_ent, "models/objects/barrel/normal/tris.fm"); + + VectorCopy(self->s.origin, grab_ent->s.origin); + grab_ent->s.origin[2] += self->maxs[2] + 4; + + self->rope_grab = grab_ent; + + VectorCopy(self->s.origin, rope_end); + rope_end[2] += self->mins[2]; + + if (self->spawnflags & ROPEFLAG_CHAIN) + { + model_type = RM_CHAIN; + } + else if (self->spawnflags & ROPEFLAG_VINE) + { + model_type = RM_VINE; + } + else if (self->spawnflags & ROPEFLAG_TENDRIL) + { + model_type = RM_TENDRIL; + } + else + { + model_type = RM_ROPE; + } + + self->bloodType = grab_ent->bloodType = end_ent->bloodType = model_type; + + VectorCopy(self->s.origin, rope_end); + rope_end[2] += self->mins[2]; + + rope_sway(self); + + gi.CreatePersistantEffect(&self->s, FX_ROPE, CEF_BROADCAST, self->s.origin, "ssbvvv", grab_id, end_id, model_type, self->s.origin, grab_ent->s.origin, end_ent->s.origin ); + + self->think = rope_sway; + self->nextthink = level.time + 1; + + gi.linkentity(self); +} diff --git a/Toolkit/Programming/GameCode/game/g_save.c b/Toolkit/Programming/GameCode/game/g_save.c new file mode 100644 index 0000000..4436736 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_save.c @@ -0,0 +1,1115 @@ + +#include "g_local.h" +#include "g_Skeletons.h" +#include "ArrayedList.h" +#include "Message.h" +#include "q_ClientServer.h" +#include "q_Physics.h" +#include "g_playstats.h" +#include "utilities.h" +#include "p_anims2.h" +#include "FX.h" + +extern void InitPlayerinfo(edict_t *ent); +void LoadPersistantEffects(FILE *f); +void SavePersistantEffects(FILE *f); + + + +field_t fields[] = { + {"classname", FOFS(classname), F_LSTRING}, + {"origin", FOFS(s.origin), F_VECTOR}, + {"model", FOFS(model), F_LSTRING}, + {"spawnflags", FOFS(spawnflags), F_INT}, + {"speed", FOFS(speed), F_FLOAT}, + {"accel", FOFS(accel), F_FLOAT}, + {"decel", FOFS(decel), F_FLOAT}, + {"target", FOFS(target), F_LSTRING}, + {"targetname", FOFS(targetname), F_LSTRING}, + {"scripttarget", FOFS(scripttarget), F_LSTRING}, + {"pathtarget", FOFS(pathtarget), F_LSTRING}, + {"jumptarget", FOFS(jumptarget), F_LSTRING}, + {"deathtarget", FOFS(deathtarget), F_LSTRING}, + {"killtarget", FOFS(killtarget), F_LSTRING}, + {"combattarget", FOFS(combattarget), F_LSTRING}, + {"message", FOFS(message), F_LSTRING}, + {"text_msg", FOFS(text_msg), F_LSTRING}, + {"team", FOFS(team), F_LSTRING}, + {"wait", FOFS(wait), F_FLOAT}, + {"delay", FOFS(delay), F_FLOAT}, + {"time", FOFS(time), F_FLOAT}, + {"random", FOFS(random), F_FLOAT}, + {"style", FOFS(style), F_INT}, + {"count", FOFS(count), F_INT}, + {"health", FOFS(health), F_INT}, + {"skinnum", FOFS(s.skinnum), F_INT}, + {"sounds", FOFS(sounds), F_INT}, + {"light", 0, F_IGNORE}, + {"dmg", FOFS(dmg), F_INT}, + {"angles", FOFS(s.angles), F_VECTOR}, + {"angle", FOFS(s.angles), F_ANGLEHACK}, + {"mass", FOFS(mass), F_INT}, + {"volume", FOFS(volume), F_FLOAT}, + {"attenuation", FOFS(attenuation), F_FLOAT}, + {"map", FOFS(map), F_LSTRING}, + {"materialtype", FOFS(materialtype), F_INT}, + {"scale", FOFS(s.scale), F_FLOAT}, + {"color", FOFS(s.color), F_RGBA}, + {"absLight", FOFS(s.absLight), F_RGB}, + {"frame", FOFS(s.frame), F_INT}, + {"mintel", FOFS(mintel), F_INT}, + {"melee_range", FOFS(melee_range), F_FLOAT}, + {"missile_range", FOFS(missile_range), F_FLOAT}, + {"min_missile_range", FOFS(min_missile_range), F_FLOAT}, + {"bypass_missile_chance", FOFS(bypass_missile_chance), F_INT}, + {"jump_chance", FOFS(jump_chance), F_INT}, + {"wakeup_distance", FOFS(wakeup_distance), F_FLOAT}, + {"c_mode", FOFS(monsterinfo.c_mode), F_INT, F_INT}, + {"homebuoy", FOFS(homebuoy), F_LSTRING}, + {"wakeup_target", FOFS(wakeup_target), F_LSTRING}, + {"pain_target", FOFS(pain_target), F_LSTRING}, + + // temp spawn vars -- only valid when the spawn function is called + {"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP}, + {"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP}, + {"height", STOFS(height), F_INT, FFL_SPAWNTEMP}, + {"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP}, + {"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP}, + {"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP}, + {"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP}, + {"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP}, + {"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP}, + {"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP}, + {"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP}, + {"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP}, + {"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP}, + {"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP}, + {"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP}, + {"rotate", STOFS(rotate), F_INT, FFL_SPAWNTEMP}, + {"target2", FOFS(target2), F_LSTRING}, + {"pathtargetname", FOFS(pathtargetname), F_LSTRING}, + {"zangle", STOFS(zangle), F_FLOAT, FFL_SPAWNTEMP}, + {"file", STOFS(file), F_LSTRING, FFL_SPAWNTEMP}, + {"radius", STOFS(radius), F_INT, FFL_SPAWNTEMP}, + {"offensive", STOFS(offensive), F_INT, FFL_SPAWNTEMP}, + {"defensive", STOFS(defensive), F_INT, FFL_SPAWNTEMP}, + {"spawnflags2", STOFS(spawnflags2), F_INT, FFL_SPAWNTEMP}, + {"cooptimeout", STOFS(cooptimeout), F_INT, FFL_SPAWNTEMP}, + + {"script", STOFS(script), F_LSTRING, FFL_SPAWNTEMP}, + {"parm1", STOFS(parms[0]), F_LSTRING, FFL_SPAWNTEMP}, + {"parm2", STOFS(parms[1]), F_LSTRING, FFL_SPAWNTEMP}, + {"parm3", STOFS(parms[2]), F_LSTRING, FFL_SPAWNTEMP}, + {"parm4", STOFS(parms[3]), F_LSTRING, FFL_SPAWNTEMP}, + {"parm5", STOFS(parms[4]), F_LSTRING, FFL_SPAWNTEMP}, + {"parm6", STOFS(parms[5]), F_LSTRING, FFL_SPAWNTEMP}, + {"parm7", STOFS(parms[6]), F_LSTRING, FFL_SPAWNTEMP}, + {"parm8", STOFS(parms[7]), F_LSTRING, FFL_SPAWNTEMP}, + {"parm9", STOFS(parms[8]), F_LSTRING, FFL_SPAWNTEMP}, + {"parm10", STOFS(parms[9]), F_LSTRING, FFL_SPAWNTEMP}, + +}; + +// -------- just for savegames ---------- +// all pointer fields should be listed here, or savegames +// won't work properly (they will crash and burn). +// this wasn't just tacked on to the fields array, because +// these don't need names, we wouldn't want map fields using +// some of these, and if one were accidentally present twice +// it would double swizzle (fuck) the pointer. + +field_t savefields[] = +{ + {"", FOFS(classname), F_LSTRING}, + {"", FOFS(target), F_LSTRING}, + {"", FOFS(target2), F_LSTRING}, + {"", FOFS(targetname), F_LSTRING}, + {"", FOFS(scripttarget), F_LSTRING}, + {"", FOFS(killtarget), F_LSTRING}, + {"", FOFS(team), F_LSTRING}, + {"", FOFS(pathtarget), F_LSTRING}, + {"", FOFS(deathtarget), F_LSTRING}, + {"", FOFS(combattarget), F_LSTRING}, + {"", FOFS(model), F_LSTRING}, + {"", FOFS(map), F_LSTRING}, + {"", FOFS(message), F_LSTRING}, + {"", FOFS(client), F_CLIENT}, + {"", FOFS(item), F_ITEM}, + {"", FOFS(goalentity), F_EDICT}, + {"", FOFS(movetarget), F_EDICT}, + {"", FOFS(enemy), F_EDICT}, + {"", FOFS(oldenemy), F_EDICT}, + {"", FOFS(activator), F_EDICT}, +#ifdef G_TRANSITION + {"", FOFS(groundentity), F_EDICT}, +#endif + {"", FOFS(teamchain), F_EDICT}, + {"", FOFS(teammaster), F_EDICT}, + {"", FOFS(owner), F_EDICT}, + {"", FOFS(mynoise), F_EDICT}, + {"", FOFS(mynoise2), F_EDICT}, + {"", FOFS(target_ent), F_EDICT}, + {"", FOFS(chain), F_EDICT}, + {"", FOFS(blockingEntity), F_EDICT}, + {"", FOFS(last_buoyed_enemy), F_EDICT}, + {"", FOFS(placeholder), F_EDICT}, + {"", FOFS(fire_damage_enemy), F_EDICT}, + + {NULL, 0, F_INT} +}; + +field_t levelfields[] = +{ + {"", LLOFS(changemap), F_LSTRING}, + {"", LLOFS(sight_client), F_EDICT}, + {"", LLOFS(sight_entity), F_EDICT}, + {NULL, 0, F_INT} +}; + +field_t bouyfields[] = +{ + {"", BYOFS(pathtarget), F_LSTRING}, + {"", BYOFS(target), F_LSTRING}, + {"", BYOFS(targetname), F_LSTRING}, + {"", BYOFS(jump_target), F_LSTRING}, + {NULL, 0, F_INT} +}; + + +field_t clientfields[] = +{ + {"", CLOFS(playerinfo.pers.weapon), F_ITEM}, + {"", CLOFS(playerinfo.pers.lastweapon), F_ITEM}, + {"", CLOFS(playerinfo.pers.defence), F_ITEM}, + {"", CLOFS(playerinfo.pers.lastdefence), F_ITEM}, + {"", CLOFS(playerinfo.pers.newweapon), F_ITEM}, + + {NULL, 0, F_INT} +}; + +trig_message_t message_text[MAX_MESSAGESTRINGS]; +unsigned *messagebuf; + +int LoadTextFile(char *name, char **addr) +{ + int length; + char *buffer; + + length = gi.FS_LoadFile(name, &buffer); + if(length <= 0) + { + Sys_Error("Unable to load %s", name); + return(0); + } + *addr = (char *)gi.TagMalloc(length + 1, 0); + memcpy(*addr, buffer, length); + *(*addr + length) = 0; + gi.FS_FreeFile(buffer); + + return(length + 1); +} + +void Load_Strings(void) +{ + char *buffer; + int i,length; + char *p,*startp,*return_p; + + length = LoadTextFile ("levelmsg.txt", &buffer); + messagebuf = (unsigned *) buffer; + startp = buffer; + p =0; + for (i=1; p < (buffer + length) ;++i) + { + if (i> MAX_MESSAGESTRINGS) + { + Com_Printf ("Too many strings\n"); + return; + } + + // Read in string up to return + return_p = strchr(startp,13); // Search for return characters 13 10 + if (!return_p) // At end of file + { + break; + } + else + *return_p = 0; + + // Search string for # + p = strchr(startp,'#'); // Search for # which signifies a wav file + if ((p) && (p < return_p)) + { + *p = 0; + message_text[i].wav = ++p; // Save stuff after # + } + + // Save stuff before # + message_text[i].string = startp; + + do + { + p = strchr(startp,'@'); // Search for # which signifies a wav file + if (p) + *p = '\n'; + } while(p); + + return_p +=2; // Hop over 13 10 + startp = return_p; // Advance to next string + + } +} + +/* +============ +InitGame + +This will be called when the dll is first loaded, which +only happens when a new game is begun +============ +*/ +void InitGame (void) +{ + void G_InitResourceManagers(); + + gi.dprintf ("==== InitGame ====\n"); + + G_InitResourceManagers(); + + gun_x = gi.cvar ("gun_x", "0", 0); + gun_y = gi.cvar ("gun_y", "0", 0); + gun_z = gi.cvar ("gun_z", "0", 0); + + //FIXME: sv_ prefix is wrong for these. + + sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0); + sv_rollangle = gi.cvar ("sv_rollangle", "2", 0); + sv_maxvelocity = gi.cvar ("sv_maxvelocity", MAX_VELOCITY_STRING, 0); + + sv_gravity = gi.cvar ("sv_gravity", GRAVITY_STRING, 0); // GRAVITY FOR ALL GAMES + sv_friction = gi.cvar ("sv_friction", FRICTION_STRING, 0); // FRICTION FOR ALL GAMES + + // Noset vars. + + dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET); + + // Latched vars. + + sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH); + gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH); + gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH); + + maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); + deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH); + coop = gi.cvar ("coop", "0", CVAR_LATCH); + skill = gi.cvar ("skill", "1", CVAR_LATCH); + maxentities = gi.cvar ("maxentities", G_MAX_ENTITIES, CVAR_LATCH); + + sv_nomonsters = gi.cvar ("nomonsters", "0", CVAR_SERVERINFO|CVAR_LATCH); + sv_freezemonsters = gi.cvar ("freezemonsters", "0", 0); + + // Change anytime vars. + + dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO); + fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO); + timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO); + password = gi.cvar ("password", "", CVAR_USERINFO); + filterban = gi.cvar ("filterban", "1", 0); + + g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE); + + run_pitch = gi.cvar ("run_pitch", "0.002", 0); + run_roll = gi.cvar ("run_roll", "0.005", 0); + bob_up = gi.cvar ("bob_up", "0.005", 0); + bob_pitch = gi.cvar ("bob_pitch", "0.002", 0); + bob_roll = gi.cvar ("bob_roll", "0.002", 0); + + autorotate = gi.cvar("autorotate", "0", 0); + blood = gi.cvar("blood", "1", 0); + + checkanim = gi.cvar("checkanim", "0", 0); + + pvs_cull = gi.cvar("pvs_cull", "1", 0); + + showbuoys = gi.cvar("showbuoys", "0", 0); + showlitebuoys = gi.cvar("showlitebuoys", "0", 0); + mgai_debug = gi.cvar("mgai_debug", "0", 0); + deactivate_buoys = gi.cvar("deactivate_buoys", "0", 0); + anarchy = gi.cvar("anarchy", "0", 0); + impact_damage = gi.cvar("impact_damage", "1", 0); + cheating_monsters = gi.cvar("cheating_monsters", "1", 0); + singing_ogles = gi.cvar("singing_ogles", "0", 0); + + game_test = gi.cvar("game_test", "0", 0); + flood_msgs = gi.cvar ("flood_msgs", "4", 0); + flood_persecond = gi.cvar ("flood_persecond", "4", 0); + flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0); + flood_killdelay = gi.cvar ("flood_killdelay", "10", 0); + sv_maplist = gi.cvar ("sv_maplist", "", 0); + + player_dll = Cvar_Get("player_dll", DEFAULT_PLAYER_LIB, 0); + + sv_cinematicfreeze = gi.cvar("sv_cinematicfreeze", "0", 0); + sv_jumpcinematic = gi.cvar("sv_jumpcinematic", "0", 0); + + blood_level = gi.cvar ("blood_level", VIOLENCE_DEFAULT_STR, CVAR_ARCHIVE); + + P_Load(player_dll->string); + + // ******************************************************************************************** + // Initialise the inventory items. + // ******************************************************************************************** + + // Stuff shared between client and server. + + InitItems(); + + // Server side only elements. + + G_InitItems(); + + // ******************************************************************************************** + // Initialise hep messages. + // ******************************************************************************************** + + Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "No help message1"); + Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "No help message2"); + + // ******************************************************************************************** + // Initialize all entities for this game. + // ******************************************************************************************** + + game.maxentities = maxentities->value; + g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); + globals.edicts = g_edicts; + globals.max_edicts = game.maxentities; + + // ******************************************************************************************** + // Initialize all clients for this game. + // ******************************************************************************************** + + game.maxclients = maxclients->value; + game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); + globals.num_edicts = game.maxclients+1; + + level.cinActive = false; + + Load_Strings(); +} + +//========================================================= + +void WriteField1 (FILE *f, field_t *field, byte *base) +{ + void *p; + int len; + int index; + + p = (void *)(base + field->ofs); + switch (field->type) + { + case F_INT: + case F_FLOAT: + case F_ANGLEHACK: + case F_VECTOR: + case F_IGNORE: + break; + + case F_LSTRING: + case F_GSTRING: + if ( *(char **)p ) + len = strlen(*(char **)p) + 1; + else + len = 0; + *(int *)p = len; + break; + case F_EDICT: + if ( *(edict_t **)p == NULL) + index = -1; + else + index = *(edict_t **)p - g_edicts; + *(int *)p = index; + break; + case F_CLIENT: + if ( *(gclient_t **)p == NULL) + index = -1; + else + index = *(gclient_t **)p - game.clients; + *(int *)p = index; + break; + case F_ITEM: + if ( *(edict_t **)p == NULL) + index = -1; + else + index = *(gitem_t **)p - p_itemlist; + *(int *)p = index; + break; + + default: + gi.error ("WriteEdict: unknown field type"); + } +} + +void WriteField2 (FILE *f, field_t *field, byte *base) +{ + int len; + void *p; + + p = (void *)(base + field->ofs); + switch (field->type) + { + case F_LSTRING: + case F_GSTRING: + if ( *(char **)p ) + { + len = strlen(*(char **)p) + 1; + fwrite (*(char **)p, len, 1, f); + } + break; + } +} + +void ReadField (FILE *f, field_t *field, byte *base) +{ + void *p; + int len; + int index; + + p = (void *)(base + field->ofs); + switch (field->type) + { + case F_INT: + case F_FLOAT: + case F_ANGLEHACK: + case F_VECTOR: + case F_IGNORE: + break; + + case F_LSTRING: + len = *(int *)p; + if (!len) + *(char **)p = NULL; + else + { + *(char **)p = gi.TagMalloc (len, TAG_LEVEL); + fread (*(char **)p, len, 1, f); + } + break; + case F_GSTRING: + len = *(int *)p; + if (!len) + *(char **)p = NULL; + else + { + *(char **)p = gi.TagMalloc (len, TAG_GAME); + fread (*(char **)p, len, 1, f); + } + break; + case F_EDICT: + index = *(int *)p; + if ( index == -1 ) + *(edict_t **)p = NULL; + else + *(edict_t **)p = &g_edicts[index]; + break; + case F_CLIENT: + index = *(int *)p; + if ( index == -1 ) + *(gclient_t **)p = NULL; + else + *(gclient_t **)p = &game.clients[index]; + break; + case F_ITEM: + index = *(int *)p; + if ( index == -1 ) + *(gitem_t **)p = NULL; + else + *(gitem_t **)p = &p_itemlist[index]; + break; + + default: + gi.error ("ReadEdict: unknown field type"); + } +} + +//========================================================= + +/* +============== +WriteClient + +All pointer variables (except function pointers) must be handled specially. +============== +*/ +void WriteClient (FILE *f, gclient_t *client) +{ + field_t *field; + gclient_t temp; + + // all of the ints, floats, and vectors stay as they are + temp = *client; + + // change the pointers to lengths or indexes + for (field=clientfields ; field->name ; field++) + { + WriteField1 (f, field, (byte *)&temp); + } + + // write the block + fwrite (&temp, sizeof(temp), 1, f); + + // now write any allocated data following the edict + for (field=clientfields ; field->name ; field++) + { + WriteField2 (f, field, (byte *)client); + } +} + +/* +============== +ReadClient + +All pointer variables (except function pointers) must be handled specially. +============== +*/ +void ReadClient (FILE *f, gclient_t *client) +{ + field_t *field; + + fread (client, sizeof(*client), 1, f); + + for (field=clientfields ; field->name ; field++) + { + ReadField (f, field, (byte *)client); + } +} + +/* +============ +WriteGame + +This will be called whenever the game goes to a new level, +and when the user explicitly saves the game. + +Game information include cross level data, like multi level +triggers, help computer info, and all client states. + +A single player death will automatically restore from the +last save position. +============ +*/ +void WriteGame (char *filename, qboolean autosave) +{ + FILE *f; + int i; + char str[16]; + PerEffectsBuffer_t *peffect; + + SaveClientData (); + + f = fopen (filename, "wb"); + if (!f) + gi.error ("Couldn't open %s", filename); + + memset (str, 0, sizeof(str)); + strcpy (str, __DATE__); + fwrite (str, sizeof(str), 1, f); + + game.autosaved = autosave; + fwrite (&game, sizeof(game), 1, f); + game.autosaved = false; + + for (i=0 ; ifx_num == FX_PLAYER_PERSISTANT) + peffect->numEffects = 0; + } + + // save all the current persistant effects + fwrite (gi.Persistant_Effects_Array, (sizeof(PerEffectsBuffer_t) * MAX_PERSISTANT_EFFECTS), 1, f); + + fclose (f); + + // this is a bit bogus - search through the client effects and renable all FX_PLAYER_EFFECTS + peffect = (PerEffectsBuffer_t*) gi.Persistant_Effects_Array; + for (i=0; ifx_num == FX_PLAYER_PERSISTANT) + peffect->numEffects = 1; + } + + +} + +void ReadGame (char *filename) +{ + FILE *f; + int i; + char str[16]; + + + f = fopen (filename, "rb"); + if (!f) + gi.error ("Couldn't open %s", filename); + + fread (str, sizeof(str), 1, f); + if (strcmp (str, __DATE__)) + { + fclose (f); + gi.error ("Savegame from an older version.\n"); + return; + } + + gi.FreeTags (TAG_GAME); + + g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); + globals.edicts = g_edicts; + + fread (&game, sizeof(game), 1, f); + game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); + for (i=0 ; iname ; field++) + { + WriteField1 (f, field, (byte *)&temp); + } + + // write the block + fwrite (&temp, sizeof(temp), 1, f); + + // now write any allocated data following the edict + for (field=savefields ; field->name ; field++) + { + WriteField2 (f, field, (byte *)ent); + } + +} + +/* +============== +WriteLevelLocals + +All pointer variables (except function pointers) must be handled specially. +============== +*/ +void WriteLevelLocals (FILE *f) +{ + field_t *field; + level_locals_t temp; + cvar_t *r_farclipdist; + cvar_t *r_fog; + cvar_t *r_fog_density; + int i; + + // set up some console vars as level save variables + r_farclipdist = gi.cvar("r_farclipdist", FAR_CLIP_DIST, 0); + level.far_clip_dist_f = r_farclipdist->value; + r_fog = Cvar_Get ("r_fog", "0", 0); + level.fog = r_fog->value; + r_fog_density = Cvar_Get ("r_fog_density", "0", 0); + level.fog_density = r_fog_density->value; + + // all of the ints, floats, and vectors stay as they are + temp = level; + + // change the pointers to lengths or indexes + for (field=levelfields ; field->name ; field++) + { + WriteField1 (f, field, (byte *)&temp); + } + + for (i = 0; i< level.active_buoys; i++) + { + // change the pointers to lengths or indexes + for (field=bouyfields ; field->name ; field++) + { + WriteField1 (f, field, (byte *)&temp.buoy_list[i]); + } + } + + // write the block + fwrite (&temp, sizeof(temp), 1, f); + + // now write any allocated data following the edict + for (field=levelfields ; field->name ; field++) + { + WriteField2 (f, field, (byte *)&level); + } + + for (i = 0; i< level.active_buoys; i++) + { + // change the pointers to lengths or indexes + for (field=bouyfields ; field->name ; field++) + { + WriteField2 (f, field, (byte *)&level.buoy_list[i]); + } + } + +} + + +/* +============== +ReadEdict + +All pointer variables (except function pointers) must be handled specially. +============== +*/ +void ReadEdict (FILE *f, edict_t *ent) +{ + field_t *field; + SinglyLinkedList_t msgs; + char *temp; + void *s; + + if(ent->s.clientEffects.buf) + { + temp = ent->s.clientEffects.buf; // buffer needs to be stored to be cleared by the engine + } + else + { + temp = NULL; + } + + msgs = ent->msgQ.msgs; + + s=ent->Script; + fread (ent, sizeof(*ent), 1, f); + ent->Script=s; + + ent->s.clientEffects.buf = temp; + + ent->msgQ.msgs = msgs; + ent->last_alert = NULL; + +/* + // Only clients need skeletons - these are set up when all else is done. -MW. + + if(ent->s.skeletalType != SKEL_NULL) + { + CreateSkeleton(ent->s.skeletalType); + } +*/ + for (field=savefields ; field->name ; field++) + { + ReadField (f, field, (byte *)ent); + } +} + +/* +============== +ReadLevelLocals + +All pointer variables (except function pointers) must be handled specially. +============== +*/ +void ReadLevelLocals (FILE *f) +{ + field_t *field; + char temp[20]; + int i; + + fread (&level, sizeof(level), 1, f); + + for (field=levelfields ; field->name ; field++) + { + ReadField (f, field, (byte *)&level); + } + + for (i = 0; i< level.active_buoys; i++) + { + // change the pointers to lengths or indexes + for (field=bouyfields ; field->name ; field++) + { + ReadField (f, field, (byte *)&level.buoy_list[i]); + } + } + + + // set those console vars we should + sprintf(temp, "%f", level.far_clip_dist_f); + gi.cvar_set("r_farclipdist", temp); + sprintf(temp, "%f", level.fog); + gi.cvar_set("r_fog", temp); + sprintf(temp, "%f", level.fog_density); + gi.cvar_set("r_fog_density", temp); + + // these are pointers and should be reset. + level.alert_entity = NULL; + level.last_alert = NULL; + for (i=0; iinuse && !ent->client) + continue; + + fwrite (&i, sizeof(i), 1, f); + WriteEdict (f, ent); + } + i = -1; + fwrite (&i, sizeof(i), 1, f); + + SaveScripts(f, false); + + // this is a bit bogus - search through the client effects and kill all the FX_PLAYER_EFFECTS before saving, since they will be re-created + // upon players re-joining the game after a load anyway. + peffect = (PerEffectsBuffer_t*) gi.Persistant_Effects_Array; + for (i=0; ifx_num == FX_PLAYER_PERSISTANT) + peffect->numEffects = 0; + } + + // save all the current persistant effects + fwrite (gi.Persistant_Effects_Array, (sizeof(PerEffectsBuffer_t) * MAX_PERSISTANT_EFFECTS), 1, f); + + fclose (f); + + // this is a bit bogus - search through the client effects and renable all FX_PLAYER_EFFECTS + peffect = (PerEffectsBuffer_t*) gi.Persistant_Effects_Array; + for (i=0; ifx_num == FX_PLAYER_PERSISTANT) + peffect->numEffects = 1; + + } +} + + +/* +================= +ReadLevel + +SpawnEntities will allready have been called on the +level the same way it was when the level was saved. + +That is necessary to get the baselines +set up identically. + +The server will have cleared all of the world links before +calling ReadLevel. +================= +*/ +void ReadLevel (char *filename) +{ + void ClearMessageQueues(); + + int entnum; + FILE *f; + int i; + void *base; + edict_t *ent; + + f = fopen (filename, "rb"); + if (!f) + gi.error ("Couldn't open %s", filename); + +// ClearMessageQueues(); + + // Free any dynamic memory allocated by loading the level base state. + + gi.FreeTags (TAG_LEVEL); + + // Wipe all the entities. + + memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0])); + + globals.num_edicts = maxclients->value+1; + + // Check edict size. + + fread (&i, sizeof(i), 1, f); + if (i != sizeof(edict_t)) + { + fclose (f); + gi.error ("ReadLevel: mismatched edict size"); + } + + fread (&base, sizeof(base), 1, f); + if (base != (void *)InitGame) + { + fclose (f); + gi.error ("ReadLevel: function pointers have moved - file was saved on different version."); + } + + // Load the level locals. + + ReadLevelLocals (f); + + // Load all the entities. + + while (1) + { + if (fread (&entnum, sizeof(entnum), 1, f) != 1) + { + fclose (f); + gi.error ("ReadLevel: failed to read entnum"); + } + if (entnum == -1) + break; + if (entnum >= globals.num_edicts) + globals.num_edicts = entnum+1; + + ent = &g_edicts[entnum]; + ReadEdict (f, ent); +/* + // -MW WriteLevel no longer write out !inuse edicts. This fixes a coop re-spawn bug. + + // Because !inuse edicts get saved out. + + if(!ent->inuse) + continue; +*/ +/* + // Only clients need skeletons - these are set up when all else is done. -MW. + + if(ent->s.skeletalType != SKEL_NULL) + { + CreateSkeleton(ent->s.skeletalType); + } +*/ + // Let the server rebuild world links for this ent. + + ent->last_alert = NULL; + memset (&ent->area, 0, sizeof(ent->area)); + + // NOTE NOTE + // Missiles must be linked in specially. G_LinkMissile links as a SOLID_NOT, even though the entity is SOLID_BBOX + if (ent->movetype == MOVETYPE_FLYMISSILE && ent->solid == SOLID_BBOX) + { + G_LinkMissile (ent); + } + else + { + gi.linkentity (ent); + } + + // Force the monsters just loaded to point at the right anim. + + if((ent->classID > 0) && (!Cid_init[ent->classID]) && (ent->classID < NUM_CLASSIDS)) // Need to call once per level that item is on + { + classStaticsInits[ent->classID](); + Cid_init[ent->classID] = -1; + } + + if ( ((ent->classname) && (*ent->classname)) && strcmp(ent->classname, "player") && ent->classID && classStatics[ent->classID].resInfo && ent->curAnimID) + SetAnim(ent, ent->curAnimID); + } + + LoadScripts(f, false); + + // Load up all the persistant effects and fire them off. + + fread (gi.Persistant_Effects_Array, (sizeof(PerEffectsBuffer_t) * MAX_PERSISTANT_EFFECTS), 1, f); + gi.ClearPersistantEffects(); + + fclose (f); + + // Mark all clients as unconnected. + + for (i=0 ; ivalue ; i++) + { + ent = &g_edicts[i+1]; + ent->client = game.clients + i; + ent->client->playerinfo.pers.connected = false; + InitPlayerinfo(ent); + SetupPlayerinfo(ent); + PlayerBasicAnimReset(&ent->client->playerinfo); + } + + // Do any load time things at this point. + + for (i=0 ; iinuse) + continue; + + // Fire any cross-level triggers. + + if (ent->classname) + if (strcmp(ent->classname, "target_crosslevel_target") == 0) + ent->nextthink = level.time + ent->delay; + } +} diff --git a/Toolkit/Programming/GameCode/game/g_shrine.c b/Toolkit/Programming/GameCode/game/g_shrine.c new file mode 100644 index 0000000..a2c664a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_shrine.c @@ -0,0 +1,1909 @@ +// g_shrine.c +// +// Heretic II - Raven software +// + +#include "FX.h" +#include "g_local.h" +#include "g_itemstats.h" +#include "random.h" +#include "vector.h" +#include "p_actions2.h" +#include "p_anims2.h" +#include "p_main2.h" +#include "m_player.h" +#include "p_funcs.h" +#include "cl_strings.h" + +// Set up those shrines that are randomly selectable. + +char delay_text[] = "shrine respawn delay"; +char chaos_text[] = "chaos shrine touch"; +char health_text[] = "health shrine touch"; +char mana_text[] = "mana shrine touch"; +char light_text[] = "light shrine touch"; +char lungs_text[] = "lungs shrine touch"; +char run_text[] = "run shrine touch"; +char staff_text[] = "staff shrine touch"; +char powerup_text[] = "powerup shrine touch"; +char ghost_text[] = "ghost shrine touch"; +char reflect_text[] = "reflect shrine touch"; +char armor_gold_text[] = "armor gold shrine touch"; +char armor_silver_text[] = "armor silver shrine touch"; + +void player_shrine_health_effect(edict_t *self); +void player_shrine_armor_silver_effect(edict_t *self); +void player_shrine_armor_gold_effect(edict_t *self); +void player_shrine_lungs_effect(edict_t *self); +void player_shrine_light_effect(edict_t *self); +void player_shrine_staff_effect(edict_t *self); +void player_shrine_mana_effect(edict_t *self); +void player_shrine_ghost_effect(edict_t *self); +void player_shrine_reflect_effect(edict_t *self); +void player_shrine_powerup_effect(edict_t *self); +void player_shrine_speed_effect(edict_t *self); + +void shrine_armor_silver_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); +void shrine_armor_gold_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); +void shrine_random_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); + +extern gitem_armor_t silver_armor_info; +extern gitem_armor_t gold_armor_info; + +#define INVUN_TIME 2.0 + +// ************************************************************************************************ +// PlayerKillShrineFX +// ------------------ +// Remove all shrine effects associated with a player. Used when he's turned into a chicken. +// ************************************************************************************************ + +void PlayerKillShrineFX(edict_t *self) +{ + playerinfo_t *playerinfo; + + playerinfo=&self->client->playerinfo; + + assert(playerinfo); + + // --- Remove Reflection + + // Remove time on the timer for the reflectivity. + + self->client->playerinfo.reflect_timer = level.time - 1.0; + + // Turn off the relection at the client effect end through client flags that are passed down. + + self->s.renderfx &= ~RF_REFLECTION; + + // --- Remove Ghosting. + + // Remove time on the timer for the ghosting. + + self->client->playerinfo.ghost_timer = level.time - 1.0; + + // Turn off the ghosting at the client effect end through client flags that are passed down. + + self->s.renderfx &= ~RF_TRANS_GHOST; + + // --- Remove the light. + + // Remove time on the timer for the light. + + self->client->playerinfo.light_timer = level.time - 1.0; + + // Turn off the light at the client effect end through client flags that are passed down. + + self->s.effects &= ~EF_LIGHT_ENABLED; + + // Kill any lights that may already be out there for this player. + + gi.RemoveEffects(&self->s, FX_PLAYER_TORCH); + + // Kill lungs. + + self->client->playerinfo.lungs_timer = 0.0; + + // Remove Armor. + + self->client->playerinfo.armor_count = 0; + + // Turn off the armor at the model level. + + playerinfo->pers.armortype = ARMOR_NONE; + + SetupPlayerinfo_effects(self); + PlayerUpdateModelAttributes(&self->client->playerinfo); + WritePlayerinfo_effects(self); + + // Remove Staff powerup. + + self->client->playerinfo.pers.stafflevel = STAFF_LEVEL_BASIC; + + // Remove Weapons powerup. + + self->client->playerinfo.powerup_timer = level.time - 1.0; + + // Kill any tomes that may already be out there for this player. + + gi.RemoveEffects(&self->s, FX_TOME_OF_POWER); + + // Turn off the tome at the client effect end through client flags that are passed down. + + self->s.effects &= ~EF_POWERUP_ENABLED; +} + +// ************************************************************************************************ +// PlayerRestartShrineFX +// --------------------- +// This is the routine that re-starts any client effects that need to be running. For instance, +// recovery of a saved game, where for example, the torch is active. +// ************************************************************************************************ + +void PlayerRestartShrineFX(edict_t *self) +{ + // If we have a light, turn it on. + + if (self->s.effects & EF_LIGHT_ENABLED) + { + // Kill any lights that may already be out there for this player. + + gi.RemoveEffects(&self->s, FX_PLAYER_TORCH); + + // Create the light and the tome of power. + + gi.CreateEffect(&self->s, FX_PLAYER_TORCH, CEF_OWNERS_ORIGIN, NULL, ""); + } + + // If we have a powerup, turn it on. + + if (self->s.effects & EF_POWERUP_ENABLED) + { + // Kill any lights that may already be out there for this player. + + gi.RemoveEffects(&self->s, FX_TOME_OF_POWER); + + // Create the light and the tome of power. + + gi.CreateEffect(&self->s, FX_TOME_OF_POWER, CEF_OWNERS_ORIGIN, NULL, ""); + } +} + +// ************************************************************************************************ +// G_PlayerActionShrineEffect +// -------------------------- +// ************************************************************************************************ + +void G_PlayerActionShrineEffect(playerinfo_t *playerinfo) +{ + edict_t *self; + + self=(edict_t *)playerinfo->self; + + switch(self->shrine_type) + { + case SHRINE_ARMOR_SILVER: + player_shrine_armor_silver_effect(self); + break; + + case SHRINE_ARMOR_GOLD: + player_shrine_armor_gold_effect(self); + break; + + case SHRINE_LIGHT: + player_shrine_light_effect(self); + break; + + case SHRINE_HEAL: + player_shrine_health_effect(self); + break; + + case SHRINE_STAFF: + player_shrine_staff_effect(self); + break; + + case SHRINE_LUNGS: + player_shrine_lungs_effect(self); + break; + + case SHRINE_GHOST: + player_shrine_ghost_effect(self); + break; + + case SHRINE_REFLECT: + player_shrine_reflect_effect(self); + break; + + case SHRINE_POWERUP: + player_shrine_powerup_effect(self); + break; + + case SHRINE_MANA: + player_shrine_mana_effect(self); + break; + + case SHRINE_SPEED: + player_shrine_speed_effect(self); + break; + + default: + player_shrine_mana_effect(self); + break; + } +} + +// ************************************************************************************************ +// PlayerRandomShrineEffect +// ------------------------ +// Called from the random Shrine - which one do we want to do? +// ************************************************************************************************ + +void PlayerRandomShrineEffect(edict_t *self, int value) +{ + switch(value) + { + case SHRINE_ARMOR_SILVER: + player_shrine_armor_silver_effect(self); + break; + + case SHRINE_ARMOR_GOLD: + player_shrine_armor_gold_effect(self); + break; + + case SHRINE_LIGHT: + player_shrine_light_effect(self); + break; + + case SHRINE_HEAL: + player_shrine_health_effect(self); + break; + + case SHRINE_STAFF: + player_shrine_staff_effect(self); + break; + + case SHRINE_LUNGS: + player_shrine_lungs_effect(self); + break; + + case SHRINE_GHOST: + player_shrine_ghost_effect(self); + break; + + case SHRINE_REFLECT: + player_shrine_reflect_effect(self); + break; + + case SHRINE_POWERUP: + player_shrine_powerup_effect(self); + break; + + case SHRINE_MANA: + player_shrine_mana_effect(self); + break; + + case SHRINE_SPEED: + player_shrine_speed_effect(self); + break; + + default: + player_shrine_powerup_effect(self); + break; + } +} + +// ************************************************************************************************ +// DelayThink +// ---------- +// Wait till we can use this shrine again. +// ************************************************************************************************ + +void DelayThink(edict_t *self) +{ + edict_t *dest; + vec3_t offset; + vec3_t offset2; + + // Handle changing shrine types in deathmatch. + + if (deathmatch->value && (self->oldtouch == shrine_armor_gold_touch)) + { + // If we were gold in death match, we won't be again. + + self->owner->touch = shrine_armor_silver_touch; + } + else if (deathmatch->value && (self->oldtouch == shrine_armor_silver_touch) && !(irand(0,8))) + { + // 1 in 9 chance in death match an armor shrine turns gold. + + self->owner->touch = shrine_armor_gold_touch; + } + else + { + // Restore the touch pad. + + self->owner->touch = self->oldtouch; + } + + // Make the ball appear in the middle. + + // Setup in playerinfo the destination entity of the teleport. + + dest = G_Find (NULL, FOFS(targetname), self->owner->target); + + if (!dest) + { +#ifdef _DEVEL + gi.dprintf ("Shrine Trigger couldn't find shrine model\n"); +#endif + G_SetToFree (self); + return; + } + + if (self->touch == shrine_armor_gold_touch) + dest->style = 6; + else + if (self->touch == shrine_armor_silver_touch) + dest->style = 7; + + // Restore the skin type. + + dest->s.skinnum = self->owner->shrine_type +1; + + VectorScale(dest->s.angles, ANGLE_TO_RAD, offset); + DirFromAngles(offset, offset2); + dest->PersistantCFX=gi.CreatePersistantEffect(&dest->s, + FX_SHRINE_BALL, + CEF_BROADCAST, + dest->s.origin, + "db", + offset2, + (byte)(dest->style-1)); + + G_SetToFree (self); +} + +// ************************************************************************************************ +// deal_with_shrine_node +// --------------------- +// Either kill or set this shrine node to unuseable for a while. +// ************************************************************************************************ + +void deal_with_shrine_node(edict_t *self) +{ + edict_t *delay,*dest; + vec3_t offset,offset2; + int time; + float clients; + + // Set up a delay so we can't use this shrine for a while. + + if (deathmatch->value || (self->spawnflags & 1)) + { + delay = G_Spawn (); + delay->svflags |= SVF_NOCLIENT; + delay->movetype = PHYSICSTYPE_NONE; + delay->solid = SOLID_NOT; + delay->think = DelayThink; + delay->owner = self; + delay->classname = delay_text; + if (deathmatch->value) + // The equation for respawn: + // --The respawn times should be normal for 8 players. + // --For 32 players the respawn should be halved + // --For 2 players the respawn should be doubled. + { +/* + time = SHRINE_DELAY * sqrt((float)game.num_clients/8.0); // This makes it a nice curve. Clever, no? + // Lemme see here: sqrt(2/8) = sqrt(1/4) = 1/2 + // sqrt(8/8) = sqrt(1) = 1 + // sqrt(32/8) = sqrt(4) = 2 +*/ + clients=(float)game.num_clients; + if (clients<2.0) + clients=2.0; + time = SHRINE_DELAY * sqrt(2.0/clients); // Spawn more frequently when more players. + // Lemme see here: sqrt(2/2) = sqrt(1) = 1 + // sqrt(2/8) = sqrt(1/4) = 1/2 + // sqrt(2/32) = sqrt(1/16) = 1/4 + } + else + { + time = SHRINE_DELAY; + } + + // sanity check + if (time < 5) + time = 5; + + delay->nextthink = level.time + time; + delay->oldtouch = self->touch; + gi.linkentity (delay); + } + + // Turn off the touch for this shrine. + + self->touch = NULL; + + // Setup in playerinfo, the destination entity of the teleport. + + dest = G_Find (NULL, FOFS(targetname), self->target); + + if (!dest) + { +#ifdef _DEVEL + gi.dprintf ("Shrine Trigger couldn't find shrine model\n"); +#endif + return; + } + + // Make the skin solid rock. + + dest->s.skinnum = 0; + + // But kill the shrine ball thats out there for this shrine. + + gi.RemoveEffects(&dest->s, FX_SHRINE_BALL); + + // Kill the glowing ball in the middle. + + gi.RemovePersistantEffect(dest->PersistantCFX); + + // Make the shrine ball explode. + + VectorScale(dest->s.angles, ANGLE_TO_RAD, offset); + DirFromAngles(offset, offset2); + gi.CreateEffect(&dest->s,FX_SHRINE_BALL_EXPLODE,CEF_OWNERS_ORIGIN,dest->s.origin,"db",offset2,(byte)(dest->style-1)); +} + +void shrine_restore_player(edict_t *other) +{ + // Stop us from being on fire. + + if(other->fire_damage_time>level.time) + { + other->fire_damage_time = 0; + + // Turn off CFX too. + other->s.effects |= EF_MARCUS_FLAG1; + } + + // Stop bleeding. + + other->client->playerinfo.flags &= ~PLAYER_FLAG_BLEED; + + // Restore limbs! + // FIXME: maybe do some cool temp effect on these nodes to show they respawned? + + ResetPlayerBaseNodes(other); + + other->client->playerinfo.flags &= ~PLAYER_FLAG_NO_LARM; + other->client->playerinfo.flags &= ~PLAYER_FLAG_NO_RARM; +} + +// ************************************************************************************************ +// Health Shrine +// ************************************************************************************************ + +// Fire off the health shrine effect. + +void player_shrine_health_effect(edict_t *self) +{ + // Start up the shrine heal effect. + + gi.CreateEffect(&self->s, FX_SHRINE_HEALTH, CEF_OWNERS_ORIGIN, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine4.wav"),1,ATTN_NORM,0); +} + +void shrine_heal_core(edict_t *self,edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Give us some health. + + if (other->health < (SHRINE_MAX_HEALTH - SHRINE_HEALTH)) + other->health += SHRINE_HEALTH; + else if (other->health < SHRINE_MAX_HEALTH) + other->health = SHRINE_MAX_HEALTH; + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); +} + +// ************************************************************************************************ +// shrine_heal_touch +// ----------------- +// Fire off a heal effect and give us some health. +// ************************************************************************************************ + +void shrine_heal_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_heal_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_HEALTH); + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_health_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_HEAL; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo,ASEQ_SHRINE); + + // Make us invunerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_heal (.5 .3 .5) ? PERMANENT +*/ + +void shrine_heal(edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_HEAL; + ent->classname = health_text; + + if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_heal_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity(ent); +} + +// ************************************************************************************************ +// Silver armor shrine. +// ************************************************************************************************ + +// Fire off the armor shrine effect. + +void player_shrine_armor_silver_effect(edict_t *self) +{ + // Start up the shrine armor effect. + + gi.CreateEffect(&self->s, FX_SHRINE_ARMOR, CEF_OWNERS_ORIGIN, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine2.wav"),1,ATTN_NORM,0); +} + +void shrine_armor_silver_core(edict_t *self,edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add armor to player. + if ((other->client->playerinfo.pers.armortype == ARMOR_TYPE_GOLD) && + (other->client->playerinfo.armor_count >= gold_armor_info.max_armor / 2)) + other->client->playerinfo.armor_count = gold_armor_info.max_armor; + else + { + other->client->playerinfo.pers.armortype = ARMOR_TYPE_SILVER; + other->client->playerinfo.armor_count = silver_armor_info.max_armor; + } + + SetupPlayerinfo_effects(other); + PlayerUpdateModelAttributes(&other->client->playerinfo); + WritePlayerinfo_effects(other); + + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); +} + +// Fire off an effect and give us some armor. + +void shrine_armor_silver_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_armor_silver_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_SILVER); + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_armor_silver_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_ARMOR_SILVER; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invunerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_armor (.5 .3 .5) ? PERMANENT +*/ + +void shrine_armor (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_ARMOR_SILVER; + ent->classname = armor_silver_text; + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_armor_silver_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Armor shrine - gold. +// ************************************************************************************************ + +// Fire off the gold armor shrine effect. + +void player_shrine_armor_gold_effect(edict_t *self) +{ + // Start up the shrine armor effect. + + gi.CreateEffect(&self->s, FX_SHRINE_ARMOR, CEF_OWNERS_ORIGIN|CEF_FLAG6, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine2.wav"),1,ATTN_NORM,0); +} + +void shrine_armor_gold_core(edict_t *self,edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add gold armor to player. + + other->client->playerinfo.pers.armortype = ARMOR_TYPE_GOLD; + other->client->playerinfo.armor_count = gold_armor_info.max_armor; + + SetupPlayerinfo_effects(other); + PlayerUpdateModelAttributes(&other->client->playerinfo); + WritePlayerinfo_effects(other); + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); + +} + +// Fire off an effect and give us some armor. + +void shrine_armor_gold_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_armor_gold_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_GOLD); + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_armor_gold_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_ARMOR_GOLD; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invunerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_armor_gold (.5 .3 .5) ? PERMANENT +*/ + +void shrine_armor_gold (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_ARMOR_GOLD; + ent->classname = armor_gold_text; + + // No touch if flags say so. + + if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_armor_gold_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Staff powerup shrine. +// ************************************************************************************************ + +// Fire off the staff shrine effect. + +void player_shrine_staff_effect(edict_t *self) +{ + int flags = CEF_OWNERS_ORIGIN; + // Start up the shrine staff effect. + + if (self->client->playerinfo.pers.stafflevel == STAFF_LEVEL_POWER2) + { + flags |= CEF_FLAG6; + gi.sound(self,CHAN_ITEM,gi.soundindex("weapons/FirewallPowerCast.wav"),1,ATTN_NORM,0); + } + else + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine7.wav"),1,ATTN_NORM,0); + + gi.CreateEffect(&self->s, FX_SHRINE_STAFF, flags, NULL, ""); + + // Do the SHRINE sound. + +} + +void shrine_staff_core(edict_t *self,edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add onto his staff. + + if (other->client->playerinfo.pers.stafflevel < STAFF_LEVEL_MAX-1) + { + other->client->playerinfo.pers.stafflevel++; + + SetupPlayerinfo_effects(other); + PlayerUpdateModelAttributes(&other->client->playerinfo); + WritePlayerinfo_effects(other); + } + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); +} + +// Fire off an effect and give us a staff powerup. + +void shrine_staff_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_staff_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_BLADE); + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_staff_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_STAFF; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invunerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_staff (.5 .3 .5) ? PERMANENT +*/ + +void shrine_staff (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_STAFF; + ent->classname = staff_text; + + if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_staff_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Lungs Shrine +// ************************************************************************************************ + +// Fire off the lungs shrine effect. + +void player_shrine_lungs_effect(edict_t *self) +{ + // Start up the shrine lung effect. + + gi.CreateEffect(&self->s, FX_SHRINE_LUNGS, CEF_OWNERS_ORIGIN, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine9.wav"),1,ATTN_NORM,0); +} + +void shrine_lung_core(edict_t *self, edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add some time in on the timer for the lungs. + + other->client->playerinfo.lungs_timer = LUNGS_DURATION; + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); + +} + +// Fire off an effect and give us lung power. + +void shrine_lung_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_lung_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_LUNGS); + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_lungs_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_LUNGS; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invulnerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_lung (.5 .3 .5) ? PERMANENT +*/ +void shrine_lung (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_LUNGS; + ent->classname = lungs_text; + + if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_lung_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Light Shrine +// ************************************************************************************************ + +// Fire off the shrine light effect . + +void player_shrine_light_effect(edict_t *self) +{ + assert(self->client); + + // Kill any lights that may already be out there for this player. + + gi.RemoveEffects(&self->s, FX_PLAYER_TORCH); + + // Create the light and the tome of power. + + gi.CreateEffect(&self->s, FX_PLAYER_TORCH, CEF_OWNERS_ORIGIN, NULL, ""); + + // Start up the shrine light effect. + + gi.CreateEffect(&self->s, FX_SHRINE_LIGHT, CEF_OWNERS_ORIGIN, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine8.wav"),1,ATTN_NORM,0); + +} + +void shrine_light_core(edict_t *self, edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add some time in on the timer for the light. + + other->client->playerinfo.light_timer = level.time + LIGHT_DURATION; + + // Turn on the light. + + other->s.effects |= EF_LIGHT_ENABLED; + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); + +} + +// Fire off an effect and give us some light. + +void shrine_light_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_light_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_LIGHT); + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_light_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_LIGHT; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invunerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_light (.5 .3 .5) ? PERMANENT +*/ + +void shrine_light (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_LIGHT; + ent->classname = light_text; + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_light_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Mana Shrine +// ************************************************************************************************ + +// Fire off the shrine mana effect. + +void player_shrine_mana_effect(edict_t *self) +{ + // Start up the shrine mana effect. + + gi.CreateEffect(&self->s, FX_SHRINE_MANA, CEF_OWNERS_ORIGIN, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine1.wav"),1,ATTN_NORM,0); +} + +void shrine_mana_core(edict_t *self, edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add mana. + + other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(FindItem("Off-mana"))] = 100; + other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(FindItem("Def-mana"))] = 100; + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); + +} + +// We hit the mana shrine pad, give us some manna, do the animation. + +void shrine_mana_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_mana_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_MANA); + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_mana_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_MANA; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invunerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_mana (.5 .3 .5) ? PERMANENT +*/ + +void shrine_mana (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_MANA; + ent->classname = mana_text; + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_mana_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Ghost (invisibilty) shrine. +// ************************************************************************************************ + +// Fire off the ghost shrine effect. + +void player_shrine_ghost_effect(edict_t *self) +{ + assert(self->client); + + // Start up the shrine ghost effect. + + gi.CreateEffect(&self->s, FX_SHRINE_GHOST, CEF_OWNERS_ORIGIN, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine6.wav"),1,ATTN_NORM,0); +} + +void shrine_ghost_core(edict_t *self,edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add some time in on the timer for the ghost effect. + + other->client->playerinfo.ghost_timer = level.time + GHOST_DURATION; + + // Update the model attributes for ghosting. + + SetupPlayerinfo_effects(other); + PlayerUpdateModelAttributes(&other->client->playerinfo); + WritePlayerinfo_effects(other); + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); + +} + +// Fire off an effect and give us a ghosting for a while powerup. + +void shrine_ghost_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_ghost_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_GHOST); + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_ghost_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_GHOST; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invulnerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_ghost (.5 .3 .5) ? PERMANENT +*/ + +void shrine_ghost (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_GHOST; + ent->classname = ghost_text; + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_ghost_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Spell reflecting shrine. +// ************************************************************************************************ + +// Fire off the reflect shrine effect. + +void player_shrine_reflect_effect(edict_t *self) +{ + assert(self->client); + + // Start up the shrine staff effect. + + gi.CreateEffect(&self->s, FX_SHRINE_REFLECT, CEF_OWNERS_ORIGIN, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine3.wav"),1,ATTN_NORM,0); +} + +void shrine_reflect_core(edict_t *self,edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add some time in on the timer for the reflectivity. + + if (deathmatch->value) + other->client->playerinfo.reflect_timer = level.time + REFLECT_DURATION_DEATHMATCH; + else + other->client->playerinfo.reflect_timer = level.time + REFLECT_DURATION_SINGLE; + + // Update the model attributes for the reflection skin. + + SetupPlayerinfo_effects(other); + PlayerUpdateModelAttributes(&other->client->playerinfo); + WritePlayerinfo_effects(other); + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); + +} + +// Fire off an effect and give us a reflecting for a while powerup. + +void shrine_reflect_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_reflect_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_REFLECT); + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_reflect_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_REFLECT; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invunerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_reflect (.5 .3 .5) ? PERMANENT +*/ + +void shrine_reflect (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_REFLECT; + ent->classname = reflect_text; + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_reflect_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Spell powerup Shrine +// ************************************************************************************************ + +// Fire off the powerup shrine effect. + +void player_shrine_powerup_effect(edict_t *self) +{ + assert(self->client); + + // Kill any tomes that may already be out there for this player. + + gi.RemoveEffects(&self->s, FX_TOME_OF_POWER); + + // Create the tome of power. + + gi.CreateEffect(&self->s, FX_TOME_OF_POWER, CEF_OWNERS_ORIGIN, NULL, ""); + + // Start up the shrine powerup effect. + + gi.CreateEffect(&self->s, FX_SHRINE_POWERUP, CEF_OWNERS_ORIGIN, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine5.wav"),1,ATTN_NORM,0); +} + +// Fire off an effect and give us a powerup for a while. + +void shrine_powerup_core (edict_t *self, edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add some time in on the timer for the reflectivity. + + other->client->playerinfo.powerup_timer = level.time + POWERUP_DURATION; + + // Turn on the light at the client end through client flags that are passed to the client. + + other->s.effects |= EF_POWERUP_ENABLED; + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); + +} + +void shrine_powerup_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_powerup_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_POWERUP); + + // If we are in death match, don't make us go through the shrine anim, just/ start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_powerup_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_POWERUP; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invunerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_powerup (.5 .3 .5) ? PERMANENT +*/ + +void shrine_powerup (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_POWERUP; + ent->classname = powerup_text; + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_powerup_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Speed Shrine +// ************************************************************************************************ + +// Fire off the powerup shrine effect. + +void player_shrine_speed_effect(edict_t *self) +{ + assert(self->client); + + // Start up the shrine powerup effect. + + gi.CreateEffect(&self->s, FX_SHRINE_SPEED, CEF_OWNERS_ORIGIN, NULL, ""); + + // Do the SHRINE sound. + + gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine10.wav"),1,ATTN_NORM,0); +} + +// Fire off an effect and give us double speed for a while + +void shrine_speed_core (edict_t *self, edict_t *other) +{ + if (other->deadflag != DEAD_NO) + return; + + // If we are a chicken, lets make us a player again. Don't give him anything else. + if (other->flags & FL_CHICKEN) + { + other->morph_timer = level.time - 0.1; + return; + } + + // Add some time in on the timer for speeding + + other->client->playerinfo.speed_timer = level.time + SPEED_DURATION; + + // restore dismemberment, and stop us being on fire + shrine_restore_player(other); + +} + +void shrine_speed_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // If we aren't a player, forget it. + + if (!other->client) + return; + + shrine_speed_core(self,other); + + gi.gamemsg_centerprintf(other, GM_S_SPEED); + + // If we are in death match, don't make us go through the shrine anim, just/ start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + player_shrine_speed_effect(other); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = SHRINE_SPEED; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invunerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_speed (.5 .3 .5) ? PERMANENT +*/ +void shrine_speed (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_SPEED; + ent->classname = run_text; + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_speed_touch; + + if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE)) + { + ent->shrine_type = SHRINE_RANDOM; + ent->touch = shrine_random_touch; + } + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + +// ************************************************************************************************ +// Random shrine. +// ************************************************************************************************ + +#define POSSIBLE_RANDOM_SHRINES 9 + +int possible_shrines[POSSIBLE_RANDOM_SHRINES] = +{ + SHRINE_MANA, + SHRINE_STAFF, + SHRINE_ARMOR_SILVER, + SHRINE_ARMOR_GOLD, +}; + + +// Fire off an effect and give us a powerup for a while powerup. +void shrine_random_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + int random_shrine_num; + int total_rand_count = 0; + int possible_shrines[9]; + + // If we aren't a player, forget it! + + if (!other->client) + return; + + if(other->client->playerinfo.flags&PLAYER_FLAG_BLEED|| + other->client->playerinfo.flags&PLAYER_FLAG_NO_LARM|| + other->client->playerinfo.flags&PLAYER_FLAG_NO_RARM) + { + // Always heal if they're missing a limb or bleeding to death - should it give full health + // too though? + + random_shrine_num = SHRINE_HEAL; + } + else + { + + // here's where we make the shrines clever. If we already have a shrine option, lets remove it from + // the possible shrine list +// if (other->client->playerinfo.speed_timer < level.time) +// { +// possible_shrines[total_rand_count] = SHRINE_SPEED; +// total_rand_count++; +// } + if (other->health < SHRINE_MAX_HEALTH) + { + possible_shrines[total_rand_count] = SHRINE_HEAL; + total_rand_count++; + } + if (other->client->playerinfo.powerup_timer < level.time) + { + possible_shrines[total_rand_count] = SHRINE_POWERUP; + total_rand_count++; + } + if (other->client->playerinfo.ghost_timer < level.time) + { + possible_shrines[total_rand_count] = SHRINE_GHOST; + total_rand_count++; + } + if (other->client->playerinfo.reflect_timer < level.time) + { + possible_shrines[total_rand_count] = SHRINE_REFLECT; + total_rand_count++; + } + if ((other->client->playerinfo.pers.armortype != ARMOR_TYPE_GOLD) || + (!other->client->playerinfo.armor_count)) + { + possible_shrines[total_rand_count] = SHRINE_ARMOR_GOLD; + total_rand_count++; + } + if ((other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(FindItem("Off-mana"))] != 100) || + (other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(FindItem("Def-mana"))] != 100)) + { + possible_shrines[total_rand_count] = SHRINE_MANA; + total_rand_count++; + } + if (other->client->playerinfo.pers.stafflevel < STAFF_LEVEL_MAX-1) + { + possible_shrines[total_rand_count] = SHRINE_STAFF; + total_rand_count++; + } + if (((other->client->playerinfo.pers.armortype != ARMOR_TYPE_GOLD) && + (other->client->playerinfo.pers.armortype != ARMOR_TYPE_SILVER)) || + (!other->client->playerinfo.armor_count)) + { + possible_shrines[total_rand_count] = SHRINE_ARMOR_SILVER; + total_rand_count++; + } + + // if we have everything, give us a powerup. thats always helpful + if (!total_rand_count) + random_shrine_num = SHRINE_POWERUP; + else + random_shrine_num = possible_shrines[irand(0,total_rand_count)]; + } + + // Give us whatever we should have from this shrine. + + switch(random_shrine_num) + { + case SHRINE_HEAL: + + shrine_heal_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_HEALTH); + + break; + + case SHRINE_ARMOR_SILVER: + + shrine_armor_silver_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_SILVER); + + break; + + case SHRINE_ARMOR_GOLD: + + shrine_armor_gold_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_GOLD); + + break; + + case SHRINE_MANA: + + shrine_mana_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_MANA); + + break; + + case SHRINE_STAFF: + + shrine_staff_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_BLADE); + + break; + + case SHRINE_GHOST: + + shrine_ghost_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_GHOST); + + break; + + case SHRINE_REFLECT: + + shrine_reflect_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_REFLECT); + + break; + + case SHRINE_POWERUP: + + shrine_powerup_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_POWERUP); + + break; + + case SHRINE_SPEED: + + shrine_speed_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_SPEED); + + break; + + default: + + shrine_powerup_core(self,other); + gi.gamemsg_centerprintf(other, GM_CS_POWERUP); + + break; + } + + // If we are in death match, don't make us go through the shrine anim, just start the effect, + // give us whatever, and leave it at that. + + if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER)) + { + PlayerRandomShrineEffect(other, random_shrine_num); + } + else + { + // Tell us what sort of shrine we just hit. + + other->shrine_type = random_shrine_num; + + // Initialise the shrine animation. + + PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE); + + // Make us invulnerable for a couple of seconds. + + other->client->shrine_framenum = level.time + INVUN_TIME; + } + + // Decide whether to delete this shrine or disable it for a while. + + deal_with_shrine_node(self); +} + +/*QUAKED shrine_random (.5 .3 .5) ? PERMANENT +*/ + +void shrine_random(edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->svflags |= SVF_NOCLIENT; + ent->solid = SOLID_TRIGGER; + ent->shrine_type = SHRINE_RANDOM; + ent->classname = chaos_text; + + if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE))) + ent->touch = shrine_random_touch; + + gi.setmodel(ent, ent->model); + gi.linkentity (ent); +} + diff --git a/Toolkit/Programming/GameCode/game/g_skeleton.h b/Toolkit/Programming/GameCode/game/g_skeleton.h new file mode 100644 index 0000000..21c3fdc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_skeleton.h @@ -0,0 +1,11 @@ +#include "q_Typedef.h" + +typedef struct G_SkeletalJoint_s +{ + int children; // must be the first field + float destAngles[3]; + float angVels[3]; + float angles[3]; + int changed[3]; + qboolean inUse; +} G_SkeletalJoint_t; \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_spawn.c b/Toolkit/Programming/GameCode/game/g_spawn.c new file mode 100644 index 0000000..a7dbf53 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_spawn.c @@ -0,0 +1,770 @@ +#include "g_local.h" + +typedef struct +{ + char *name; + void (*spawn)(edict_t *ent); + int CID; +} spawn_t; + +void SP_info_player_start (edict_t *ent); +void SP_info_player_deathmatch (edict_t *ent); +void SP_info_player_coop (edict_t *ent); +void SP_info_player_intermission (edict_t *ent); +void SP_info_buoy (edict_t *ent); + +void SP_func_plat (edict_t *ent); +void SP_func_rotating (edict_t *ent); +void SP_func_button (edict_t *ent); +void SP_func_door (edict_t *ent); +void SP_func_door_secret (edict_t *ent); +void SP_func_door_rotating (edict_t *ent); +void SP_func_water (edict_t *ent); +void SP_func_train (edict_t *ent); +void SP_func_wall (edict_t *self); +void SP_func_object (edict_t *self); +void SP_func_timer (edict_t *self); +void SP_func_areaportal (edict_t *ent); +void SP_func_monsterspawner (edict_t *ent); + +void SP_trigger_Activate(edict_t *self); +void SP_trigger_Always (edict_t *ent); +void SP_trigger_Counter (edict_t *ent); +void SP_trigger_Damage(edict_t *self); +void SP_trigger_Deactivate(edict_t *self); +void SP_trigger_Elevator (edict_t *ent); +//void SP_trigger_flamethrower (edict_t *ent); +void SP_trigger_fogdensity(edict_t *self); +void SP_trigger_Gravity(edict_t *self); +void SP_trigger_mappercentage(edict_t *self); +void SP_trigger_quit_to_menu(edict_t *self); +void SP_trigger_mission_give(edict_t *self); +void SP_trigger_mission_take(edict_t *self); +void SP_trigger_MonsterJump(edict_t *self); +void SP_trigger_goto_buoy(edict_t *self); +void SP_trigger_Multiple (edict_t *ent); +void SP_trigger_Once (edict_t *ent); +void SP_trigger_PlayerPushButton (edict_t *ent); +void SP_trigger_PlayerPushLever (edict_t *ent); +void SP_trigger_PlayerUsePuzzle (edict_t *ent); +void SP_trigger_push(edict_t *self); +void SP_trigger_puzzle (edict_t *ent); +void SP_trigger_quake (edict_t *ent); +void SP_trigger_Relay (edict_t *ent); +void SP_trigger_lightning (edict_t *ent); +void SP_trigger_farclip (edict_t *ent); +void SP_trigger_endgame(edict_t *self); + + +void SP_choose_CDTrack(edict_t *self); + +void SP_target_explosion (edict_t *ent); +void SP_target_changelevel (edict_t *ent); +void SP_target_crosslevel_trigger (edict_t *ent); +void SP_target_crosslevel_target (edict_t *ent); +void SP_target_lightramp (edict_t *self); +void SP_target_earthquake (edict_t *ent); + +void SP_worldspawn (edict_t *ent); + +void SP_light (edict_t *self); +void SP_info_null (edict_t *self); +void SP_info_notnull (edict_t *self); +void SP_path_corner (edict_t *self); +void SP_point_combat (edict_t *self); + +void SP_misc_teleporter (edict_t *self); +void SP_misc_teleporter_dest (edict_t *self); +void misc_update_spawner (edict_t *self); +void SP_misc_remote_camera (edict_t *self); +void SP_misc_magic_portal (edict_t *self); +void SP_misc_fire_sparker (edict_t *ent); + +void SP_Monster_Gkrokon(edict_t *Self); +void SP_misc_flag (edict_t *ent); +void SP_monster_gorgon (edict_t *self); +void SP_monster_gorgon_leader (edict_t *self); +void SP_monster_rat (edict_t *self); +void SP_monster_rat_giant (edict_t *self); +void SP_monster_chicken (edict_t *self); +void SP_monster_plagueElf(edict_t *self); +void SP_monster_palace_plague_guard(edict_t *self); +void SP_monster_palace_plague_guard_invisible(edict_t *self); +void SP_monster_fish (edict_t *self); +void SP_monster_harpy (edict_t *self); +void SP_monster_spreader (edict_t *self); +void SP_monster_elflord (edict_t *self); +void SP_monster_plague_ssithra (edict_t *self); +void SP_monster_mssithra (edict_t *self); +void SP_monster_chkroktk (edict_t *self); +void SP_monster_tcheckrik_male (edict_t *self); +void SP_monster_tcheckrik_female (edict_t *self); +void SP_monster_tcheckrik_mothers (edict_t *self); +void SP_monster_high_priestess (edict_t *self); +void SP_monster_ogle (edict_t *self); +void SP_monster_seraph_overlord (edict_t *self); +void SP_monster_seraph_guard (edict_t *self); +void SP_monster_assassin (edict_t *self); +void SP_monster_morcalavin (edict_t *self); +void SP_monster_trial_beast (edict_t *self); +void SP_monster_imp (edict_t *self); +void SP_monster_bee (edict_t *self); + +void SP_character_corvus1 (edict_t *self); +void SP_character_corvus2 (edict_t *self); +void SP_character_corvus3 (edict_t *self); +void SP_character_corvus4 (edict_t *self); +void SP_character_corvus5 (edict_t *self); +void SP_character_corvus6 (edict_t *self); +void SP_character_corvus7 (edict_t *self); +void SP_character_corvus8 (edict_t *self); +void SP_character_corvus9 (edict_t *self); +void SP_character_dranor (edict_t *self); +void SP_character_elflord (edict_t *self); +void SP_character_highpriestess (edict_t *self); +void SP_character_highpriestess2 (edict_t *self); +void SP_character_morcalavin (edict_t *self); +void SP_character_sidhe_guard (edict_t *self); +void SP_character_siernan1 (edict_t *self); +void SP_character_siernan2 (edict_t *self); +void SP_character_ssithra_scout (edict_t *self); +void SP_character_ssithra_victim (edict_t *self); +void SP_character_tome (edict_t *self); + +void SP_breakable_brush (edict_t *ent); + +void SP_light_walltorch (edict_t *ent); +//void SP_light_flame (edict_t *ent); +void SP_light_floortorch (edict_t *ent); +void SP_light_torch1(edict_t *ent); +void SP_light_gem2(edict_t *ent); +void SP_light_chandelier1 (edict_t *ent); +void SP_light_chandelier2 (edict_t *ent); +void SP_light_chandelier3 (edict_t *ent); +void SP_light_lantern1 (edict_t *ent); +void SP_light_lantern2 (edict_t *ent); +void SP_light_lantern3 (edict_t *ent); +void SP_light_lantern4 (edict_t *ent); +void SP_light_lantern5 (edict_t *ent); +void SP_light_buglight (edict_t *ent); + +void SP_env_fire (edict_t *self); +void SP_env_dust (edict_t *self); +void SP_env_smoke (edict_t *self); +void SP_env_mist(edict_t *self); +void SP_env_bubbler(edict_t *self); +void SP_env_water_drip(edict_t *self); +void SP_env_water_fountain(edict_t *self); +void SP_env_waterfall_base(edict_t *self); +void SP_env_sun1(edict_t *ent); +void SP_env_muck(edict_t *ent); +//void SP_env_galaxy (edict_t *ent); + +void SP_sound_ambient_silverspring (edict_t *ent); +void SP_sound_ambient_swampcanyon (edict_t *ent); +void SP_sound_ambient_andoria (edict_t *ent); +void SP_sound_ambient_hive (edict_t *ent); +void SP_sound_ambient_mine (edict_t *ent); +void SP_sound_ambient_cloudfortress (edict_t *ent); + +// Object stuff +void SP_obj_andwallhanging(edict_t *ent); + +void SP_obj_banner(edict_t *ent); +void SP_obj_banneronpole(edict_t *ent); +void SP_obj_barrel(edict_t *ent); +void SP_obj_barrel_explosive(edict_t *ent); +void SP_obj_barrel_metal(edict_t *ent); +void SP_obj_basket(edict_t *ent); +void SP_obj_bench(edict_t *ent); +void SP_obj_bigcrystal(edict_t *self); +void SP_obj_biotank (edict_t *self); +void SP_obj_bloodsplat(edict_t *ent); +void SP_obj_bookclosed(edict_t *ent); +void SP_obj_bookopen(edict_t *ent); +void SP_obj_bottle1(edict_t *ent); +void SP_obj_broom (edict_t *ent); +void SP_obj_bucket (edict_t *ent); +void SP_obj_bush1 (edict_t *ent); +void SP_obj_bush2 (edict_t *ent); + +void SP_obj_cactus (edict_t *ent); +void SP_obj_cactus3 (edict_t *ent); +void SP_obj_cactus4 (edict_t *ent); +void SP_obj_cauldron(edict_t *ent); +void SP_obj_chair1(edict_t *ent); +void SP_obj_chair2(edict_t *ent); +void SP_obj_chair3(edict_t *ent); +void SP_obj_chest1(edict_t *ent); +void SP_obj_chest2(edict_t *ent); +void SP_obj_chest3(edict_t *ent); +void SP_obj_choppeddude(edict_t *ent); +void SP_obj_claybowl (edict_t *ent); +void SP_obj_clayjar (edict_t *ent); +void SP_obj_cocoon(edict_t *ent); +void SP_obj_cocoonopen(edict_t *ent); +void SP_obj_cog1(edict_t *ent); +void SP_obj_corpse1(edict_t *self); +void SP_obj_corpse2(edict_t *self); +void SP_obj_corpse_ogle(edict_t *self); +void SP_obj_corpse_ssithra(edict_t *self); + +void SP_obj_dying_elf(edict_t *self); + +void SP_obj_eggpan(edict_t *ent); +void SP_obj_eyeball_jar(edict_t *ent); + +void SP_obj_firepot(edict_t *ent); +void SP_obj_fishhead1(edict_t *ent); +void SP_obj_fishhead2(edict_t *ent); +void SP_obj_fishtrap (edict_t *ent); +void SP_obj_flagonpole (edict_t *ent); +void SP_obj_floor_candelabrum(edict_t *ent); +void SP_obj_fountain_fish(edict_t *ent); +void SP_obj_frypan(edict_t *ent); + +void SP_obj_gascan(edict_t *ent); +void SP_obj_gorgonbones(edict_t *ent); +void SP_obj_grass(edict_t *ent); + +void SP_obj_hangingdude(edict_t *ent); +void SP_obj_hanging_ogle(edict_t *ent); +void SP_obj_hivepriestessssymbol (edict_t *self); + +void SP_obj_jawbone(edict_t *ent); +void SP_obj_jug1(edict_t *ent); + +void SP_obj_kettle(edict_t *ent); + +void SP_obj_lab_parts_container(edict_t *ent); +void SP_obj_lab_tray(edict_t *ent); +void SP_obj_larva(edict_t *ent); +void SP_obj_larvabrokenegg(edict_t *ent); +void SP_obj_larvaegg(edict_t *ent); +void SP_obj_lever1 (edict_t *ent); +void SP_obj_lever2 (edict_t *ent); +void SP_obj_lever3 (edict_t *ent); + +void SP_obj_metalchunk1(edict_t *ent); +void SP_obj_metalchunk2(edict_t *ent); +void SP_obj_metalchunk3(edict_t *ent); +void SP_obj_minecart(edict_t *ent); +void SP_obj_minecart2(edict_t *ent); +void SP_obj_minecart3(edict_t *ent); +void SP_obj_moss1(edict_t *self); +void SP_obj_moss2(edict_t *self); +void SP_obj_moss3(edict_t *self); +void SP_obj_moss4(edict_t *self); +void SP_obj_moss5(edict_t *self); + +void SP_obj_nest(edict_t *self); + +void SP_obj_pick(edict_t *ent); +void SP_obj_pipe1(edict_t *ent); +void SP_obj_pipe2(edict_t *ent); +void SP_obj_pipewheel(edict_t *ent); +void SP_obj_plant1(edict_t *ent); +void SP_obj_plant2(edict_t *ent); +void SP_obj_plant3(edict_t *ent); +void SP_obj_pot1(edict_t *ent); +void SP_obj_pot2(edict_t *ent); +void SP_obj_pottedplant(edict_t *ent); +void SP_obj_pushcart(edict_t *ent); + +void SP_obj_queenchair(edict_t *ent); +void SP_obj_queenthrone(edict_t *ent); + +void SP_obj_ring_plaque2 (edict_t *ent); +void SP_obj_rocks1(edict_t *ent); +void SP_obj_rocks2(edict_t *ent); +void SP_obj_rope(edict_t *ent); +void SP_obj_ropechain (edict_t *ent); + +void SP_obj_scroll(edict_t *ent); +void SP_obj_seasonglobe(edict_t *ent); +void SP_obj_shovel(edict_t *ent); +void SP_obj_shrine(edict_t *ent); +void SP_obj_sign1(edict_t *ent); +void SP_obj_sign4(edict_t *ent); +void SP_obj_skullpole(edict_t *ent); +void SP_obj_spellbook(edict_t *ent); +void SP_obj_stalactite1(edict_t *ent); +void SP_obj_stalactite2(edict_t *ent); +void SP_obj_stalactite3(edict_t *ent); +void SP_obj_stalagmite1(edict_t *ent); +void SP_obj_stalagmite2(edict_t *ent); +void SP_obj_stalagmite3(edict_t *ent); +void SP_obj_statue_corvus (edict_t *ent); +void SP_obj_statue_boulderfish (edict_t *ent); +void SP_obj_statue_dolphin1(edict_t *ent); +void SP_obj_statue_dolphin2(edict_t *ent); +void SP_obj_statue_dolphin3(edict_t *ent); +void SP_obj_statue_dolphin4(edict_t *ent); +void SP_obj_statue_dragon (edict_t *ent); +void SP_obj_statue_dragonhead (edict_t *ent); +void SP_obj_statue_duckbill1(edict_t *ent); +void SP_obj_statue_duckbill2(edict_t *ent); +void SP_obj_statue_guardian(edict_t *ent); +void SP_obj_statue_saraphbust(edict_t *ent); +void SP_obj_statue_sariph(edict_t *ent); +void SP_obj_statue_sithraguard(edict_t *ent); +void SP_obj_statue_tchecktrik_bust (edict_t *self); +void SP_obj_statue_techeckrikleft (edict_t *self); +void SP_obj_statue_techeckrikright (edict_t *self); +void SP_obj_statue_techeckriktomb (edict_t *self); +void SP_obj_stein(edict_t *ent); +void SP_obj_swampflat_top(edict_t *ent); +void SP_obj_swampflat_bottom(edict_t *ent); + +void SP_obj_table1(edict_t *ent); +void SP_obj_table2(edict_t *ent); +void SP_obj_tapper(edict_t *ent); +void SP_obj_throne (edict_t *ent); +void SP_obj_torture_bed (edict_t *ent); +void SP_obj_torture_ironmaiden (edict_t *ent); +void SP_obj_torture_rack (edict_t *ent); +void SP_obj_torture_table (edict_t *ent); +void SP_obj_torture_wallring (edict_t *ent); +void SP_obj_tree(edict_t *ent); +void SP_obj_tree2(edict_t *ent); +void SP_obj_tree3(edict_t *ent); +void SP_obj_treefallen(edict_t *ent); +void SP_obj_treestump(edict_t *ent); +void SP_obj_treetall(edict_t *ent); +void SP_obj_treetop(edict_t *ent); + +void SP_obj_urn (edict_t *ent); + +void SP_obj_venusflytrap(edict_t *ent); + +void SP_obj_wallringplaque(edict_t *ent); +void SP_obj_web(edict_t *ent); +void SP_obj_wheelbarrow(edict_t *ent); +void SP_obj_wheelbarrowdamaged(edict_t *ent); +void SP_obj_woodpile(edict_t *ent); + +void SP_obj_morcalavin_barrier(edict_t *ent); + +void SP_flamethrower(edict_t *ent); + +void SP_item_spitter(edict_t *ent); + +// shrine stuff + +void shrine_heal (edict_t *ent); +void shrine_armor (edict_t *ent); +void shrine_armor_gold (edict_t *ent); +void shrine_staff (edict_t *ent); +void shrine_lung (edict_t *ent); +void shrine_light (edict_t *ent); +void shrine_mana (edict_t *ent); +void shrine_ghost (edict_t *ent); +void shrine_reflect (edict_t *ent); +void shrine_powerup (edict_t *ent); +void shrine_random (edict_t *ent); +void shrine_speed (edict_t *ent); + +void SP_script_runner (edict_t *ent); + +spawn_t spawns[]= +{ + // Quake2 specific spawns. + {"info_player_start", SP_info_player_start,-1}, + {"info_player_deathmatch", SP_info_player_deathmatch,-1}, + {"info_player_coop", SP_info_player_coop,-1}, + {"info_player_intermission", SP_info_player_intermission,-1}, + + {"func_plat", SP_func_plat,-1}, + {"func_button", SP_func_button,CID_BUTTON}, + {"func_door", SP_func_door,CID_FUNC_DOOR}, + {"func_door_secret", SP_func_door_secret,-1}, + {"func_door_rotating", SP_func_door_rotating,CID_FUNC_ROTATE}, + {"func_rotating", SP_func_rotating,CID_FUNC_ROTATE}, + {"func_train", SP_func_train,-1}, + {"func_water", SP_func_water,-1}, + {"func_areaportal", SP_func_areaportal,-1}, + {"func_monsterspawner", SP_func_monsterspawner,-1}, + {"func_wall", SP_func_wall,-1}, + {"func_object", SP_func_object,-1}, + {"func_timer", SP_func_timer,-1}, + + {"trigger_Activate", SP_trigger_Activate,CID_TRIGGER}, + {"trigger_always", SP_trigger_Always,CID_TRIGGER}, + {"trigger_Damage", SP_trigger_Damage,CID_TRIG_DAMAGE}, + {"trigger_Deactivate", SP_trigger_Deactivate,CID_TRIGGER}, + {"trigger_counter", SP_trigger_Counter,CID_TRIGGER}, + {"trigger_elevator", SP_trigger_Elevator,CID_TRIGGER}, +// {"trigger_flamethrower", SP_trigger_flamethrower,CID_TRIGGER}, + {"trigger_fogdensity", SP_trigger_fogdensity,CID_TRIGGER}, + {"trigger_Gravity", SP_trigger_Gravity,-1}, + {"trigger_lightning", SP_trigger_lightning,CID_TRIGGER}, + {"trigger_mappercentage", SP_trigger_mappercentage,CID_TRIGGER}, + {"trigger_quit_to_menu", SP_trigger_quit_to_menu,CID_TRIGGER}, + {"trigger_mission_give", SP_trigger_mission_give,CID_TRIGGER}, + {"trigger_mission_take", SP_trigger_mission_take,CID_TRIGGER}, + {"trigger_MonsterJump", SP_trigger_MonsterJump,-1}, + {"trigger_goto_buoy", SP_trigger_goto_buoy,-1}, + {"trigger_multiple", SP_trigger_Multiple,CID_TRIGGER}, + {"trigger_playerpushbutton", SP_trigger_PlayerPushButton,CID_TRIGGER}, + {"trigger_playerpushlever", SP_trigger_PlayerPushLever,CID_TRIGGER}, + {"trigger_playerusepuzzle", SP_trigger_PlayerUsePuzzle,CID_TRIGGER}, + {"trigger_push", SP_trigger_push,CID_TRIG_PUSH}, + {"trigger_puzzle", SP_trigger_puzzle,CID_TRIGGER}, + {"trigger_once", SP_trigger_Once,CID_TRIGGER}, + {"trigger_quake", SP_trigger_quake,CID_TRIGGER}, + {"trigger_relay", SP_trigger_Relay,CID_TRIGGER}, + {"trigger_farclip", SP_trigger_farclip,CID_TRIGGER}, + {"trigger_endgame", SP_trigger_endgame,CID_TRIGGER}, + + {"choose_CDTrack", SP_choose_CDTrack,-1}, + + {"target_explosion", SP_target_explosion,-1}, + {"target_changelevel", SP_target_changelevel,-1}, + {"target_crosslevel_trigger", SP_target_crosslevel_trigger,-1}, + {"target_crosslevel_target", SP_target_crosslevel_target,-1}, + //{"target_actor", SP_target_actor,-1}, + {"target_lightramp", SP_target_lightramp,-1}, + {"target_earthquake", SP_target_earthquake,-1}, + + {"worldspawn", SP_worldspawn,-1}, + + {"light", SP_light,-1}, + {"info_null", SP_info_null,-1}, + {"func_group", SP_info_null,-1}, + {"info_notnull", SP_info_notnull,-1}, + {"path_corner", SP_path_corner,-1}, + {"point_combat", SP_point_combat,-1}, + + //{"misc_actor", SP_misc_actor,-1}, + {"misc_teleporter", SP_misc_teleporter,CID_TELEPORTER}, + {"misc_teleporter_dest", SP_misc_teleporter_dest,-1}, + {"misc_update_spawner", misc_update_spawner, CID_TRIGGER}, + {"misc_remote_camera", SP_misc_remote_camera,-1}, + {"misc_magic_portal", SP_misc_magic_portal, -1}, + {"misc_fire_sparker", SP_misc_fire_sparker, -1}, + + {"misc_flag", SP_misc_flag,-1}, + + {"monster_gorgon",SP_monster_gorgon,CID_GORGON}, + {"monster_rat",SP_monster_rat,CID_RAT}, + {"monster_plagueElf", SP_monster_plagueElf,CID_PLAGUEELF}, + {"monster_fish", SP_monster_fish,CID_FISH}, + {"monster_harpy", SP_monster_harpy,CID_HARPY}, + {"monster_spreader", SP_monster_spreader,CID_SPREADER}, + {"monster_assassin",SP_monster_assassin,CID_ASSASSIN}, + {"monster_chicken",SP_monster_chicken,CID_CHICKEN}, + {"monster_tcheckrik_male",SP_monster_tcheckrik_male,CID_TCHECKRIK}, + {"monster_gkrokon", SP_Monster_Gkrokon,CID_GKROKON}, + +#if !DEMO_CODE + {"monster_gorgon_leader",SP_monster_gorgon_leader,CID_GORGON}, + {"monster_rat_giant",SP_monster_rat_giant,CID_RAT}, + {"monster_palace_plague_guard", SP_monster_palace_plague_guard,CID_PLAGUEELF}, + {"monster_palace_plague_guard_invisible", SP_monster_palace_plague_guard_invisible,CID_PLAGUEELF}, + {"monster_elflord", SP_monster_elflord,CID_ELFLORD}, + {"monster_ssithra",SP_monster_plague_ssithra,CID_SSITHRA}, + {"monster_mssithra",SP_monster_mssithra,CID_MSSITHRA}, + {"monster_chkroktk",SP_monster_chkroktk,CID_RAT}, + {"monster_tcheckrik_female",SP_monster_tcheckrik_female,CID_TCHECKRIK}, + {"monster_tcheckrik_mothers",SP_monster_tcheckrik_mothers,CID_MOTHER}, + {"monster_high_priestess",SP_monster_high_priestess,CID_HIGHPRIESTESS}, + {"monster_ogle",SP_monster_ogle,CID_OGLE}, + {"monster_seraph_overlord",SP_monster_seraph_overlord,CID_SERAPH_OVERLORD}, + {"monster_seraph_guard",SP_monster_seraph_guard,CID_SERAPH_GUARD}, + {"monster_bee",SP_monster_bee,CID_BEE}, + {"monster_morcalavin",SP_monster_morcalavin,CID_MORK}, + {"monster_trial_beast",SP_monster_trial_beast,CID_TBEAST}, + {"monster_imp", SP_monster_imp,CID_IMP}, +#endif + {"character_corvus1",SP_character_corvus1,CID_CORVUS}, + {"character_corvus2",SP_character_corvus2,CID_CORVUS2}, + {"character_corvus3",SP_character_corvus3,CID_CORVUS3}, + {"character_corvus4",SP_character_corvus4,CID_CORVUS4}, + {"character_corvus5",SP_character_corvus5,CID_CORVUS5}, + {"character_corvus6",SP_character_corvus6,CID_CORVUS6}, + {"character_corvus7",SP_character_corvus7,CID_CORVUS7}, + {"character_corvus8",SP_character_corvus8,CID_CORVUS8}, + {"character_corvus9",SP_character_corvus9,CID_CORVUS9}, + {"character_dranor",SP_character_dranor,CID_DRANOR}, + {"character_elflord",SP_character_elflord,CID_C_ELFLORD}, + {"character_highpriestess",SP_character_highpriestess,CID_C_HIGHPRIESTESS}, + {"character_highpriestess2",SP_character_highpriestess2,CID_C_HIGHPRIESTESS2}, + {"character_morcalavin",SP_character_morcalavin,CID_C_MORCALAVIN}, + {"character_sidhe_guard",SP_character_sidhe_guard,CID_PLAGUEELF}, + {"character_siernan1",SP_character_siernan1,CID_C_SIERNAN1}, + {"character_siernan2",SP_character_siernan2,CID_C_SIERNAN2}, + {"character_ssithra_scout",SP_character_ssithra_scout,CID_SSITHRA_SCOUT}, + {"character_ssithra_victim",SP_character_ssithra_victim,CID_SSITHRA_VICTIM}, + {"character_tome",SP_character_tome,CID_C_TOME}, + + // Heretic2 specific spawns. + + {"breakable_brush",SP_breakable_brush,CID_BBRUSH}, + + + {"light_walltorch",SP_light_walltorch,CID_LIGHT}, + {"light_floortorch",SP_light_floortorch,CID_LIGHT}, +// {"light_flame",SP_light_flame,CID_LIGHT}, + {"light_torch1",SP_light_torch1,CID_LIGHT}, + {"light_gem2",SP_light_gem2,CID_LIGHT}, + {"light_chandelier1",SP_light_chandelier1,CID_LIGHT}, + {"light_chandelier2",SP_light_chandelier2,CID_LIGHT}, + {"light_chandelier3",SP_light_chandelier3,CID_LIGHT}, + {"light_lantern1",SP_light_lantern1,CID_LIGHT}, + {"light_lantern2",SP_light_lantern2,CID_LIGHT}, + {"light_lantern3",SP_light_lantern3,CID_LIGHT}, + {"light_lantern4",SP_light_lantern4,CID_LIGHT}, + {"light_lantern5",SP_light_lantern5,CID_LIGHT}, + {"light_buglight",SP_light_buglight,CID_LIGHT}, + + {"env_fire",SP_env_fire,CID_OBJECT}, + {"env_dust",SP_env_dust,CID_OBJECT}, + {"env_smoke",SP_env_smoke,CID_OBJECT}, + {"env_mist",SP_env_mist,CID_OBJECT}, + {"env_bubbler",SP_env_bubbler,CID_OBJECT}, + {"env_water_drip",SP_env_water_drip,CID_OBJECT}, + {"env_water_fountain",SP_env_water_fountain,CID_OBJECT}, + {"env_waterfall_base",SP_env_waterfall_base,CID_OBJECT}, + {"env_sun1",SP_env_sun1,CID_OBJECT}, + {"env_muck",SP_env_muck,CID_OBJECT}, +// {"env_galaxy",SP_env_galaxy,CID_OBJECT}, + + {"sound_ambient_silverspring",SP_sound_ambient_silverspring,-1}, + {"sound_ambient_swampcanyon",SP_sound_ambient_swampcanyon,-1}, + {"sound_ambient_andoria",SP_sound_ambient_andoria,-1}, + {"sound_ambient_hive",SP_sound_ambient_hive,-1}, + {"sound_ambient_mine",SP_sound_ambient_mine,-1}, + {"sound_ambient_cloudfortress",SP_sound_ambient_cloudfortress,-1}, + + {"obj_andwallhanging",SP_obj_andwallhanging,CID_OBJECT}, + {"obj_banner",SP_obj_banner,CID_OBJECT}, + {"obj_banneronpole",SP_obj_banneronpole,CID_OBJECT}, + {"obj_barrel",SP_obj_barrel,CID_OBJECT}, + {"obj_barrel_explosive",SP_obj_barrel_explosive,CID_OBJECT}, + {"obj_barrel_metal",SP_obj_barrel_metal,CID_OBJECT}, + {"obj_basket",SP_obj_basket,CID_OBJECT}, + {"obj_bench",SP_obj_bench,CID_OBJECT}, + {"obj_bigcrystal",SP_obj_bigcrystal,CID_OBJECT}, + {"obj_biotank",SP_obj_biotank,CID_OBJECT}, + {"obj_bloodsplat",SP_obj_bloodsplat,CID_OBJECT}, + {"obj_bookclosed",SP_obj_bookclosed,CID_OBJECT}, + {"obj_bookopen",SP_obj_bookopen,CID_OBJECT}, + {"obj_bottle1",SP_obj_bottle1,CID_OBJECT}, + {"obj_broom",SP_obj_broom,CID_OBJECT}, + {"obj_bucket",SP_obj_bucket,CID_OBJECT}, + {"obj_bush1",SP_obj_bush1,CID_OBJECT}, + {"obj_bush2",SP_obj_bush2,CID_OBJECT}, + {"obj_cactus",SP_obj_cactus,CID_OBJECT}, + {"obj_cactus3",SP_obj_cactus3,CID_OBJECT}, + {"obj_cactus4",SP_obj_cactus4,CID_OBJECT}, + {"obj_cauldron",SP_obj_cauldron,CID_OBJECT}, + {"obj_chair1",SP_obj_chair1,CID_OBJECT}, + {"obj_chair2",SP_obj_chair2,CID_OBJECT}, + {"obj_chair3",SP_obj_chair3,CID_OBJECT}, + {"obj_chest1",SP_obj_chest1,CID_OBJECT}, + {"obj_chest2",SP_obj_chest2,CID_OBJECT}, + {"obj_chest3",SP_obj_chest3,CID_OBJECT}, + {"obj_choppeddude",SP_obj_choppeddude,CID_OBJECT}, + {"obj_claybowl",SP_obj_claybowl,CID_OBJECT}, + {"obj_clayjar",SP_obj_clayjar,CID_OBJECT}, + {"obj_cocoon",SP_obj_cocoon,CID_OBJECT}, + {"obj_cocoonopen",SP_obj_cocoonopen,CID_OBJECT}, + {"obj_cog1",SP_obj_cog1,CID_OBJECT}, + {"obj_corpse1",SP_obj_corpse1,CID_OBJECT}, + {"obj_corpse2",SP_obj_corpse2,CID_OBJECT}, + {"obj_corpse_ogle",SP_obj_corpse_ogle,CID_OBJECT}, + {"obj_corpse_ssithra",SP_obj_corpse_ssithra,CID_OBJECT}, + {"obj_dying_elf",SP_obj_dying_elf,CID_OBJECT}, + {"obj_eggpan",SP_obj_eggpan,CID_OBJECT}, + {"obj_eyeball_jar",SP_obj_eyeball_jar,CID_OBJECT}, + {"obj_firepot",SP_obj_firepot,CID_OBJECT}, + {"obj_fishhead1",SP_obj_fishhead1,CID_OBJECT}, + {"obj_fishhead2",SP_obj_fishhead2,CID_OBJECT}, + {"obj_fishtrap",SP_obj_fishtrap,CID_OBJECT}, + {"obj_flagonpole",SP_obj_flagonpole,CID_OBJECT}, + {"obj_floor_candelabrum",SP_obj_floor_candelabrum,CID_OBJECT}, + {"obj_fountain_fish",SP_obj_fountain_fish,CID_OBJECT}, + {"obj_frypan",SP_obj_frypan,CID_OBJECT}, + {"obj_gascan",SP_obj_gascan,CID_OBJECT}, + {"obj_gorgonbones",SP_obj_gorgonbones,CID_OBJECT}, + {"obj_grass",SP_obj_grass,CID_OBJECT}, + {"obj_hangingdude",SP_obj_hangingdude,CID_OBJECT}, + {"obj_hanging_ogle",SP_obj_hanging_ogle,CID_OBJECT}, + {"obj_hivepriestessssymbol",SP_obj_hivepriestessssymbol,CID_OBJECT}, + {"obj_jawbone",SP_obj_jawbone,CID_OBJECT}, + {"obj_jug1",SP_obj_jug1,CID_OBJECT}, + {"obj_kettle",SP_obj_kettle,CID_OBJECT}, + {"obj_lab_parts_container",SP_obj_lab_parts_container,CID_OBJECT}, + {"obj_lab_tray",SP_obj_lab_tray,CID_OBJECT}, + {"obj_larva",SP_obj_larva,CID_OBJECT}, + {"obj_larvabrokenegg",SP_obj_larvabrokenegg,CID_OBJECT}, + {"obj_larvaegg",SP_obj_larvaegg,CID_OBJECT}, + {"obj_lever1",SP_obj_lever1,CID_LEVER}, + {"obj_lever2",SP_obj_lever2,CID_LEVER}, + {"obj_lever3",SP_obj_lever3,CID_LEVER}, + {"obj_metalchunk1",SP_obj_metalchunk1,CID_OBJECT}, + {"obj_metalchunk2",SP_obj_metalchunk2,CID_OBJECT}, + {"obj_metalchunk3",SP_obj_metalchunk3,CID_OBJECT}, + {"obj_minecart",SP_obj_minecart,CID_OBJECT}, + {"obj_minecart2",SP_obj_minecart2,CID_OBJECT}, + {"obj_minecart3",SP_obj_minecart3,CID_OBJECT}, + {"obj_moss1",SP_obj_moss1,CID_OBJECT}, + {"obj_moss2",SP_obj_moss2,CID_OBJECT}, + {"obj_moss3",SP_obj_moss3,CID_OBJECT}, + {"obj_moss4",SP_obj_moss4,CID_OBJECT}, + {"obj_moss5",SP_obj_moss5,CID_OBJECT}, + {"obj_nest",SP_obj_nest,CID_OBJECT}, + {"obj_pick",SP_obj_pick,CID_OBJECT}, + {"obj_pipe1",SP_obj_pipe1,CID_OBJECT}, + {"obj_pipe2",SP_obj_pipe2,CID_OBJECT}, + {"obj_pipewheel",SP_obj_pipewheel,CID_OBJECT}, + {"obj_plant1",SP_obj_plant1,CID_OBJECT}, + {"obj_plant2",SP_obj_plant2,CID_OBJECT}, + {"obj_plant3",SP_obj_plant3,CID_OBJECT}, + {"obj_pot1",SP_obj_pot1,CID_OBJECT}, + {"obj_pot2",SP_obj_pot2,CID_OBJECT}, + {"obj_pottedplant",SP_obj_pottedplant,CID_OBJECT}, + {"obj_pushcart",SP_obj_pushcart,CID_OBJECT}, + {"obj_queenthrone",SP_obj_queenthrone,CID_OBJECT}, + {"obj_queenchair",SP_obj_queenchair,CID_OBJECT}, + {"obj_ring_plaque2",SP_obj_ring_plaque2,CID_OBJECT}, + {"obj_rocks1",SP_obj_rocks1,CID_OBJECT}, + {"obj_rocks2",SP_obj_rocks2,CID_OBJECT}, + {"obj_rope",SP_obj_rope,CID_OBJECT}, + {"obj_ropechain",SP_obj_ropechain,CID_OBJECT}, + {"obj_scroll",SP_obj_scroll,CID_OBJECT}, + {"obj_seasonglobe",SP_obj_seasonglobe,CID_OBJECT}, + {"obj_shovel",SP_obj_shovel,CID_OBJECT}, + {"obj_shrine",SP_obj_shrine,CID_OBJECT}, + {"obj_sign1",SP_obj_sign1,CID_OBJECT}, + {"obj_sign4",SP_obj_sign4,CID_OBJECT}, + {"obj_skullpole",SP_obj_skullpole,CID_OBJECT}, + {"obj_spellbook",SP_obj_spellbook,CID_OBJECT}, + {"obj_stalactite1",SP_obj_stalactite1,CID_OBJECT}, + {"obj_stalactite2",SP_obj_stalactite2,CID_OBJECT}, + {"obj_stalactite3",SP_obj_stalactite3,CID_OBJECT}, + {"obj_stalagmite1",SP_obj_stalagmite1,CID_OBJECT}, + {"obj_stalagmite2",SP_obj_stalagmite2,CID_OBJECT}, + {"obj_stalagmite3",SP_obj_stalagmite3,CID_OBJECT}, + {"obj_statue_boulderfish",SP_obj_statue_boulderfish,CID_OBJECT}, + {"obj_statue_corvus",SP_obj_statue_corvus,CID_OBJECT}, + {"obj_statue_dolphin1",SP_obj_statue_dolphin1,CID_OBJECT}, + {"obj_statue_dolphin2",SP_obj_statue_dolphin2,CID_OBJECT}, + {"obj_statue_dolphin3",SP_obj_statue_dolphin3,CID_OBJECT}, + {"obj_statue_dolphin4",SP_obj_statue_dolphin4,CID_OBJECT}, + {"obj_statue_dragon",SP_obj_statue_dragon,CID_OBJECT}, + {"obj_statue_dragonhead",SP_obj_statue_dragonhead,CID_OBJECT}, + {"obj_statue_duckbill1",SP_obj_statue_duckbill1,CID_OBJECT}, + {"obj_statue_duckbill2",SP_obj_statue_duckbill2,CID_OBJECT}, + {"obj_statue_guardian",SP_obj_statue_guardian,CID_OBJECT}, + {"obj_statue_saraphbust",SP_obj_statue_saraphbust,CID_OBJECT}, + {"obj_statue_sariph",SP_obj_statue_sariph,CID_OBJECT}, + {"obj_statue_sithraguard",SP_obj_statue_sithraguard,CID_OBJECT}, + {"obj_statue_tchecktrik_bust",SP_obj_statue_tchecktrik_bust,CID_OBJECT}, + {"obj_statue_techeckrikleft",SP_obj_statue_techeckrikleft,CID_OBJECT}, + {"obj_statue_techeckrikright",SP_obj_statue_techeckrikright,CID_OBJECT}, + {"obj_statue_techeckriktomb",SP_obj_statue_techeckriktomb,CID_OBJECT}, + {"obj_stein",SP_obj_stein,CID_OBJECT}, + {"obj_swampflat_top",SP_obj_swampflat_top,CID_OBJECT}, + {"obj_swampflat_bottom",SP_obj_swampflat_bottom,CID_OBJECT}, + {"obj_table1",SP_obj_table1,CID_OBJECT}, + {"obj_table2",SP_obj_table2,CID_OBJECT}, + {"obj_tapper",SP_obj_tapper,CID_OBJECT}, + {"obj_throne",SP_obj_throne,CID_OBJECT}, + {"obj_torture_bed",SP_obj_torture_bed,CID_OBJECT}, + {"obj_torture_ironmaiden",SP_obj_torture_ironmaiden,CID_OBJECT}, + {"obj_torture_rack",SP_obj_torture_rack,CID_OBJECT}, + {"obj_torture_table",SP_obj_torture_table,CID_OBJECT}, + {"obj_torture_wallring",SP_obj_torture_wallring,CID_OBJECT}, + {"obj_tree",SP_obj_tree,CID_OBJECT}, + {"obj_tree2",SP_obj_tree2,CID_OBJECT}, + {"obj_tree3",SP_obj_tree3,CID_OBJECT}, + {"obj_treefallen",SP_obj_treefallen,CID_OBJECT}, + {"obj_treestump",SP_obj_treestump,CID_OBJECT}, + {"obj_treetall",SP_obj_treetall,CID_OBJECT}, + {"obj_treetop",SP_obj_treetop,CID_OBJECT}, + {"obj_urn",SP_obj_urn,CID_OBJECT}, + {"obj_venusflytrap",SP_obj_venusflytrap,CID_OBJECT}, + {"obj_wallringplaque",SP_obj_wallringplaque,CID_OBJECT}, + {"obj_web",SP_obj_web,CID_OBJECT}, + {"obj_wheelbarrow",SP_obj_wheelbarrow,CID_OBJECT}, + {"obj_wheelbarrowdamaged",SP_obj_wheelbarrowdamaged,CID_OBJECT}, + {"obj_woodpile",SP_obj_woodpile,CID_OBJECT}, + + {"obj_morcalavin_barrier",SP_obj_morcalavin_barrier,CID_OBJECT}, + + {"flamethrower",SP_flamethrower,CID_FLAMETHROWER}, + + {"item_spitter", SP_item_spitter,-1}, + + {"info_buoy", SP_info_buoy,-1}, + + {"shrine_heal", shrine_heal, CID_TRIGGER}, + {"shrine_armor", shrine_armor, CID_TRIGGER}, + {"shrine_staff", shrine_staff, CID_TRIGGER}, + {"shrine_lung", shrine_lung, CID_TRIGGER}, + {"shrine_armor_gold", shrine_armor_gold, CID_TRIGGER}, + {"shrine_light", shrine_light, CID_TRIGGER}, + {"shrine_mana", shrine_mana, CID_TRIGGER}, + {"shrine_ghost", shrine_ghost, CID_TRIGGER}, + {"shrine_reflect", shrine_reflect, CID_TRIGGER}, + {"shrine_powerup", shrine_powerup, CID_TRIGGER}, + {"shrine_speed", shrine_speed, CID_TRIGGER}, + {"shrine_random", shrine_random, CID_TRIGGER}, + + {"script_runner", SP_script_runner, CID_TRIGGER}, + {NULL, NULL,-1} +}; + +/* +=============== +ED_CallSpawn + +Finds the spawn function for the entity and calls it +=============== +*/ +void ED_CallSpawn (edict_t *ent) +{ + extern qboolean loadingBaseEnts; + + spawn_t *s; + gitem_t *item; + + if (!ent->classname) + { + gi.dprintf ("ED_CallSpawn: NULL classname\n"); + return; + } + + if(item = IsItem(ent)) + { + SpawnItem(ent, item); + + return; + } + + // check normal spawn functions + for (s=spawns ; s->name ; s++) + { + if (!strcmp(s->name, ent->classname)) + { // found it + if((s->CID != -1) && !Cid_init[s->CID]) // Need to call once per level that item is on + { + classStaticsInits[s->CID](); + Cid_init[s->CID] = -1; + ent->classID = s->CID; // Make sure classID is set + } + + ent->classID = 0; + if(s->CID != -1) + { + ent->classID = s->CID; + } + s->spawn (ent); // Need to call for every item + return; + } + } + gi.dprintf ("%s doesn't have a spawn function\n", ent->classname); +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_spawnf.c b/Toolkit/Programming/GameCode/game/g_spawnf.c new file mode 100644 index 0000000..206df83 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_spawnf.c @@ -0,0 +1,558 @@ +#include "g_local.h" +#include "g_Skeletons.h" +#include "ArrayedList.h" +#include "PrimitiveDisplayHack.h" +#include "q_Physics.h" + +void ED_CallSpawn (edict_t *ent); +void Cvar_SetValue (char *var_name, float value); + +extern char *dm_statusbar; +extern char *single_statusbar; + +/* +============= +ED_NewString +============= +*/ +char *ED_NewString (char *string) +{ + char *newb, *new_p; + int i,l; + + l = strlen(string) + 1; + + newb = gi.TagMalloc (l, TAG_LEVEL); + + new_p = newb; + + for (i=0 ; i< l ; i++) + { + if (string[i] == '\\' && i < l-1) + { + i++; + if (string[i] == 'n') + *new_p++ = '\n'; + else + *new_p++ = '\\'; + } + else + *new_p++ = string[i]; + } + + return newb; +} + +/* +=============== +ED_ParseField + +Takes a key/value pair and sets the binary values +in an edict +=============== +*/ +void ED_ParseField (char *key, char *value, edict_t *ent) +{ + field_t *f; + byte *b; + float v; + vec3_t vec; + int color[4]; + + for (f=fields ; f->name ; f++) + { + if (!Q_stricmp(f->name, key)) + { // found it + if (f->flags & FFL_SPAWNTEMP) + b = (byte *)&st; + else + b = (byte *)ent; + + switch (f->type) + { + case F_LSTRING: + *(char **)(b+f->ofs) = ED_NewString (value); + break; + case F_VECTOR: + sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]); + ((float *)(b+f->ofs))[0] = vec[0]; + ((float *)(b+f->ofs))[1] = vec[1]; + ((float *)(b+f->ofs))[2] = vec[2]; + break; + case F_INT: + *(int *)(b+f->ofs) = atoi(value); + break; + case F_FLOAT: + *(float *)(b+f->ofs) = atof(value); + break; + case F_ANGLEHACK: + v = atof(value); + ((float *)(b+f->ofs))[0] = 0; + ((float *)(b+f->ofs))[1] = v; + ((float *)(b+f->ofs))[2] = 0; + break; + case F_IGNORE: + break; + case F_RGBA: + sscanf(value, "%i %i %i %i", color, color + 1, color + 2, color + 3); + ((byte *)(b+f->ofs))[0] = color[0]; + ((byte *)(b+f->ofs))[1] = color[1]; + ((byte *)(b+f->ofs))[2] = color[2]; + ((byte *)(b+f->ofs))[3] = color[3]; + break; + case F_RGB: + sscanf(value, "%i %i %i", color, color + 1, color + 2); + ((byte *)(b+f->ofs))[0] = color[0]; + ((byte *)(b+f->ofs))[1] = color[1]; + ((byte *)(b+f->ofs))[2] = color[2]; + break; + } + return; + } + } +#ifdef _DEVEL + gi.dprintf ("%s is not a field\n", key); +#endif +} + +/* +==================== +ED_ParseEdict + +Parses an edict out of the given string, returning the new position +ed should be a properly initialized empty edict. +==================== +*/ +char *ED_ParseEdict (char *data, edict_t *ent) +{ + qboolean init; + char keyname[256]; + char *com_token; + + init = false; + memset (&st, 0, sizeof(st)); + +// go through all the dictionary pairs + while (1) + { + // parse key + com_token = COM_Parse (&data); + if (com_token[0] == '}') + break; + if (!data) + gi.error ("ED_ParseEntity: EOF without closing brace"); + + strncpy (keyname, com_token, sizeof(keyname)-1); + + // parse value + com_token = COM_Parse (&data); + if (!data) + gi.error ("ED_ParseEntity: EOF without closing brace"); + + if (com_token[0] == '}') + gi.error ("ED_ParseEntity: closing brace without data"); + + init = true; + + // keynames with a leading underscore are used for utility comments, + // and are immediately discarded by quake + if (keyname[0] == '_') + continue; + + ED_ParseField (keyname, com_token, ent); + } + + if (!init) + memset (ent, 0, sizeof(*ent)); + + return data; +} + + +/* +================ +G_FindTeams + +Chain together all entities with a matching team field. + +All but the first will have the FL_TEAMSLAVE flag set. +All but the last will have the teamchain field set to the next one +================ +*/ +void G_FindTeams (void) +{ + edict_t *e, *e2, *chain; + int i, j; + int c, c2; + + c = 0; + c2 = 0; + for (i=1, e=g_edicts+i ; i < globals.num_edicts ; i++,e++) + { + if (!e->inuse) + continue; + if (!e->team) + continue; + if (e->flags & FL_TEAMSLAVE) + continue; + chain = e; + e->teammaster = e; + c++; + c2++; + for (j=i+1, e2=e+1 ; j < globals.num_edicts ; j++,e2++) + { + if (!e2->inuse) + continue; + if (!e2->team) + continue; + if (e2->flags & FL_TEAMSLAVE) + continue; + if (!strcmp(e->team, e2->team)) + { + c2++; + chain->teamchain = e2; + e2->teammaster = e; + chain = e2; + e2->flags |= FL_TEAMSLAVE; + } + } + } + +#ifdef _DEVEL + gi.dprintf ("%i teams with %i entities\n", c, c2); +#endif +} + +void ConstructEntities(void) +{ + edict_t *ent; + int i; + + // Create message queues for entites. + + for(i = 0, ent = g_edicts; i < maxentities->value ; i++, ent++) + { + SLList_DefaultCon(&ent->msgQ.msgs); + +#ifdef BBOX_DISPLAY_HACK + InitBBoxDisplayInfo(i, ent->mins, ent->maxs); +#endif + + ent->s.skeletalType = SKEL_NULL; + } + + // Allocate skeletons for clients only. + + for (i=0 ; is.skeletalType=SKEL_CORVUS; + ent->s.rootJoint = CreateSkeleton(ent->s.skeletalType); + } + + game.entitiesSpawned = true; +} + +void CheckCoopTimeout(qboolean BeenHereBefore) +{ + // Reset to zero cooptimeout if we've already been to the current level (no cinematic to see). + + if(BeenHereBefore) + Cvar_SetValue("sv_cooptimeout",0); +} + +/* +============== +SpawnEntities + +Creates a server's entity / program execution context by +parsing textual entity definitions out of an ent file. +============== +*/ +int loadingBaseEnts; + +void SpawnEntities (char *mapname, char *entities, char *spawnpoint, qboolean loadgame) +{ + edict_t *ent; + int inhibit; + char *com_token; + int i; + float skill_level; + + loadingBaseEnts = loadgame; + + skill_level = floor (skill->value); + if (skill_level < 0) + skill_level = 0; + if (skill_level > 3) + skill_level = 3; + if (skill->value != skill_level) + gi.cvar_forceset("skill", va("%f", skill_level)); + + SaveClientData (); + + ShutdownScripts(false); + gi.FreeTags (TAG_LEVEL); + + memset (&level, 0, sizeof(level)); + memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0])); + + memset(skeletalJoints, 0, sizeof(skeletalJoints)); + memset(jointNodes, 0, sizeof(jointNodes)); + memset(classStatics, 0, sizeof(classStatics)); + memset(Cid_init, 0, sizeof(Cid_init)); + + strncpy (level.mapname, mapname, sizeof(level.mapname)-1); + strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1); + + // Set client fields on player ents. + + for (i=0 ; ivalue) + { + if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH ) + { + G_FreeEdict (ent); + inhibit++; + continue; + } + } + else + { + if (((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || + ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || + ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || + (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) + ) + { + G_FreeEdict (ent); + inhibit++; + continue; + } + } + + // Check if it's a monster and if we're nomonster here... + if (sv_nomonsters && sv_nomonsters->value && strstr(ent->classname, "monster_")) + { +#ifdef _DEVEL + gi.dprintf("monster '%s' not spawned.\n", ent->classname); +#endif + G_FreeEdict (ent); + inhibit++; + continue; + } + + ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH); + } + + ED_CallSpawn (ent); + } + +#ifdef _DEVEL + gi.dprintf ("%i entities inhibited\n", inhibit); +#endif + G_FindTeams (); +} + +//=================================================================== + +/*QUAKED worldspawn (0 0 0) ? NOBODIES + +Only used for the world. + +NOBODIES - In DM, no bodies will be left behind by players- for maps with large amounts of visibility + +"sky" environment map name: + + andoria + desert + hive + sky1 - Night Sky + storm + swamp + town + +"skyaxis" vector axis for rotating sky +"skyrotate" speed of rotation in degrees/second +"sounds" music cd track number +"gravity" 800 is default gravity +"message" text to print at user logon +"skinnum" plague level for corvus: 0-2 +"cooptimeout" time to wait (in seconds) for all clients to have joined a map in coop (default is 0). + +"offensive" starting offensive weapons (flag bits): + + 1 - swordstaff + 2 - fireball + 4 - hellstaff + 8 - magic missile array + 16 - red-rain bow + 32 - sphere of annihlation + 64 - phoenix bow + 128 - mace balls + 256 - firewall + +"defensive" starting defensive weapons (flag bits): + + 1 - ring of repulsion + 2 - lightning shield + 4 - teleport + 8 - morph ovum + 16 - meteor barrier + +*/ + +void SP_worldspawn (edict_t *ent) +{ + ent->movetype = PHYSICSTYPE_PUSH; + ent->solid = SOLID_BSP; + ent->inuse = true; // since the world doesn't use G_Spawn() + ent->s.modelindex = 1; // world model is always index 1 + + //--------------- + + // Reserve some spots for dead player bodies. + + InitBodyQue (); + + if((ent->spawnflags & 1) && (deathmatch->value || coop->value)) + level.body_que = -1; + + // Set configstrings for items. + + SetItemNames (); + + if (st.nextmap) + strcpy (level.nextmap, st.nextmap); + + // Make some data visible to the server. + + if (ent->message && ent->message[0]) + { + gi.configstring (CS_LEVEL_NUMBER, ent->message ); + gi.configstring (CS_NAME, message_text[atoi(ent->message)].string); + strncpy (level.level_name, ent->message, sizeof(level.level_name)); + gi.dprintf("Unique Level Index : %d\n", atoi(ent->message)); + } + else + { + if(ent->text_msg) + gi.configstring (CS_NAME, ent->text_msg); + strncpy (level.level_name, level.mapname, sizeof(level.level_name)); + gi.dprintf("Warning : No Unique Level Index\n"); + } + + if (st.sky && st.sky[0]) + gi.configstring (CS_SKY, st.sky); + else + gi.configstring (CS_SKY, "desert"); + + gi.configstring (CS_SKYROTATE, va("%f", st.skyrotate) ); + + gi.configstring (CS_SKYAXIS, va("%f %f %f", + st.skyaxis[0], st.skyaxis[1], st.skyaxis[2]) ); + + gi.configstring (CS_CDTRACK, va("%i", ent->sounds) ); + + gi.configstring (CS_MAXCLIENTS, va("%i", (int)(maxclients->value) ) ); + + // Status bar program. + + if (deathmatch->value) + gi.configstring (CS_STATUSBAR, dm_statusbar); + else + gi.configstring (CS_STATUSBAR, single_statusbar); + + // Starting weapons for players entering a coop game. + + level.offensive_weapons=(!st.offensive)?0:st.offensive; + level.defensive_weapons=(!st.defensive)?0:st.defensive; + + // Save away cooptimeout so it is accessible to the server (SV_) functions. + + Cvar_SetValue("sv_cooptimeout",(!st.cooptimeout)?0:st.cooptimeout); + + //--------------- + + // GRAVITY for all games. + + if (!st.gravity) + gi.cvar_set("sv_gravity", "675"); + else + gi.cvar_set("sv_gravity", st.gravity); + + // FRICTION for all games. + + sv_friction = gi.cvar ("sv_friction", FRICTION_STRING, 0); + + // + // Setup light animation tables. 'a' is total darkness, 'z' is doublebright. + // + + // 0 normal + gi.configstring(CS_LIGHTS+0, "m"); + + // 1 FLICKER (first variety) + gi.configstring(CS_LIGHTS+1, "mmnmmommommnonmmonqnmmo"); + + // 2 SLOW STRONG PULSE + gi.configstring(CS_LIGHTS+2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); + + // 3 CANDLE (first variety) + gi.configstring(CS_LIGHTS+3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); + + // 4 FAST STROBE + gi.configstring(CS_LIGHTS+4, "mamamamamama"); + + // 5 GENTLE PULSE 1 + gi.configstring(CS_LIGHTS+5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj"); + + // 6 FLICKER (second variety) + gi.configstring(CS_LIGHTS+6, "nmonqnmomnmomomno"); + + // 7 CANDLE (second variety) + gi.configstring(CS_LIGHTS+7, "mmmaaaabcdefgmmmmaaaammmaamm"); + + // 8 CANDLE (third variety) + gi.configstring(CS_LIGHTS+8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); + + // 9 SLOW STROBE (fourth variety) + gi.configstring(CS_LIGHTS+9, "aaaaaaaazzzzzzzz"); + + // 10 FLUORESCENT FLICKER + gi.configstring(CS_LIGHTS+10, "mmamammmmammamamaaamammma"); + + // 11 SLOW PULSE NOT FADE TO BLACK + gi.configstring(CS_LIGHTS+11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); + + // styles 32-62 are assigned by the light program for switchable lights + + // 63 testing + gi.configstring(CS_LIGHTS+63, "a"); +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_surface.c b/Toolkit/Programming/GameCode/game/g_surface.c new file mode 100644 index 0000000..6097bca --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_surface.c @@ -0,0 +1,6 @@ +// +// g_surfacematerials.c +// +// Heretic II +// Copyright 1998 Raven Software +// \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_surface.h b/Toolkit/Programming/GameCode/game/g_surface.h new file mode 100644 index 0000000..6b6a3a4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_surface.h @@ -0,0 +1,6 @@ +// +// g_surfacematerials.h +// +// Heretic II +// Copyright 1998 Raven Software +// diff --git a/Toolkit/Programming/GameCode/game/g_svcmds.c b/Toolkit/Programming/GameCode/game/g_svcmds.c new file mode 100644 index 0000000..e16fc73 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_svcmds.c @@ -0,0 +1,281 @@ + +#include "g_local.h" + + +void Svcmd_Test_f (void) +{ + gi.cprintf (NULL, PRINT_HIGH, "Svcmd_Test_f()\n"); +} + +/* +============================================================================== + +PACKET FILTERING + + +You can add or remove addresses from the filter list with: + +addip +removeip + +The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with "addip 192.246.40". + +Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host. + +listip +Prints the current list of filters. + +writeip +Dumps "addip " commands to listip.cfg so it can be execed at a later date. The filter lists are not saved and restored by default, because I beleive it would cause too much confusion. + +filterban <0 or 1> + +If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting. + +If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network. + + +============================================================================== +*/ + +typedef struct +{ + unsigned mask; + unsigned compare; +} ipfilter_t; + +#define MAX_IPFILTERS 1024 + +ipfilter_t ipfilters[MAX_IPFILTERS]; +int numipfilters; + +/* +================= +StringToFilter +================= +*/ +static qboolean StringToFilter (char *s, ipfilter_t *f) +{ + char num[128]; + int i, j; + byte b[4]; + byte m[4]; + + for (i=0 ; i<4 ; i++) + { + b[i] = 0; + m[i] = 0; + } + + for (i=0 ; i<4 ; i++) + { + if (*s < '0' || *s > '9') + { + gi.cprintf(NULL, PRINT_HIGH, "Bad filter address: %s\n", s); + return false; + } + + j = 0; + while (*s >= '0' && *s <= '9') + { + num[j++] = *s++; + } + num[j] = 0; + b[i] = atoi(num); + if (b[i] != 0) + m[i] = 255; + + if (!*s) + break; + s++; + } + + f->mask = *(unsigned *)m; + f->compare = *(unsigned *)b; + + return true; +} + +/* +================= +SV_FilterPacket +================= +*/ +qboolean SV_FilterPacket (char *from) +{ + int i; + unsigned in; + byte m[4]; + char *p; + + i = 0; + p = from; + while (*p && i < 4) { + m[i] = 0; + while (*p >= '0' && *p <= '9') { + m[i] = m[i]*10 + (*p - '0'); + p++; + } + if (!*p || *p == ':') + break; + i++, p++; + } + + in = *(unsigned *)m; + + for (i=0 ; ivalue; + + return (int)!filterban->value; +} + + +/* +================= +SV_AddIP_f +================= +*/ +void SVCmd_AddIP_f (void) +{ + int i; + + if (gi.argc() < 3) { + gi.cprintf(NULL, PRINT_HIGH, "Usage: addip \n"); + return; + } + + for (i=0 ; i\n"); + return; + } + + if (!StringToFilter (gi.argv(2), &f)) + return; + + for (i=0 ; istring) + sprintf (name, "%s/listip.cfg", GAMEVERSION); + else + sprintf (name, "%s/listip.cfg", game->string); + + gi.cprintf (NULL, PRINT_HIGH, "Writing %s.\n", name); + + f = fopen (name, "wb"); + if (!f) + { + gi.cprintf (NULL, PRINT_HIGH, "Couldn't open %s\n", name); + return; + } + + fprintf(f, "set filterban %d\n", (int)filterban->value); + + for (i=0 ; istyle, 0, ent->s.origin, NULL); +} + +void SP_target_temp_entity (edict_t *ent) +{ + ent->use = Use_Target_Tent; +} + + +void target_explosion_explode (edict_t *self) +{ + float save; + + gi.CreateEffect(NULL, FX_EXPLOSION1, 0, self->s.origin, NULL); + + T_DamageRadius(self, self->activator, NULL, self->dmg+40, + self->dmg, self->dmg/4, DAMAGE_NORMAL,MOD_DIED); + + save = self->delay; + self->delay = 0; + G_UseTargets (self, self->activator); + self->delay = save; +} + +void use_target_explosion (edict_t *self, edict_t *other, edict_t *activator) +{ + self->activator = activator; + + if (!self->delay) + { + target_explosion_explode (self); + return; + } + + self->think = target_explosion_explode; + self->nextthink = level.time + self->delay; +} + +void SP_target_explosion (edict_t *ent) +{ + ent->use = use_target_explosion; + ent->svflags = SVF_NOCLIENT; +} + + +//========================================================== + +/*QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8) +Changes map player is on. + +map - the map to change to + 'newmap'$'target' + +newmap is the map the player is changing to +$ - has to be there +target is the targetname of the info_player_start to go to. + +If an info_player_start is not given a random one on the level is chosen + + +*/ +void use_target_changelevel (edict_t *self, edict_t *other, edict_t *activator) +{ + if (level.intermissiontime) + return; // allready activated + + if (!deathmatch->value && !coop->value) + { + if (g_edicts[1].health <= 0) + return; + } + + // if noexit, do a ton of damage to other + if (deathmatch->value && !( (int)dmflags->value & DF_ALLOW_EXIT) && other != world) + { + T_Damage (activator, self, self, vec3_origin, other->s.origin, vec3_origin, 10000, 10000, DAMAGE_AVOID_ARMOR,MOD_EXIT); + return; + } + + // if multiplayer, let everyone know who hit the exit + if (deathmatch->value) + { + if (activator && activator->client) + gi.Obituary (PRINT_HIGH, GM_EXIT, activator->s.number, 0); + } + + // if going to a new unit, clear cross triggers + if (strstr(self->map, "*")) + game.serverflags &= ~(SFL_CROSS_TRIGGER_MASK); + + gi.dprintf("***\n*** Unit complete. ***\n***\n"); + + BeginIntermission (self); +} + +void SP_target_changelevel (edict_t *ent) +{ + if (!ent->map) + { + gi.dprintf("target_changelevel with no map at %s\n", vtos(ent->s.origin)); + G_FreeEdict (ent); + return; + } + ent->use = use_target_changelevel; + ent->svflags = SVF_NOCLIENT; +} + + +//========================================================== + +/*QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8) +Creates a particle splash effect when used. + +Set "sounds" to one of the following: + 1) sparks + 2) blue water + 3) brown water + 4) slime + 5) lava + 6) blood + +"count" how many pixels in the splash +"dmg" if set, does a radius damage at this location when it splashes + useful for lava/sparks +*/ + +void use_target_splash (edict_t *self, edict_t *other, edict_t *activator) +{ + gi.CreateEffect(NULL, FX_SPLASH, 0, self->s.origin, "b", self->count); + + if (self->dmg) + T_DamageRadius(self, activator, NULL, self->dmg+40, + self->dmg, self->dmg/4, DAMAGE_NORMAL,MOD_DIED); +} + +void SP_target_splash (edict_t *self) +{ + self->use = use_target_splash; + G_SetMovedir (self->s.angles, self->movedir); + + if (!self->count) + self->count = 32; + + self->svflags = SVF_NOCLIENT; +} + + +//========================================================== + +/*QUAK-ED target_spawner (1 0 0) (-8 -8 -8) (8 8 8) +Set target to the type of entity you want spawned. +Useful for spawning monsters and gibs in the factory levels. + +For monsters: + Set direction to the facing you want it to have. + +For gibs: + Set direction if you want it moving and + speed how fast it should be moving otherwise it + will just be dropped +*/ +void ED_CallSpawn (edict_t *ent); +/* +void use_target_spawner (edict_t *self, edict_t *other, edict_t *activator) +{ + edict_t *ent; + + ent = G_Spawn(); + ent->classname = self->target; + VectorCopy (self->s.origin, ent->s.origin); + VectorCopy (self->s.angles, ent->s.angles); + ED_CallSpawn (ent); + gi.unlinkentity (ent); + KillBox (ent); + gi.linkentity (ent); + if (self->speed) + VectorCopy (self->movedir, ent->velocity); +} +*/ +/* +void SP_target_spawner (edict_t *self) +{ + self->use = use_target_spawner; + self->svflags = SVF_NOCLIENT; + if (self->speed) + { + G_SetMovedir (self->s.angles, self->movedir); + VectorScale (self->movedir, self->speed, self->movedir); + } +} +*/ +//========================================================== + +/*QUAK-ED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS +Fires a blaster bolt in the set direction when triggered. + +dmg default is 15 +speed default is 1000 +*/ +/* +void use_target_blaster (edict_t *self, edict_t *other, edict_t *activator) +{ + int effect; + + if (self->spawnflags & 2) + effect = 0; + else if (self->spawnflags & 1) + effect = EF_HYPERBLASTER; + else + effect = EF_BLASTER; + + fire_blaster (self, self->s.origin, self->movedir, self->dmg, self->speed, EF_BLASTER); + gi.sound (self, CHAN_VOICE, self->noise_index, 1, ATTN_NORM, 0); +} + +void SP_target_blaster (edict_t *self) +{ + self->use = use_target_blaster; + G_SetMovedir (self->s.angles, self->movedir); + self->noise_index = gi.soundindex ("weapons/laser2.wav"); + + if (!self->dmg) + self->dmg = 15; + if (!self->speed) + self->speed = 1000; + + self->svflags = SVF_NOCLIENT; +} + +*/ +//========================================================== + +/*QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 +Once this trigger is touched/used, any trigger_crosslevel_target with the same trigger number is automatically used when a level is started within the same unit. It is OK to check multiple triggers. Message, delay, target, and killtarget also work. +*/ +void trigger_crosslevel_trigger_use (edict_t *self, edict_t *other, edict_t *activator) +{ + game.serverflags |= self->spawnflags; + G_FreeEdict (self); +} + +void SP_target_crosslevel_trigger (edict_t *self) +{ + self->svflags = SVF_NOCLIENT; + self->use = trigger_crosslevel_trigger_use; +} + +/*QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 +Triggered by a trigger_crosslevel elsewhere within a unit. If multiple triggers are checked, all must be true. Delay, target and +killtarget also work. + +"delay" delay before using targets if the trigger has been activated (default 1) +*/ +void target_crosslevel_target_think (edict_t *self) +{ + if (self->spawnflags == (game.serverflags & SFL_CROSS_TRIGGER_MASK & self->spawnflags)) + { + G_UseTargets (self, self); + G_FreeEdict (self); + } + self->nextthink = level.time + FRAMETIME; +} + +void SP_target_crosslevel_target (edict_t *self) +{ + if (! self->delay) + self->delay = 1; + self->svflags = SVF_NOCLIENT; + + self->think = target_crosslevel_target_think; + self->nextthink = level.time + self->delay; +} + +//========================================================== + +/*QUAK-ED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT +When triggered, fires a laser. You can either set a target +or a direction. +*/ +/* +void target_laser_think (edict_t *self) +{ + edict_t *ignore; + vec3_t start; + vec3_t end; + trace_t tr; + vec3_t point; + vec3_t last_movedir; + int count; + static vec3_t lmins = {-4, -4, -4}; + static vec3_t lmaxs = {4, 4, 4}; + + if (self->spawnflags & 0x80000000) + count = 8; + else + count = 4; + + if (self->enemy) + { + VectorCopy (self->movedir, last_movedir); + VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point); + VectorSubtract (point, self->s.origin, self->movedir); + VectorNormalize (self->movedir); + if (!VectorCompare(self->movedir, last_movedir)) + self->spawnflags |= 0x80000000; + } + + ignore = self; + VectorCopy (self->s.origin, start); + VectorMA (start, 2048, self->movedir, end); + while(1) + { + tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER); + + if (!tr.ent) + break; + + // hurt it if we can + if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && (tr.ent != self->owner)) + T_Damage (tr.ent, self, self->owner, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, 0); + + // if we hit something that's not a monster or player or is immune to lasers, we're done + if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) + { + if (self->spawnflags & 0x80000000) + { + self->spawnflags &= ~0x80000000; + gi.WriteByte (svc_temp_entity); + gi.WriteByte (TE_LASER_SPARKS); + gi.WriteByte (count); + gi.WritePosition (tr.endpos); + gi.WriteDir (tr.plane.normal); + gi.WriteByte (self->s.skinnum); + gi.multicast (tr.endpos, MULTICAST_PVS); + } + break; + } + + ignore = tr.ent; + VectorCopy (tr.endpos, start); + } + + VectorCopy (tr.endpos, self->s.old_origin); + + self->nextthink = level.time + FRAMETIME; +} + +void target_laser_on (edict_t *self) +{ + self->spawnflags |= 0x80000001; + self->svflags &= ~SVF_NOCLIENT; + target_laser_think (self); +} + +void target_laser_off (edict_t *self) +{ + self->spawnflags &= ~1; + self->svflags |= SVF_NOCLIENT; + self->nextthink = 0; +} + +void target_laser_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->spawnflags & 1) + target_laser_off (self); + else + target_laser_on (self); +} + +void target_laser_start (edict_t *self) +{ + edict_t *ent; + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_NOT; + self->s.renderfx |= RF_BEAM|RF_TRANSLUCENT; + self->s.modelindex = 1; // must be non-zero + + // set the beam diameter + if (self->spawnflags & 64) + self->s.frame = 16; + else + self->s.frame = 4; + + // set the color + if (self->spawnflags & 2) + self->s.skinnum = 0xf2f2f0f0; + else if (self->spawnflags & 4) + self->s.skinnum = 0xd0d1d2d3; + else if (self->spawnflags & 8) + self->s.skinnum = 0xf3f3f1f1; + else if (self->spawnflags & 16) + self->s.skinnum = 0xdcdddedf; + else if (self->spawnflags & 32) + self->s.skinnum = 0xe0e1e2e3; + + if (!self->owner) + self->owner = self; + + if (!self->enemy) + { + if (self->target) + { + ent = G_Find (NULL, FOFS(targetname), self->target); + if (!ent) + gi.dprintf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target); + self->enemy = ent; + } + else + { + G_SetMovedir (self->s.angles, self->movedir); + } + } + self->use = target_laser_use; + self->think = target_laser_think; + + if (!self->dmg) + self->dmg = 1; + + VectorSet (self->mins, -8, -8, -8); + VectorSet (self->maxs, 8, 8, 8); + gi.linkentity (self); + + if (self->spawnflags & 1) + target_laser_on (self); + else + target_laser_off (self); +} + +void SP_target_laser (edict_t *self) +{ + // let everything else get spawned before we start firing + self->think = target_laser_start; + self->nextthink = level.time + 1; +} +*/ +//========================================================== + +/*QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE +speed How many seconds the ramping will take +message two letters; starting lightlevel and ending lightlevel +*/ + +void target_lightramp_think (edict_t *self) +{ + char style[2]; + + style[0] = 'a' + self->movedir[0] + (level.time - self->timestamp) / FRAMETIME * self->movedir[2]; + style[1] = 0; + gi.configstring (CS_LIGHTS+self->enemy->style, style); + + if ((level.time - self->timestamp) < self->speed) + { + self->nextthink = level.time + FRAMETIME; + } + else if (self->spawnflags & 1) + { + char temp; + + temp = self->movedir[0]; + self->movedir[0] = self->movedir[1]; + self->movedir[1] = temp; + self->movedir[2] *= -1; + } +} + +void target_lightramp_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if (!self->enemy) + { + edict_t *e; + + // check all the targets + e = NULL; + while (1) + { + e = G_Find (e, FOFS(targetname), self->target); + if (!e) + break; + if (strcmp(e->classname, "light") != 0) + { +#ifdef _DEVEL + gi.dprintf("%s at %s ", self->classname, vtos(self->s.origin)); + gi.dprintf("target %s (%s at %s) is not a light\n", self->target, e->classname, vtos(e->s.origin)); +#endif + } + else + { + self->enemy = e; + } + } + + if (!self->enemy) + { +#ifdef _DEVEL + gi.dprintf("%s target %s not found at %s\n", self->classname, self->target, vtos(self->s.origin)); +#endif + G_FreeEdict (self); + return; + } + } + + self->timestamp = level.time; + target_lightramp_think (self); +} + +void SP_target_lightramp (edict_t *self) +{ + if (!self->message || strlen(self->message) != 2 || self->message[0] < 'a' || self->message[0] > 'z' || self->message[1] < 'a' || self->message[1] > 'z' || self->message[0] == self->message[1]) + { +#ifdef _DEVEL + gi.dprintf("target_lightramp has bad ramp (%s) at %s\n", self->message, vtos(self->s.origin)); +#endif + G_FreeEdict (self); + return; + } + + if (deathmatch->value) + { + G_FreeEdict (self); + return; + } + + if (!self->target) + { +#ifdef _DEVEL + gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin)); +#endif + G_FreeEdict (self); + return; + } + + self->svflags |= SVF_NOCLIENT; + self->use = target_lightramp_use; + self->think = target_lightramp_think; + + self->movedir[0] = self->message[0] - 'a'; + self->movedir[1] = self->message[1] - 'a'; + self->movedir[2] = (self->movedir[1] - self->movedir[0]) / (self->speed / FRAMETIME); +} + +//========================================================== + +/*QUAK-ED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8) +When triggered, this initiates a level-wide earthquake. +All players and monsters are affected. +"speed" severity of the quake (default:200) +"count" duration of the quake (default:5) +*/ + +void target_earthquake_think (edict_t *self) +{ + int i; + edict_t *e; + + if (sv_jumpcinematic->value) // Don't do this if jumping a cinematic + return; + + if (self->last_move_time < level.time) + { + gi.positioned_sound (self->s.origin, self, CHAN_AUTO, self->noise_index, 1.0, ATTN_NONE, 0); + self->last_move_time = level.time + 0.5; + } + + for (i=1, e=g_edicts+i; i < globals.num_edicts; i++,e++) + { + if (!e->inuse) + continue; + if (!e->client) + continue; + if (!e->groundentity) + continue; + +// e->groundentity = NULL; + e->velocity[0] += flrand(-150.0F, 150.0F); + e->velocity[1] += flrand(-150.0F, 150.0F); + e->velocity[2] = self->speed * (100.0 / e->mass); + } + + if (level.time < self->timestamp) + self->nextthink = level.time + FRAMETIME; +} + +void target_earthquake_use (edict_t *self, edict_t *other, edict_t *activator) +{ + + if (sv_jumpcinematic->value) // Don't do this if jumping a cinematic + return; + + self->timestamp = level.time + self->count; + self->nextthink = level.time + FRAMETIME; + self->activator = activator; + self->last_move_time = 0; +} + +void SP_target_earthquake (edict_t *self) +{ + if (!self->targetname) + gi.dprintf("untargeted %s at %s\n", self->classname, vtos(self->s.origin)); + + if (!self->count) + self->count = 5; + + if (!self->speed) + self->speed = 200; + + self->svflags |= SVF_NOCLIENT; + self->think = target_earthquake_think; + self->use = target_earthquake_use; + + self->noise_index = gi.soundindex ("world/quake.wav"); +} diff --git a/Toolkit/Programming/GameCode/game/g_teleport.h b/Toolkit/Programming/GameCode/game/g_teleport.h new file mode 100644 index 0000000..c5ff1b0 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_teleport.h @@ -0,0 +1,28 @@ +#ifndef _G_TELEPORT_H_ +#define _G_TELEPORT_H_ + +#include "g_local.h" + +// TELEPORT defines + +#define TELE_TIME 4 // number of server frames we take to do the fades +#define TELE_FADE 255/TELE_TIME // amount to fade the player by each fade + +#define TELE_TIME_OUT 5 // number of server frames we take to do the fades +#define TELE_FADE_OUT 255/TELE_TIME_OUT // amount to fade the player by each fade + +#define MORPH_TELE_TIME 5 // number of server frames to do the fade +#define MORPH_TELE_FADE 255/MORPH_TELE_TIME + +#define DEATHMATCH_RANDOM 2 + +void teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); +void SpellCastTeleport(edict_t *caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value); +void CleanUpTeleport(edict_t *self); +void Perform_Teleport(edict_t *self); +void Perform_Morph(edict_t *self); +void CleanUpMorph(edict_t *self); +void reset_morph_to_elf(edict_t *ent); +extern void SP_misc_teleport(edict_t *ent); + +#endif // _G_TELEPORT_H_ \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/g_trigger.c b/Toolkit/Programming/GameCode/game/g_trigger.c new file mode 100644 index 0000000..4dc7c4b --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_trigger.c @@ -0,0 +1,1204 @@ +#include "g_local.h" +#include "Vector.h" +#include "g_DefaultMessageHandler.h" +#include "fx.h" +#include "g_playstats.h" +#include "cl_strings.h" + +#define TRIGGER_MONSTER 1 +#define TRIGGER_NOT_PLAYER 2 +#define TRIGGER_TRIGGERED 4 +#define TRIGGER_ANY 8 + +#define PUZZLE_SHOWNO_INVENTORY 16 +#define PUZZLE_DONT_REMOVE 32 + +void Trigger_Deactivate(edict_t *self, G_Message_t *msg); +void Trigger_Activate(edict_t *self, G_Message_t *msg); + +void trigger_enable(edict_t *self, edict_t *other, edict_t *activator); +void Use_Multi(edict_t *self, edict_t *other, edict_t *activator); + +void TriggerStaticsInit() +{ + classStatics[CID_TRIGGER].msgReceivers[G_MSG_SUSPEND] = Trigger_Deactivate; + classStatics[CID_TRIGGER].msgReceivers[G_MSG_UNSUSPEND] = Trigger_Activate; +} + +// the wait time has passed, so set back up for another activation +void multi_wait(edict_t *self) +{ + self->think = NULL; + if(self->activator) + { + self->activator->target_ent = NULL; + } +} + +// the trigger was just activated +// self->activator should be set to the activator so it can be held through a delay +// so wait for the delay time before firing +void TriggerActivated(edict_t *self) +{ + if(self->think) + { + return; // already been triggered + } + + assert(self->TriggerActivated); + + self->TriggerActivated(self, self->activator); + + if(self->wait > 0) + { + self->think = multi_wait; + self->nextthink = level.time + self->wait; + } + else + { + self->touch = NULL; + self->nextthink = level.time + FRAMETIME; + self->think = G_FreeEdict; + } +} + +void Touch_Multi(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // Monsters or players can trigger it + if ((self->spawnflags & TRIGGER_ANY) && ((strcmp(other->classname, "player") == 0) || + (other->svflags & SVF_MONSTER))) + ; + // Player cannot trigger it + else if(strcmp(other->classname, "player") == 0) + { + if(self->spawnflags & TRIGGER_NOT_PLAYER) + { + return; + } + } + // Just monster will trigger it + else if(other->svflags & SVF_MONSTER) + { + if(!(self->spawnflags & TRIGGER_MONSTER)) + { + return; + } + } + else + { + return; + } + + if(!Vec3IsZero(self->movedir)) + { + vec3_t forward; + + AngleVectors(other->s.angles, forward, NULL, NULL); + + if(DotProduct(forward, self->movedir) < 0) + { + return; + } + } + + self->activator = other; + + TriggerActivated(self); +} + +void InitTrigger(edict_t *self) +{ + self->msgHandler = DefaultMsgHandler; + self->classID = CID_TRIGGER; + + if(!self->wait) + { + self->wait = 0.2; + } + + // Triggers still use the touch function even with the new physics + self->touch = Touch_Multi; + self->movetype = PHYSICSTYPE_NONE; + self->svflags |= SVF_NOCLIENT; + + if(self->spawnflags & TRIGGER_TRIGGERED) + { + self->solid = SOLID_NOT; + self->use = trigger_enable; + } + else + { + self->solid = SOLID_TRIGGER; + self->use = Use_Multi; + } + + if(!Vec3IsZero(self->s.angles)) + { + G_SetMovedir(self->s.angles, self->movedir); + } + + gi.setmodel(self, self->model); + gi.linkentity(self); +} + +void Trigger_Deactivate(edict_t *self, G_Message_t *msg) +{ + self->solid = SOLID_NOT; + self->use = NULL; +} + +void Trigger_Activate(edict_t *self, G_Message_t *msg) +{ + self->solid = SOLID_TRIGGER; + self->use = Use_Multi; + gi.linkentity (self); +} + +void Trigger_Sounds(edict_t *self) +{ + if (self->sounds == 1) + self->noise_index = gi.soundindex ("misc/secret.wav"); + else if (self->sounds == 3) + self->noise_index = gi.soundindex ("misc/talk.wav"); + else + self->noise_index = 0; +} + +//---------------------------------------------------------------------- +// One Time Trigger +//---------------------------------------------------------------------- + +/*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED ANY +Variable sized repeatable trigger. Must be targeted at one or more entities. +-------SPAWN FLAGS------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it +--------KEYS--------- +delay - Time to wait after activating before firing. +message - text string to display when activated +wait - Seconds between triggerings. (.2 default) +sounds - sound made when activating +1) secret +2) none +3) large switch +*/ +void SP_trigger_Multiple(edict_t *self) +{ + InitTrigger(self); + + self->TriggerActivated = G_UseTargets; + + Trigger_Sounds(self); + +} + +void trigger_enable(edict_t *self, edict_t *other, edict_t *activator) +{ + self->solid = SOLID_TRIGGER; + self->use = Use_Multi; + gi.linkentity (self); +} + +void Use_Multi(edict_t *self, edict_t *other, edict_t *activator) +{ + self->activator = activator; + TriggerActivated(self); +} + +//---------------------------------------------------------------------- +// One Time Trigger +//---------------------------------------------------------------------- + +/*QUAKED trigger_once (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED ANY +Triggers once, then removes itself. +You must set the key "target" to the name of another object in the level that has a matching "targetname". +-------SPAWN FLAGS------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it + +sounds + 1) secret + 2) no sound + 3) large switch + +"message" string to be displayed when triggered +*/ + +void SP_trigger_Once(edict_t *self) +{ + InitTrigger(self); + + self->TriggerActivated = G_UseTargets; + + self->wait = -1; + + Trigger_Sounds(self); + +} + +//---------------------------------------------------------------------- +// Relay Trigger +//---------------------------------------------------------------------- + +void trigger_relay_use(edict_t *self, edict_t *other, edict_t *activator); + +/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) +This fixed size trigger cannot be touched, it can only be fired by other events. +*/ +void SP_trigger_Relay(edict_t *self) +{ + self->use = trigger_relay_use; +} + +void trigger_relay_use(edict_t *self, edict_t *other, edict_t *activator) +{ + G_UseTargets (self, activator); +} + +//---------------------------------------------------------------------- +// Key Trigger +//---------------------------------------------------------------------- + +void trigger_key_use(edict_t *self, edict_t *other, edict_t *activator); + +/*QUAKED trigger_puzzle (.5 .5 .5) (-8 -8 -8) (8 8 8) NO_TEXT NO_TAKE +A relay trigger that only fires it's targets if player has the proper puzzle item. +------KEYS-------------- +NO_TEXT - won't generate the "You need..." text when triggered +NO_TAKE - don't take puzzle item from player inventory +------FIELDS------------ +Use "item" to specify the required puzzle item, for example "key_data_cd" +*/ +void SP_trigger_puzzle(edict_t *self) +{ + self->classID = CID_TRIGGER; + + if (!st.item) + { + gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin)); + return; + } + self->item = FindItemByClassname (st.item); + + if (!self->item) + { + gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin)); + return; + } + + if (!self->target) + { + gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin)); + return; + } + + self->use = trigger_key_use; +} + +void trigger_key_use(edict_t *self, edict_t *other, edict_t *activator) +{ + int index; + edict_t *puzzle; + + if (!self->item) + return; + if (!activator->client) + return; + + index = ITEM_INDEX(self->item); + + if (!activator->client->playerinfo.pers.inventory.Items[index]) + { + if (level.time < self->touch_debounce_time) + return; + self->touch_debounce_time = level.time + 5.0; + if (!(self->spawnflags & 1)) + gi.gamemsg_centerprintf (activator, self->item->msg_nouse); + + return; + } + + // Clear out the puzzle piece from all clients. + + if (!(self->spawnflags & 2)) + { + int i; + edict_t *ent; + + if (coop->value) // If COOP remove model from world if puzzle item is used. + { + puzzle = NULL; + + puzzle = G_Find(puzzle, FOFS(classname), (char *) self->item->classname); + + if (puzzle) + { + gi.sound(puzzle, CHAN_ITEM, gi.soundindex(self->item->pickup_sound), 1, ATTN_NORM, 0); + + gi.CreateEffect(NULL, FX_PICKUP, 0, puzzle->s.origin, ""); + + puzzle->solid = SOLID_NOT; + + // Once picked up, the item is gone forever, so remove it's client effect(s). + gi.RemoveEffects(&puzzle->s,0); + + // The persistent part is removed from the server here. + G_SetToFree(puzzle); + } + } + + + for (i=0 ; ivalue ; i++) + { + ent = g_edicts + 1 + i; + + if (!ent->inuse) + continue; + + ent->client->playerinfo.pers.inventory.Items[index]=0; + } + } + + gi.sound (self, CHAN_AUTO, gi.soundindex ("player/useobject.wav"), 2, ATTN_NORM, 0); + + G_UseTargets (self, activator); + + self->use = NULL; + + if (!(other->spawnflags & PUZZLE_DONT_REMOVE)) // Get rid of it. + { + G_SetToFree(other); + activator->target_ent=activator->client->playerinfo.target_ent = 0; + } +} + +//---------------------------------------------------------------------- +// Counter Trigger +//---------------------------------------------------------------------- + +void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator); + +#define TRIGGER_COUNTER_NOMESSAGE 1 +/*QUAKED trigger_counter (.5 .5 .5) ? NOMESSAGE +Acts as an intermediary for an action that takes multiple inputs. + +If NOMESSAGE is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. + +After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself. +*/ +void SP_trigger_Counter(edict_t *self) +{ + self->classID = CID_TRIGGER; + + self->wait = -1; + + if (!self->count) + { + self->count = 2; + } + + self->use = trigger_counter_use; + + self->TriggerActivated = G_UseTargets; +} + +void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator) +{ + if (self->count == 0) + { + return; + } + + self->count--; + + if (self->count) + { + if (! (self->spawnflags & TRIGGER_COUNTER_NOMESSAGE)) + { + gi.gamemsg_centerprintf(activator, (short)(self->count + GM_SEQCOMPLETE)); +// gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); + } + return; + } + + if (! (self->spawnflags & TRIGGER_COUNTER_NOMESSAGE)) + { + gi.gamemsg_centerprintf(activator, GM_SEQCOMPLETE); +// gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); + } + + self->activator = activator; + + TriggerActivated(self); +} + +//---------------------------------------------------------------------- +// Always Trigger +//---------------------------------------------------------------------- + +/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8) +This trigger will always fire. It is activated by the world. +*/ +void SP_trigger_Always(edict_t *self) +{ + self->classID = CID_TRIGGER; + + // we must have some delay to make sure our use targets are present + if (self->delay < 0.2) + { + self->delay = 0.2; + } + + G_UseTargets(self, self); +} + +//---------------------------------------------------------------------- +// Player Use Item +//---------------------------------------------------------------------- + +void trigger_playerusepuzzle(edict_t *self, edict_t *activator) +{ + if (!(self->spawnflags & PUZZLE_SHOWNO_INVENTORY)) + { + if(!strcmp(activator->classname, "player")) + { + activator->target_ent = self; + self->activator = activator; + } + } + else + G_UseTargets(self,activator); + +} + +/*QUAKED trigger_playerusepuzzle (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED ANY NO_INVENTORY DONT_REMOVE +Player can 'use' puzzle items within this entity. Will remove itself after one use. +-------SPAWN FLAGS------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it +NO_INVENTORY - don't show inventory bar, don't take puzzle piece +DONT_REMOVE - entity won't remove itself after one use +*/ + +void SP_trigger_PlayerUsePuzzle(edict_t *self) +{ + InitTrigger(self); + + self->wait = 1.0; + self->TriggerActivated = trigger_playerusepuzzle; + + gi.setmodel (self, self->model); + gi.linkentity (self); +} + +//---------------------------------------------------------------------- +// Player Push Button Trigger +//---------------------------------------------------------------------- + +void trigger_playerpushbutton(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + if(!strcmp(other->classname, "player")) + { + other->target = self->target; + } +} + +/*QUAKED trigger_playerpushbutton (.5 .5 .5) ? +Triggers player to know he is near a button. +*/ +void SP_trigger_PlayerPushButton(edict_t *self) +{ + self->classID = CID_TRIGGER; + + self->wait = FRAMETIME; + self->touch = trigger_playerpushbutton; + self->movetype = PHYSICSTYPE_NONE; + self->svflags |= SVF_NOCLIENT; + self->solid = SOLID_TRIGGER; + + gi.setmodel (self, self->model); + gi.linkentity (self); +} + +//---------------------------------------------------------------------- +// Player Push Button Trigger +//---------------------------------------------------------------------- + +void trigger_elevator_use (edict_t *self, edict_t *other, edict_t *activator); +void trigger_elevator_init (edict_t *self); + +/*QUAKED trigger_elevator (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) +*/ +void SP_trigger_Elevator (edict_t *self) +{ + self->classID = CID_TRIGGER; + + self->think = trigger_elevator_init; + self->nextthink = level.time + FRAMETIME; +} + +void trigger_elevator_use (edict_t *self, edict_t *other, edict_t *activator) +{ + void train_resume (edict_t *self); + edict_t *target; + + if (self->movetarget->nextthink) + { +// gi.dprintf("elevator busy\n"); + return; + } + + if (!other->pathtarget) + { +#ifdef _DEVEL + gi.dprintf("elevator used with no pathtarget\n"); +#endif + return; + } + + target = G_PickTarget (other->pathtarget); + if (!target) + { +#ifdef _DEVEL + gi.dprintf("elevator used with bad pathtarget: %s\n", other->pathtarget); +#endif + return; + } + + self->movetarget->target_ent = target; + train_resume (self->movetarget); +} + +void trigger_elevator_init (edict_t *self) +{ + if (!self->target) + { +#ifdef _DEVEL + gi.dprintf("trigger_elevator has no target\n"); +#endif + return; + } + self->movetarget = G_PickTarget (self->target); + if (!self->movetarget) + { +#ifdef _DEVEL + gi.dprintf("trigger_elevator unable to find target %s\n", self->target); +#endif + return; + } + if (strcmp(self->movetarget->classname, "func_train") != 0) + { +#ifdef _DEVEL + gi.dprintf("trigger_elevator target %s is not a train\n", self->target); +#endif + return; + } + + self->use = trigger_elevator_use; + self->svflags = SVF_NOCLIENT; +} + +//---------------------------------------------------------------------- +// Suspend Trigger +//---------------------------------------------------------------------- + +void SuspendTrigger_Activated(edict_t *self, edict_t *activator); + +/*QUAKED trigger_Deactivate (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED ANY +Variable sized repeatable trigger, which posts a SUSPEND message to its target. +Must be targeted at one or more entities. +-------SPAWN FLAGS------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it +--------KEYS----------- +delay - If set, the trigger waits this amount after activating before firing. +wait - Seconds between triggerings. (.2 default) +message - text string displayed when triggered +*/ +void SP_trigger_Deactivate(edict_t *self) +{ + InitTrigger(self); + + self->TriggerActivated = SuspendTrigger_Activated; +} + +void SuspendTrigger_Activated(edict_t *self, edict_t *activator) +{ + edict_t *t; + + assert(self->target); + +// +// DeActivate all targets +// + t = NULL; + while ((t = G_Find (t, FOFS(targetname), self->target))) + { + if (t->msgHandler) + QPostMessage(t, G_MSG_SUSPEND, PRI_ORDER, "f", self->time); + } +} + +//---------------------------------------------------------------------- +// Unsuspend Trigger +//---------------------------------------------------------------------- + +void ActivateTrigger_Activated(edict_t *self, edict_t *activator); + +/*QUAKED trigger_Activate (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED ANY +Variable sized repeatable trigger, which posts a UNSUSPEND message to its target. +Must be targeted at one or more entities. +-------SPAWN FLAGS------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it +------KEYS----------- +delay - If set, the trigger waits this amount after activating before firing. +wait - Seconds between triggerings. (.2 default) +message - text string displayed when triggered +*/ +void SP_trigger_Activate(edict_t *self) +{ + InitTrigger(self); + + self->TriggerActivated = ActivateTrigger_Activated; +} + +void ActivateTrigger_Activated(edict_t *self, edict_t *activator) +{ + edict_t *t; + + assert(self->target); + +// +// Activate all targets +// + t = NULL; + while ((t = G_Find (t, FOFS(targetname), self->target))) + { + if (t->msgHandler) + QPostMessage(t, G_MSG_UNSUSPEND, PRI_ORDER, "f", self->time); + } +} + +// make every active client out there change CD track. +void everyone_play_track(int track, int loop) +{ + int j; + edict_t *other; + + // play the track - make sure everyone gets sent this over the next in the client messages + for (j = 1; j <= game.maxclients; j++) + { + other = &g_edicts[j]; + if (!other->inuse) + continue; + if (!other->client) + continue; + gi.changeCDtrack(other, track, loop); + } +} + +void choose_CDTrack_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // if we aren't a player, forget it + if (!other->client) + return; + + // make everyone play this track + everyone_play_track(self->style, self->spawnflags); + // kill this trigger + G_SetToFree(self); +} + +void choose_CDTrack_use (edict_t *self, edict_t *other, edict_t *activator) +{ + // make everyone play this track + everyone_play_track(self->style, self->spawnflags); + // kill this trigger + G_SetToFree(self); +} + +/*QUAKED choose_CDTrack (.5 .5 .5) ? NO_LOOP +Variable sized repeatable trigger which chooses a CD track. +------KEYS----------- +style - # of CD track to play +NO_LOOP - allows you to set the track to play not to loop +*/ +void SP_choose_CDTrack(edict_t *self) +{ + self->msgHandler = DefaultMsgHandler; + self->classID = CID_TRIGGER; + + self->use = choose_CDTrack_use; + + if (self->spawnflags & 1) + self->spawnflags = FALSE; + else + self->spawnflags = TRUE; + + if(!self->wait) + { + self->wait = 0.2; + } + + // Triggers still use the touch function even with the new physics + self->touch = choose_CDTrack_touch; + self->movetype = PHYSICSTYPE_NONE; + self->svflags |= SVF_NOCLIENT; + self->solid = SOLID_TRIGGER; + + gi.setmodel(self, self->model); + gi.linkentity(self); + +} +void M_Menu_Quit_f (void); + +void trigger_quit_to_menu_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + if(!other->client) + return; + + gi.AddCommandString ("menu_main\n"); +} + +void trigger_quit_to_menu_use (edict_t *self, edict_t *other, edict_t *activator) +{ + if(!activator->client) + return; + + gi.AddCommandString ("menu_main\n"); +} + +/*QUAKED trigger_quit_to_menu (.5 .5 .5) ? +Player only, quits to menu +*/ + +void SP_trigger_quit_to_menu(edict_t *self) +{ + self->msgHandler = DefaultMsgHandler; + self->classID = CID_TRIGGER; + + self->touch = trigger_quit_to_menu_touch; + self->use = trigger_quit_to_menu_use; + self->movetype = PHYSICSTYPE_NONE; + self->svflags |= SVF_NOCLIENT; + + self->solid = SOLID_TRIGGER; + + if(!Vec3IsZero(self->s.angles)) + { + G_SetMovedir(self->s.angles, self->movedir); + } + + gi.setmodel(self, self->model); + gi.linkentity(self); +} + +void mappercentage_use (edict_t *self, edict_t *other) +{ + if (!other->client) // Only players use these + return; + + other->client->ps.map_percentage = (byte) self->count; + + G_UseTargets(self, self); + +#ifdef _DEVEL + gi.dprintf("Map percentage updated to %d\n", (byte) self->count); +#endif +} + +/*QUAKED trigger_mappercentage (0.3 0.1 0.6) ? MONSTER NOT_PLAYER TRIGGERED ANY +When triggered it updates Player with the percentage of the level completed. +--------FLAGS---------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it +----------KEYS--------------- +count - amount of level completed +*/ +void SP_trigger_mappercentage (edict_t *self) +{ + InitTrigger(self); + + self->TriggerActivated = mappercentage_use; + + if (self->count > 100) + self->count = 100; +} + + +void lightning_use (edict_t *self, edict_t *other) +{ + edict_t *target=NULL; + byte width, duration; + + width=self->style; + if (width<1) width=6; + duration=(byte)(self->delay*10); + + G_UseTargets(self, self); + + // Find the entities targeted by this entity. + while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL) + { + if (target->classname) + { + if (strcmp(target->classname, "info_notnull") == 0) + { + // Found another with this target. + if (self->materialtype) // Red lightning + gi.CreateEffect(NULL, FX_LIGHTNING, CEF_FLAG6, self->s.origin, "vbb", target->s.origin, width, duration); + else + gi.CreateEffect(NULL, FX_LIGHTNING, 0, self->s.origin, "vbb", target->s.origin, width, duration); + } + } + } + + if (self->pain_debounce_time < level.time) + { + self->pain_debounce_time = level.time + 2; + gi.sound (self, CHAN_AUTO, gi.soundindex ("world/lightningloop.wav"), 1, ATTN_NORM, 0); + } +} +void lightning_go (edict_t *self, edict_t *other, edict_t *activator) +{ + lightning_use (self,other); +} + +/*QUAKED trigger_lightning (0.3 0.1 0.6) ? MONSTER NOT_PLAYER TRIGGERED ANY +Triggers a lightning bolt +-------SPAWN FLAGS------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it +-------KEYS-------------------- +origin-- Starting point. +target-- Ending point entity. + There may be more than one with a given targetname. +delay-- (0-25.5) Sec. duration of lightning. + Leave this at zero for a normal strike +materialtype-- 0=blue, 1=red +style-- Width of bolt. Red rain uses 6. +wait - amount of time until it will become active again (default 10). +*/ +void SP_trigger_lightning (edict_t *self) +{ + InitTrigger(self); + + if (!self->wait) + self->wait = 10; + + self->TriggerActivated = lightning_use; + self->use = lightning_go; // This is so a trigger_relay can use it. +} + +void quake_quiet(edict_t *self) +{ + gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE,self->moveinfo.sound_end, 2, ATTN_NORM, 0); + self->nextthink = level.time + FRAMETIME; + self->think = G_FreeEdict; +} + +void quake_use (edict_t *self, edict_t *other) +{ + edict_t *killsound; + int count,time; + + if (self->touch_debounce_time > level.time) + return; + + self->touch_debounce_time = level.time + self->wait; + + count = (byte)self->count; + time = (byte) self->time * 10; + + gi.CreateEffect(&self->s, FX_QUAKE, CEF_BROADCAST, self->s.origin,"bbb",count,time,self->style); + + G_UseTargets(self, self); + + if (self->wait==-1) + { + self->touch = NULL; + self->nextthink = level.time + FRAMETIME; + self->think = G_FreeEdict; + } + + // Because nextthink is multi_use for a trigger I have to create a new entity with the sound + // so I can then kill the sound at the right time + killsound = G_Spawn(); + + gi.sound (killsound, CHAN_NO_PHS_ADD+CHAN_VOICE,self->moveinfo.sound_middle, 2, ATTN_NORM, 0); + VectorCopy(self->s.origin,killsound->s.origin); + killsound->moveinfo.sound_end = self->moveinfo.sound_end; + killsound->nextthink = level.time + self->time; + killsound->think = quake_quiet; +} + +/*QUAKED trigger_quake (0.3 0.1 0.6) ? MONSTER NOT_PLAYER TRIGGERED ANY +Triggers an earth quake +-------SPAWN FLAGS------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it +--------KEYS--------------------- +wait - amount of time until it will become active again (default 10). -1 makes it go away for ever. +count - max number of pixels to shake screen (default 20) +time - duration to the tenth of a second (range 0 - 12.8) (default 2) +style - direction of shake +1 - SHAKE_LATERAL +2 - SHAKE_VERTICAL +4 - SHAKE_DEPTH +7 - SHAKE_ALL_DIR (default) +*/ +void SP_trigger_quake (edict_t *self) +{ + if (!self->wait) + self->wait = 10; + + self->moveinfo.sound_middle = gi.soundindex ("world/quake.wav"); + self->moveinfo.sound_end = gi.soundindex ("world/quakend.wav"); + + InitTrigger(self); + + if (!self->count) // Amount of shake + self->count = 20; + + if (!self->time) // Duration + self->time = 2.0; + + if (!self->style) + self->style = SHAKE_ALL_DIR; + + self->TriggerActivated = quake_use; +} + +void trig_done(edict_t *self) +{ + self = self; +} + +void mission_give_use (edict_t *self, edict_t *other) +{ + int num, i; + player_state_t *ps; + + num = atoi(self->message); + for (i = 1; i <= game.maxclients; i++) + { + other = &g_edicts[i]; + if (!other->inuse) + continue; + if (!other->client) + continue; + + ps = &other->client->ps; + if((ps->mission_num1 != num) && (ps->mission_num2 != num)) + { + if (!ps->mission_num1) + { + ps->mission_num1 = num; + } + else + { + ps->mission_num2 = num; + } + gi.gamemsg_centerprintf(other, GM_NEWOBJ); + } + } + G_UseTargets(self, self); +} + +/*QUAKED trigger_mission_give (0.3 0.1 0.6) ? MONSTER NOT_PLAYER TRIGGERED ANY +Gives player(s) the current mission objectives +-------SPAWN FLAGS------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it +-------KEYS-------------------- +message - number of line from strings.txt, put in objectives +wait - amount of time until it will become active again (default 10). +*/ +void SP_trigger_mission_give (edict_t *self) +{ + InitTrigger(self); + + if (!self->wait) + self->wait = 10; + + self->TriggerActivated = mission_give_use; +} + +#define MISSION_TAKE1 16 +#define MISSION_TAKE2 32 + +void mission_take_use (edict_t *self, edict_t *other) +{ + player_state_t *ps; + int i; + + for (i = 1; i <= game.maxclients; i++) + { + other = &g_edicts[i]; + if (!other->inuse) + continue; + if (!other->client) + continue; + + ps = &other->client->ps; + + if (self->spawnflags & MISSION_TAKE1) + ps->mission_num1 = 0; + + if (self->spawnflags & MISSION_TAKE2) + ps->mission_num2 = 0; + } + G_UseTargets(self, self); + +} + +/*QUAKED trigger_mission_take (0.3 0.1 0.6) ? MONSTER NOT_PLAYER TRIGGERED ANY TAKE1 TAKE2 +Removes player(s) the current mission objectives +-------SPAWN FLAGS------------- +MONSTER - only a monster will trigger it +NOT_PLAYER - can't be triggered by player +TRIGGERED - starts trigger deactivated +ANY - anything can activate it +TAKE1 mission statement 1 +TAKE2 mission statement 2 +-------KEYS-------------------- +wait - amount of time until it will become active again (default 10). +*/ +void SP_trigger_mission_take (edict_t *self) +{ + InitTrigger(self); + + if (!self->wait) + self->wait = 10; + + self->TriggerActivated = mission_take_use; +} + +void ClipDistance_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + char temp[10]; + cvar_t *r_farclipdist; + r_farclipdist = gi.cvar("r_farclipdist", FAR_CLIP_DIST, 0); + + // if we aren't a player, forget it + if (!other->client) + return; + + if (self->pain_debounce_time < level.time) + { + if (r_farclipdist->value == FAR_CLIP_DIST_VAL) + { + sprintf(temp, "%f", self->s.scale); + gi.cvar_set("r_farclipdist", temp); + + } + else + { + gi.cvar_set("r_farclipdist", FAR_CLIP_DIST); + } + self->pain_debounce_time = level.time + 0.5; + } +} + +/*QUAKED trigger_farclip (0.5 0.5 0.5) ? +Allows the console var Farclip to be reset - this is a toggle function - if triggered +and far-clip is set to the default, it will be reset to the value passed in. If its the +value passed in, its reset to the default. Be aware that there must be no teleport +destinations within the area that has a reset far-clip. +-------SPAWN FLAGS------------- +-------KEYS-------------------- +scale - distance to set far clip to. Default of farclip is 4096.0 +*/ +void SP_trigger_farclip (edict_t *self) +{ + InitTrigger(self); + + self->touch = ClipDistance_touch; + self->solid = SOLID_TRIGGER; + +} + +void Touch_endgame(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + // if we aren't a player, forget it + if (!other->client) + return; + + if (deathmatch->value) + return; + + gi.AddCommandString ("endgame\n"); + + G_SetToFree(self); +} + +void Use_endgame (edict_t *self, edict_t *other, edict_t *activator) +{ + + if (deathmatch->value) + return; + + gi.AddCommandString ("endgame\n"); + + G_SetToFree(self); +} + + +/*QUAKED trigger_endgame (.5 .5 .5) ? +End game trigger. once used, game over +*/ +void SP_trigger_endgame(edict_t *self) +{ + InitTrigger(self); + self->touch = Touch_endgame; + self->solid = SOLID_TRIGGER; + self->use = Use_endgame; + +} + +//---------------------------------------------------------------------- +// Player Push Lever Trigger +//---------------------------------------------------------------------- + +//void trigger_playerpushlever(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +void trigger_playerpushlever(edict_t *self, edict_t *other) +{ + if(!strcmp(other->classname, "player")) + { + other->target = self->target; + } +} + +/*QUAKED trigger_playerpushlever (.5 .5 .5) ? x1 x2 TRIGGERED +Triggers player to know he is near a lever. +*/ +void SP_trigger_PlayerPushLever(edict_t *self) +{ + InitTrigger(self); + + self->TriggerActivated = trigger_playerpushlever; + +} + +//---------------------------------------------------------------------- +// Player Push Lever Trigger +//---------------------------------------------------------------------- diff --git a/Toolkit/Programming/GameCode/game/g_utils.c b/Toolkit/Programming/GameCode/game/g_utils.c new file mode 100644 index 0000000..37e3234 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_utils.c @@ -0,0 +1,1087 @@ +// g_utils.c -- misc utility functions for game module + +#include "g_local.h" +#include "FX.h" +#include "g_Skeletons.h" +#include "random.h" +#include "vector.h" +#include "g_BoundingForm.h" +#include "g_Physics.h" + +void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result) +{ + result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1]; + result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1]; + result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2]; +} + + +void G_SetToFree(edict_t *self) +{ + if(self->PersistantCFX) + { + gi.RemovePersistantEffect(self->PersistantCFX); + self->PersistantCFX = 0; + } + + self->think = G_FreeEdict; + self->nextthink = level.time + FRAMETIME; + self->svflags &= ~SVF_NOCLIENT; +// if (self->s.modelindex || (self->s.effects & (EF_ALWAYS_ADD_EFFECTS|EF_NODRAW_ALWAYS_SEND))) +// self->svflags |= SVF_ALWAYS_SEND; + + self->next_pre_think = -1; + self->next_post_think = -1; + + self->takedamage = DAMAGE_NO; + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_NOT; + self->touch = NULL; + self->blocked = NULL; + self->isBlocked = NULL; + self->isBlocking = NULL; + self->bounced = NULL; + VectorClear(self->mins); + VectorClear(self->maxs); + + gi.linkentity(self); +} + +/* +============= +G_Find + +Searches all active entities for the next one that holds +the matching string at fieldofs (use the FOFS() macro) in the structure. + +Searches beginning at the edict after from, or the beginning if NULL +NULL will be returned if the end of the list is reached. + +============= +*/ +edict_t *G_Find (edict_t *from, int fieldofs, char *match) +{ + char *s; + + // if we aren't trying to find anything, then exit. + if (match == NULL) + return NULL; + + if (!from) + from = g_edicts; + else + from++; + + for ( ; from < &g_edicts[globals.num_edicts] ; from++) + { + if (!from->inuse) + continue; + s = *(char **) ((byte *)from + fieldofs); + if (!s) + continue; + if (!Q_stricmp (s, match)) + return from; + } + + return NULL; +} + + +// +//================= +// FindOnPath +// +// Returns damageable entities that lie along a given pathway. This is NOT 100% guaranteed to return a given edict only once. +// +//================= + +edict_t *findonpath(edict_t *startent, vec3_t startpos, vec3_t endpos, vec3_t mins, vec3_t maxs, vec3_t *resultpos) +{ + vec3_t vect, curpos; + trace_t trace; + float skipamount; + edict_t *tracebuddy; + + VectorCopy(startpos, curpos); + tracebuddy = startent; + while(1) + { + gi.trace(curpos, mins, maxs, endpos, tracebuddy, MASK_SHOT,&trace); + + // If we started inside something. + if (trace.startsolid || trace.allsolid) + { + if (trace.ent && trace.ent->takedamage) + { // Found an item. Skip forward a distance and return the ent. + skipamount = maxs[2]; + if (skipamount < 4) + skipamount = 4; + VectorSubtract(endpos, curpos, vect); + if (VectorNormalize(vect) < skipamount) // skip to the end. + VectorCopy(endpos, *resultpos); + else + VectorMA(curpos, skipamount, vect, *resultpos); + + return(trace.ent); + } + else + { // Didn't stop on anything useful, continue to next trace. + skipamount = maxs[2]; // Skip forward a bit. + if (skipamount < 4) + skipamount = 4; + VectorSubtract(endpos, curpos, vect); + if (VectorNormalize(vect) < skipamount) // skip to the end. + return(NULL); // Didn't find anything. + else + VectorMA(curpos, skipamount, vect, curpos); + if (trace.ent) + tracebuddy = trace.ent; + continue; // Do another trace. + } + } + + // If we did not start inside something, but stopped at something. + if (trace.fraction < .99) + { + if (trace.ent && trace.ent->takedamage) + { // Found an item. Skip forward a distance and return the ent. + skipamount = maxs[2]; + if (skipamount < 4) + skipamount = 4; + VectorSubtract(endpos, trace.endpos, vect); + if (VectorNormalize(vect) < skipamount) // skip to the end. + VectorCopy(endpos, *resultpos); + else + VectorMA(trace.endpos, skipamount, vect, *resultpos); + + return(trace.ent); + } + else + { // Didn't stop on anything useful, continue to next trace. + skipamount = maxs[2]; // Skip forward a bit. + if (skipamount < 4) + skipamount = 4; + VectorSubtract(endpos, trace.endpos, vect); + if (VectorNormalize(vect) < skipamount) // skip to the end. + return(NULL); // Didn't find anything. + else + VectorMA(trace.endpos, skipamount, vect, curpos); + if (trace.ent) + tracebuddy = trace.ent; + continue; // Do another trace. + } + } + + // If we finished the whole move. + { + VectorCopy(endpos, *resultpos); + return(NULL); + } + }; + + return(NULL); // Never gets here. +} + +#define NEW_FINDS (1) + +#if !NEW_FINDS +/* +================= +findradius + +Returns entities that have origins within a spherical area + +findradius (origin, radius) +================= +*/ +edict_t *findradius (edict_t *from, vec3_t org, float rad) +{ + vec3_t eorg; + int j; + + if (!from) + from = g_edicts; + else + from++; + for ( ; from < &g_edicts[globals.num_edicts]; from++) + { + if (!from->inuse) + continue; + if (from->solid == SOLID_NOT) + continue; + for (j=0 ; j<3 ; j++) + eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5); + if (VectorLength(eorg) > rad) + continue; + return from; + } + + return NULL; +} + +// THis works like findradius, except it uses the bbox of an ent to indicate the area to check. +edict_t *findinblocking(edict_t *from, edict_t *checkent) +{ + vec3_t min, max; + int j; + qboolean ok; + + if (!from) + from = g_edicts; + else + from++; + + VectorAdd(checkent->s.origin, checkent->mins, min); + VectorAdd(checkent->s.origin, checkent->maxs, max); + for ( ; from < &g_edicts[globals.num_edicts]; from++) + { + if (!from->inuse) + continue; + if (from->solid == SOLID_NOT) + continue; + if (from == checkent) + continue; + ok=true; + for (j=0 ; j<3 ; j++) + { + if ( from->s.origin[j] + from->mins[j] > max[j] || + from->s.origin[j] + from->maxs[j] < min[j]) + { // Automatic failure. + ok=false; + break; + } + } + if (ok) + return from; + } + + return NULL; +} + + +/* +================= +finddistance + +Returns entities that have origins within a spherical shell area + +finddistance (origin, mindist, maxdist) +================= +*/ +edict_t *finddistance (edict_t *from, vec3_t org, float mindist, float maxdist) +{ + vec3_t eorg; + int j; + float elen; + + if (!from) + from = g_edicts; + else + from++; + for ( ; from < &g_edicts[globals.num_edicts]; from++) + { + if (!from->inuse) + continue; + if (from->solid == SOLID_NOT) + continue; + for (j=0 ; j<3 ; j++) + eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5); + elen = VectorLength(eorg); + if (elen > maxdist) + continue; + if (elen < mindist) + continue; + return from; + } + + return NULL; +} + +// THis works like findradius, except it uses two absolute positions to define where to search. +edict_t *findinbounds(edict_t *from, vec3_t min, vec3_t max) +{ + int j; + qboolean ok; + + if (!from) + from = g_edicts; + else + from++; + + for ( ; from < &g_edicts[globals.num_edicts]; from++) + { + if (!from->inuse) + continue; + if (from->solid == SOLID_NOT) + continue; + + ok=true; + for (j=0 ; j<3 ; j++) + { + if ( from->s.origin[j] + from->mins[j] > max[j] || + from->s.origin[j] + from->maxs[j] < min[j]) + { // Automatic failure. + ok=false; + break; + } + } + if (ok) + return from; + } + + return NULL; +} + +#else + +// THis works like findradius, except it uses the bbox of an ent to indicate the area to check. +edict_t *findinblocking(edict_t *from, edict_t *checkent) +{ + static vec3_t min, max; + + if (!from) + { + VectorAdd(checkent->s.origin, checkent->mins, min); + VectorAdd(checkent->s.origin, checkent->maxs, max); + } + while (1) + { + from=findinbounds(from,min,max); + if (!from) + return 0; + if (!from->inuse) + continue; + if (from == checkent) + continue; + return from; + } +} + +/* +================= +findradius + +Returns entities that have origins within a spherical area + +findradius (origin, radius) +================= +*/ +edict_t *findradius (edict_t *from, vec3_t org, float rad) +{ + static float max2; + static vec3_t min; + static vec3_t max; + vec3_t eorg; + int j; + float elen; + + if (!from) + { + max2=rad*rad; + VectorCopy(org,min); + VectorCopy(org,max); + for (j=0 ; j<3 ; j++) + { + min[j]-=rad; + max[j]+=rad; + } + } + while (1) + { + from=findinbounds(from,min,max); + if (!from) + return 0; + if (!from->inuse) + continue; + for (j=0 ; j<3 ; j++) + eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5); + elen = DotProduct(eorg,eorg); + if (elen > max2) + continue; + return from; + } +} + +/* +================= +finddistance + +Returns entities that have origins within a spherical shell area + +finddistance (origin, mindist, maxdist) +================= +*/ +edict_t *finddistance (edict_t *from, vec3_t org, float mindist, float maxdist) +{ + static float min2; + static float max2; + static vec3_t min; + static vec3_t max; + vec3_t eorg; + int j; + float elen; + + if (!from) + { + min2=mindist*mindist; + max2=maxdist*maxdist; + VectorCopy(org,min); + VectorCopy(org,max); + for (j=0 ; j<3 ; j++) + { + min[j]-=maxdist; + max[j]+=maxdist; + } + } + while (1) + { + from=findinbounds(from,min,max); + if (!from) + return 0; + if (!from->inuse) + continue; + for (j=0 ; j<3 ; j++) + eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5); + elen = DotProduct(eorg,eorg); + if (elen > max2) + continue; + if (elen < min2) + continue; + return from; + } +} + +edict_t *findinbounds(edict_t *from, vec3_t min, vec3_t max) +{ + static edict_t *touchlist[MAX_EDICTS]; + static int index=-1; + static int num; + + if (!from) + { + num = gi.BoxEdicts(min,max, touchlist, MAX_EDICTS, AREA_SOLID); + index=0; + } + else + { + assert(touchlist[index]==from); + // you cannot adjust the pointers yourself... + // this means you did not call it with the previous edict + index++; + } + for (;indexinuse) + continue; + return touchlist[index]; + } + return NULL; +} +#endif + +/* +============= +G_PickTarget + +Searches all active entities for the next one that holds +the matching string at fieldofs (use the FOFS() macro) in the structure. + +Searches beginning at the edict after from, or the beginning if NULL +NULL will be returned if the end of the list is reached. + +============= +*/ +#define MAXCHOICES 8 + +edict_t *G_PickTarget (char *targetname) +{ + edict_t *ent = NULL; + int num_choices = 0; + edict_t *choice[MAXCHOICES]; + + if (!targetname) + { +#ifdef _DEVEL + gi.dprintf("G_PickTarget called with NULL targetname\n"); +#endif + return NULL; + } + + while(1) + { + ent = G_Find (ent, FOFS(targetname), targetname); + if (!ent) + break; + choice[num_choices++] = ent; + if (num_choices == MAXCHOICES) + break; + } + + if (!num_choices) + { +#ifdef _DEVEL + gi.dprintf("G_PickTarget: target %s not found\n", targetname); +#endif + return NULL; + } + + return choice[irand(0, num_choices - 1)]; +} + + + +void Think_Delay (edict_t *ent) +{ + G_UseTargets (ent, ent->activator); + G_FreeEdict (ent); +} + +/* +============================== +G_UseTargets + +the global "activator" should be set to the entity that initiated the firing. + +If self.delay is set, a DelayedUse entity will be created that will actually +do the SUB_UseTargets after that many seconds have passed. + +Centerprints any self.message to the activator. + +Search for (string)targetname in all entities that +match (string)self.target and call their .use function + +============================== +*/ +void G_UseTargets (edict_t *ent, edict_t *activator) +{ + edict_t *t; + +// +// check for a delay +// + if (ent->delay) + { + // create a temp object to fire at a later time + t = G_Spawn(); + t->movetype = PHYSICSTYPE_NONE; + t->classname = "DelayedUse"; + t->nextthink = level.time + ent->delay; + t->think = Think_Delay; + t->activator = activator; +#ifdef _DEVEL + if (!activator) + gi.dprintf ("Think_Delay with no activator\n"); +#endif + t->message = ent->message; + t->text_msg = ent->text_msg; + t->target = ent->target; + t->killtarget = ent->killtarget; + return; + } + + +// +// print the message +// + if ((ent->message) && !(activator->svflags & SVF_MONSTER)) + { + gi.levelmsg_centerprintf (activator, (short)atoi(ent->message)); + if (ent->noise_index) + { + gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0); + } + } + + if ((ent->text_msg) && !(activator->svflags & SVF_MONSTER)) + { + gi.centerprintf (activator, "%s", ent->text_msg); + } + +// +// kill killtargets +// + if (ent->killtarget) + { + t = NULL; + while ((t = G_Find (t, FOFS(targetname), ent->killtarget))) + { + QPostMessage(t,MSG_DEATH,PRI_DIRECTIVE,"eeei",t,ent,activator,100000); + + if (!ent->inuse) + { +#ifdef _DEVEL + gi.dprintf("entity was removed while using killtargets\n"); +#endif + return; + } + } + } + +// +// fire targets +// + if (ent->target) + { + t = NULL; + while ((t = G_Find (t, FOFS(targetname), ent->target))) + { + // doors fire area portals in a specific way + if (!Q_stricmp(t->classname, "func_areaportal") && + (!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating"))) + continue; + + if (t == ent) + { +#ifdef _DEVEL + gi.dprintf ("WARNING: %s used itself.\n", t->classname); +#endif + } + else + { + if (t->use) + t->use (t, ent, activator); + } + if (!ent->inuse) + { +#ifdef _DEVEL + gi.dprintf("entity was removed while using targets\n"); +#endif + return; + } + } + } +} + +qboolean PossessCorrectItem(edict_t *ent, gitem_t *item) +{ + edict_t *t; + + if(!ent->target_ent) + { + return(false); + } + ent = ent->target_ent; + t = NULL; + while ((t = G_Find (t, FOFS(targetname), ent->target))) + { + // doors fire area portals in a specific way + if (!Q_stricmp(t->classname, "func_areaportal") && + (!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating"))) + continue; + + if(t->item == item) + { + return(true); + } + } + return(false); +} + +/* +============= +VectorToString + +This is just a convenience function +for printing vectors +============= +*/ +char *vtos (vec3_t v) +{ + static int index; + static char str[8][32]; + char *s; + + // use an array so that multiple vtos won't collide + s = str[index]; + index = (index + 1)&7; + + Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]); + + return s; +} + + +vec3_t VEC_UP = {0.0, -1.0, 0.0}; +vec3_t MOVEDIR_UP = {0.0, 0.0, 1.0}; +vec3_t VEC_DOWN = {0.0, -2.0, 0.0}; +vec3_t MOVEDIR_DOWN = {0.0, 0.0, -1.0}; + +void G_SetMovedir (vec3_t angles, vec3_t movedir) +{ + if (VectorCompare (angles, VEC_UP)) + { + VectorCopy (MOVEDIR_UP, movedir); + } + else if (VectorCompare (angles, VEC_DOWN)) + { + VectorCopy (MOVEDIR_DOWN, movedir); + } + else + { + AngleVectors (angles, movedir, NULL, NULL); + } + + VectorClear (angles); +} + + +float vectoyaw (vec3_t vec) +{ + float yaw; + + if (vec[YAW] == 0 && vec[PITCH] == 0) + yaw = 0; + else + { + yaw = (float) (atan2(vec[YAW], vec[PITCH]) * (180 / M_PI)); + if (yaw < 0) + yaw += 360; + } + + return yaw; +} + +char *G_CopyString (char *in) +{ + char *out; + + out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL); + strcpy (out, in); + return out; +} + + +void G_InitEdict (edict_t *self) +{ + self->s.clientEffects.buf = NULL; + self->s.clientEffects.bufSize = 0; + self->s.clientEffects.freeBlock = 0; + self->s.clientEffects.numEffects = 0; + + self->inuse = true; + self->movetype = PHYSICSTYPE_NONE; + self->classname = "noclass"; + self->gravity = 1.0F; + self->friction = 1.0F; + self->elasticity = ELASTICITY_SLIDE; + self->s.number = self - g_edicts; + self->s.scale = 1.0F; + self->msgHandler = NULL; + self->svflags = 0; + self->ready_cull = 0; + +} + +/* +================= +G_Spawn + +Either finds a free edict, or allocates a new one. +Try to avoid reusing an entity that was recently freed, because it +can cause the client to think the entity morphed into something else +instead of being removed and recreated, which can cause interpolated +angles and bad trails. +================= +*/ +edict_t *G_Spawn (void) +{ + int i; + edict_t *e; + //static unsigned int entID = 0; + + e = &g_edicts[(int)maxclients->value+1]; + for(i=maxclients->value + 1; i < globals.num_edicts; ++i, ++e) + { + // the first couple seconds of server time can involve a lot of + // freeing and allocating, so relax the replacement policy + if(!e->inuse && e->freetime <= level.time) + { + G_InitEdict (e); + + ++e->s.usageCount; + return e; + } + } + + if (i == game.maxentities) + { + assert(0); + gi.error ("ED_Alloc: Spawning more than %d edicts", game.maxentities); + } + + globals.num_edicts++; + G_InitEdict (e); + return e; +} + +/* +================= +G_FreeEdict + +Marks the edict as free +================= +*/ +void G_FreeEdict(edict_t *self) +{ + SinglyLinkedList_t msgs; + char *temp; + unsigned int usageCount; + int ready_cull; + int entnum; + + gi.unlinkentity (self); // unlink from world + + // From Quake2 3.17 code release. + + if ((self - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE)) + { +#ifdef _DEVEL + gi.dprintf("tried to free special edict\n"); +#endif + return; + } + + // Start non-quake2. + + // Portals need to be marked as open even if they are freed in deathmatch, only when deliberately removed for netplay. + if (self->classname && level.time <= 0.2) // Just upon startup + { + if (Q_stricmp(self->classname, "func_areaportal") == 0) + gi.SetAreaPortalState (self->style, true); + } + + if(self->s.effects & EF_JOINTED) + { + FreeSkeleton(self->s.rootJoint); + } + + if(self->s.clientEffects.buf) + { + temp = self->s.clientEffects.buf; // buffer needs to be stored to be cleared by the engine + } + else + { + temp = NULL; + } + + msgs = self->msgQ.msgs; + usageCount = self->s.usageCount; + ready_cull = self->ready_cull; + entnum = self->s.number; + + // End non-quake2. + + memset(self, 0, sizeof(*self)); + + // Start non-quake2. + + self->s.usageCount = usageCount; + self->msgQ.msgs = msgs; + self->s.clientEffects.buf = temp; + self->ready_cull = ready_cull|SERVER_DELETED; + self->s.number = entnum; + + // End non-quake2. + + self->classname = "freed"; + self->freetime = level.time + 2.0; + self->inuse = false; + self->s.skeletalType = SKEL_NULL; + + self->svflags = SVF_NOCLIENT; // so it will get removed from the client properly +} + + +/* +============ +G_TouchTriggers + +============ +*/ +void G_TouchTriggers (edict_t *ent) +{ + int i, num; + edict_t *touch[MAX_EDICTS], *hit; + + // dead things don't activate triggers! + if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0)) + return; + + num = gi.BoxEdicts (ent->absmin, ent->absmax, touch + , MAX_EDICTS, AREA_TRIGGERS); + + // be careful, it is possible to have an entity in this + // list removed before we get to it (killtriggered) + for (i=0 ; iinuse) + continue; + if (!hit->touch) + continue; + hit->touch (hit, ent, NULL, NULL); + } +} + +/* +============ +G_TouchSolids + +Call after linking a new trigger in during gameplay +to force all entities it covers to immediately touch it +============ +*/ +void G_TouchSolids (edict_t *ent) +{ + int i, num; + edict_t *touch[MAX_EDICTS], *hit; + + num = gi.BoxEdicts (ent->absmin, ent->absmax, touch + , MAX_EDICTS, AREA_SOLID); + + // be careful, it is possible to have an entity in this + // list removed before we get to it (killtriggered) + for (i=0 ; iinuse) + continue; + if (ent->touch) + ent->touch (hit, ent, NULL, NULL); + if (!ent->inuse) + break; + } +} + + + + +/* +============================================================================== + +Kill box + +============================================================================== +*/ + +/* +================= +KillBox + +Kills all entities that would touch the proposed new positioning +of ent. Ent should be unlinked before calling this! +================= +*/ +qboolean KillBox (edict_t *ent) +{ + edict_t *current=NULL; + vec3_t mins, maxs; + + // since we can't trust the absmin and absmax to be set correctly on entry, I'll create my own versions + + VectorAdd(ent->s.origin, ent->mins, mins); + VectorAdd(ent->s.origin, ent->maxs, maxs); + + while (1) + { + current = findinbounds(current, mins, maxs); + + // don't allow us to kill the player + if(current == ent) + continue; + + // we've checked everything + if(!current) + break; + + // nail it + if (current->takedamage) + T_Damage (current, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, + DAMAGE_NO_PROTECTION|DAMAGE_AVOID_ARMOR|DAMAGE_HURT_FRIENDLY,MOD_TELEFRAG); + + } + + return true; // all clear +} + +/* +ClearBBox + +returns true if there is nothing in you BBOX +*/ + +qboolean ClearBBox (edict_t *self) +{ + vec3_t top, bottom, mins, maxs; + trace_t trace; + VectorSet(mins, self->mins[0], self->mins[1], 0); + VectorSet(maxs, self->maxs[0], self->maxs[1], 1); + VectorSet(bottom, self->s.origin[0], self->s.origin[1], self->absmin[2]); + VectorSet(top, self->s.origin[0], self->s.origin[1], self->absmax[2] - 1); + + gi.trace(top, mins, maxs, bottom, self, self->clipmask,&trace); + if(trace.startsolid || trace.allsolid) + return false; + + if(trace.fraction == 1.0) + return true; + + return false; +} + +/* +================= +oldfindradius + +Returns entities that have origins within a spherical area + +oldfindradius (origin, radius) +================= +*/ +edict_t *oldfindradius (edict_t *from, vec3_t org, float rad) +{ + vec3_t eorg; + int j; + + if (!from) + from = g_edicts; + else + from++; + for ( ; from < &g_edicts[globals.num_edicts]; from++) + { + if (!from->inuse) + continue; + if (from->solid == SOLID_NOT) + continue; + for (j=0 ; j<3 ; j++) + eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5); + if (VectorLength(eorg) > rad) + continue; + return from; + } + + return NULL; +} + + + +// ======================================== +// LinkMissile(edict_t *self) +// +// This is a way to kinda "cheat" the system. +// We don't want missiles to be considered for collision, +// yet we want them to collide with other things. +// So when we link the entity (for rendering, etc) we set +// SOLID_NOT so certain things don't happen. +// ======================================== +void G_LinkMissile(edict_t *self) +{ + int oldsolid; + + oldsolid=self->solid; + +// self->solid=SOLID_NOT; // comment this line out for old behaviour + gi.linkentity(self); + self->solid=oldsolid; +} + diff --git a/Toolkit/Programming/GameCode/game/g_volume_effect.h b/Toolkit/Programming/GameCode/game/g_volume_effect.h new file mode 100644 index 0000000..2132108 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_volume_effect.h @@ -0,0 +1,40 @@ +#ifndef _G_VOLUME_EFFECT_H_ +#define _G_VOLUME_EFFECT_H_ + +#include "q_Typedef.h" +#include "g_local.h" + +#define VE_FLAG1 0x00000001 // place holder + +/*------------------------------------------------------------------------- + volume_effect_s +-------------------------------------------------------------------------*/ +typedef struct volume_effect_s +{ + // fill these fields in when you pass this to AddVolumeEffect + int flags; + vec3_t origin; //center of the volume + vec3_t velocity; //direction that area is moving + float growdelta; //how much it grows/shrinks per think + float radius; //for spherical volumes + float expiration; //time that volume ceases to effect + float think_increment; //frequency of effect in seconds + float nextthinktime; + + void (*effect)(edict_t *ent, struct volume_effect_s *vol); //callback func for effect + + edict_t *owner; //the edict used as "inflictor" or "attacker" + //for damage effects + + struct volume_effect_s *next; // next effect in global list, don't set this + +} volume_effect_t; + + +/*------------------------------------------------------------------------- + Prototypes +-------------------------------------------------------------------------*/ +void VolumeEffectThink(); +volume_effect_t *AddVolumeEffect(edict_t *owner, int flags, float thinkIncrement); + +#endif diff --git a/Toolkit/Programming/GameCode/game/g_waterfx.c b/Toolkit/Programming/GameCode/game/g_waterfx.c new file mode 100644 index 0000000..62c097d --- /dev/null +++ b/Toolkit/Programming/GameCode/game/g_waterfx.c @@ -0,0 +1,392 @@ +// Water related fx, including +// 1. Fountain + +#include "g_local.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#define OBJ_INVULNERABLE 1 +#define OBJ_ANIMATE 2 +#define OBJ_EXPLODING 4 +#define OBJ_NOPUSH 8 + +void BboxYawAndScale(edict_t *self); + +void waterdrip_go(edict_t *self) +{ + byte frame; + + frame = 0; + if(self->spawnflags & 1) + { + frame = 1; + } + + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, FX_DRIPPER, CEF_BROADCAST, + self->s.origin, "bb", self->count, frame); + + self->think = NULL; +} + +void waterdrip_use (edict_t *self, edict_t *other, edict_t *activator) +{ + + if (!self->PersistantCFX) + waterdrip_go(self); + else + { + gi.RemoveEffects(&self->s,0); + self->PersistantCFX = 0; + } +} + +/*QUAKED env_water_drip (1 .5 0) (-4 -4 0) (4 4 4) YELLOW +Spawns a drip of water which falls straight down +---- SPAWN FLAGS ------ +if YELLOW set.. uses a yellow drip +------- KEYS ---------- +count - drips per minute (default 20) +*/ + +// This really ought to be sent over as a flag +// but its a persistant effect, so not critical + +void SP_env_water_drip(edict_t *self) +{ + + if(!self->count) + { + self->count = 20; + } + + self->use = waterdrip_use; + self->solid = SOLID_NOT; + self->s.effects |= EF_NODRAW_ALWAYS_SEND; + gi.linkentity(self); + + self->think = waterdrip_go; + self->nextthink = level.time + 4; + +} + +#define FOUNTAIN_OFF 32 + +void fountain_use (edict_t *self, edict_t *other, edict_t *activator) +{ + byte frame; + short drop; + + drop = -self->delay * 8.0; + frame = 0; + if (self->spawnflags & FOUNTAIN_OFF) + { + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, FX_FOUNTAIN, CEF_BROADCAST, self->s.origin, "vsb", self->s.angles, drop, frame); + self->s.sound = gi.soundindex("ambient/fountainloop.wav"); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; + self->spawnflags &= ~FOUNTAIN_OFF; + } + else + { + gi.RemovePersistantEffect(self->PersistantCFX); + gi.RemoveEffects(&self->s, FX_FOUNTAIN); + self->spawnflags |= FOUNTAIN_OFF; + self->s.sound = 0; + } +} + +/*QUAKED env_water_fountain (1 .5 0) (-4 -4 0) (4 4 4) RED GREEN BLUE DARK DARKER START_OFF +-------SPAWN FLAGS-------- +START_OFF - fountain will be off until triggered + +--------KEYS----------- +angles - xyz velocity of spawned particles +delay - the distance from emitter to ground (128 is Okay, max is 256) + +If targeted it can be turned on/off but it will start on unless START_OFF + +*/ + + +// At the time of creation of this effect, I thought +ve z was down +// Hence the MINUS sign for the distance to fall + +void SP_env_water_fountain(edict_t *self) +{ + byte frame; + short drop; + + if (self->targetname) + { + self->use = fountain_use; + } + + self->s.effects |= EF_NODRAW_ALWAYS_SEND|EF_ALWAYS_ADD_EFFECTS; + gi.linkentity(self); + + if (self->spawnflags & FOUNTAIN_OFF) // Start off + { + return; + } + + drop = -self->delay * 8.0; + frame = 0; + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, FX_FOUNTAIN, CEF_BROADCAST, self->s.origin, "vsb", self->s.angles, drop, frame); + self->s.sound = gi.soundindex("ambient/fountainloop.wav"); + self->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_STATIC; +} + +void SpawnDripper(edict_t *self, vec3_t offset) +{ + vec3_t origin; + + VectorAdd(self->s.origin, offset, origin); + gi.CreatePersistantEffect(NULL, FX_DRIPPER, 0, origin, "bb", self->count, 2); +} + +/*QUAKED env_waterfall_base (1 1 0) (-8 -8 -8) (8 8 8) +angles - this first field is the x radius + second is the yaw + third is the y radius +*/ + +void SP_env_waterfall_base(edict_t *self) +{ + short xrad, yrad; + byte yaw; + + self->s.effects |= EF_NODRAW_ALWAYS_SEND|EF_ALWAYS_ADD_EFFECTS; + + self->svflags = 0; + + xrad = Q_ftol(self->s.angles[0]); + yrad = Q_ftol(self->s.angles[2]); + yaw = Q_ftol((self->s.angles[1] * 256.0) / 360.0); + + gi.linkentity(self); + gi.CreatePersistantEffect(&self->s, FX_WATERFALLBASE, CEF_BROADCAST, self->s.origin, "bbb", xrad, yrad, yaw); + +} + +/*QUAKED obj_fishhead1 (1 .5 0) (0 -76 -86) (136 76 86) NODRIP + Large fish head fountain. No teeth in mouth and the fins on top are connected. Also spawns 4 drips frame 0 +------- FIELDS ------------------ +NODRIP - won't drip +----------------------------------- +*/ +void SP_obj_fishhead1 (edict_t *self) +{ + vec3_t offset; + + if (!(self->spawnflags & 1)) + { + if(!self->count) + self->count = 20; + + VectorSet(offset, -20, -60, -50); + SpawnDripper(self, offset); + VectorSet(offset, 55, 30, -70); + SpawnDripper(self, offset); + VectorSet(offset, 0, 60, -70); + SpawnDripper(self, offset); + VectorSet(offset, 65, -7, -60); + SpawnDripper(self, offset); + } + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Cant push it + + VectorSet(self->mins, 0, -76, -86); + VectorSet(self->maxs, 136, 76, 86); + self->s.modelindex = gi.modelindex("models/objects/fishheads/fishhead1/tris.fm"); + + ObjectInit(self,100,500,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAKED obj_fishhead2 (1 .5 0) (0 -110 -118) (136 110 118) NODRIP +Large fish head fountain. The mouth has teeth. The fins on top are not conntected. Also spawns 4 drips frame 0 +------- FIELDS ------------------ +NODRIP - won't drip +----------------------------------- +*/ +void SP_obj_fishhead2 (edict_t *self) +{ + vec3_t offset; + + if (!(self->spawnflags & 1)) + { + if(!self->count) + self->count = 20; + + VectorSet(offset, -20, -60, -50); + SpawnDripper(self, offset); + VectorSet(offset, 55, 30, -70); + SpawnDripper(self, offset); + VectorSet(offset, 0, 60, -70); + SpawnDripper(self, offset); + VectorSet(offset, 65, -7, -60); + SpawnDripper(self, offset); + } + + VectorSet(self->mins, 0, -110, -118); + VectorSet(self->maxs, 136, 110, 118); + self->s.modelindex = gi.modelindex("models/objects/fishheads/fishhead2/tris.fm"); + + self->spawnflags |= OBJ_INVULNERABLE; // Always indestructible + self->spawnflags |= OBJ_NOPUSH; // Cant push it + self->takedamage = DAMAGE_NO; + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_BBOX; + self->takedamage = DAMAGE_NO; + self->clipmask = MASK_MONSTERSOLID; + + BboxYawAndScale(self); + + + + gi.linkentity(self); +// ObjectInit(self,100,500,MAT_GREYSTONE,SOLID_BBOX); +} + +/*QUAK-ED obj_stalactite1 (1 .5 0) (-24 -24 -99) (24 24 99) DRIP DARKSKIN + + A big long thick stalactite. These point down. + + DARKSKIN - if checked it uses the dark skin + Also spawns a drip at the end + Use the "count" field as number of drips per min +*/ +void SP_obj_stalactite1(edict_t *self) +{ + vec3_t origin; + + if(self->spawnflags & 1) + { + if(!self->count) + self->count = 20; + + VectorCopy(self->s.origin, origin); + origin[2] += 200.0F; + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_DRIPPER, 0, origin, "bb", self->count, 2); + } + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_BBOX; + + VectorSet(self->mins, -24, -24, -99); + VectorSet(self->maxs, 24, 24, 99); + + self->s.modelindex = gi.modelindex("models/objects/stalactite/stalact1/tris.fm"); + if (self->spawnflags & 2) + self->s.skinnum = 1; + + gi.linkentity(self); +} + + +/*QUAK-ED obj_stalactite2 (1 .5 0) (-60 -60 -64) (60 60 64) DRIP DARKSKIN + + A big short stalactite. These point down. + + DARKSKIN - if checked it uses the dark skin + Also spawns a drip at the end + Use the "count" field as number of drips per min +*/ +void SP_obj_stalactite2(edict_t *self) +{ + vec3_t origin; + + if(self->spawnflags & 1) + { + if(!self->count) + self->count = 20; + + VectorCopy(self->s.origin, origin); + origin[2] += 128.0F; + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_DRIPPER, 0, origin, "bb", self->count, 2); + } + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_BBOX; + + VectorSet(self->mins,-60,-60,-64); + VectorSet(self->maxs,60,60,64); + + self->s.modelindex = gi.modelindex("models/objects/stalactite/stalact2/tris.fm"); + if (self->spawnflags & 2) + self->s.skinnum = 1; + + gi.linkentity(self); +} + +/*QUAK-ED obj_stalactite3 (1 .5 0) (-23 -23 -98) (23 23 98) DRIP DARKSKIN + + A long pointy stalactite. These point down. + + DARKSKIN - if checked it uses the dark skin + Also spawns a drip at the end + Use the "count" field as number of drips per min +*/ +void SP_obj_stalactite3(edict_t *self) +{ + vec3_t origin; + + if(self->spawnflags & 1) + { + if(!self->count) + self->count = 20; + + VectorCopy(self->s.origin, origin); + origin[2] += 200.0F; + self->PersistantCFX = gi.CreatePersistantEffect(NULL, FX_DRIPPER, 0, origin, "bb", self->count, 2); + } + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_BBOX; + + VectorSet(self->mins, -23, -23, -98); + VectorSet(self->maxs, 23, 23, 98); + + self->s.modelindex = gi.modelindex("models/objects/stalactite/stalact3/tris.fm"); + if (self->spawnflags & 2) + self->s.skinnum = 1; + + gi.linkentity(self); +} + +/*QUAKED env_mist (1 .5 0) (-64 -1 -32) (64 1 32) +scale sets the scale +*/ +void SP_env_mist(edict_t *self) +{ + byte scale; + + self->s.effects |= EF_ALWAYS_ADD_EFFECTS; + scale = Q_ftol(self->s.scale * 10.0); + VectorSet(self->mins, -5, -5, -5); + VectorSet(self->maxs, 5, 5, 5); + + gi.CreatePersistantEffect(&self->s, FX_MIST, CEF_BROADCAST, self->s.origin, "b", scale); + gi.linkentity(self); +} + +/*QUAKED env_bubbler (1 .5 0) (-4 -4 0) (4 4 4) +Makes bubbles +---------KEYS-------- +count - bubbles spawned per minute +*/ +void SP_env_bubbler(edict_t *self) +{ + if(!self->count) + self->count = 120; + VectorSet(self->mins, -5, -5, -5); + VectorSet(self->maxs, 5, 5, 5); + + self->s.effects |= EF_ALWAYS_ADD_EFFECTS; + gi.CreatePersistantEffect(&self->s, FX_BUBBLER, CEF_BROADCAST, self->s.origin, "b", self->count); + gi.linkentity(self); +} + +// end + diff --git a/Toolkit/Programming/GameCode/game/game.def b/Toolkit/Programming/GameCode/game/game.def new file mode 100644 index 0000000..df4958f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/game.def @@ -0,0 +1,2 @@ +EXPORTS + GetGameAPI diff --git a/Toolkit/Programming/GameCode/game/game.dsp b/Toolkit/Programming/GameCode/game/game.dsp new file mode 100644 index 0000000..f05018c --- /dev/null +++ b/Toolkit/Programming/GameCode/game/game.dsp @@ -0,0 +1,1545 @@ +# Microsoft Developer Studio Project File - Name="game" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=game - Win32 Release +!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 "game.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 "game.mak" CFG="game - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "game - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "game - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "game - Win32 Final" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/SOF/Code/game", RQIAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "game - 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 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MT /W3 /Zi /O2 /I "..\qcommon" /I "..\game" /I "..\Player" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_HERETIC2_" /D "_DEVEL" /D "_GAME_DLL" /FR /Fp"" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /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 /dll /machine:I386 +# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib H2Common.lib quake2.lib /nologo /base:"0x10F50000" /version:1.0 /subsystem:windows /dll /profile /debug /machine:I386 /out:"..\Release/gamex86.dll" /libpath:"../Release" + +!ELSEIF "$(CFG)" == "game - 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 /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MTd /W3 /Gm /Gi /Zi /Od /I "..\qcommon" /I "..\game" /I "..\Player" /D "_DEBUG" /D "BUILDING_REF_GL" /D "WIN32" /D "_WINDOWS" /D "_HERETIC2_" /D "_DEVEL" /D "_GAME_DLL" /FR /Fp"" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /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 /dll /debug /machine:I386 +# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib H2Common.lib quake2.lib /nologo /base:"0x10F50000" /version:1.0 /subsystem:windows /dll /debug /machine:I386 /out:"..\Debug/gamex86.dll" /libpath:"../Debug" +# SUBTRACT LINK32 /incremental:no + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Final" +# PROP BASE Intermediate_Dir "Final" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\Final" +# PROP Intermediate_Dir ".\Final" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /Zi /O2 /I "..\qcommon" /I "..\game" /I "..\Player" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_HERETIC2_" /D "_DEVEL" /D "_GAME_DLL" /FR /Fp"" /YX /FD /c +# ADD CPP /nologo /MT /W3 /O2 /I "..\qcommon" /I "..\game" /I "..\Player" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_HERETIC2_" /D "_GAME_DLL" /Fp"" /YX /FD /c +# SUBTRACT CPP /Fr +# 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 winmm.lib kernel32.lib user32.lib gdi32.lib H2Common.lib quake2.lib /nologo /version:1.0 /subsystem:windows /dll /profile /debug /machine:I386 /out:"..\Release/gamex86.dll" /libpath:"../Release" +# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib H2Common.lib quake2.lib /nologo /base:"0x10F50000" /version:1.0 /subsystem:windows /dll /machine:I386 /out:"..\base/gamex86.dll" /libpath:"../Final" /release +# SUBTRACT LINK32 /profile /debug + +!ENDIF + +# Begin Target + +# Name "game - Win32 Release" +# Name "game - Win32 Debug" +# Name "game - Win32 Final" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\buoy.c +# End Source File +# Begin Source File + +SOURCE=.\c_ai.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus1.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus1_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus2.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus2_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus3.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus3_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus4.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus4_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus5.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus5_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus6.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus6_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus7.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus7_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus8.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus8_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus9.c +# End Source File +# Begin Source File + +SOURCE=.\c_corvus9_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_dranor.c +# End Source File +# Begin Source File + +SOURCE=.\c_dranor_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_elflord.c +# End Source File +# Begin Source File + +SOURCE=.\c_elflord_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_morcalavin.c +# End Source File +# Begin Source File + +SOURCE=.\c_morcalavin_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_priestess.c +# End Source File +# Begin Source File + +SOURCE=.\c_priestess2.c +# End Source File +# Begin Source File + +SOURCE=.\c_priestess2_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_priestess_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_siernan1.c +# End Source File +# Begin Source File + +SOURCE=.\c_siernan1_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_siernan2.c +# End Source File +# Begin Source File + +SOURCE=.\c_siernan2_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_ssithrascout.c +# End Source File +# Begin Source File + +SOURCE=.\c_ssithrascout_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_tome.c +# End Source File +# Begin Source File + +SOURCE=.\c_tome_anim.c +# End Source File +# Begin Source File + +SOURCE=.\c_victimSsithra.c +# End Source File +# Begin Source File + +SOURCE=.\c_victimSsithra_anim.c +# End Source File +# Begin Source File + +SOURCE=.\decals.c +# End Source File +# Begin Source File + +SOURCE=.\decals.h +# End Source File +# Begin Source File + +SOURCE=.\ds.cpp +# End Source File +# Begin Source File + +SOURCE=.\g_ai.c +# End Source File +# Begin Source File + +SOURCE=.\g_breakable.c +# End Source File +# Begin Source File + +SOURCE=.\g_ClassStatics.c +# End Source File +# Begin Source File + +SOURCE=.\g_cmds.c +# End Source File +# Begin Source File + +SOURCE=.\g_combat.c +# End Source File +# Begin Source File + +SOURCE=.\g_DefaultMessageHandler.c +# End Source File +# Begin Source File + +SOURCE=.\g_env.c +# End Source File +# Begin Source File + +SOURCE=.\g_field.c +# End Source File +# Begin Source File + +SOURCE=.\g_flamethrow.c +# End Source File +# Begin Source File + +SOURCE=.\g_func.c +# End Source File +# Begin Source File + +SOURCE=.\g_HitLocation.c +# End Source File +# Begin Source File + +SOURCE=.\g_items.c +# End Source File +# Begin Source File + +SOURCE=.\g_light.c +# End Source File +# Begin Source File + +SOURCE=.\g_main.c +# End Source File +# Begin Source File + +SOURCE=.\g_Message.c +# End Source File +# Begin Source File + +SOURCE=.\g_misc.c +# End Source File +# Begin Source File + +SOURCE=.\g_monster.c +# End Source File +# Begin Source File + +SOURCE=.\g_obj.c +# End Source File +# Begin Source File + +SOURCE=.\g_phys.c +# End Source File +# Begin Source File + +SOURCE=.\g_Physics.c +# End Source File +# Begin Source File + +SOURCE=.\g_ResourceManagers.c +# End Source File +# Begin Source File + +SOURCE=.\g_rope.c +# End Source File +# Begin Source File + +SOURCE=.\g_save.c +# End Source File +# Begin Source File + +SOURCE=.\g_shrine.c +# End Source File +# Begin Source File + +SOURCE=.\g_Skeletons.c +# End Source File +# Begin Source File + +SOURCE=.\g_spawn.c +# End Source File +# Begin Source File + +SOURCE=.\g_spawnf.c +# End Source File +# Begin Source File + +SOURCE=.\g_surface.c +# End Source File +# Begin Source File + +SOURCE=.\g_svcmds.c +# End Source File +# Begin Source File + +SOURCE=.\g_target.c +# End Source File +# Begin Source File + +SOURCE=.\g_trigger.c +# End Source File +# Begin Source File + +SOURCE=.\g_utils.c +# End Source File +# Begin Source File + +SOURCE=.\g_waterfx.c +# End Source File +# Begin Source File + +SOURCE=.\m_assassin.c +# End Source File +# Begin Source File + +SOURCE=.\m_assassin_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_beast.c +# End Source File +# Begin Source File + +SOURCE=.\m_beast_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_bee.c +# End Source File +# Begin Source File + +SOURCE=.\m_chicken.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_chicken_anim.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_elflord.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_elflord_anims.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_fish.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_fish_anim.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_FMtest.c +# End Source File +# Begin Source File + +SOURCE=.\m_gkrokon.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_gkrokon_anim.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_gorgon.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_gorgon_anim.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_harpy.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_harpy_anim.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_imp.c +# End Source File +# Begin Source File + +SOURCE=.\m_imp_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_morcalavin.c +# End Source File +# Begin Source File + +SOURCE=.\m_morcalavin_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_mother.c +# End Source File +# Begin Source File + +SOURCE=.\m_mother_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_move.c +# End Source File +# Begin Source File + +SOURCE=.\m_mssithra.c +# End Source File +# Begin Source File + +SOURCE=.\m_mssithra_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_ogle.c +# End Source File +# Begin Source File + +SOURCE=.\m_ogle_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_plagueElf.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_plagueElf_anim.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_plagueSsithra.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_plagueSsithra_anim.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_priestess.c +# End Source File +# Begin Source File + +SOURCE=.\m_priestess_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_rat.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_rat_anim.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_seraph.c +# End Source File +# Begin Source File + +SOURCE=.\m_seraph_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_seraph_guard.c +# End Source File +# Begin Source File + +SOURCE=.\m_seraph_guard_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_spreader.c + +!IF "$(CFG)" == "game - Win32 Release" + +# ADD CPP /O2 /Yc"" + +!ELSEIF "$(CFG)" == "game - Win32 Debug" + +# ADD CPP /Yc + +!ELSEIF "$(CFG)" == "game - Win32 Final" + +# ADD BASE CPP /O2 /Yc"" +# ADD CPP /O2 /Yc"" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\m_spreader_anim.c +# ADD CPP /Yc +# End Source File +# Begin Source File + +SOURCE=.\m_spreadermist.c +# End Source File +# Begin Source File + +SOURCE=.\m_stats.c +# End Source File +# Begin Source File + +SOURCE=.\m_tcheckrik.c +# End Source File +# Begin Source File + +SOURCE=.\m_tcheckrik_anim.c +# End Source File +# Begin Source File + +SOURCE=.\m_tcheckrik_spells.c +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Message.c +# End Source File +# Begin Source File + +SOURCE=.\mg_ai.c +# End Source File +# Begin Source File + +SOURCE=.\mg_guide.c +# End Source File +# Begin Source File + +SOURCE=.\p_client.c +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_dll.c +# End Source File +# Begin Source File + +SOURCE=.\p_funcs.c +# End Source File +# Begin Source File + +SOURCE=.\p_hud.c +# End Source File +# Begin Source File + +SOURCE=.\p_item.c +# End Source File +# Begin Source File + +SOURCE=.\p_view.c +# End Source File +# Begin Source File + +SOURCE=.\p_weapon.c +# End Source File +# Begin Source File + +SOURCE=.\Script.c +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Skeletons.c +# End Source File +# Begin Source File + +SOURCE=.\spl_blast.c +# End Source File +# Begin Source File + +SOURCE=.\spl_BlueRing.c +# End Source File +# Begin Source File + +SOURCE=.\spl_flyingfist.c +# End Source File +# Begin Source File + +SOURCE=.\spl_HellStaff.c +# End Source File +# Begin Source File + +SOURCE=.\spl_maceballs.c +# End Source File +# Begin Source File + +SOURCE=.\spl_magicmissile.c +# End Source File +# Begin Source File + +SOURCE=.\spl_meteorbarrier.c +# End Source File +# Begin Source File + +SOURCE=.\spl_morph.c +# End Source File +# Begin Source File + +SOURCE=.\spl_Phoenix.c +# End Source File +# Begin Source File + +SOURCE=.\spl_powerup.c +# End Source File +# Begin Source File + +SOURCE=.\spl_RedRain.c +# End Source File +# Begin Source File + +SOURCE=.\spl_ripper.c +# End Source File +# Begin Source File + +SOURCE=.\spl_shield.c +# End Source File +# Begin Source File + +SOURCE=.\spl_sphereofannihlation.c +# End Source File +# Begin Source File + +SOURCE=.\spl_teleport.c +# End Source File +# Begin Source File + +SOURCE=.\spl_wall.c +# End Source File +# Begin Source File + +SOURCE=.\Utilities.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=..\qcommon\Angles.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\ArrayedList.h +# End Source File +# Begin Source File + +SOURCE=.\buoy.h +# End Source File +# Begin Source File + +SOURCE=.\c_ai.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus1.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus1_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus2.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus2_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus3.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus3_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus4.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus4_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus5.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus5_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus6.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus6_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus7.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus7_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus8.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus8_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus9.h +# End Source File +# Begin Source File + +SOURCE=.\c_corvus9_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_Dranor.h +# End Source File +# Begin Source File + +SOURCE=.\c_dranor_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_elflord.h +# End Source File +# Begin Source File + +SOURCE=.\c_elflord_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_morcalavin.h +# End Source File +# Begin Source File + +SOURCE=.\c_morcalavin_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_priestess.h +# End Source File +# Begin Source File + +SOURCE=.\c_priestess2.h +# End Source File +# Begin Source File + +SOURCE=.\c_priestess2_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_priestess_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_siernan1.h +# End Source File +# Begin Source File + +SOURCE=.\c_siernan1_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_siernan2.h +# End Source File +# Begin Source File + +SOURCE=.\c_siernan2_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_ssithrascout.h +# End Source File +# Begin Source File + +SOURCE=.\c_ssithrascout_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_tome.h +# End Source File +# Begin Source File + +SOURCE=.\c_tome_anim.h +# End Source File +# Begin Source File + +SOURCE=.\c_victimSsithra.h +# End Source File +# Begin Source File + +SOURCE=.\c_victimSsithra_anim.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\cl_strings.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\compfmod.h +# End Source File +# Begin Source File + +SOURCE=.\ds.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\EffectFlags.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\FX.h +# End Source File +# Begin Source File + +SOURCE=.\g_BoundingForm.h +# End Source File +# Begin Source File + +SOURCE=.\g_ClassStatics.h +# End Source File +# Begin Source File + +SOURCE=.\g_DefaultMessageHandler.h +# End Source File +# Begin Source File + +SOURCE=.\g_Edict.h +# End Source File +# Begin Source File + +SOURCE=.\g_HitLocation.h +# End Source File +# Begin Source File + +SOURCE=.\g_items.h +# End Source File +# Begin Source File + +SOURCE=.\g_itemstats.h +# End Source File +# Begin Source File + +SOURCE=.\g_local.h +# End Source File +# Begin Source File + +SOURCE=.\g_Message.h +# End Source File +# Begin Source File + +SOURCE=.\g_misc.h +# End Source File +# Begin Source File + +SOURCE=.\g_monster.h +# End Source File +# Begin Source File + +SOURCE=.\g_NewSystem.h +# End Source File +# Begin Source File + +SOURCE=.\g_Physics.h +# End Source File +# Begin Source File + +SOURCE=.\g_playstats.h +# End Source File +# Begin Source File + +SOURCE=.\g_Skeleton.h +# End Source File +# Begin Source File + +SOURCE=.\g_Skeletons.h +# End Source File +# Begin Source File + +SOURCE=.\g_surface.h +# End Source File +# Begin Source File + +SOURCE=.\g_teleport.h +# End Source File +# Begin Source File + +SOURCE=.\g_Typedef.h +# End Source File +# Begin Source File + +SOURCE=.\g_volume_effect.h +# End Source File +# Begin Source File + +SOURCE=.\game.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\GenericUnions.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\H2Common.h +# End Source File +# Begin Source File + +SOURCE=.\ICScript.h +# End Source File +# Begin Source File + +SOURCE=.\list.h +# End Source File +# Begin Source File + +SOURCE=.\m_actor.h +# End Source File +# Begin Source File + +SOURCE=.\m_assassin.h +# End Source File +# Begin Source File + +SOURCE=.\m_assassin_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_beast.h +# End Source File +# Begin Source File + +SOURCE=.\m_beast_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_chicken.h +# End Source File +# Begin Source File + +SOURCE=.\m_chicken_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_elf.h +# End Source File +# Begin Source File + +SOURCE=.\m_elflord.h +# End Source File +# Begin Source File + +SOURCE=.\m_elflord_anims.h +# End Source File +# Begin Source File + +SOURCE=.\m_fish.h +# End Source File +# Begin Source File + +SOURCE=.\m_fish_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_gkrokon.h +# End Source File +# Begin Source File + +SOURCE=.\m_gkrokon_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_gorgon.h +# End Source File +# Begin Source File + +SOURCE=.\m_gorgon_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_harpy.h +# End Source File +# Begin Source File + +SOURCE=.\m_harpy_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_imp.h +# End Source File +# Begin Source File + +SOURCE=.\m_imp_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_morcalavin.h +# End Source File +# Begin Source File + +SOURCE=.\m_morcalavin_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_mother.h +# End Source File +# Begin Source File + +SOURCE=.\m_mother_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_mssithra.h +# End Source File +# Begin Source File + +SOURCE=.\m_mssithra_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_ogle.h +# End Source File +# Begin Source File + +SOURCE=.\m_ogle_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_plagueElf.h +# End Source File +# Begin Source File + +SOURCE=.\m_plagueElf_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_plagueSsithra.h +# End Source File +# Begin Source File + +SOURCE=.\m_plagueSsithra_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_player.h +# End Source File +# Begin Source File + +SOURCE=.\m_priestess.h +# End Source File +# Begin Source File + +SOURCE=.\m_priestess_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_rat.h +# End Source File +# Begin Source File + +SOURCE=.\m_rat_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_seraph.h +# End Source File +# Begin Source File + +SOURCE=.\m_seraph_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_seraph_guard.h +# End Source File +# Begin Source File + +SOURCE=.\m_seraph_guard_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_spreader.h +# End Source File +# Begin Source File + +SOURCE=.\m_spreader_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_spreaderbomb_anim.h +# End Source File +# Begin Source File + +SOURCE=.\m_spreadermist.h +# End Source File +# Begin Source File + +SOURCE=.\m_stats.h +# End Source File +# Begin Source File + +SOURCE=.\m_tcheckrik.h +# End Source File +# Begin Source File + +SOURCE=.\m_tcheckrik_anim.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Matrix.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Message.h +# End Source File +# Begin Source File + +SOURCE=.\mg_guide.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_actions2.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_anim_branch2.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_anim_data2.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_animactor.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_anims2.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_chicken.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_ctrl2.h +# End Source File +# Begin Source File + +SOURCE=.\p_funcs.h +# End Source File +# Begin Source File + +SOURCE=.\p_item.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_main2.h +# End Source File +# Begin Source File + +SOURCE=..\Player\P_NewMove.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_types.h +# End Source File +# Begin Source File + +SOURCE=.\p_weapon.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\p_weapon2.h +# End Source File +# Begin Source File + +SOURCE=.\pcode.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Placement.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\PrimitiveDisplayHack.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_ClientServer.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_Physics.h +# End Source File +# Begin Source File + +SOURCE=.\q_shared.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_Surface.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_Typedef.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\random.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Reference.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\ResourceManager.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\SinglyLinkedList.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Skeletons.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\timing.h +# End Source File +# Begin Source File + +SOURCE=.\Utilities.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Vector.h +# End Source File +# Begin Source File + +SOURCE=.\waypoint.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\game.def +# End Source File +# End Group +# End Target +# End Project diff --git a/Toolkit/Programming/GameCode/game/game.dsw b/Toolkit/Programming/GameCode/game/game.dsw new file mode 100644 index 0000000..330b7b6 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/game.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "game"=.\game.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Toolkit/Programming/GameCode/game/game.h b/Toolkit/Programming/GameCode/game/game.h new file mode 100644 index 0000000..36ad0f1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/game.h @@ -0,0 +1,369 @@ +// game.h -- game dll information visible to server. + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN +#include + +#include "q_ClientServer.h" +#include "g_NewSystem.h" +#include "g_BoundingForm.h" + +#define GAME_API_VERSION 3 + +// ************************************************************************************************ +// 'SVF_XXX'. +// ---------- +// Held in 'edict_t'->svflags. +// ************************************************************************************************ + +#define SVF_NOCLIENT 0x00000001 // Don't send entity to clients, even if it has effects. + // This overides SVF_ALWAYS_SEND +#define SVF_DEADMONSTER 0x00000002 // Treat as CONTENTS_DEADMONSTER for collision. +#define SVF_MONSTER 0x00000004 // Treat as CONTENTS_MONSTER for collision. +#define SVF_INUSE 0x00000008 // Used to replace the inuse field. +#define SVF_ALWAYS_SEND 0x00000010 // Always send the ent to all the clients, regardless of + // of PVS or view culling +#define SVF_NO_AUTOTARGET 0x00000020 // This entity will not be chosen by FindNearestVisibleActorInFrustum +#define SVF_REFLECT 0x00000040 // Reflect shots +#define SVF_TAKE_NO_IMPACT_DMG 0x00000080 // Don't apply impact damage to this entity +#define SVF_BOSS 0x00000100 // Immunity to a number of things +#define SVF_TOUCHED_BEAST 0x00000200 // Used for beast faked physics hack +#define SVF_DO_NO_IMPACT_DMG 0x00000400 // This entity Doesn't do impact damage to others +#define SVF_NO_PLAYER_DAMAGE 0x00000800 // This entity Doesn't take damage from players +#define SVF_PARTS_GIBBED 0x00001000 // Used to delay gibbing so monsters can throw body parts +#define SVF_WAIT_NOTSOLID 0x00002000 // Hacky flag to postpone dead monsters from turning notsolid +#define SVF_ONFIRE 0x00004000 // He likes it Hot! Hot! Hot! +#define SVF_SHOW_START_BUOY 0x00008000 // just puts an effect on a buoy for showbuoy debug mode +#define SVF_SHOW_END_BUOY 0x00010000 // just puts an effect on a buoy for showbuoy debug mode +#define SVF_FLOAT 0x00020000 // Allows walkmonsters to walk off ledges, assumes a low gravity +#define SVF_ALLOW_AUTO_TARGET 0x00040000 // Used to allow player to autotarget non-monsters +#define SVF_ALERT_NO_SHADE 0x00080000 // only used by alert_entity to make monsters check the alert as a sound alert + + +// ************************************************************************************************ +// 'solid_t'. +// ---------- +// edict->solid values +// ************************************************************************************************ + +typedef enum +{ + SOLID_NOT, // No interaction with other objects. + SOLID_TRIGGER, // Only touch when inside, after moving. + SOLID_BBOX, // Touch on edge. + SOLID_BSP // BSP clip, touch on edge. +} solid_t; + +// ************************************************************************************************ +// 'link_t'. +// --------- +// Only used for entity area links. +// ************************************************************************************************ + +typedef struct link_s +{ + struct link_s *prev,*next; +} link_t; + +#define MAX_ENT_CLUSTERS 16 + +// Forward define these two as they are needed below. + +typedef struct gclient_s gclient_t; + +// Do not define the following short, server-visible 'gclient_t' and 'edict_t' structures because +// when we are being #inclued in g_local.h. + +#ifndef GAME_INCLUDE + +// ************************************************************************************************ +// 'gclient_t'. +// ------------ +// This structure is cleared on each PutClientInServer(). +// ************************************************************************************************ + +typedef struct gclient_s +{ + // Following two fields are known to the server. + + player_state_t ps; // Communicated by server to clients. + int ping; + + // DO NOT MODIFY ANYTHING ABOVE THIS! THE SERVER EXPECTS THE FIELDS IN THAT ORDER! The game dll + // can add anything it wants after this point. + + //============================================================================================= +} gclient_t; + +// ************************************************************************************************ +// 'edict_s'. +// ------------ +// ************************************************************************************************ + +struct edict_s +{ + // This is sent to the server as part of each client frame. + + entity_state_t s; + + // NULL if not a player. The server expects the first part of a 'gclient_s' to be a + // 'player_state_t' but the rest of it is opaque. + + struct gclient_s *client; + + // House keeping information not used by the game logic. + + qboolean inuse; + int ready_cull; + int linkcount; + + // FIXME: move these fields to a server private sv_entity_t + + link_t area; // Linked to a division node or leaf. + int num_clusters; // If -1, use headnode instead. + int clusternums[MAX_ENT_CLUSTERS]; + int headnode; // Unused if num_clusters is -1. + int areanum,areanum2; + + int svflags; + + edict_t *groundentity; // entity serving as ground + int groundentity_linkcount; // if self and groundentity's don't match, groundentity should be cleared + vec3_t groundNormal; // normal of the ground + + vec3_t intentMins, intentMaxs; // if PF_RESIZE is set, then physics will attempt to change + // the ents bounding form to the new one indicated + // If it was succesfully resized, the PF_RESIZE is turned off + // otherwise it will remain on. + + solid_t solid; + int clipmask; + edict_t *owner; + + vec3_t mins,maxs; + vec3_t absmin,absmax,size; + + // called when self is the collidee in a collision, resulting in the impediment or bouncing of trace->ent + void (*isBlocking)(edict_t *self, struct trace_s *trace); + + // The game dll can add anything it wants after this point in the edict_t in g_Edict.h. + + //============================================================================================= +}; + +#endif // GAME_INCLUDE + +// ************************************************************************************************ +// 'game_import_t'. +// ---------------- +// The game dll imports these functions which are provided by the main engine code. +// ************************************************************************************************ + +typedef struct +{ + // Special message printing routines. + + void (*bprintf) (int printlevel, char *fmt, ...); + void (*bcaption) (int printlevel, short stringid); + void (*Obituary) (int printlevel, short stringid, short client1, short client2); + void (*dprintf) (char *fmt, ...); + void (*cprintf) (edict_t *ent, int printlevel, char *fmt, ...); + void (*centerprintf) (edict_t *ent, char *fmt, ...); + void (*gamemsg_centerprintf) (edict_t *ent, short msg); + void (*levelmsg_centerprintf) (edict_t *ent, short msg); + void (*msgvar_centerprintf) (edict_t *ent, short msg, int vari); + void (*msgdual_centerprintf) (edict_t *ent, short msg1, short msg2); + void (*captionprintf) (edict_t *ent, short msg); + + // Sound playing routines. + + void (*sound) (edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs); + void (*positioned_sound) (vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs); + + // Config strings hold all the index strings, the lightstyles and misc data, like the sky + // definition and cdtrack. All of the current configstrings are sent to clients when they + // connect and changes are sent to all connected clients. + + void (*configstring) (int num, char *string); + + // Error, bailout routine. + + void (*error) (char *fmt, ...); + + // routine that sends over new CD track + void (*changeCDtrack) (edict_t *ent, int track, int loop ); + + // New names can only be added during spawning but existing names can be looked up at any time. + + void (*cleanlevel) (void); + int (*modelindex) (char *name); + void (*modelremove) (char *name); + int (*soundindex) (char *name); + void (*soundremove) (char *name); + int (*imageindex) (char *name); + + void (*setmodel) (edict_t *ent, char *name); + + // Collision detection. + + void (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask,trace_t *tr); + int (*pointcontents) (vec3_t point); + + // Potentially visible / invisible set routines. + + qboolean (*inPVS) (vec3_t p1, vec3_t p2); + qboolean (*inPHS) (vec3_t p1, vec3_t p2); + void (*SetAreaPortalState) (int portalnum, qboolean open); + qboolean (*AreasConnected) (int area1, int area2); + + // An entity will never be sent to a client or used for collision if it is not passed to + // linkentity. If the size, position, or solidity changes, it must be relinked. + + void (*linkentity) (edict_t *ent); + void (*unlinkentity) (edict_t *ent); // Call before removing an interactive edict. + int (*BoxEdicts) (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype); + void (*Pmove) (pmove_t *pmove, qboolean server); // Player movement code, common with client prediction. + + // New_Physics + + int (*FindEntitiesInBounds) (vec3_t mins, vec3_t maxs, struct SinglyLinkedList_s *list, int areatype); + void (*TraceBoundingForm) (struct FormMove_s *formMove); + qboolean (*ResizeBoundingForm) (edict_t *self, struct FormMove_s *formMove); + int (*GetContentsAtPoint) (vec3_t point); + qboolean (*CheckDistances)(vec3_t origin, float dist); + + // End New_Physics + + // Network messaging services. + + void (*multicast) (vec3_t origin, multicast_t to); + void (*unicast) (edict_t *ent, qboolean reliable); + void (*WriteChar) (int c); + void (*WriteByte) (int c); + void (*WriteShort) (int c); + void (*WriteLong) (int c); + void (*WriteFloat) (float f); + void (*WriteString) (char *s); + void (*WritePosition) (vec3_t pos); // Some fractional bits. + void (*WriteDir) (vec3_t pos); // Single byte encoded, very coarse. + void (*WriteAngle) (float f); + void (*CreateEffect) (entity_state_t *ent, int type, int flags, vec3_t origin, char *format, ...); + int (*CreatePersistantEffect) (entity_state_t *ent, int type, int flags, vec3_t origin, char *format, ...); + qboolean (*RemovePersistantEffect) (int toRemove); + // removes the effect from the server's persistant effect list. + // The effect is not removed on the client + // This should be done by removing the effects from the owning entity or freeing + + void (*RemoveEffects)(entity_state_t *ent, int type); + + // Managed memory allocation. + + void *(*TagMalloc) (int size, int tag); + void (*TagFree) (void *block); + void (*FreeTags) (int tag); + + // Console variable interaction. + + cvar_t *(*cvar) (char *var_name, char *value, int flags); + cvar_t *(*cvar_set) (char *var_name, char *value); + cvar_t *(*cvar_forceset) (char *var_name, char *value); + + // ClientCommand and console command parameter checking. + + int (*argc) (void); + char *(*argv) (int n); + char *(*args) (void); + + // Add commands to the server console as if they were typed in for map changing, etc. + + void (*AddCommandString) (char *text); + + // Debugging aid. + + void (*DebugGraph) (float value, byte r, byte g, byte b); + + // Files will be memory mapped read only. The returned buffer may be part of a larger '.pak' + // file, or a discrete file from anywhere in the quake search path. A -1 return means the file + // does not exist. NULL can be passed for buf to just determine existance. + + int (*FS_LoadFile) (char *name, void **buf); + void (*FS_FreeFile) (void *buf); + + void (*Sys_LoadGameDll)(const char *name, HINSTANCE *hinst, DWORD *chkSum); + void (*Sys_UnloadGameDll)(const char *name, HINSTANCE *hinst); + + // pointer to the server side persistant effects arrary + void (*ClearPersistantEffects) (void); + void *Persistant_Effects_Array; + +} game_import_t; + +// ************************************************************************************************ +// 'game_export_t'. +// ---------------- +// The game dll exports these functions. +// ************************************************************************************************ + +typedef struct +{ + int apiversion; + + int numSkeletalJoints; + struct G_SkeletalJoint_s *skeletalJoints; + struct ArrayedListNode_s *jointNodes; + + // The init() function will only be called when a game starts, not each time a level is loaded. + // Persistant data for clients and the server can be allocated in init(). + + void (*Init) (void); + void (*Shutdown) (void); + + // Each new level entered will cause a call to SpawnEntities(). + + void (*SpawnEntities) (char *mapname, char *entstring, char *spawnpoint, qboolean loadgame); + void (*ConstructEntities)(void); + void (*CheckCoopTimeout)(qboolean BeenHereBefore); + + // Read/Write Game is for storing persistant cross level information about the world state and + // the clients. WriteGame is called every time a level is exited. ReadGame is called on a + // loadgame. + + void (*WriteGame) (char *filename, qboolean autosave); + void (*ReadGame) (char *filename); + + // ReadLevel is called after the default map information has been loaded with SpawnEntities, so + // any stored client spawn spots will be used when the clients reconnect. + + void (*WriteLevel) (char *filename); + void (*ReadLevel) (char *filename); + + // + + qboolean (*ClientConnect) (edict_t *ent, char *userinfo); + void (*ClientBegin) (edict_t *ent); + void (*ClientUserinfoChanged) (edict_t *ent, char *userinfo); + void (*ClientDisconnect) (edict_t *ent); + void (*ClientCommand) (edict_t *ent); + void (*ClientThink) (edict_t *ent, usercmd_t *cmd); + + // + + void (*RunFrame) (void); + + // ServerCommand will be called when an "sv " command is issued on the server console. + // The game can issue gi.argc() / gi.argv() commands to get the rest of the parameters. + + void (*ServerCommand) (void); + + + // Global variables shared between game and server. The edict array is allocated in the game dll + // so it can vary in size from one game to another. The size will be fixed when ge->Init() is + // called. + + struct edict_s *edicts; + int edict_size; + int num_edicts; // Current number of edicts. Always <= max_edicts. + int max_edicts; +} game_export_t; + +game_export_t *GetGameApi (game_import_t *import); diff --git a/Toolkit/Programming/GameCode/game/game.opt b/Toolkit/Programming/GameCode/game/game.opt new file mode 100644 index 0000000..506016a Binary files /dev/null and b/Toolkit/Programming/GameCode/game/game.opt differ diff --git a/Toolkit/Programming/GameCode/game/list.h b/Toolkit/Programming/GameCode/game/list.h new file mode 100644 index 0000000..af9ab2b --- /dev/null +++ b/Toolkit/Programming/GameCode/game/list.h @@ -0,0 +1,90 @@ +#pragma once + +template +class List +{ + struct Node; + friend struct Node; + struct Node + { + Node *next; + Node *prev; + V value; + }; + + Node *NewNode() + { + Node *r=new Node; + r->prev=r; + r->next=r; + return r; + } + Node *NewNode(const V& val,Node *n=0,Node *p=0) + { + Node *r=new Node; + r->value=val; + r->prev=p?p:r; + r->next=n?n:r; + return r; + } + void DelNode(Node *n) {delete n;} + Node *Head; + int size; +public: + class Iter; + friend class Iter; + class Iter + { + Node *cur; + public: + Iter() {} + Iter(Node *t) {cur=t;} + V & operator*() const {return cur->value;} + Iter& operator++() {cur=cur->next;return *this;} + Iter operator++(int) {Iter Tmp = *this;++*this;return Tmp;} + Iter& operator--() {cur=cur->prev;return *this;} + Iter operator--(int) {Iter Tmp = *this;--*this;return Tmp;} + bool operator==(const Iter& x) const {return cur == x.cur; } + bool operator!=(const Iter& x) const {return !(*this == x); } + Node *Mynode() const {return cur;} + }; + + List() {Head=NewNode();size=0;} + ~List() + { + Erase(Begin(), End()); + DelNode(Head); + Head = 0; + size = 0; + } + int Size() const {return size;} + Iter Begin() {return Iter(Head->next);} + Iter End() {return Iter(Head);} + void Insert(Iter P, const V& X) + { + Node *S = P.Mynode(); + S->prev = NewNode(X,S,S->prev); + S = S->prev; + S->prev->next=S; + size++; + } + Iter Erase(Iter P) + { + Node *S = (P++).Mynode(); + S->prev->next=S->next; + S->next->prev=S->prev; + DelNode(S); + --size; + return (P); + } + Iter Erase(Iter F,Iter L) + { + while (F != L) + Erase(F++); + return (F); + } + void PushFront(const V& X) {Insert(Begin(), X); } + void PopFront() {Erase(Begin()); } + void PushBack(const V& X) {Insert(End(), X); } + void PopBack() {Erase(--End()); } +}; diff --git a/Toolkit/Programming/GameCode/game/m_FMtest.c b/Toolkit/Programming/GameCode/game/m_FMtest.c new file mode 100644 index 0000000..fa04b74 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_FMtest.c @@ -0,0 +1,74 @@ +#include "g_local.h" +#include "Random.h" +#include "vector.h" + +void MakeSolidObject(edict_t *ent, char *Model, float MinX, float MinY, float MinZ, + float MaxX, float MaxY, float MaxZ) +{ + ent->movetype = PHYSICSTYPE_NONE; + ent->solid = SOLID_BBOX; + VectorSet (ent->mins, MinX, MinY, MinZ); + VectorSet (ent->maxs, MaxX, MaxY, MaxZ); + gi.setmodel(ent, Model); + + gi.linkentity (ent); +} + +void flag_think (edict_t *self) +{ + self->s.frame++; + if (self->s.frame > 10) + self->s.frame = 0; + +/* self->s.fmnodeinfo[1].skin++; + if (self->s.fmnodeinfo[1].skin > 5) + self->s.fmnodeinfo[1].skin = 0; + + + self->s.fmnodeinfo[0].flags &= ~FMNI_NO_DRAW; + if (random() > 0.5) + self->s.fmnodeinfo[0].flags |= FMNI_NO_DRAW; + + self->s.fmnodeinfo[1].flags &= ~FMNI_NO_DRAW; + if (random() > 0.5) + self->s.fmnodeinfo[1].flags |= FMNI_NO_DRAW; + + self->s.fmnodeinfo[2].flags &= ~FMNI_NO_DRAW; + if (random() > 0.5) + self->s.fmnodeinfo[2].flags |= FMNI_NO_DRAW; + + self->s.fmnodeinfo[3].flags &= ~FMNI_NO_DRAW; + if (random() > 0.5) + self->s.fmnodeinfo[3].flags |= FMNI_NO_DRAW;*/ + + self->nextthink = level.time + FRAMETIME; +} + +/*QUAKED misc_flag (1 .5 0) (-10 -10 0) (10 10 80) +*/ +void SP_misc_flag (edict_t *ent) +{ + MakeSolidObject(ent, "models/rj5/tris.fm", -10, -10, 0, 10, 10, 80); + + ent->think = flag_think; + ent->nextthink = level.time + flrand(0.0F, 1.0F); + +/* ent->s.fmnodeinfo[1].skin = 2; + + ent->s.fmnodeinfo[0].color.r = 255; + ent->s.fmnodeinfo[0].color.a = 120; + ent->s.fmnodeinfo[0].flags |= FMNI_USE_COLOR; + + ent->s.fmnodeinfo[1].color.g = 255; + ent->s.fmnodeinfo[1].color.a = 255; + ent->s.fmnodeinfo[1].flags |= FMNI_USE_COLOR; + + ent->s.fmnodeinfo[2].color.b = 255; + ent->s.fmnodeinfo[2].color.a = 200; + ent->s.fmnodeinfo[2].flags |= FMNI_USE_COLOR; + + ent->s.fmnodeinfo[3].color.r = 255; + ent->s.fmnodeinfo[3].color.g = 255; + ent->s.fmnodeinfo[3].color.a = 80; + ent->s.fmnodeinfo[3].flags |= FMNI_USE_COLOR;*/ +} diff --git a/Toolkit/Programming/GameCode/game/m_actor.h b/Toolkit/Programming/GameCode/game/m_actor.h new file mode 100644 index 0000000..acae477 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_actor.h @@ -0,0 +1,487 @@ +// G:\quake2\baseq2\models/player_y + +// This file generated by ModelGen - Do NOT Modify + +#define FRAME_attak01 0 +#define FRAME_attak02 1 +#define FRAME_attak03 2 +#define FRAME_attak04 3 +#define FRAME_death101 4 +#define FRAME_death102 5 +#define FRAME_death103 6 +#define FRAME_death104 7 +#define FRAME_death105 8 +#define FRAME_death106 9 +#define FRAME_death107 10 +#define FRAME_death201 11 +#define FRAME_death202 12 +#define FRAME_death203 13 +#define FRAME_death204 14 +#define FRAME_death205 15 +#define FRAME_death206 16 +#define FRAME_death207 17 +#define FRAME_death208 18 +#define FRAME_death209 19 +#define FRAME_death210 20 +#define FRAME_death211 21 +#define FRAME_death212 22 +#define FRAME_death213 23 +#define FRAME_death301 24 +#define FRAME_death302 25 +#define FRAME_death303 26 +#define FRAME_death304 27 +#define FRAME_death305 28 +#define FRAME_death306 29 +#define FRAME_death307 30 +#define FRAME_death308 31 +#define FRAME_death309 32 +#define FRAME_death310 33 +#define FRAME_death311 34 +#define FRAME_death312 35 +#define FRAME_death313 36 +#define FRAME_death314 37 +#define FRAME_death315 38 +#define FRAME_flip01 39 +#define FRAME_flip02 40 +#define FRAME_flip03 41 +#define FRAME_flip04 42 +#define FRAME_flip05 43 +#define FRAME_flip06 44 +#define FRAME_flip07 45 +#define FRAME_flip08 46 +#define FRAME_flip09 47 +#define FRAME_flip10 48 +#define FRAME_flip11 49 +#define FRAME_flip12 50 +#define FRAME_flip13 51 +#define FRAME_flip14 52 +#define FRAME_grenad01 53 +#define FRAME_grenad02 54 +#define FRAME_grenad03 55 +#define FRAME_grenad04 56 +#define FRAME_grenad05 57 +#define FRAME_grenad06 58 +#define FRAME_grenad07 59 +#define FRAME_grenad08 60 +#define FRAME_grenad09 61 +#define FRAME_grenad10 62 +#define FRAME_grenad11 63 +#define FRAME_grenad12 64 +#define FRAME_grenad13 65 +#define FRAME_grenad14 66 +#define FRAME_grenad15 67 +#define FRAME_jump01 68 +#define FRAME_jump02 69 +#define FRAME_jump03 70 +#define FRAME_jump04 71 +#define FRAME_jump05 72 +#define FRAME_jump06 73 +#define FRAME_pain101 74 +#define FRAME_pain102 75 +#define FRAME_pain103 76 +#define FRAME_pain201 77 +#define FRAME_pain202 78 +#define FRAME_pain203 79 +#define FRAME_pain301 80 +#define FRAME_pain302 81 +#define FRAME_pain303 82 +#define FRAME_push01 83 +#define FRAME_push02 84 +#define FRAME_push03 85 +#define FRAME_push04 86 +#define FRAME_push05 87 +#define FRAME_push06 88 +#define FRAME_push07 89 +#define FRAME_push08 90 +#define FRAME_push09 91 +#define FRAME_run01 92 +#define FRAME_run02 93 +#define FRAME_run03 94 +#define FRAME_run04 95 +#define FRAME_run05 96 +#define FRAME_run06 97 +#define FRAME_run07 98 +#define FRAME_run08 99 +#define FRAME_run09 100 +#define FRAME_run10 101 +#define FRAME_run11 102 +#define FRAME_run12 103 +#define FRAME_runs01 104 +#define FRAME_runs02 105 +#define FRAME_runs03 106 +#define FRAME_runs04 107 +#define FRAME_runs05 108 +#define FRAME_runs06 109 +#define FRAME_runs07 110 +#define FRAME_runs08 111 +#define FRAME_runs09 112 +#define FRAME_runs10 113 +#define FRAME_runs11 114 +#define FRAME_runs12 115 +#define FRAME_salute01 116 +#define FRAME_salute02 117 +#define FRAME_salute03 118 +#define FRAME_salute04 119 +#define FRAME_salute05 120 +#define FRAME_salute06 121 +#define FRAME_salute07 122 +#define FRAME_salute08 123 +#define FRAME_salute09 124 +#define FRAME_salute10 125 +#define FRAME_salute11 126 +#define FRAME_salute12 127 +#define FRAME_stand101 128 +#define FRAME_stand102 129 +#define FRAME_stand103 130 +#define FRAME_stand104 131 +#define FRAME_stand105 132 +#define FRAME_stand106 133 +#define FRAME_stand107 134 +#define FRAME_stand108 135 +#define FRAME_stand109 136 +#define FRAME_stand110 137 +#define FRAME_stand111 138 +#define FRAME_stand112 139 +#define FRAME_stand113 140 +#define FRAME_stand114 141 +#define FRAME_stand115 142 +#define FRAME_stand116 143 +#define FRAME_stand117 144 +#define FRAME_stand118 145 +#define FRAME_stand119 146 +#define FRAME_stand120 147 +#define FRAME_stand121 148 +#define FRAME_stand122 149 +#define FRAME_stand123 150 +#define FRAME_stand124 151 +#define FRAME_stand125 152 +#define FRAME_stand126 153 +#define FRAME_stand127 154 +#define FRAME_stand128 155 +#define FRAME_stand129 156 +#define FRAME_stand130 157 +#define FRAME_stand131 158 +#define FRAME_stand132 159 +#define FRAME_stand133 160 +#define FRAME_stand134 161 +#define FRAME_stand135 162 +#define FRAME_stand136 163 +#define FRAME_stand137 164 +#define FRAME_stand138 165 +#define FRAME_stand139 166 +#define FRAME_stand140 167 +#define FRAME_stand201 168 +#define FRAME_stand202 169 +#define FRAME_stand203 170 +#define FRAME_stand204 171 +#define FRAME_stand205 172 +#define FRAME_stand206 173 +#define FRAME_stand207 174 +#define FRAME_stand208 175 +#define FRAME_stand209 176 +#define FRAME_stand210 177 +#define FRAME_stand211 178 +#define FRAME_stand212 179 +#define FRAME_stand213 180 +#define FRAME_stand214 181 +#define FRAME_stand215 182 +#define FRAME_stand216 183 +#define FRAME_stand217 184 +#define FRAME_stand218 185 +#define FRAME_stand219 186 +#define FRAME_stand220 187 +#define FRAME_stand221 188 +#define FRAME_stand222 189 +#define FRAME_stand223 190 +#define FRAME_swim01 191 +#define FRAME_swim02 192 +#define FRAME_swim03 193 +#define FRAME_swim04 194 +#define FRAME_swim05 195 +#define FRAME_swim06 196 +#define FRAME_swim07 197 +#define FRAME_swim08 198 +#define FRAME_swim09 199 +#define FRAME_swim10 200 +#define FRAME_swim11 201 +#define FRAME_swim12 202 +#define FRAME_sw_atk01 203 +#define FRAME_sw_atk02 204 +#define FRAME_sw_atk03 205 +#define FRAME_sw_atk04 206 +#define FRAME_sw_atk05 207 +#define FRAME_sw_atk06 208 +#define FRAME_sw_pan01 209 +#define FRAME_sw_pan02 210 +#define FRAME_sw_pan03 211 +#define FRAME_sw_pan04 212 +#define FRAME_sw_pan05 213 +#define FRAME_sw_std01 214 +#define FRAME_sw_std02 215 +#define FRAME_sw_std03 216 +#define FRAME_sw_std04 217 +#define FRAME_sw_std05 218 +#define FRAME_sw_std06 219 +#define FRAME_sw_std07 220 +#define FRAME_sw_std08 221 +#define FRAME_sw_std09 222 +#define FRAME_sw_std10 223 +#define FRAME_sw_std11 224 +#define FRAME_sw_std12 225 +#define FRAME_sw_std13 226 +#define FRAME_sw_std14 227 +#define FRAME_sw_std15 228 +#define FRAME_sw_std16 229 +#define FRAME_sw_std17 230 +#define FRAME_sw_std18 231 +#define FRAME_sw_std19 232 +#define FRAME_sw_std20 233 +#define FRAME_taunt01 234 +#define FRAME_taunt02 235 +#define FRAME_taunt03 236 +#define FRAME_taunt04 237 +#define FRAME_taunt05 238 +#define FRAME_taunt06 239 +#define FRAME_taunt07 240 +#define FRAME_taunt08 241 +#define FRAME_taunt09 242 +#define FRAME_taunt10 243 +#define FRAME_taunt11 244 +#define FRAME_taunt12 245 +#define FRAME_taunt13 246 +#define FRAME_taunt14 247 +#define FRAME_taunt15 248 +#define FRAME_taunt16 249 +#define FRAME_taunt17 250 +#define FRAME_walk01 251 +#define FRAME_walk02 252 +#define FRAME_walk03 253 +#define FRAME_walk04 254 +#define FRAME_walk05 255 +#define FRAME_walk06 256 +#define FRAME_walk07 257 +#define FRAME_walk08 258 +#define FRAME_walk09 259 +#define FRAME_walk10 260 +#define FRAME_walk11 261 +#define FRAME_wave01 262 +#define FRAME_wave02 263 +#define FRAME_wave03 264 +#define FRAME_wave04 265 +#define FRAME_wave05 266 +#define FRAME_wave06 267 +#define FRAME_wave07 268 +#define FRAME_wave08 269 +#define FRAME_wave09 270 +#define FRAME_wave10 271 +#define FRAME_wave11 272 +#define FRAME_wave12 273 +#define FRAME_wave13 274 +#define FRAME_wave14 275 +#define FRAME_wave15 276 +#define FRAME_wave16 277 +#define FRAME_wave17 278 +#define FRAME_wave18 279 +#define FRAME_wave19 280 +#define FRAME_wave20 281 +#define FRAME_wave21 282 +#define FRAME_bl_atk01 283 +#define FRAME_bl_atk02 284 +#define FRAME_bl_atk03 285 +#define FRAME_bl_atk04 286 +#define FRAME_bl_atk05 287 +#define FRAME_bl_atk06 288 +#define FRAME_bl_flp01 289 +#define FRAME_bl_flp02 290 +#define FRAME_bl_flp13 291 +#define FRAME_bl_flp14 292 +#define FRAME_bl_flp15 293 +#define FRAME_bl_jmp01 294 +#define FRAME_bl_jmp02 295 +#define FRAME_bl_jmp03 296 +#define FRAME_bl_jmp04 297 +#define FRAME_bl_jmp05 298 +#define FRAME_bl_jmp06 299 +#define FRAME_bl_pn101 300 +#define FRAME_bl_pn102 301 +#define FRAME_bl_pn103 302 +#define FRAME_bl_pn201 303 +#define FRAME_bl_pn202 304 +#define FRAME_bl_pn203 305 +#define FRAME_bl_pn301 306 +#define FRAME_bl_pn302 307 +#define FRAME_bl_pn303 308 +#define FRAME_bl_psh08 309 +#define FRAME_bl_psh09 310 +#define FRAME_bl_run01 311 +#define FRAME_bl_run02 312 +#define FRAME_bl_run03 313 +#define FRAME_bl_run04 314 +#define FRAME_bl_run05 315 +#define FRAME_bl_run06 316 +#define FRAME_bl_run07 317 +#define FRAME_bl_run08 318 +#define FRAME_bl_run09 319 +#define FRAME_bl_run10 320 +#define FRAME_bl_run11 321 +#define FRAME_bl_run12 322 +#define FRAME_bl_rns03 323 +#define FRAME_bl_rns04 324 +#define FRAME_bl_rns05 325 +#define FRAME_bl_rns06 326 +#define FRAME_bl_rns07 327 +#define FRAME_bl_rns08 328 +#define FRAME_bl_rns09 329 +#define FRAME_bl_sal10 330 +#define FRAME_bl_sal11 331 +#define FRAME_bl_sal12 332 +#define FRAME_bl_std01 333 +#define FRAME_bl_std02 334 +#define FRAME_bl_std03 335 +#define FRAME_bl_std04 336 +#define FRAME_bl_std05 337 +#define FRAME_bl_std06 338 +#define FRAME_bl_std07 339 +#define FRAME_bl_std08 340 +#define FRAME_bl_std09 341 +#define FRAME_bl_std10 342 +#define FRAME_bl_std11 343 +#define FRAME_bl_std12 344 +#define FRAME_bl_std13 345 +#define FRAME_bl_std14 346 +#define FRAME_bl_std15 347 +#define FRAME_bl_std16 348 +#define FRAME_bl_std17 349 +#define FRAME_bl_std18 350 +#define FRAME_bl_std19 351 +#define FRAME_bl_std20 352 +#define FRAME_bl_std21 353 +#define FRAME_bl_std22 354 +#define FRAME_bl_std23 355 +#define FRAME_bl_std24 356 +#define FRAME_bl_std25 357 +#define FRAME_bl_std26 358 +#define FRAME_bl_std27 359 +#define FRAME_bl_std28 360 +#define FRAME_bl_std29 361 +#define FRAME_bl_std30 362 +#define FRAME_bl_std31 363 +#define FRAME_bl_std32 364 +#define FRAME_bl_std33 365 +#define FRAME_bl_std34 366 +#define FRAME_bl_std35 367 +#define FRAME_bl_std36 368 +#define FRAME_bl_std37 369 +#define FRAME_bl_std38 370 +#define FRAME_bl_std39 371 +#define FRAME_bl_std40 372 +#define FRAME_bl_swm01 373 +#define FRAME_bl_swm02 374 +#define FRAME_bl_swm03 375 +#define FRAME_bl_swm04 376 +#define FRAME_bl_swm05 377 +#define FRAME_bl_swm06 378 +#define FRAME_bl_swm07 379 +#define FRAME_bl_swm08 380 +#define FRAME_bl_swm09 381 +#define FRAME_bl_swm10 382 +#define FRAME_bl_swm11 383 +#define FRAME_bl_swm12 384 +#define FRAME_bl_swk01 385 +#define FRAME_bl_swk02 386 +#define FRAME_bl_swk03 387 +#define FRAME_bl_swk04 388 +#define FRAME_bl_swk05 389 +#define FRAME_bl_swk06 390 +#define FRAME_bl_swp01 391 +#define FRAME_bl_swp02 392 +#define FRAME_bl_swp03 393 +#define FRAME_bl_swp04 394 +#define FRAME_bl_swp05 395 +#define FRAME_bl_sws01 396 +#define FRAME_bl_sws02 397 +#define FRAME_bl_sws03 398 +#define FRAME_bl_sws04 399 +#define FRAME_bl_sws05 400 +#define FRAME_bl_sws06 401 +#define FRAME_bl_sws07 402 +#define FRAME_bl_sws08 403 +#define FRAME_bl_sws09 404 +#define FRAME_bl_sws10 405 +#define FRAME_bl_sws11 406 +#define FRAME_bl_sws12 407 +#define FRAME_bl_sws13 408 +#define FRAME_bl_sws14 409 +#define FRAME_bl_tau14 410 +#define FRAME_bl_tau15 411 +#define FRAME_bl_tau16 412 +#define FRAME_bl_tau17 413 +#define FRAME_bl_wlk01 414 +#define FRAME_bl_wlk02 415 +#define FRAME_bl_wlk03 416 +#define FRAME_bl_wlk04 417 +#define FRAME_bl_wlk05 418 +#define FRAME_bl_wlk06 419 +#define FRAME_bl_wlk07 420 +#define FRAME_bl_wlk08 421 +#define FRAME_bl_wlk09 422 +#define FRAME_bl_wlk10 423 +#define FRAME_bl_wlk11 424 +#define FRAME_bl_wav19 425 +#define FRAME_bl_wav20 426 +#define FRAME_bl_wav21 427 +#define FRAME_cr_atk01 428 +#define FRAME_cr_atk02 429 +#define FRAME_cr_atk03 430 +#define FRAME_cr_atk04 431 +#define FRAME_cr_atk05 432 +#define FRAME_cr_atk06 433 +#define FRAME_cr_atk07 434 +#define FRAME_cr_atk08 435 +#define FRAME_cr_pan01 436 +#define FRAME_cr_pan02 437 +#define FRAME_cr_pan03 438 +#define FRAME_cr_pan04 439 +#define FRAME_cr_std01 440 +#define FRAME_cr_std02 441 +#define FRAME_cr_std03 442 +#define FRAME_cr_std04 443 +#define FRAME_cr_std05 444 +#define FRAME_cr_std06 445 +#define FRAME_cr_std07 446 +#define FRAME_cr_std08 447 +#define FRAME_cr_wlk01 448 +#define FRAME_cr_wlk02 449 +#define FRAME_cr_wlk03 450 +#define FRAME_cr_wlk04 451 +#define FRAME_cr_wlk05 452 +#define FRAME_cr_wlk06 453 +#define FRAME_cr_wlk07 454 +#define FRAME_crbl_a01 455 +#define FRAME_crbl_a02 456 +#define FRAME_crbl_a03 457 +#define FRAME_crbl_a04 458 +#define FRAME_crbl_a05 459 +#define FRAME_crbl_a06 460 +#define FRAME_crbl_a07 461 +#define FRAME_crbl_p01 462 +#define FRAME_crbl_p02 463 +#define FRAME_crbl_p03 464 +#define FRAME_crbl_p04 465 +#define FRAME_crbl_s01 466 +#define FRAME_crbl_s02 467 +#define FRAME_crbl_s03 468 +#define FRAME_crbl_s04 469 +#define FRAME_crbl_s05 470 +#define FRAME_crbl_s06 471 +#define FRAME_crbl_s07 472 +#define FRAME_crbl_s08 473 +#define FRAME_crbl_w01 474 +#define FRAME_crbl_w02 475 +#define FRAME_crbl_w03 476 +#define FRAME_crbl_w04 477 +#define FRAME_crbl_w05 478 +#define FRAME_crbl_w06 479 +#define FRAME_crbl_w07 480 + +#define MODEL_SCALE 1.000000 diff --git a/Toolkit/Programming/GameCode/game/m_assassin.c b/Toolkit/Programming/GameCode/game/m_assassin.c new file mode 100644 index 0000000..47e66d8 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_assassin.c @@ -0,0 +1,2958 @@ +//============================================================================== +// +// m_assassin.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// +// AI : +// +// STAND1 : Looking straight ahead +// +// WALK1 : a normal straight line +// WALK2 : another normal straight line +// +// MELEE1 : Attack +// MELEE2 : Attack +// +// RUNATTACK : Running and swinging +// RUN1 : chasing an enemy straight ahead +// SHAKE : stand and spaz +// DIE1 : Fall back dead +// LEAN1 : lean agains the wall +// FIST1 : Beat against the wall in rage and desperation +// +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" +#include "g_playstats.h" +#include "m_assassin.h" +#include "m_assassin_anim.h" +#include "g_HitLocation.h" +#include "g_misc.h" +#include "angles.h" +#include "c_ai.h" +#include "p_anim_branch2.h" +#include "p_anims2.h" +#include "m_stats.h" + +qboolean clear_visible (edict_t *self, edict_t *other); +void extrapolateFiredir (edict_t *self,vec3_t p1,float pspeed,edict_t *targ,float accept,vec3_t vec2); +void create_assassin_dagger(edict_t *Arrow); +void assassinInitDeCloak (edict_t *self); +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); + +/*---------------------------------------------------------------------- + assassin Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + &assassin_move_daggerl,// = {14, assassin_frames_daggerl, assassin_pause}, + &assassin_move_daggerr,//= {15, assassin_frames_daggerr, assassin_pause}, + &assassin_move_daggerb,// = {15, assassin_frames_daggerb, assassin_pause}, + &assassin_move_daggerc,// = {11, assassin_frames_daggerc, assassin_pause}, + &assassin_move_newdagger, + &assassin_move_newdaggerb, + &assassin_move_backflip,// = {16, assassin_frames_backflip, assassin_pause}, + &assassin_move_frontflip,// = {16, assassin_frames_frontflip, assassin_pause}, + &assassin_move_dodge_right,// = {10, assassin_frames_dodge_right, assassin_pause}, + &assassin_move_dodge_left,// = {10, assassin_frames_dodge_left, assassin_pause}, + &assassin_move_deatha,// = {14, assassin_frames_deatha, assassin_dead}, + &assassin_move_deathb,// = {14, assassin_frames_deathb, assassin_dead}, + &assassin_move_jump,// = {17, assassin_frames_jump, assassin_pause}, + &assassin_move_run,// = {10, assassin_frames_run, assassin_pause}, + &assassin_move_pain1,// = {5, assassin_frames_pain1, assassin_pause}, + &assassin_move_pain2,// = {4, assassin_frames_pain2, assassin_pause}, + &assassin_move_delay,// = {1, assassin_frames_delay, assassin_pause}, + &assassin_move_stand, + &assassin_move_crouch, + &assassin_move_uncrouch, + &assassin_move_evade_jump, + &assassin_move_evade_backflip, + &assassin_move_evade_frontflip, + &assassin_move_inair, + &assassin_move_land, + &assassin_move_forcedjump, + &assassin_move_fjump, + &assassin_move_bfinair, + &assassin_move_bfland, + &assassin_move_ffinair, + &assassin_move_ffland, + &assassin_move_evinair, + &assassin_move_teleport, + &assassin_move_cloak, + &assassin_move_walk, + &assassin_move_walk_loop, + &assassin_move_backspring, +//crouches + &assassin_move_crouch_trans, + &assassin_move_crouch_idle, + &assassin_move_crouch_look_right, + &assassin_move_crouch_look_right_idle, + &assassin_move_crouch_look_l2r, + &assassin_move_crouch_look_left, + &assassin_move_crouch_look_left_idle, + &assassin_move_crouch_look_r2l, + &assassin_move_crouch_look_r2c, + &assassin_move_crouch_look_l2c, + &assassin_move_crouch_poke, + &assassin_move_crouch_end, + + // Cinematic Anims + &assassin_move_c_idle1, + &assassin_move_c_run1, + &assassin_move_c_attack1, + &assassin_move_c_attack2, +}; + +static int Sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + + +/*------------------------------------------------------------------------- + assassin_c_anims +-------------------------------------------------------------------------*/ +void assassin_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ATTACK1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK1; + break; + case MSG_C_ATTACK2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK2; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_RUN1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_RUN1; + break; + default: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE1; + break; + } + + SetAnim(self, curr_anim); +} + + + +/*---------------------------------------------------------------------- + Action Functions for the monster +-----------------------------------------------------------------------*/ + +void assassinApplyJump (edict_t *self) +{ + self->jump_time = level.time + 2; + VectorCopy(self->movedir, self->velocity); + VectorNormalize(self->movedir); +// gi.dprintf("Jump velocity will be: %4.2f %4.2f %4.2f\n", self->velocity[0], self->velocity[1], self->velocity[2]); + self->monsterinfo.aiflags &= ~AI_OVERRIDE_GUIDE; +} + +void assassin_jump(edict_t *self, G_Message_t *msg) +{ +// gi.dprintf("Assassin Jumping from AI RUN!\n"); + SetAnim(self, ANIM_FORCED_JUMP); + self->monsterinfo.aiflags |= AI_OVERRIDE_GUIDE; +} + +void bounce_arrow(edict_t *self) +{ + edict_t *Arrow; + + Arrow = G_Spawn(); + + Arrow->owner = self->owner; + + Arrow->touch = self->touch; + Arrow->s.modelindex = self->s.modelindex; + VectorCopy(self->s.origin, Arrow->s.origin); + Arrow->owner = self->owner; + Arrow->enemy = self->enemy; + Arrow->nextthink=self->nextthink; + create_assassin_dagger(Arrow); + VectorScale(self->avelocity, -0.5, Arrow->avelocity); + + Create_rand_relect_vect(self->velocity, Arrow->velocity); + vectoangles(Arrow->velocity, Arrow->s.angles); + Vec3ScaleAssign(ASSASSIN_DAGGER_SPEED / 2,Arrow->velocity); + Arrow->reflect_debounce_time = self->reflect_debounce_time -1; + + gi.CreateEffect(&Arrow->s, + FX_M_EFFECTS, + 0, + Arrow->avelocity, + "bv", + FX_ASS_DAGGER, + Arrow->velocity); + + G_LinkMissile(Arrow); +} + + +// The blocked function isn't currently used. +/* +void assassinDaggerBlocked (edict_t *self, trace_t *trace) +{ + float damage; + vec3_t hitangles; + edict_t *Other; + Other = trace->ent; + + if(Other==self->owner||Other->owner == self->owner) + { + return; + } + + // are we reflecting ? + if(EntReflecting(trace->ent, true, true)) + { + bounce_arrow(self); + + G_SetToFree(self); + + return; + } + + if(trace->surface&&(trace->surface->flags&SURF_SKY)) + { + SkyFly(self); + return; + } + +//take into account if angle is within 45 of 0? + if(Other->takedamage) + { + if(Other->materialtype == MAT_FLESH||Other->client) + gi.sound(self,CHAN_AUTO,Sounds[SND_DAGHITF],1,ATTN_NORM,0); + else + gi.sound(self,CHAN_AUTO,Sounds[SND_DAGHITW],1,ATTN_NORM,0); + if(skill->value < 2) + damage = flrand(ASSASSIN_MIN_DAMAGE * 0.5, ASSASSIN_MAX_DAMAGE * 0.5); + else + { + damage = flrand(ASSASSIN_MIN_DAMAGE,ASSASSIN_MAX_DAMAGE); + if(Q_fabs(self->s.angles[PITCH])<45)//up to extra 10 pts damage if pointed correctly + damage += 45/(45 - Q_fabs(self->s.angles[PITCH])) * 10; + } + T_Damage(Other,self,self->owner,self->movedir,self->s.origin,trace->plane.normal, damage, 0, 0,MOD_DIED); + } + else//spark + { + if(Vec3NotZero(trace->plane.normal)) + vectoangles(trace->plane.normal, hitangles); + else + VectorSet(hitangles, 0, 0, 90); + gi.CreateEffect(NULL, FX_SPARKS, 0, self->s.origin, "d", hitangles); + gi.sound(self,CHAN_AUTO,Sounds[SND_DAGHITW],1,ATTN_NORM,0); + } + + G_FreeEdict(self); +} +*/ + +void assassinDaggerTouch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + float damage; + vec3_t hitangles, normal; + + if(other==self->owner||other->owner == self->owner) + { + return; + } + + // are we reflecting ? + if(EntReflecting(other, true, true) && self->reflect_debounce_time) + { + bounce_arrow(self); + + G_SetToFree(self); + + return; + } + + if(surface&&(surface->flags&SURF_SKY)) + { + SkyFly(self); + return; + } + +//take into account if angle is within 45 of 0? + VectorSet(normal, 0, 0, 1); + if(plane) + { + if(plane->normal) + { + VectorCopy(plane->normal, normal); + } + } + + if(other->takedamage) + { + if(other->materialtype == MAT_FLESH||other->client) + gi.sound(self,CHAN_AUTO,Sounds[SND_DAGHITF],1,ATTN_NORM,0); + else + gi.sound(self,CHAN_AUTO,Sounds[SND_DAGHITW],1,ATTN_NORM,0); + damage = flrand(ASSASSIN_MIN_DAMAGE,ASSASSIN_MAX_DAMAGE); + if(skill->value >= 2 && Q_fabs(self->s.angles[PITCH])<45)//up to extra 10 pts damage if pointed correctly AND on hard skill + damage += 45/(45 - Q_fabs(self->s.angles[PITCH])) * 10; + + T_Damage(other,self,self->owner,self->movedir,self->s.origin,normal, damage, 0, 0,MOD_DIED); + } + else//spark + { + if(Vec3NotZero(normal)) + vectoangles(normal, hitangles); + else + VectorSet(hitangles, 0, 0, 90); + gi.CreateEffect(NULL, FX_SPARKS, 0, self->s.origin, "d", hitangles); + gi.sound(self,CHAN_AUTO,Sounds[SND_DAGHITW],1,ATTN_NORM,0); + } + + G_FreeEdict(self); +} + +// create the guts of the dagger +void create_assassin_dagger(edict_t *Arrow) +{ + Arrow->movetype=MOVETYPE_FLYMISSILE; + Arrow->solid=SOLID_BBOX; + Arrow->classname="Assassin_Dagger"; + Arrow->touch=assassinDaggerTouch; + Arrow->gravity = 0.0f; + Arrow->clipmask=MASK_SHOT; + Arrow->s.effects |= EF_CAMERA_NO_CLIP; + Arrow->svflags |= SVF_ALWAYS_SEND; + Arrow->s.scale = 0.5; + Arrow->think=G_FreeEdict;//ssithraArrowThink; + + VectorSet(Arrow->mins, -1.0, -1.0, -1.0); + VectorSet(Arrow->maxs, 1.0, 1.0, 1.0); +} + +void assassinThrowDagger(edict_t *self, float right_ofs) +{//fixme; adjust for up/down + vec3_t Forward,check_lead, right, enemy_pos, enemy_dir;//, up; + edict_t *Arrow; + float enemy_dist, eta;//, spoo_arc; + + +// if(self->s.fmnodeinfo[MESH__RIGHTARM].flags&FMNI_NO_DRAW) +// return; + + +// gi.sound(self,CHAN_WEAPON,Sounds[SND_ARROW1],1,ATTN_NORM,0); + self->monsterinfo.attack_finished = level.time + 0.4; + Arrow = G_Spawn(); + + create_assassin_dagger(Arrow); + + Arrow->reflect_debounce_time = MAX_REFLECT; + Arrow->nextthink=level.time+3; + Arrow->enemy=self->enemy; + Arrow->owner=self; + VectorCopy(self->enemy->s.origin, enemy_pos); + enemy_pos[2] += self->enemy->viewheight; + + AngleVectors (self->s.angles, Forward, right, NULL); + VectorCopy (self->s.origin, Arrow->s.origin); + Arrow->s.origin[2] += 8; + VectorMA (Arrow->s.origin, 8, Forward, Arrow->s.origin); + VectorMA (Arrow->s.origin, right_ofs, right, Arrow->s.origin); + VectorCopy (self->movedir, Arrow->movedir); + vectoangles (Forward, Arrow->s.angles); + + extrapolateFiredir (self, Arrow->s.origin, ASSASSIN_DAGGER_SPEED, self->enemy, 0.3, check_lead); + + VectorSubtract(enemy_pos, Arrow->s.origin, enemy_dir); + enemy_dist = VectorNormalize(enemy_dir); + if(Vec3IsZero(check_lead)) + { + if(DotProduct(enemy_dir, Forward)>0.3) + VectorScale(enemy_dir, ASSASSIN_DAGGER_SPEED, Arrow->velocity); + else + VectorScale(Forward, ASSASSIN_DAGGER_SPEED, Arrow->velocity); + } + else + { + VectorScale(check_lead, ASSASSIN_DAGGER_SPEED, Arrow->velocity); + } + + VectorCopy(Arrow->velocity, Arrow->movedir); + VectorNormalize(Arrow->movedir); + vectoangles(Arrow->movedir, Arrow->s.angles); + Arrow->s.angles[PITCH] = -90; + + eta = enemy_dist / ASSASSIN_DAGGER_SPEED;//eta + +// gi.dprintf("ETA: %f\n", eta); + //ideally, spin @1110 degrees in 1 sec + Arrow->avelocity[PITCH] = -1/eta * (360*3 +30 + flrand(-10,10)); +// gi.dprintf("avel: %f\n", Arrow->avelocity[PITCH]); +// gi.dprintf("final rotation: %f\n", Arrow->avelocity[PITCH]*eta); +// gi.dprintf("final angle: %f\n", anglemod(Arrow->s.angles[PITCH]+Arrow->avelocity[PITCH]*eta)); + +/* +//doesn't make desired effect + if(right_ofs>0) + Arrow->s.angles[ROLL] = flrand(0, 35); + else if(right_ofs<0) + Arrow->s.angles[ROLL] = flrand(-35, 0); +*/ + + gi.CreateEffect(&Arrow->s, + FX_M_EFFECTS, + 0, + Arrow->avelocity, + "bv", + FX_ASS_DAGGER, + Arrow->velocity); + + G_LinkMissile(Arrow); +} + +/*------------------------------------------------------------------------- + assassin dagger +-------------------------------------------------------------------------*/ +void assassindagger (edict_t *self, float right_ofs) +{ + vec3_t v, off, dir, org, ang; + float len; + int damage; + int thrownum = 0; + + if(!self->enemy) + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + return; + } + + if(self->enemy->health<0) + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + return; + } + + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + + if (len <= (self->maxs[0] + self->enemy->maxs[0] + 56) ) // A hit + { + if (infront(self, self->enemy)) + { + if (1)//one or two hands? + gi.sound (self, CHAN_WEAPON, Sounds[SND_SLASH1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_WEAPON, Sounds[SND_SLASH2], 1, ATTN_NORM, 0); + + VectorSet(off, 35.0, 0.0, 32.0); + VectorGetOffsetOrigin(off, self->s.origin, self->s.angles[YAW], org); + VectorCopy(self->s.angles, ang); + ang[YAW] += DEGREE_90; + AngleVectors(ang, dir, NULL, NULL); + //4 to 8 + damage = irand(ASSASSIN_MIN_DAMAGE, ASSASSIN_MAX_DAMAGE); + + if(skill->value >= 2) + { + if(!infront(self->enemy, self)) + {//backstab! + damage = self->enemy->health + irand(-20, 10); + if(damages.fmnodeinfo[MESH__HANDLE].flags & FMNI_NO_DRAW) + damage-=5; + else if(self->s.fmnodeinfo[MESH__HOE].flags & FMNI_NO_DRAW) + damage+=5; + else if(self->s.fmnodeinfo[MESH__GAFF].flags & FMNI_NO_DRAW) + damage+=7; + else if(self->s.fmnodeinfo[MESH__HAMMER].flags & FMNI_NO_DRAW) + damage+=10;*/ + + T_Damage (self->enemy, self, self, dir, org, vec3_origin, damage, 0, 0,MOD_DIED); + } + } + else // A misssss + { + if((int)right_ofs & BIT_RKNIFE) + {//turn off dagger + thrownum++; + if(!(self->s.fmnodeinfo[MESH__RKNIFE].flags & FMNI_NO_DRAW)) + { + self->s.fmnodeinfo[MESH__RKNIFE].flags |= FMNI_NO_DRAW; + assassinThrowDagger(self, 12); + } + } + + if((int)right_ofs & BIT_LKNIFE) + { + thrownum++; + if(!(self->s.fmnodeinfo[MESH__LKNIFE].flags & FMNI_NO_DRAW)) + { + self->s.fmnodeinfo[MESH__LKNIFE].flags |= FMNI_NO_DRAW; + assassinThrowDagger(self, -12); + } + } + + if(thrownum>1) + gi.sound (self, CHAN_WEAPON, Sounds[SND_THROW2], 1, ATTN_NORM, 0); + else if(thrownum>0) + gi.sound (self, CHAN_WEAPON, Sounds[SND_THROW1], 1, ATTN_NORM, 0); + } +} + + +void assassin_Touch(edict_t *self, trace_t *trace) +{ + vec3_t dir; + float strength; + edict_t *other; + + other = trace->ent; + + if(self->health <= 0) + return; + + if(!trace) + return; + + if((!self->groundentity||self->groundentity==other) && Vec3NotZero(self->velocity)) + { + strength = VectorLength(self->velocity); + + if(strength > 50) + { + if(movable(other) && (other->svflags&SVF_MONSTER || other->client)) + { + + VectorCopy(self->velocity, dir); + if(dir[2] < 0) + dir[2] = 0; + VectorNormalize(dir); + + // VectorAdd(other->velocity, dir, other->knockbackvel); + + if(self->s.origin[2]+self->mins[2] > other->s.origin[2] + other->maxs[2] * 0.8) + { + if(other->client) + KnockDownPlayer(&other->client->playerinfo); + + gi.sound(self, CHAN_BODY, Sounds[SND_LANDF], 1, ATTN_NORM, 0); + /* + VectorMA(other->velocity, strength, dir, other->velocity); + other->groundentity = NULL; + other->velocity[2] = 101; + */ + + if(other->takedamage) + { + if(strength>5) + strength = 5; + T_Damage(other, self, self, dir, trace->endpos, dir, strength, strength*4, 0,MOD_DIED); + } + + SetAnim(self, ANIM_EVFRONTFLIP); + } + } + } + /* + //backflip off walls! Too late to implement + else if(trace->plane) + { + if(Vec3NotZero(trace->plane.normal)) + { + if(trace->plane.normal[2] < 0.75) + { + VectorCopy(self->velocity, dir); + VectorNormalize(dir); + if(DotProduct(dir, trace->plane.normal) < -0.3) + { + SetAnim(self, ANIM_EVBACKFLIP); + } + } + } + } + */ + } +} + + +/*------------------------------------------------------------------------- + assassin_dead +-------------------------------------------------------------------------*/ +void assassin_dead(edict_t *self) +{ + self->msgHandler = DeadMsgHandler; + self->deadState = DEAD_DEAD; + M_EndDeath(self); +} + +/*------------------------------------------------------------------------- + assassin_death +-------------------------------------------------------------------------*/ +void assassin_random_death_sound (edict_t *self) +{ + gi.sound(self, CHAN_VOICE, Sounds[SND_DIE1], 1, ATTN_NORM, 0); +} + +void assassin_death(edict_t *self, G_Message_t *msg) +{ + int chance; + + if(self->monsterinfo.aiflags&AI_DONT_THINK) + { + if (irand(0,10) < 5) // Big enough death to be thrown back + SetAnim(self, ANIM_DEATHB);//gib? + else + SetAnim(self, ANIM_DEATHA); + return; + } + +// gi.dprintf("Dead\n"); + self->msgHandler = DeadMsgHandler; + + if(self->deadflag == DEAD_DEAD) //Dead but still being hit + return; + + self->isBlocked = self->bounced = NULL; + + self->deadflag = DEAD_DEAD; + + assassin_dropweapon (self, BIT_LKNIFE|BIT_RKNIFE); + + if(self->health <= -80) //gib death + { + gi.sound(self, CHAN_BODY, Sounds[SND_GIB], 1, ATTN_NORM, 0); + if(irand(0,10)<5) + { + self->s.fmnodeinfo[MESH__TORSOFT].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__TORSOBK].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HEAD].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__R4ARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__L4ARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__KNIFES].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__LUPARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__RUPARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__LKNIFE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__RKNIFE].flags |= FMNI_NO_DRAW; + + SprayDebris(self, self->s.origin, 12, 100); + } + else + { + self->think = BecomeDebris; + self->nextthink = level.time + FRAMETIME; + return; + } + } + else + { + assassin_random_death_sound(self); + self->msgHandler = DyingMsgHandler; + } + + + chance = irand(0,10); + if(chance < 5 && self->health <= -80) + SetAnim(self, ANIM_DEATHA); + else + SetAnim(self, ANIM_DEATHB); + + self->pre_think = NULL; + self->next_pre_think = -1; + + if(self->s.renderfx & RF_ALPHA_TEXTURE) + if(self->pre_think != assassinDeCloak) + assassinInitDeCloak(self); +} + + +/*------------------------------------------------------------------------- + assassingrowl +-------------------------------------------------------------------------*/ +void assassingrowl (edict_t *self) +{ + int chance; + + if (!irand(0, 20)) + { + chance = irand(0, 9); + if (chance < 3) + gi.sound (self, CHAN_AUTO, Sounds[SND_GROWL1], 1, ATTN_IDLE, 0); + else if (chance < 6) + gi.sound(self, CHAN_AUTO, Sounds[SND_GROWL2], 1, ATTN_IDLE, 0); + else + gi.sound(self, CHAN_AUTO, Sounds[SND_GROWL3], 1, ATTN_IDLE, 0); + } +} + +void assassin_random_attack(edict_t *self) +{ + int chance; + + chance = irand(0,3); + + + if((chance < 1&&!(self->s.fmnodeinfo[MESH__L4ARM].flags&FMNI_NO_DRAW)) || + (self->s.fmnodeinfo[MESH__R4ARM].flags&FMNI_NO_DRAW&&!(self->s.fmnodeinfo[MESH__L4ARM].flags&FMNI_NO_DRAW)) ) + { + SetAnim(self, ANIM_DAGGERL); + } + else if((chance < 2&&!(self->s.fmnodeinfo[MESH__R4ARM].flags&FMNI_NO_DRAW)) || + (!(self->s.fmnodeinfo[MESH__R4ARM].flags&FMNI_NO_DRAW)&&self->s.fmnodeinfo[MESH__L4ARM].flags&FMNI_NO_DRAW) ) + { + if(irand(0, 1)) + SetAnim(self, ANIM_DAGGERR); + else + SetAnim(self, ANIM_NEWDAGGER); + } + else if(!(self->s.fmnodeinfo[MESH__R4ARM].flags&FMNI_NO_DRAW)&& + !(self->s.fmnodeinfo[MESH__L4ARM].flags&FMNI_NO_DRAW)) + { + if(irand(0, 1)) + SetAnim(self, ANIM_DAGGERB); + else + SetAnim(self, ANIM_NEWDAGGERB); + } + else + { +// gi.dprintf("Can't attack! Run away!\n"); + self->monsterinfo.aiflags |= AI_COWARD; + SetAnim(self, ANIM_RUN); + } +} + +/*------------------------------------------------------------------------- + assassin_melee +-------------------------------------------------------------------------*/ +void assassin_melee(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + if(!irand(0,7)) + { + /*if(self->s.renderfx & RF_ALPHA_TEXTURE) + { + if(self->pre_think != assassinDeCloak) + { + gi.sound(self,CHAN_AUTO,Sounds[SND_DECLOAK],1,ATTN_NORM,0); + self->pre_think = assassinDeCloak; + self->next_pre_think = level.time + FRAMETIME; + assassin_pause(self); + return; + } + }*/ + + if(assassinCheckTeleport(self, ASS_TP_OFF)) + { +// gi.dprintf("melee->teleport\n"); + return;//try to get away + } + } + assassin_random_attack(self); + } + else + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void assassin_missile(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + if(!irand(0, 10)) + {//10% chance try special action + if(!irand(0, 2)) + {//25% chance teleport + if(assassinCheckTeleport(self, ASS_TP_OFF)) + { +// gi.dprintf("missile->teleport\n"); + return; + } + } + else if(!(self->s.renderfx & RF_ALPHA_TEXTURE)) + {//75% cloak + if(!(self->spawnflags&MSF_ASS_NOSHADOW)) + { + SetAnim(self, ANIM_CLOAK); + return; + } + }//else uncloak - unncloak when die + } + //need to check for if behind player- diff behaviour- get close and backstab? + assassin_random_attack(self); + } + else + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} +/*------------------------------------------------------------------------- + assassin_pain +-------------------------------------------------------------------------*/ +void assassin_post_pain (edict_t *self) +{ + /*if(self->s.renderfx & RF_ALPHA_TEXTURE) + { + if(!irand(0,4)) + { + if(self->pre_think != assassinDeCloak) + { + gi.sound(self,CHAN_AUTO,Sounds[SND_DECLOAK],1,ATTN_NORM,0); + self->pre_think = assassinDeCloak; + self->next_pre_think = level.time + FRAMETIME; + assassin_pause(self); + return; + } + } + }*/ + if(self->fire_damage_time < level.time)//don't teleport if burning + { + if(assassinCheckTeleport(self, ASS_TP_ANY)) + { +// gi.dprintf("pain->teleport\n"); + return; + } + } + + assassin_pause(self); +} + +int Bit_for_MeshNode_as [16] = +{ + BIT_DADDYNULL, + BIT_TORSOFT, + BIT_TORSOBK, + BIT_HEAD, + BIT_LKNIFE, + BIT_RKNIFE, + BIT_R4ARM, + BIT_L4ARM, + BIT_HIPS, + BIT_LCALF, + BIT_RCALF, + BIT_RTHIGH, + BIT_LTHIGH, + BIT_KNIFES, + BIT_LUPARM, + BIT_RUPARM +}; + +qboolean canthrownode_as (edict_t *self, int BP, int *throw_nodes) +{//see if it's on, if so, add it to throw_nodes + //turn it off on thrower + if(!(self->s.fmnodeinfo[BP].flags & FMNI_NO_DRAW)) + { + *throw_nodes |= Bit_for_MeshNode_as[BP]; + self->s.fmnodeinfo[BP].flags |= FMNI_NO_DRAW; + return true; + } + return false; +} + +//THROWS weapon, turns off those nodes, sets that weapon as gone +void assassin_dropweapon (edict_t *self, int whichknives) +{//NO PART FLY FRAME! + vec3_t handspot, right; + + AngleVectors(self->s.angles,NULL,right,NULL); + + if(!(self->s.fmnodeinfo[MESH__LKNIFE].flags & FMNI_NO_DRAW)&&whichknives & BIT_LKNIFE) + { + VectorClear(handspot); + VectorMA(handspot, -12, right, handspot); + ThrowWeapon(self, &handspot, BIT_LKNIFE, 0, FRAME_prtfly);//FRAME_atakc3); + self->s.fmnodeinfo[MESH__LKNIFE].flags |= FMNI_NO_DRAW; + } + if(!(self->s.fmnodeinfo[MESH__RKNIFE].flags & FMNI_NO_DRAW)&&whichknives & BIT_RKNIFE) + { + VectorClear(handspot); + VectorMA(handspot, 12, right, handspot); + ThrowWeapon(self, &handspot, BIT_RKNIFE, 0, FRAME_prtfly);//FRAME_atakc3); + self->s.fmnodeinfo[MESH__RKNIFE].flags |= FMNI_NO_DRAW; + } +} + +int assassin_convert_hitloc_dead(int hl) +{ + switch(hl) + { + case hl_Head: + return hl_TorsoFront; + break; + + case hl_TorsoFront://split in half? + if(!irand(0,1)) + return hl_LegUpperRight; + else + return hl_LegUpperLeft; + break; + + case hl_TorsoBack://split in half? + return hl_Head; + break; + + case hl_ArmUpperLeft: + return hl_ArmLowerLeft; + break; + + case hl_ArmLowerLeft://left arm + return hl_ArmUpperLeft; + break; + + case hl_ArmUpperRight: + return hl_ArmLowerRight; + break; + + case hl_ArmLowerRight://right arm + return hl_ArmUpperRight; + break; + + case hl_LegUpperLeft: + return hl_LegLowerLeft; + break; + + case hl_LegLowerLeft://left leg + return hl_LegUpperLeft; + break; + + case hl_LegUpperRight: + return hl_LegLowerRight; + break; + + case hl_LegLowerRight://right leg + return hl_LegUpperRight; + break; + + default: + return irand(hl_Head, hl_LegLowerRight); + break; + } + +} + +void assassin_dismember(edict_t *self, int damage, int HitLocation) +{ + int throw_nodes = 0; + vec3_t gore_spot, right; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; +// gi.dprintf("HL: %d",HitLocation); + + if(self->health>0) + { + if(self->curAnimID==ANIM_DAGGERL||(self->curAnimID==ANIM_DAGGERB&&irand(0,2)<1)) + {//Hit chest during melee, may have hit arms + if(HitLocation == hl_TorsoFront&&irand(0,10)<4) + { + if(irand(0,10)<7) + HitLocation = hl_ArmLowerRight; + else + HitLocation = hl_ArmLowerLeft; + } + } + + if(self->curAnimID==ANIM_DAGGERR||self->curAnimID==ANIM_DAGGERC||(self->curAnimID==ANIM_DAGGERB&&irand(0,2)<1)) + {//Hit chest during melee, may have hit arms + if(HitLocation == hl_TorsoFront&&irand(0,10)<4) + { + if(irand(0,10)<7) + HitLocation = hl_ArmLowerRight; + else + HitLocation = hl_ArmLowerLeft; + } + } + + if( + (HitLocation == hl_ArmUpperLeft&& self->s.fmnodeinfo[MESH__LUPARM].flags & FMNI_NO_DRAW) || + (HitLocation == hl_ArmUpperRight&& self->s.fmnodeinfo[MESH__RUPARM].flags & FMNI_NO_DRAW)|| + ( + (HitLocation == hl_TorsoFront|| HitLocation == hl_TorsoBack) && + self->s.fmnodeinfo[MESH__LUPARM].flags & FMNI_NO_DRAW && + self->s.fmnodeinfo[MESH__RUPARM].flags & FMNI_NO_DRAW && + irand(0,10)<4) + ) + HitLocation = hl_Head;//Decap + } + else + HitLocation = assassin_convert_hitloc_dead(HitLocation); + + VectorClear(gore_spot); + switch(HitLocation) + { + case hl_Head: + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,8,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { + self->s.fmnodeinfo[MESH__HEAD].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__HEAD].skin = self->s.skinnum+1; + } + break; + + case hl_TorsoFront://split in half? + if(self->s.fmnodeinfo[MESH__TORSOFT].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__TORSOFT].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,12,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { +// if(flrand(0,self->health)s.fmnodeinfo[MESH__TORSOFT].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__TORSOFT].skin = self->s.skinnum+1; + } + break; + case hl_TorsoBack://split in half? + if(self->s.fmnodeinfo[MESH__TORSOBK].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__TORSOBK].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,12,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { +// if(flrand(0,self->health)s.fmnodeinfo[MESH__TORSOBK].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__TORSOBK].skin = self->s.skinnum+1; + } + break; + + case hl_ArmUpperLeft: + if(self->s.fmnodeinfo[MESH__LUPARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__LUPARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged +// if(flrand(0,self->health)health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + assassin_dropweapon (self, BIT_LKNIFE); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_prtfly); + } + } + else + { + self->s.fmnodeinfo[MESH__LUPARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LUPARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmLowerLeft://left arm + if(self->s.fmnodeinfo[MESH__L4ARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__L4ARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + assassin_dropweapon (self, BIT_LKNIFE); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_prtfly); + } + } + else + { + self->s.fmnodeinfo[MESH__L4ARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__L4ARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperRight: + if(self->s.fmnodeinfo[MESH__RUPARM].flags & FMNI_NO_DRAW) + break; + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + assassin_dropweapon (self, BIT_RKNIFE); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_prtfly); + } + } + else + { + self->s.fmnodeinfo[MESH__RUPARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RUPARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmLowerRight://right arm + if(self->s.fmnodeinfo[MESH__R4ARM].flags & FMNI_NO_DRAW) + break; + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + assassin_dropweapon (self, BIT_RKNIFE); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_prtfly); + } + } + else + { + self->s.fmnodeinfo[MESH__R4ARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__R4ARM].skin = self->s.skinnum+1; + } + break; + + case hl_LegUpperLeft: + if(self->health>0) + { + if(self->s.fmnodeinfo[MESH__LTHIGH].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__LTHIGH].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LTHIGH].skin = self->s.skinnum+1; + break; + } + else + { + if(self->s.fmnodeinfo[MESH__LTHIGH].flags & FMNI_NO_DRAW) + break; + canthrownode_as(self, MESH__LCALF, &throw_nodes); + if(canthrownode_as(self, MESH__LTHIGH, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + case hl_LegLowerLeft://left leg + if(self->health>0) + { + if(self->s.fmnodeinfo[MESH__LCALF].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__LCALF].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LCALF].skin = self->s.skinnum+1; + break; + } + else + { + if(self->s.fmnodeinfo[MESH__LCALF].flags & FMNI_NO_DRAW) + break; + if(canthrownode_as(self, MESH__LCALF, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + + case hl_LegUpperRight: + if(self->health>0) + { + if(self->s.fmnodeinfo[MESH__RTHIGH].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__RTHIGH].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RTHIGH].skin = self->s.skinnum+1; + break; + } + else + { + if(self->s.fmnodeinfo[MESH__RTHIGH].flags & FMNI_NO_DRAW) + break; + canthrownode_as(self, MESH__RCALF, &throw_nodes); + if(canthrownode_as(self, MESH__RTHIGH, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + case hl_LegLowerRight://right leg + if(self->health>0) + { + if(self->s.fmnodeinfo[MESH__RCALF].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__RCALF].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RCALF].skin = self->s.skinnum+1; + break; + } + else + { + if(self->s.fmnodeinfo[MESH__RCALF].flags & FMNI_NO_DRAW) + break; + if(canthrownode_as(self, MESH__RCALF, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + + default: + if(flrand(0,self->health)s.fmnodeinfo[MESH__L4ARM].flags&FMNI_NO_DRAW&& + self->s.fmnodeinfo[MESH__R4ARM].flags&FMNI_NO_DRAW) + { + self->monsterinfo.aiflags |= AI_COWARD; + self->monsterinfo.aiflags |= AI_NO_MELEE; + self->monsterinfo.aiflags |= AI_NO_MISSILE; + } +// gi.dprintf(" done\n"); +} + +void assassin_dismember_msg(edict_t *self, G_Message_t *msg) +{//fixme: throw current weapon +//fixme - make part fly dir the vector from hit loc to sever loc +//remember- turn on caps! + int damage; + HitLocation_t HitLocation; + + ParseMsgParms(msg, "ii", &damage, &HitLocation); + assassin_dismember(self, damage, HitLocation); +} + +void assassin_dead_pain (edict_t *self, G_Message_t *msg) +{ + if(msg) + if(!(self->svflags & SVF_PARTS_GIBBED)) + assassin_dismember_msg(self, msg); +} + +void assassin_random_pain_sound (edict_t *self) +{ + if(irand(0,1)) + gi.sound(self, CHAN_VOICE, Sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, Sounds[SND_PAIN2], 1, ATTN_NORM, 0); +} + +void assassin_pain(edict_t *self, G_Message_t *msg) +{ + edict_t *attacker, *inflictor; + int damage, temp; + qboolean force_pain; + + if(self->curAnimID == ANIM_TELEPORT) + return; + + ParseMsgParms(msg, "eeiii", &inflictor, &attacker, &force_pain, &damage, &temp); + + if(inflictor == attacker || !stricmp(inflictor->classname, "Spell_RedRain")||!stricmp(inflictor->classname, "Spell_Hellbolt")) + {//melee hit or contant effect, don't stick around! + if(!(self->spawnflags&MSF_ASS_NOTELEPORT)&& + !(self->spawnflags&MSF_FIXED)&& + self->groundentity) + { + if(assassinChooseTeleportDestination(self, ASS_TP_ANY, true, false)) + return; + } + } + + if(!force_pain) + if(flrand(0,self->health)>damage) + return; + + self->monsterinfo.aiflags &= ~AI_OVERRIDE_GUIDE; + + if(!self->maxs[2]) + assassinUndoCrouched (self); + + assassin_random_pain_sound(self); + + if (self->pain_debounce_time < level.time||force_pain) + { + self->pain_debounce_time = level.time + skill->value + 2; + SetAnim(self, ANIM_PAIN2); + if(irand(0, 10) > skill->value) + { + self->monsterinfo.misc_debounce_time = level.time + 3;//3 seconds before can re-cloak + assassinInitDeCloak(self); + } + } +} + +void assassinSkipFrameSkillCheck (edict_t *self) +{ + if(irand(0, 3) < skill->value) + self->s.frame++; +} + +/*------------------------------------------------------------------------- + assassin_pause +-------------------------------------------------------------------------*/ +void assassin_pause (edict_t *self) +{ + vec3_t v; + float len; + +//this gets stuck on, sometimes + self->s.fmnodeinfo[MESH__LKNIFE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__RKNIFE].flags |= FMNI_NO_DRAW; + + if(self->monsterinfo.aiflags&AI_OVERRIDE_GUIDE) + return; + + if(self->spawnflags & MSF_FIXED && self->curAnimID == ANIM_DELAY && self->enemy) + { + self->monsterinfo.searchType = SEARCH_COMMON; + MG_FaceGoal(self, true); + } + + self->mood_think(self); + + if (self->ai_mood == AI_MOOD_NORMAL) + { + FindTarget(self); + + if(self->enemy) + { + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + + if ((len > 80) || (self->monsterinfo.aiflags & AI_FLEE)) // Far enough to run after + { + QPostMessage(self, MSG_RUN,PRI_DIRECTIVE, NULL); + } + else // Close enough to Attack + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + } + } + } + else + { + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + if(self->ai_mood_flags & AI_MOOD_FLAG_MISSILE) + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_PURSUE: + case AI_MOOD_NAVIGATE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_STAND: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_WALK: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_DELAY: + SetAnim(self, ANIM_DELAY); + break; + + case AI_MOOD_WANDER: + if(self->spawnflags&MSF_FIXED) + { + SetAnim(self, ANIM_DELAY); + return; + } + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_JUMP: + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_FJUMP);//fjump will apply the movedir when he's ready + break; + + default : +#ifdef _DEVEL + gi.dprintf("assassin: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } + } +} + +void assassinChooseJumpAmbush(edict_t *self) +{ + float dot; + vec3_t forward, enemy_dir; + + if(!self->enemy) + { + if(irand(0, 10)<4) + SetAnim(self, ANIM_JUMP); + else + SetAnim(self, ANIM_FRONTFLIP); + return; + } + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorSubtract(self->enemy->s.origin, self->s.origin, enemy_dir); + VectorNormalize(enemy_dir); + dot = DotProduct(forward, enemy_dir); + if(dot<0) + {//behind + SetAnim(self, ANIM_BACKFLIP); + return; + } + + if(!irand(0, 3)) + SetAnim(self, ANIM_JUMP); + else + SetAnim(self, ANIM_FRONTFLIP); + return; +} + +qboolean assassinChooseSideJumpAmbush(edict_t *self) +{//OR: turn and jump? + float dot; + vec3_t right, enemy_dir; + + if(!self->enemy) + return false; + + AngleVectors(self->s.angles, NULL, right, NULL); + VectorSubtract(self->enemy->s.origin, self->s.origin, enemy_dir); + VectorNormalize(enemy_dir); + + dot = DotProduct(right, enemy_dir); + if(dot>0) + VectorScale(right, 300, self->movedir); + else + VectorScale(right, -300, self->movedir); + + self->movedir[2] = 200; + SetAnim(self, ANIM_FJUMP); + return true; +} +/*------------------------------------------------------------------------- + assassin_run +-------------------------------------------------------------------------*/ +void assassin_run(edict_t *self, G_Message_t *msg) +{ + if(!self->enemy&&self->spawnflags&MSF_WANDER) + { + SetAnim(self, ANIM_RUN); + return; + } + + if(self->spawnflags&MSF_ASS_STARTSHADOW)//decloak + {//FIXME: should I wait until infront of enemy and visible to him? + self->spawnflags &= ~MSF_ASS_STARTSHADOW; + assassinInitCloak(self); + } + + if(!(self->spawnflags&MSF_FIXED)) + { + if(self->spawnflags&MSF_ASS_JUMPAMBUSH)//jump out + { + self->spawnflags &= ~MSF_ASS_JUMPAMBUSH; + assassinChooseJumpAmbush(self); + return; + } + + if(self->spawnflags&MSF_ASS_SIDEJUMPAMBUSH)//side-jump out + { + self->spawnflags &= ~MSF_ASS_SIDEJUMPAMBUSH; + if(assassinChooseSideJumpAmbush(self)) + return; + } + } + + if(self->curAnimID >= ANIM_CROUCH_IDLE && self->curAnimID < ANIM_CROUCH_END) + { + SetAnim(self, ANIM_CROUCH_END); + return; + } + + if (M_ValidTarget(self, self->enemy)) + { + if(!irand(0, 7)) + { + if(assassinCheckTeleport(self, ASS_TP_OFF)) + { +// gi.dprintf("run->teleport\n"); + return; + } + else if(!irand(0, 3)) + { + if(!(self->s.renderfx & RF_ALPHA_TEXTURE)) + { + if(!(self->spawnflags&MSF_ASS_NOSHADOW)) + { + SetAnim(self, ANIM_CLOAK); + return; + } + }//else uncloak - unncloak when die + } + } + if(!(self->spawnflags&MSF_FIXED)) + SetAnim(self, ANIM_RUN); + else + SetAnim(self, ANIM_DELAY); + } + else + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + + +void assassin_go_run(edict_t *self, float dist) +{ + if(!self->maxs[2]) + assassinUndoCrouched (self); + + if(self->enemy) + ai_run(self, dist); + else + ai_walk(self, dist); +} +/*---------------------------------------------------------------------- + assassin runorder - order the assassin to choose an run animation +-----------------------------------------------------------------------*/ +void assassin_runorder(edict_t *self) +{ + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); +} + + +/*------------------------------------------------------------------------- + assassinsqueal +-------------------------------------------------------------------------*/ +void assassinsqueal (edict_t *self) +{ +/* + if(irand(0, 1)) + gi.sound(self, CHAN_WEAPON, Sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_WEAPON, Sounds[SND_PAIN2], 1, ATTN_NORM, 0); +*/ +} + +/*------------------------------------------------------------------------- + assassin_stand +-------------------------------------------------------------------------*/ +void assassin_stand(edict_t *self, G_Message_t *msg) +{ + if (self->ai_mood == AI_MOOD_DELAY) + SetAnim(self, ANIM_DELAY); + else + { + if(self->s.renderfx & RF_ALPHA_TEXTURE) + { + if(self->pre_think != assassinDeCloak) + assassinInitDeCloak(self); + } + SetAnim(self, ANIM_STAND); + } + + return; +} + + +/*------------------------------------------------------------------------- + assassin_walk +-------------------------------------------------------------------------*/ +void assassin_crouch_idle_decision (edict_t *self) +{//FIXME: need to uncrouch + int chance; + + chance = irand(0, 100); + switch(self->curAnimID) + { + case ANIM_CROUCH_IDLE: + if(chance < 55) + SetAnim(self, ANIM_CROUCH_IDLE); + else if(chance < 75) + SetAnim(self, ANIM_CROUCH_POKE); + else if(chance < 85) + SetAnim(self, ANIM_CROUCH_LOOK_RIGHT); + else if(chance < 95) + SetAnim(self, ANIM_CROUCH_LOOK_LEFT); + else + SetAnim(self, ANIM_CROUCH_END); + break; + + case ANIM_CROUCH_LOOK_RIGHT: + case ANIM_CROUCH_LOOK_RIGHT_IDLE: + case ANIM_CROUCH_LOOK_L2R: + if(chance < 60) + SetAnim(self, ANIM_CROUCH_LOOK_RIGHT_IDLE); + else if(chance < 85) + SetAnim(self, ANIM_CROUCH_LOOK_R2C); + else + SetAnim(self, ANIM_CROUCH_LOOK_R2L); + break; + + case ANIM_CROUCH_LOOK_LEFT: + case ANIM_CROUCH_LOOK_LEFT_IDLE: + case ANIM_CROUCH_LOOK_R2L: + if(chance < 60) + SetAnim(self, ANIM_CROUCH_LOOK_LEFT_IDLE); + else if(chance < 85) + SetAnim(self, ANIM_CROUCH_LOOK_L2C); + else + SetAnim(self, ANIM_CROUCH_LOOK_L2R); + break; + + case ANIM_CROUCH_TRANS: + self->monsterinfo.pausetime = 99999999; + SetAnim(self, ANIM_CROUCH_IDLE); + break; + + case ANIM_CROUCH_LOOK_R2C: + case ANIM_CROUCH_LOOK_L2C: + case ANIM_CROUCH_POKE: + SetAnim(self, ANIM_CROUCH_IDLE); + break; + + case ANIM_CROUCH_END: + self->damage_debounce_time = level.time + 10; + self->monsterinfo.pausetime = -1; + SetAnim(self, ANIM_STAND); + break; + + default: + SetAnim(self, ANIM_CROUCH_END); + break; + } +} + +void assassin_ai_walk (edict_t *self, float dist) +{ + if(self->damage_debounce_time < level.time) + { + if(self->enemy) + { + if(vhlen(self->s.origin, self->enemy->s.origin) < 48 && infront(self, self->enemy)) + { + assassinNodeOn (self, MESH__LKNIFE); + SetAnim(self, ANIM_CROUCH_TRANS); + return; + } + } + else if(self->oldenemy) + { + if(vhlen(self->s.origin, self->oldenemy->s.origin) < 48 && infront(self, self->oldenemy)) + { + assassinNodeOn (self, MESH__LKNIFE); + SetAnim(self, ANIM_CROUCH_TRANS); + return; + } + } + } + ai_walk(self, dist); +} + +void assassin_walk(edict_t *self, G_Message_t *msg) +{ + if(self->spawnflags&MSF_FIXED) + { + SetAnim(self, ANIM_DELAY); + return; + } + if(self->curAnimID == ANIM_WALK_LOOP) + SetAnim(self, ANIM_WALK_LOOP); + else + SetAnim(self, ANIM_WALK); + return; +} + +void assasin_walk_loop_go (edict_t *self) +{ + SetAnim(self, ANIM_WALK_LOOP); +} +//============================================================= + +// EVASION + +//============================================================= + +void assassinDodgeLeft (edict_t *self) +{ + SetAnim(self, ANIM_DODGE_LEFT); +} + +void assassinDodgeRight (edict_t *self) +{ + SetAnim(self, ANIM_DODGE_RIGHT); +} + +void assassinFrontFlip (edict_t *self) +{ + SetAnim(self, ANIM_EVFRONTFLIP); +} + +void assassinBackFlip (edict_t *self) +{ + SetAnim(self, ANIM_EVBACKFLIP); +} + +void assassinBackSprings (edict_t *self) +{ + SetAnim(self, ANIM_BACKSPRING); +} + +void assassinJump (edict_t *self) +{ + SetAnim(self, ANIM_EVJUMP); +} + +void assassinCrouch (edict_t *self) +{ + SetAnim(self, ANIM_CROUCH); +} + +void assassinCrouchedAttack (edict_t *self) +{ + SetAnim(self, ANIM_DAGGERC); +} + +void assassin_evade (edict_t *self, G_Message_t *msg) +{ + edict_t *projectile; + HitLocation_t HitLocation; + int duck_chance, dodgeleft_chance, dodgeright_chance, jump_chance, backflip_chance, frontflip_chance; + int chance; + float eta; + + if(!self->groundentity) + return; + + ParseMsgParms(msg, "eif", &projectile, &HitLocation, &eta); + + if(eta < 2) + self->evade_debounce_time = level.time + eta; + else + self->evade_debounce_time = level.time + 2; + + if(skill->value || self->spawnflags & MSF_ASS_TELEPORTDODGE) + {//Pussies were complaining about assassins teleporting away from certain death, so don't do that unless in hard + if(!stricmp(projectile->classname, "Spell_PhoenixArrow") || + !stricmp(projectile->classname, "Spell_FireWall") || + !stricmp(projectile->classname, "Spell_SphereOfAnnihilation") || + !stricmp(projectile->classname, "Spell_Maceball")) + { + if(assassinChooseTeleportDestination(self, ASS_TP_OFF, true, true)) + return; + } + } + + switch(HitLocation) + { + case hl_Head: + duck_chance = 95; + dodgeleft_chance = 50; + dodgeright_chance = 50; + jump_chance = 0; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_TorsoFront://split in half? + duck_chance = 85; + dodgeleft_chance = 40; + dodgeright_chance = 40; + jump_chance = 0; + backflip_chance = 60; + frontflip_chance = 0; + break; + case hl_TorsoBack://split in half? + duck_chance = 80; + dodgeleft_chance = 40; + dodgeright_chance = 40; + jump_chance = 0; + backflip_chance = 0; + frontflip_chance = 60; + break; + case hl_ArmUpperLeft: + duck_chance = 75; + dodgeleft_chance = 0; + dodgeright_chance = 90; + jump_chance = 0; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_ArmLowerLeft://left arm + duck_chance = 75; + dodgeleft_chance = 0; + dodgeright_chance = 80; + jump_chance = 30; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_ArmUpperRight: + duck_chance = 60; + dodgeleft_chance = 90; + dodgeright_chance = 0; + jump_chance = 0; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_ArmLowerRight://right arm + duck_chance = 20; + dodgeleft_chance = 80; + dodgeright_chance = 0; + jump_chance = 30; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_LegUpperLeft: + duck_chance = 0; + dodgeleft_chance = 0; + dodgeright_chance = 60; + jump_chance = 50; + backflip_chance = 30; + frontflip_chance = 30; + break; + case hl_LegLowerLeft://left leg + duck_chance = 0; + dodgeleft_chance = 0; + dodgeright_chance = 30; + jump_chance = 80; + backflip_chance = 40; + frontflip_chance = 40; + break; + case hl_LegUpperRight: + duck_chance = 0; + dodgeleft_chance = 60; + dodgeright_chance = 0; + jump_chance = 50; + backflip_chance = 30; + frontflip_chance = 30; + break; + case hl_LegLowerRight://right leg + duck_chance = 0; + dodgeleft_chance = 30; + dodgeright_chance = 0; + jump_chance = 80; + backflip_chance = 40; + frontflip_chance = 40; + break; + default: + duck_chance = 20; + dodgeleft_chance = 10; + dodgeright_chance = 10; + jump_chance = 10; + backflip_chance = 10; + frontflip_chance = 10; + break; + } + + if(irand(0, 100) < skill->value * 10) + { + if(self->pre_think != assassinCloak) + assassinInitCloak(self); + } + + chance = irand(0, 10); + if(skill->value || self->spawnflags & MSF_ASS_TELEPORTDODGE) + {//Pussies were complaining about assassins teleporting away from certain death, so don't do that unless in hard + if(chance > 8 && !(self->spawnflags&MSF_ASS_NOTELEPORT)) + if(assassinChooseTeleportDestination(self, ASS_TP_DEF, false, false)) + { +// gi.dprintf("Assassin teleport evade\n"); + return; + } + } + + chance = irand(0, 100); + if(chance < frontflip_chance) + { +// gi.dprintf("Assassin fflip evade\n"); + assassinFrontFlip(self); + return; + } + + chance = irand(0, 100); + if(chance < backflip_chance) + { + if(self->curAnimID == ANIM_RUN && irand(0, 3))//running, do the front flip + { +// gi.dprintf("Assassin fflip evade\n"); + assassinFrontFlip(self); + } + else + { + if(irand(0, 1)) + { +// gi.dprintf("Assassin bspring evade\n"); + assassinBackSprings(self); + } + else + { +// gi.dprintf("Assassin bflip evade\n"); + assassinBackFlip(self); + } + } + return; + } + + chance = irand(0, 100); + if(chance < duck_chance) + { + self->evade_debounce_time = level.time + eta + 2 - skill->value; +// gi.dprintf("Assassin crouch evade\n"); + assassinCrouch(self); + return; + } + + chance = irand(0, 100); + if(chance < dodgeleft_chance) + { +// gi.dprintf("Assassin dleft evade\n"); + assassinDodgeLeft(self); + return; + } + + chance = irand(0, 100); + if(chance < dodgeright_chance) + { +// gi.dprintf("Assassin dright evade\n"); + assassinDodgeRight(self); + return; + } + + chance = irand(0, 100); + if(chance < jump_chance) + { + if(self->curAnimID == ANIM_RUN && irand(0, 4))//running, do the front flip + { +// gi.dprintf("Assassin fflip evade\n"); + assassinFrontFlip(self); + } + else + { +// gi.dprintf("Assassin jump evade\n"); + assassinJump(self); + } + return; + } + + if(skill->value || self->spawnflags & MSF_ASS_TELEPORTDODGE) + {//Pussies were complaining about assassins teleporting away from certain death, so don't do that unless in hard + if(!(self->spawnflags&MSF_ASS_NOTELEPORT)) + if(assassinChooseTeleportDestination(self, ASS_TP_DEF, false, false)) + { +// gi.dprintf("Assassin tport(desperate) evade\n"); + return; + } + } + + self->evade_debounce_time = 0; +// gi.dprintf("Assassin failed to evade\n"); +} + +void assassinCrouchedCheckAttack (edict_t *self, float attack) +{ + if(!clear_visible(self, self->enemy)) + return; + + if(!infront(self, self->enemy)) + return; + + if(irand(0,10)<5) + return; + + if(attack == true) + assassindagger(self, BIT_RKNIFE); + else if(attack == 2)//start crouched attack anim + SetAnim(self, ANIM_DAGGERC); + else//loop back inside that anim + self->monsterinfo.currframeindex = 2; +} + +void assassinNodeOn (edict_t *self, float node) +{ + self->s.fmnodeinfo[(int)node].flags &= ~FMNI_NO_DRAW; +} + +void assassinStop (edict_t *self) +{ + if(self->evade_debounce_time - level.time> 0.1f) + self->nextthink = level.time + (self->evade_debounce_time - level.time); +} + +void assassinSetCrouched (edict_t *self) +{ + VectorSet (self->maxs, 16, 16, 0); + self->viewheight = 0; +} + +void assassinUndoCrouched (edict_t *self) +{ + VectorSet (self->maxs, 16, 16, 48); + self->viewheight = 40; +} + +void assassin_sound(edict_t *self, float channel, float soundnum, float attn) +{ + gi.sound (self, (int)(channel), Sounds[(int)(soundnum)], 1, (int)(attn), 0); +} + +void assassinGoJump (edict_t *self, float fwdspd,float upspd,float rtspd) +{//fixme: do checks and traces first + vec3_t up, forward, right; + + self->monsterinfo.aiflags &= ~AI_OVERRIDE_GUIDE; + assassin_sound(self, CHAN_VOICE, SND_JUMP, ATTN_NORM); + AngleVectors(self->s.angles, forward, right, up); + + VectorMA(self->velocity, upspd, up, self->velocity); + VectorMA(self->velocity, fwdspd, forward, self->velocity); + VectorMA(self->velocity, rtspd, right, self->velocity); +} + +void assassin_go_inair(edict_t *self) +{ + SetAnim(self, ANIM_INAIR); +} + +void assassin_go_evinair(edict_t *self) +{ + SetAnim(self, ANIM_EVINAIR); +} + +void assassin_go_ffinair(edict_t *self) +{ + SetAnim(self, ANIM_FFINAIR); +} + +void assassin_go_bfinair(edict_t *self) +{ + SetAnim(self, ANIM_BFINAIR); +} + +void assassinCheckLoop (edict_t *self, float frame) +{//see if should fire again + vec3_t v; + float len, melee_range, min_seperation, jump_range; + + if(!self->enemy) + return; + + ai_charge2(self, 0); + + if(!clear_visible(self, self->enemy)) + return; + + if(!infront(self, self->enemy)) + return; + + if(irand(0, 100) < self->bypass_missile_chance) + { + self->monsterinfo.attack_finished = level.time + 3 - skill->value; + return; + } + + if(self->ai_mood_flags&AI_MOOD_FLAG_BACKSTAB) + return; + + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + melee_range = 64; + jump_range = 128; + min_seperation = self->maxs[0] + self->enemy->maxs[0]; + + if (infront(self, self->enemy)) + {//don't loop if enemy close enough + if (len < min_seperation + melee_range) + return; + else if (len < min_seperation + jump_range && irand(0,10)<3) + return; + } + + self->monsterinfo.currframeindex = (int)frame; +} + +void assassinSmoke(edict_t *self) +{ + vec3_t pos; + VectorCopy(self->s.origin, pos); + pos[2]+=self->mins[2]; + gi.CreateEffect(NULL, FX_TPORTSMOKE, 0, pos, "");//, "db", hitangles, 5); + //gi.CreateEffect(&self->s, FX_DUST_PUFF, CEF_OWNERS_ORIGIN, self->s.origin, NULL); +} + +void assassinGone(edict_t *self) +{ + vec3_t enemy_dir; + + if(self->placeholder) + G_FreeEdict(self->placeholder); + + VectorCopy(self->pos2, self->s.origin); + + if(self->enemy) + {//face enemy + VectorSubtract(self->enemy->s.origin, self->s.origin, enemy_dir); + self->s.angles[YAW] = anglemod(vectoyaw(enemy_dir)); + } + + assassinSmoke(self); + + VectorCopy(self->pos2, enemy_dir);//reuse + enemy_dir[2] += 100; + if(gi.pointcontents(enemy_dir) == CONTENTS_EMPTY&&!irand(0,3)) + assassinFrontFlip(self); + else + SetAnim(self, ANIM_UNCROUCH); + + self->monsterinfo.aiflags &= ~AI_OVERRIDE_GUIDE; + self->svflags &= ~SVF_NO_AUTOTARGET; + + //dumbed down + self->touch_debounce_time = level.time + (10 - skill->value*3); + + //Should we clear velocity too? + //VectorClear(self->velocity); + gi.linkentity(self); +} + +void assassinPrepareTeleportDest(edict_t *self, vec3_t spot, qboolean instant) +{ + if(self->s.renderfx & RF_ALPHA_TEXTURE) + { + if(self->pre_think != assassinDeCloak) + { + assassinInitDeCloak(self); + self->monsterinfo.misc_debounce_time = level.time + 3; + } + } + + VectorCopy(spot, self->pos2); + + self->placeholder = G_Spawn(); + VectorCopy(self->pos2, self->placeholder->s.origin); + self->placeholder->solid = SOLID_BBOX; + VectorCopy(self->mins, self->placeholder->mins); + VectorCopy(self->maxs, self->placeholder->mins); + self->placeholder->think = G_FreeEdict; + self->placeholder->nextthink = level.time + 2;//just in case + + //dumbed down + if(instant && skill->value > 1) + { + assassinReadyTeleport(self); + assassinGone(self); + } + else + { + SetAnim(self, ANIM_TELEPORT); + } +} + +qboolean assassinChooseTeleportDestination(edict_t *self, int type, qboolean imperative, qboolean instant) +{//FIXME: don't teleport into area with red rain or ripper balls! + vec3_t teleport_angles, forward, endpos, startpos; + trace_t trace; + int chance, num_tries, i; + edict_t *noblockent; + float tracedist; + + //Instead of chance, do around self if evade, around other if ambush + + if(!self->enemy)//fixme- choose my spot? + return false; + + if(self->spawnflags&MSF_FIXED) + return false; + + if(imperative) + num_tries = (skill->value + 1) * 10; + else + num_tries = 1; + + for(i = 0; i < num_tries; i++) + { + switch(type) + { + case ASS_TP_OFF: + chance = irand(0, 66); + break; + case ASS_TP_ANY: + chance = irand(0, 100); + break; + case ASS_TP_DEF: + chance = irand(33, 100); + break; + } + + if(chance<33) + {//ANY, OFF to behind enemy + VectorSet(teleport_angles, 0, anglemod(self->enemy->s.angles[YAW] + flrand(-90, 90)), 0); + AngleVectors(teleport_angles, forward, NULL, NULL); + VectorCopy(self->enemy->s.origin, startpos); + startpos[2]+=self->enemy->mins[2]; + startpos[2]-=self->mins[2]; + tracedist = irand(self->min_missile_range, self->missile_range); + VectorMA(startpos, -tracedist, forward, endpos); + noblockent = self->enemy; + } + else if(chance<66) + {//ANY to anywhere around enemy + VectorSet(teleport_angles, 0, anglemod(flrand(0, 360)), 0); + AngleVectors(teleport_angles, forward, NULL, NULL); + VectorCopy(self->enemy->s.origin, startpos); + startpos[2]+=self->enemy->mins[2]; + startpos[2]-=self->mins[2]; + tracedist = irand(self->min_missile_range, self->missile_range); + VectorMA(startpos, -tracedist, forward, endpos); + noblockent = self->enemy; + } + else + {//ANY, DEF to anywhere around me + VectorSet(teleport_angles, 0, anglemod(flrand(0, 360)), 0); + AngleVectors(teleport_angles, forward, NULL, NULL); + VectorCopy(self->s.origin, startpos); + tracedist = irand(self->min_missile_range, self->missile_range/2); + VectorMA(startpos, -tracedist, forward, endpos); + noblockent = self; + } + + gi.trace(startpos, self->mins, self->maxs, endpos, noblockent, MASK_MONSTERSOLID,&trace); + + if(trace.fraction*tracedist < 100)//min origin lerp dist + continue; + + if(trace.allsolid || trace.startsolid) + continue; + + if(vhlen(trace.endpos, self->enemy->s.origin)>=self->min_missile_range) + { + VectorCopy(trace.endpos, startpos); + VectorCopy(trace.endpos, endpos); + endpos[2] -=64; + gi.trace(startpos, self->mins, self->maxs, endpos, noblockent, MASK_MONSTERSOLID,&trace); + if(trace.fraction<1.0 && !trace.allsolid && !trace.startsolid)//the last two should be false if trace.fraction is < 1.0 but doesn't hurt to check + { + assassinPrepareTeleportDest(self, trace.endpos, instant); + return true; + } + } + } + return false; +} + +void assassinReadyTeleport (edict_t *self) +{ + assassinSmoke(self); + self->svflags |= SVF_NO_AUTOTARGET; +} + +qboolean assassinCheckTeleport (edict_t *self, int type) +{ + if(self->spawnflags&MSF_ASS_NOTELEPORT) + return false; + + if(self->spawnflags&MSF_FIXED) + return false; + + if(!self->groundentity) + return false; + + if(!M_ValidTarget(self, self->enemy)) + return false; + +/* if(!infront(self->enemy, self)) + return false; + + if(!visible(self->enemy, self)) + return false;*/ + + return assassinChooseTeleportDestination(self, type, false, false); +} + +void assassinUnCrouch (edict_t *self) +{ + SetAnim(self, ANIM_UNCROUCH); +} + +qboolean assassinCheckCloak (edict_t *self) +{ + int chance = 0; + + if(!self->monsterinfo.awake) + return (false); + + if(self->monsterinfo.misc_debounce_time > level.time)//cloak debounce time + return (false); + + if(self->spawnflags & MSF_ASS_NOSHADOW) + return (false); + + if(self->ai_mood == AI_MOOD_FLEE) + return (true); + + if(!self->enemy) + return (false); + + if(infront(self->enemy, self)) + chance = -3; + + if(irand(0, 10 - skill->value + chance) <= 0) + return (true); + + return (false); +} + +qboolean assassinCheckDeCloak (edict_t *self) +{ + float dist; + int chance = 0; + + if(!self->monsterinfo.awake) + return (false); + + if(self->monsterinfo.misc_debounce_time > level.time)//cloak debounce time + return (false); + + if(!self->enemy) + { + if(!(self->spawnflags & MSF_ASS_STARTSHADOW)) + return (true); + return (false); + } + + dist = M_DistanceToTarget(self, self->enemy); + if(distenemy, self)) + chance = -3; + + if(irand(0, 10 + skill->value * 2 + chance) <= 0) + return (true); + + return (false); +} + +void assassinCloakThink (edict_t *self) +{ + edict_t *found = NULL; + int lowerseq, upperseq; + vec3_t mins, maxs, startpos, endpos, tport_dest; + trace_t trace; + + self->pre_think = assassinCloakThink; + self->next_pre_think = level.time + FRAMETIME; +//check cloak or decloak + if(!(self->s.renderfx & RF_ALPHA_TEXTURE)) + {//not cloaked + if(assassinCheckCloak(self)) + { + self->monsterinfo.misc_debounce_time = level.time + 7;//10 seconds before will willingly uncloak + assassinInitCloak(self); + } + } + else + {//cloaked + if(assassinCheckDeCloak(self)) + assassinInitDeCloak(self); + } +//check to teleport + + //dumbed down + if(!skill->value)//was < 2 + { + if(self->touch_debounce_time > level.time) + { + return; + } + } + + if(self->waterlevel == 3 && self->air_finished <= level.time)//going to drown! + {//pick either last buoy or my startspot + VectorCopy(self->pos1, tport_dest); + if(self->lastbuoy>NULL_BUOY) + { + if(!(gi.pointcontents(level.buoy_list[self->lastbuoy].origin) & MASK_WATER)) + VectorCopy(level.buoy_list[self->lastbuoy].origin, tport_dest); + } + + VectorCopy(tport_dest, startpos); + VectorCopy(self->mins, mins); + mins[2] = 0; + VectorCopy(self->maxs, maxs); + maxs[2] = 1; + startpos[2] -= self->size[2]; + + gi.trace(startpos, mins, maxs, endpos, self, MASK_MONSTERSOLID,&trace); + if(!trace.allsolid && !trace.startsolid) + { + VectorCopy(trace.endpos, startpos); + VectorCopy(trace.endpos, endpos); + startpos[2] +=self->size[2]; + gi.trace(startpos, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&trace); + if(trace.fraction == 1.0 && !trace.allsolid && !trace.startsolid) + { + assassinPrepareTeleportDest(self, trace.endpos, false); + return; + } + } + } + + if(skill->value || self->spawnflags & MSF_ASS_TELEPORTDODGE) + {//Pussies were complaining about assassins teleporting away from certain death, so don't do that unless in hard + if(!(self->spawnflags & MSF_ASS_NOTELEPORT) && !(self->spawnflags&MSF_FIXED) && self->groundentity) + { + if(irand(0, 4 - skill->value) <= 0) + {//easy is 40% chance per second, hard is 60% chance to check per second + while(found = findradius(found, self->s.origin, 200 + skill->value * 50)) + { + if(!stricmp(found->classname, "Spell_Maceball")) + { + if(!self->enemy) + { + if(found->owner) + { + self->enemy = found->owner; + FoundTarget(self, false); + } + } + if(assassinChooseTeleportDestination(self, ASS_TP_OFF, true, true)) + return; + } + + if(!stricmp(found->classname, "Spell_RedRain") || + !stricmp(found->classname, "Spell_PhoenixArrow") || + !stricmp(found->classname, "Spell_FireWall") || + !stricmp(found->classname, "Spell_SphereOfAnnihilation")) + { + if(!self->enemy) + { + if(found->owner) + { + self->enemy = found->owner; + FoundTarget(self, false); + } + } + if(assassinChooseTeleportDestination(self, ASS_TP_ANY, true, false)) + return; + } + + if(found==self->enemy && found->client) + { + if(M_DistanceToTarget(self, self->enemy) < 128) + { + if(infront(self->enemy, self)) + { + //is he using his staff or jumping into me? + lowerseq = found->client->playerinfo.lowerseq; + switch(lowerseq) + { + case ASEQ_WSWORD_SPIN: + case ASEQ_WSWORD_SPIN2: + case ASEQ_WSWORD_STEP2: + case ASEQ_WSWORD_STEP: + case ASEQ_POLEVAULT2: + case ASEQ_POLEVAULT1_W: + case ASEQ_POLEVAULT1_R: + if(assassinChooseTeleportDestination(self, ASS_TP_ANY, true, true)) + return; + break; + default: + break; + } + + upperseq = found->client->playerinfo.upperseq; + switch(upperseq) + { + case ASEQ_WSWORD_SPIN: + case ASEQ_WSWORD_SPIN2: + case ASEQ_WSWORD_STEP2: + case ASEQ_WSWORD_STEP: + case ASEQ_POLEVAULT2: + case ASEQ_POLEVAULT1_W: + case ASEQ_POLEVAULT1_R: + if(assassinChooseTeleportDestination(self, ASS_TP_ANY, true, true)) + return; + break; + default: + break; + } + } + + if(found->client->playerinfo.shield_timer > level.time) + { + if(assassinChooseTeleportDestination(self, ASS_TP_OFF, true, true)) + return; + } + } + + } + } + } + } + } + + if(self->evade_debounce_time < level.time) + MG_CheckEvade(self); +} + +void assassinCloak (edict_t *self) +{ + int interval = 15; + + if(self->s.color.r > 50) + self->s.color.r += irand(-interval*3, 0); + if(self->s.color.g > 50) + self->s.color.g += irand(-interval*3, 0); + if(self->s.color.b > 50) + self->s.color.b += irand(-interval*3, 0); + + if(self->s.color.a > 150) + self->s.color.a += irand(-interval, 0); + + if(self->s.color.r > 50|| + self->s.color.g > 50|| + self->s.color.b > 50|| + self->s.color.a > 150) + { + self->pre_think = assassinCloak; + self->next_pre_think = level.time + FRAMETIME; + } + else + { + self->pre_think = assassinCloakThink; + self->next_pre_think = level.time + FRAMETIME; + } + + if(self->evade_debounce_time < level.time) + MG_CheckEvade(self); +} + +void assassinDeCloak (edict_t *self) +{ + if(!(self->s.renderfx & RF_ALPHA_TEXTURE)) + return; + + if(self->s.color.r<255 - 10) + self->s.color.r += 10; + else + self->s.color.r = 255; + + if(self->s.color.g<255 - 10) + self->s.color.g += 10; + else + self->s.color.g = 255; + + if(self->s.color.b<255 - 10) + self->s.color.b += 10; + else + self->s.color.b = 255; + + if(self->s.color.a<255 - 5) + self->s.color.a += 5; + else + self->s.color.a = 255; + + if(self->s.color.r == 255&& + self->s.color.g == 255&& + self->s.color.b == 255&& + self->s.color.a == 255) + { + self->svflags &= ~SVF_NO_AUTOTARGET; + self->s.renderfx &= ~RF_ALPHA_TEXTURE; + if(self->health > 0) + { + self->pre_think = assassinCloakThink; + self->next_pre_think = level.time + FRAMETIME; + } + else + { + self->pre_think = NULL; + self->next_pre_think = -1; + } + } + else + { + self->pre_think = assassinDeCloak; + self->next_pre_think = level.time + FRAMETIME; + } + + if(self->evade_debounce_time < level.time) + MG_CheckEvade(self); +} + +void assassinInitDeCloak (edict_t *self) +{ + gi.sound(self,CHAN_AUTO,Sounds[SND_DECLOAK],1,ATTN_NORM,0); + self->pre_think = assassinDeCloak; + self->next_pre_think = level.time + FRAMETIME; +} + +void assassinInitCloak (edict_t *self) +{ + self->s.renderfx |= RF_ALPHA_TEXTURE; + self->svflags |= SVF_NO_AUTOTARGET; + gi.sound(self,CHAN_AUTO,Sounds[SND_CLOAK],1,ATTN_NORM,0); + self->s.color.r = 255; + self->s.color.g = 255; + self->s.color.b = 255; + self->s.color.a = 255; + self->pre_think = assassinCloak; + self->next_pre_think = level.time + FRAMETIME; +} + +void assassin_check_mood (edict_t *self, G_Message_t *msg) +{ + ParseMsgParms(msg, "i", &self->ai_mood); + + assassin_pause(self); +} +//============================================================= + +/*------------------------------------------------------------------------- + AssassinStaticsInit +-------------------------------------------------------------------------*/ +void AssassinStaticsInit() +{ + classStatics[CID_ASSASSIN].msgReceivers[MSG_STAND] = assassin_stand; + classStatics[CID_ASSASSIN].msgReceivers[MSG_WALK] = assassin_walk; + classStatics[CID_ASSASSIN].msgReceivers[MSG_RUN] = assassin_run; + classStatics[CID_ASSASSIN].msgReceivers[MSG_MELEE] = assassin_melee; + classStatics[CID_ASSASSIN].msgReceivers[MSG_MISSILE] = assassin_missile; + classStatics[CID_ASSASSIN].msgReceivers[MSG_PAIN] = assassin_pain; + classStatics[CID_ASSASSIN].msgReceivers[MSG_DEATH] = assassin_death; + classStatics[CID_ASSASSIN].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_ASSASSIN].msgReceivers[MSG_JUMP] = assassin_jump; + classStatics[CID_ASSASSIN].msgReceivers[MSG_EVADE] = assassin_evade; + classStatics[CID_ASSASSIN].msgReceivers[MSG_DEATH_PAIN] = assassin_dead_pain; + classStatics[CID_ASSASSIN].msgReceivers[MSG_CHECK_MOOD] = assassin_check_mood; + + classStatics[CID_ASSASSIN].msgReceivers[MSG_C_IDLE1] = assassin_c_anims; + classStatics[CID_ASSASSIN].msgReceivers[MSG_C_RUN1] = assassin_c_anims; + classStatics[CID_ASSASSIN].msgReceivers[MSG_C_ATTACK1] = assassin_c_anims; + classStatics[CID_ASSASSIN].msgReceivers[MSG_C_ATTACK2] = assassin_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + //note that the name is different in the path + resInfo.modelIndex = gi.modelindex("models/monsters/assassin/tris.fm"); + + Sounds[SND_PAIN1]=gi.soundindex("monsters/assassin/pain1.wav"); + Sounds[SND_PAIN2]=gi.soundindex("monsters/assassin/pain2.wav"); + Sounds[SND_DIE1]=gi.soundindex("monsters/assassin/death1.wav"); + Sounds[SND_GIB]=gi.soundindex("monsters/assassin/gib.wav"); + Sounds[SND_THROW1]=gi.soundindex("monsters/assassin/throw1.wav"); + Sounds[SND_THROW2]=gi.soundindex("monsters/assassin/throw2.wav"); + Sounds[SND_DAGHITF]=gi.soundindex("monsters/assassin/daghitf.wav"); + Sounds[SND_DAGHITW]=gi.soundindex("monsters/assassin/daghitw.wav"); + Sounds[SND_JUMP]=gi.soundindex("monsters/assassin/jump.wav"); + Sounds[SND_FLIP]=gi.soundindex("monsters/assassin/flip.wav"); + Sounds[SND_LAND]=gi.soundindex("monsters/assassin/land.wav"); + Sounds[SND_LANDF]=gi.soundindex("monsters/assassin/landf.wav"); + Sounds[SND_SLIDE]=gi.soundindex("monsters/assassin/slide.wav"); + Sounds[SND_SLASH1]=gi.soundindex("monsters/assassin/slash1.wav"); + Sounds[SND_SLASH2]=gi.soundindex("monsters/assassin/slash2.wav"); + Sounds[SND_GROWL1] = gi.soundindex ("monsters/assassin/growl1.wav"); + Sounds[SND_GROWL2]=gi.soundindex("monsters/assassin/growl2.wav"); + Sounds[SND_GROWL3] = gi.soundindex ("monsters/assassin/growl3.wav"); + Sounds[SND_CLOAK]=gi.soundindex("monsters/assassin/cloak.wav"); + Sounds[SND_DECLOAK] = gi.soundindex ("monsters/assassin/decloak.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = Sounds; + + classStatics[CID_ASSASSIN].resInfo = &resInfo; +} + +void assassinCheckDefense(edict_t *self, float enemydist, qboolean enemyvis, qboolean enemyinfront) +{ + if(!enemyinfront&&enemyvis&&enemydistmelee_range) + { +#ifdef _DEVEL + if(assassinCheckTeleport(self, ASS_TP_DEF)) + gi.dprintf("defense->teleport\n"); +#else + assassinCheckTeleport(self, ASS_TP_DEF); +#endif + } + else if(!enemyvis && self->monsterinfo.last_successful_enemy_tracking_time + 6 - skill->value < level.time) + { + if(irand(0, 10) > 10 - (3 * (skill->value + 1)))//hard = 90%, med is 40%, easy is 30% + { +#ifdef _DEVEL + gi.dprintf("Assassin trying to teleport to %s since can't find them...\n", self->classname, self->enemy->classname); +#endif + assassinCheckTeleport(self, ASS_TP_OFF); + } + } +} + +/*QUAKED monster_assassin (1 .5 0) (-16 -16 -32) (16 16 48) AMBUSH ASLEEP WALKING FwdJumpAmbush NoCloak NoTeleport CINEMATIC FIXED WANDER MELEE_LEAD STALK COWARD TeleportAmbush CloakAmbush SideJumpAmbush TeleportDodge + +The assassin + +SPAWNFLAGS: + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING - use WANDER instead + +FwdJumpAmbush - will jump out front or back when triggered (depending on whether player is in front or behind him) + +NoCloak - can't turn into a shadow + +NoTeleport - can't use smoke grenades to trick player and teleport + +CINEMATIC - puts monster into cinematic mode for scripting + +FIXED - Will stand in place and attack from afar. Never moves. + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +TeleportAmbush - Will teleport into his origin when triggered (before triggered, is not anywhere at all, like "ASLEEP") + +CloakAmbush - Start as a shadow and decloak when wakes up + +SideJumpAmbush - Will jump out to left or right (depending on which side of the assassin the player is) + +TeleportDodge - Can use teleporting to dodge attacks + +FIELDS: + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 64 +melee_range = 48 +missile_range = 1024 +min_missile_range = 64 +bypass_missile_chance = 10 +jump_chance = 100 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +/*------------------------------------------------------------------------- + SP_monster_assassin +-------------------------------------------------------------------------*/ +void SP_monster_assassin (edict_t *self) +{ + if(self->spawnflags & MSF_WALKING) + { + self->spawnflags |= MSF_WANDER; + self->spawnflags &= ~MSF_WALKING; + } + + if(self->spawnflags&MSF_ASS_JUMPAMBUSH|| + self->spawnflags&MSF_ASS_SIDEJUMPAMBUSH|| + self->spawnflags&MSF_ASS_STARTSHADOW) + self->spawnflags |= MSF_AMBUSH; + + if(self->spawnflags & MSF_ASS_TPORTAMBUSH) + self->spawnflags|=MSF_ASLEEP; + + if (!walkmonster_start(self)) // Unsuccessful initialization. + return; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_ASSASSIN; + self->monsterinfo.dismember = assassin_dismember; + + if(!self->health) + self->health = ASSASSIN_HEALTH * (skill->value + 1)/3; + + self->mass = ASSASSIN_MASS; + self->yaw_speed = 20; + + self->movetype = PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + self->viewheight = 40; + + self->isBlocked = self->bounced = assassin_Touch; + + self->s.modelindex = classStatics[CID_ASSASSIN].resInfo->modelIndex; + + self->materialtype = MAT_FLESH; + + //FIXME (somewhere: otherenemy should be more than just *one* kind + self->monsterinfo.otherenemyname = "monster_rat"; + + //set up my mood function + MG_InitMoods(self); + if(!irand(0,2)) + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + self->cant_attack_think = assassinCheckDefense; + + self->monsterinfo.aiflags |= AI_NIGHTVISION; + + if(self->spawnflags & MSF_WANDER) + { + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + } + else if(self->spawnflags & MSF_ASS_CINEMATIC) + { + self->monsterinfo.c_mode = 1; + QPostMessage(self, MSG_C_IDLE1, PRI_DIRECTIVE, "iiige",0,0,0,NULL,NULL); + } + else + { + if(self->spawnflags&MSF_ASS_STARTSHADOW) + assassinInitCloak (self); + + self->pre_think = assassinCloakThink; + self->next_pre_think = level.time + FRAMETIME; + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } + + self->svflags |= SVF_WAIT_NOTSOLID; + + self->s.fmnodeinfo[MESH__KNIFES].flags |= FMNI_NO_DRAW; + + VectorCopy(self->s.origin, self->pos1); +} + diff --git a/Toolkit/Programming/GameCode/game/m_assassin.h b/Toolkit/Programming/GameCode/game/m_assassin.h new file mode 100644 index 0000000..8d01b8b --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_assassin.h @@ -0,0 +1,224 @@ +typedef enum AnimID_e +{ + ANIM_DAGGERL,// = {14, assassin_frames_daggerl, assassin_pause}, + ANIM_DAGGERR,//= {15, assassin_frames_daggerr, assassin_pause}, + ANIM_DAGGERB,// = {15, assassin_frames_daggerb, assassin_pause}, + ANIM_DAGGERC,// = {11, assassin_frames_daggerc, assassin_pause}, + ANIM_NEWDAGGER, + ANIM_NEWDAGGERB, + ANIM_BACKFLIP,// = {16, assassin_frames_backflip, assassin_pause}, + ANIM_FRONTFLIP,// = {16, assassin_frames_frontflip, assassin_pause}, + ANIM_DODGE_RIGHT,// = {10, assassin_frames_dodge_right, assassin_pause}, + ANIM_DODGE_LEFT,// = {10, assassin_frames_dodge_left, assassin_pause}, + ANIM_DEATHA,// = {14, assassin_frames_deatha, assassin_dead}, + ANIM_DEATHB,// = {14, assassin_frames_deathb, assassin_dead}, + ANIM_JUMP,// = {17, assassin_frames_jump, assassin_pause}, + ANIM_RUN,// = {10, assassin_frames_run, assassin_pause}, + ANIM_PAIN1,// = {5, assassin_frames_pain1, assassin_pause}, + ANIM_PAIN2,// = {4, assassin_frames_pain2, assassin_pause}, + ANIM_DELAY,// = {1, assassin_frames_delay, assassin_pause}, + ANIM_STAND,// = {1, assassin_frames_delay, assassin_pause}, + ANIM_CROUCH,// = {1, assassin_frames_delay, assassin_pause}, + ANIM_UNCROUCH,// = {1, assassin_frames_delay, assassin_pause}, + ANIM_EVJUMP,// = {17, assassin_frames_jump, assassin_pause}, + ANIM_EVBACKFLIP,// = {16, assassin_frames_backflip, assassin_pause}, + ANIM_EVFRONTFLIP,// = {16, assassin_frames_frontflip, assassin_pause}, + ANIM_INAIR, + ANIM_LAND, + ANIM_FORCED_JUMP, + ANIM_FJUMP, + ANIM_BFINAIR, + ANIM_BFLAND, + ANIM_FFINAIR, + ANIM_FFLAND, + ANIM_EVINAIR, + ANIM_TELEPORT, + ANIM_CLOAK, + ANIM_WALK, + ANIM_WALK_LOOP, + ANIM_BACKSPRING, +//crouches + ANIM_CROUCH_TRANS, + ANIM_CROUCH_IDLE, + ANIM_CROUCH_LOOK_RIGHT, + ANIM_CROUCH_LOOK_RIGHT_IDLE, + ANIM_CROUCH_LOOK_L2R, + ANIM_CROUCH_LOOK_LEFT, + ANIM_CROUCH_LOOK_LEFT_IDLE, + ANIM_CROUCH_LOOK_R2L, + ANIM_CROUCH_LOOK_R2C, + ANIM_CROUCH_LOOK_L2C, + ANIM_CROUCH_POKE, + ANIM_CROUCH_END, + + ANIM_C_IDLE1, + ANIM_C_RUN1, + ANIM_C_ATTACK1, + ANIM_C_ATTACK2, + + NUM_ANIMS +} AnimID_t; + + +typedef enum SoundID_e +{ + SND_PAIN1, + SND_PAIN2, + SND_DIE1, + SND_GIB, + SND_THROW1, + SND_THROW2, + SND_DAGHITF, + SND_DAGHITW, + SND_JUMP, + SND_FLIP, + SND_LAND, + SND_LANDF, + SND_SLIDE, + SND_SLASH1, + SND_SLASH2, + SND_GROWL1, + SND_GROWL2, + SND_GROWL3, + SND_CLOAK, + SND_DECLOAK, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t assassin_move_daggerl;// = {14, assassin_frames_daggerl, assassin_pause}; +extern animmove_t assassin_move_daggerr;//= {15, assassin_frames_daggerr, assassin_pause}; +extern animmove_t assassin_move_daggerb;// = {15, assassin_frames_daggerb, assassin_pause}; +extern animmove_t assassin_move_daggerc;// = {11, assassin_frames_daggerc, assassin_pause}; +extern animmove_t assassin_move_newdagger; +extern animmove_t assassin_move_newdaggerb; +extern animmove_t assassin_move_backflip;// = {16, assassin_frames_backflip, assassin_pause}; +extern animmove_t assassin_move_frontflip;// = {16, assassin_frames_frontflip, assassin_pause}; +extern animmove_t assassin_move_dodge_right;// = {10, assassin_frames_dodge_right, assassin_pause}; +extern animmove_t assassin_move_dodge_left;// = {10, assassin_frames_dodge_left, assassin_pause}; +extern animmove_t assassin_move_deatha;// = {14, assassin_frames_deatha, assassin_dead}; +extern animmove_t assassin_move_deathb;// = {14, assassin_frames_deathb, assassin_dead}; +extern animmove_t assassin_move_jump;// = {17, assassin_frames_jump, assassin_pause}; +extern animmove_t assassin_move_run;// = {10, assassin_frames_run, assassin_pause}; +extern animmove_t assassin_move_pain1;// = {5, assassin_frames_pain1, assassin_pause}; +extern animmove_t assassin_move_pain2;// = {4, assassin_frames_pain2, assassin_pause}; +extern animmove_t assassin_move_delay;// = {1, assassin_frames_delay, assassin_pause}; +extern animmove_t assassin_move_stand;// = {1, assassin_frames_stand, assassin_pause}; +extern animmove_t assassin_move_crouch; +extern animmove_t assassin_move_uncrouch; + +extern animmove_t assassin_move_evade_jump;// = {17, assassin_frames_jump, assassin_pause}; +extern animmove_t assassin_move_evade_backflip;// = {16, assassin_frames_backflip, assassin_pause}; +extern animmove_t assassin_move_evade_frontflip;// = {16, assassin_frames_frontflip, assassin_pause}; +extern animmove_t assassin_move_inair; +extern animmove_t assassin_move_evinair; +extern animmove_t assassin_move_land; +extern animmove_t assassin_move_forcedjump; +extern animmove_t assassin_move_fjump; +extern animmove_t assassin_move_ffinair; +extern animmove_t assassin_move_ffland; +extern animmove_t assassin_move_bfinair; +extern animmove_t assassin_move_bfland; +extern animmove_t assassin_move_teleport; +extern animmove_t assassin_move_cloak; +extern animmove_t assassin_move_walk; +extern animmove_t assassin_move_walk_loop; +extern animmove_t assassin_move_backspring; +//crouch +extern animmove_t assassin_move_crouch_trans; +extern animmove_t assassin_move_crouch_idle; +extern animmove_t assassin_move_crouch_look_right; +extern animmove_t assassin_move_crouch_look_right_idle; +extern animmove_t assassin_move_crouch_look_l2r; +extern animmove_t assassin_move_crouch_look_left; +extern animmove_t assassin_move_crouch_look_left_idle; +extern animmove_t assassin_move_crouch_look_r2l; +extern animmove_t assassin_move_crouch_look_r2c; +extern animmove_t assassin_move_crouch_look_l2c; +extern animmove_t assassin_move_crouch_poke; +extern animmove_t assassin_move_crouch_end; + +extern animmove_t assassin_move_c_idle1; +extern animmove_t assassin_move_c_run1; +extern animmove_t assassin_move_c_attack1; +extern animmove_t assassin_move_c_attack2; + + + +void MG_CheckLanded (edict_t *self, float next_anim); +void MG_InAirMove (edict_t *self, float fwdspd,float upspd,float rtspd); +void MG_ApplyJump (edict_t *self); +void MG_InitMoods(edict_t *self); + + + +void assassin_blocked(edict_t *self, G_Message_t *msg); +void assassin_death(edict_t *self, G_Message_t *msg); +void assassin_run(edict_t *self, G_Message_t *msg); +void assassin_walk(edict_t *self, G_Message_t *msg); +void assassin_melee(edict_t *self, G_Message_t *msg); +void assassin_stand(edict_t *self, G_Message_t *msg); +void assassin_pain(edict_t *self, G_Message_t *msg); + +void assassindagger(edict_t *self, float right_ofs); +void assassin_dead(edict_t *self); +void assassindeathsqueal(edict_t *self); +void assassinsqueal(edict_t *self); +void assassingrowl(edict_t *self); +void assassinbite(edict_t *self); +void assassin_think_pain(edict_t *self); +void assassin_pause (edict_t *self); +void assassin_dropweapon (edict_t *self, int whichknives); +void ai_charge2 (edict_t *self, float dist); +void assassinCrouchedCheckAttack (edict_t *self, float attack); +void assassinSetCrouched (edict_t *self); +void assassinUndoCrouched (edict_t *self); +void assassinGoJump (edict_t *self, float upspd,float fwdspd,float rtspd); +void assassinStop (edict_t *self); +void assassin_go_run(edict_t *self, float dist); +void mg_ai_charge (edict_t *self, float dist); +void assassinCheckLoop (edict_t *self, float frame); +void assassinCheckLanded (edict_t *self, float nextanim); +void assassin_go_inair(edict_t *self); +void assassin_go_ffinair(edict_t *self); +void assassin_go_bfinair(edict_t *self); +void assassinNodeOn (edict_t *self, float node); +void assassinApplyJump (edict_t *self); +void assassinInAirMove (edict_t *self, float fwdspd,float upspd,float rtspd); +void assassin_go_evinair(edict_t *self); +void assassin_sound(edict_t *self, float channel, float soundnum, float attn); +qboolean assassinCheckTeleport (edict_t *self, int type); +qboolean assassinChooseTeleportDestination(edict_t *self, int type, qboolean imperative, qboolean instant); +void assassinGone(edict_t *self); +void assassinSmoke(edict_t *self); +void SP_monster_assassin (edict_t *self); +void assassin_post_pain (edict_t *self); +void assassinCloak (edict_t *self); +void M_MoveFrame (edict_t *self); +void assassinInitCloak (edict_t *self); +void assassinDeCloak (edict_t *self); +void assassinReadyTeleport (edict_t *self); +void assassinUnCrouch (edict_t *self); +void assassinSkipFrameSkillCheck (edict_t *self); +void MG_CheckEvade (edict_t *self); +void FoundTarget (edict_t *self, qboolean setsightent); +void assasin_walk_loop_go (edict_t *self); +void assassin_ai_walk (edict_t *self, float dist); +void assassin_crouch_idle_decision (edict_t *self); + + +#define BIT_DADDYNULL 0 +#define BIT_TORSOFT 1 +#define BIT_TORSOBK 2 +#define BIT_HEAD 4 +#define BIT_LKNIFE 8 +#define BIT_RKNIFE 16 +#define BIT_R4ARM 32 +#define BIT_L4ARM 64 +#define BIT_HIPS 128 +#define BIT_LCALF 256 +#define BIT_RCALF 512 +#define BIT_RTHIGH 1024 +#define BIT_LTHIGH 2048 +#define BIT_KNIFES 4096 +#define BIT_LUPARM 8192 +#define BIT_RUPARM 16384 diff --git a/Toolkit/Programming/GameCode/game/m_assassin_anim.c b/Toolkit/Programming/GameCode/game/m_assassin_anim.c new file mode 100644 index 0000000..dcf1455 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_assassin_anim.c @@ -0,0 +1,949 @@ +//============================================================================== +// +// m_assassin_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "c_ai.h" +#include "m_assassin_anim.h" +#include "m_assassin.h" +#include "g_monster.h" + +//all of the anim frames that used to live in m_assassin.h + +void ai_moveright(edict_t *self, float dist); + + +//========================================================================== + +//ATTACKS + +//========================================================================== + +/*---------------------------------------------------------------------- + assassin daggerL - assassin attacking left hand +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_daggerl [] = +{ + FRAME_ataka1, NULL, 0, 0, 0, mg_ai_charge, 0, assassingrowl, + FRAME_ataka2, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_ataka3, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_ataka4, NULL, 0, 0, 0, assassinNodeOn, MESH__LKNIFE, NULL,//loop in from an attack, no windup + FRAME_ataka5, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_ataka6, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_ataka7, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_ataka8, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_ataka9, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_ataka10, NULL, 0, 0, 0, assassindagger, BIT_LKNIFE, NULL, + FRAME_ataka11, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_ataka12, NULL, 0, 0, 0, assassinCheckLoop, 2, NULL,//check for loop to other attack + FRAME_ataka13, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_ataka14, NULL, 0, 0, 0, mg_ai_charge, 0, NULL +}; +animmove_t assassin_move_daggerl = {14, assassin_frames_daggerl, assassin_pause}; + +/*---------------------------------------------------------------------- + assassin daggerR - assassin attacking right hand +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_daggerr [] = +{ + FRAME_atakb1, NULL, 0, 0, 0, mg_ai_charge, 0, assassingrowl, + FRAME_atakb2, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakb3, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakb4, NULL, 0, 0, 0, assassinNodeOn, MESH__RKNIFE, NULL, + FRAME_atakb5, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakb6, NULL, 0, 0, 0, mg_ai_charge, 0, NULL,//loop in from an attack, no windup + FRAME_atakb7, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakb8, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakb9, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakb10, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakb11, NULL, 0, 0, 0, assassindagger, BIT_RKNIFE, NULL, + FRAME_atakb12, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakb13, NULL, 0, 0, 0, assassinCheckLoop, 2, NULL,//check for loop to other attack + FRAME_atakb14, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakb15, NULL, 0, 0, 0, mg_ai_charge, 0, NULL +}; +animmove_t assassin_move_daggerr = {15, assassin_frames_daggerr, assassin_pause}; + +/*---------------------------------------------------------------------- + assassin daggerB - assassin attacking left hand +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_daggerb [] = +{ + FRAME_atakc1, NULL, 0, 0, 0, mg_ai_charge, 0, assassingrowl, + FRAME_atakc2, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakc3, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakc4, NULL, 0, 0, 0, assassinNodeOn, MESH__LKNIFE, NULL, + FRAME_atakc5, NULL, 0, 0, 0, assassinNodeOn, MESH__RKNIFE, NULL, + FRAME_atakc6, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakc7, NULL, 0, 0, 0, mg_ai_charge, 0, NULL,//loop in from an attack, no windup + FRAME_atakc8, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakc9, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakc10, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakc11, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_atakc12, NULL, 0, 0, 0, assassindagger, BIT_LKNIFE|BIT_RKNIFE, NULL, + FRAME_atakc13, NULL, 0, 0, 0, assassinCheckLoop, 2, NULL,//check for loop to other attack + FRAME_atakc14, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, +}; +animmove_t assassin_move_daggerb = {14, assassin_frames_daggerb, assassin_pause}; + +/*---------------------------------------------------------------------- + assassin daggerC - assassin attacking crouched +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_daggerc [] = +{ + FRAME_lndatk1, NULL, 0, 0, 0, mg_ai_charge, 0, assassingrowl, + FRAME_lndatk2, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_lndatk3, NULL, 0, 0, 0, assassinNodeOn, MESH__RKNIFE, NULL, + FRAME_lndatk4, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_lndatk5, NULL, 0, 0, 0, mg_ai_charge, 0, NULL,//loop in from an attack, no windup + FRAME_lndatk6, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_lndatk7, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_lndatk8, NULL, 0, 0, 0, assassinCrouchedCheckAttack, true, NULL, + FRAME_lndatk9, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_lndatk10, NULL, 0, 0, 0, assassinCrouchedCheckAttack, 0, NULL,//check for loop to other attack + FRAME_lndatk11, NULL, 0, 0, 0, mg_ai_charge, 0, NULL +}; +animmove_t assassin_move_daggerc = {11, assassin_frames_daggerc, assassin_pause}; + +animframe_t assassin_frames_newdagger [] = +{ + FRAME_newattackA1, NULL, 0, 0, 0, assassinNodeOn, MESH__RKNIFE, assassingrowl, + FRAME_newattackA2, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA3, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA4, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA5, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA6, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA7, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA8, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA9, NULL, 0, 0, 0, assassindagger, BIT_RKNIFE, NULL, + FRAME_newattackA10, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA11, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA12, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA13, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA14, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackA15, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, +}; +animmove_t assassin_move_newdagger = {15, assassin_frames_newdagger, assassin_pause}; + +animframe_t assassin_frames_newdaggerb [] = +{ + FRAME_newattackB1, NULL, 0, 0, 0, mg_ai_charge, 0, assassingrowl, + FRAME_newattackB2, NULL, 0, 0, 0, assassinNodeOn, MESH__RKNIFE, NULL, + FRAME_newattackB3, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackB4, NULL, 0, 0, 0, mg_ai_charge, 0, NULL,//loop in from an attack, no windup + FRAME_newattackB5, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackB6, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackB7, NULL, 0, 0, 0, assassinNodeOn, MESH__LKNIFE, NULL, + FRAME_newattackB8, NULL, 0, 0, 0, assassindagger, BIT_RKNIFE, NULL, + FRAME_newattackB9, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackB10, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackB11, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackB12, NULL, 0, 0, 0, mg_ai_charge, 0, NULL,//check for loop to other attack + FRAME_newattackB13, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackB14, NULL, 0, 0, 0, assassindagger, BIT_LKNIFE, NULL, + FRAME_newattackB15, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackB16, NULL, 0, 0, 0, mg_ai_charge, 0, NULL, + FRAME_newattackB17, NULL, 0, 0, 0, assassinCheckLoop, 4, NULL, +}; +animmove_t assassin_move_newdaggerb = {17, assassin_frames_newdaggerb, assassin_pause}; +//=========================================================================== + +// ASSASSIN EVASION + +//============================================================================= + +/*---------------------------------------------------------------------- + assassin crouch +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_crouch [] = +{ + FRAME_jump14, NULL, 0, 0, 0, NULL, 0, assassinSetCrouched, + FRAME_jump15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump16, NULL, 0, 0, 0, NULL, 0, assassinStop, +}; +animmove_t assassin_move_crouch = {3, assassin_frames_crouch, assassin_pause}; + +/*---------------------------------------------------------------------- + assassin uncrouch +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_uncrouch [] = +{ + FRAME_jump17, NULL, 0, 0, 0, NULL, 0, assassinUndoCrouched +}; +animmove_t assassin_move_uncrouch = {1, assassin_frames_uncrouch, assassin_pause}; + +/*---------------------------------------------------------------------- + assassin in air +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_evinair [] = +{ + FRAME_jump12, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL//hang here until land +}; +animmove_t assassin_move_evinair = {1, assassin_frames_evinair, NULL}; + +/*---------------------------------------------------------------------- + assassin in air +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_inair [] = +{ + FRAME_jump12, MG_InAirMove, 50, 0, 0, MG_CheckLanded, ANIM_LAND, NULL//hang here until land +}; +animmove_t assassin_move_inair = {1, assassin_frames_inair, NULL}; + +/*---------------------------------------------------------------------- + assassin land +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_land [] = +{ + FRAME_jump13, assassin_sound, CHAN_BODY, SND_LAND, ATTN_NORM, NULL, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, NULL, 0, assassinSetCrouched, + FRAME_jump15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump17, NULL, 0, 0, 0, assassinCrouchedCheckAttack, 2, assassinUndoCrouched +}; +animmove_t assassin_move_land = {5, assassin_frames_land, assassin_pause}; + +/*---------------------------------------------------------------------- + assassin jump +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_evade_jump [] = +{ + FRAME_jump7, assassinGoJump, 100, 400, 0, ai_charge, 0, assassingrowl, + FRAME_jump8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump11, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, +}; +animmove_t assassin_move_evade_jump = {5, assassin_frames_evade_jump, assassin_go_evinair}; + +/*---------------------------------------------------------------------- + assassin backflipping +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_evade_backflip [] = +{ + FRAME_bkflp6, assassinGoJump, -150, 400, 0, NULL, 0, assassingrowl, + FRAME_bkflp7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp9, assassin_sound, CHAN_ITEM, SND_FLIP, ATTN_NORM, NULL, 0, NULL, + FRAME_bkflp10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_BFLAND, NULL, + FRAME_bkflp11, NULL, 0, 0, 0, MG_CheckLanded, ANIM_BFLAND, NULL, + FRAME_bkflp12, NULL, 0, 0, 0, MG_CheckLanded, ANIM_BFLAND, NULL, +}; +animmove_t assassin_move_evade_backflip = {7, assassin_frames_evade_backflip, assassin_go_bfinair}; + +/*---------------------------------------------------------------------- + assassin front flipping +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_evade_frontflip [] = +{ + FRAME_fntflp6, assassinGoJump, 150, 400, 0, NULL, 0, assassingrowl, + FRAME_fntflp7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp8, assassin_sound, CHAN_ITEM, SND_FLIP, ATTN_NORM, NULL, 0, NULL, + FRAME_fntflp9, NULL, 0, 0, 0, MG_CheckLanded, ANIM_FFLAND, NULL, + FRAME_fntflp10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_FFLAND, NULL, + FRAME_fntflp11, NULL, 0, 0, 0, MG_CheckLanded, ANIM_FFLAND, NULL, +}; +animmove_t assassin_move_evade_frontflip = {6, assassin_frames_evade_frontflip, assassin_go_ffinair}; + +/*---------------------------------------------------------------------- + assassin dodging right +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_dodge_right [] = +{ +// FRAME_dgert1, NULL, 0, 0, 0, ai_moveright, 10, NULL, +// FRAME_dgert2, NULL, 0, 0, 0, ai_moveright, 11, NULL, +// FRAME_dgert3, NULL, 0, 0, 0, ai_moveright, 12, NULL, + FRAME_dgert4, assassin_sound, CHAN_BODY, SND_SLIDE, ATTN_NORM, ai_moveright, 24, NULL, + FRAME_dgert5, NULL, 0, 0, 0, ai_moveright, 16, NULL, + FRAME_dgert6, NULL, 0, 0, 0, ai_moveright, 12, NULL, + FRAME_dgert7, NULL, 0, 0, 0, ai_moveright, 8, NULL, + FRAME_dgert8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dgert9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dgert10, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t assassin_move_dodge_right = {7, assassin_frames_dodge_right, assassin_pause}; + +/*---------------------------------------------------------------------- + assassin dodging left +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_dodge_left [] = +{ +// FRAME_dgelft1, NULL, 0, 0, 0, ai_moveright, -10, NULL, +// FRAME_dgelft2, NULL, 0, 0, 0, ai_moveright, -11, NULL, +// FRAME_dgelft3, NULL, 0, 0, 0, ai_moveright, -12, NULL, +// FRAME_dgelft4, NULL, 0, 0, 0, ai_moveright, -12, NULL, + FRAME_dgelft5, assassin_sound, CHAN_BODY, SND_SLIDE, ATTN_NORM, ai_moveright, -24, NULL, + FRAME_dgelft6, NULL, 0, 0, 0, ai_moveright, -16, NULL, + FRAME_dgelft7, NULL, 0, 0, 0, ai_moveright, -12, NULL, + FRAME_dgelft8, NULL, 0, 0, 0, ai_moveright, -8, NULL, + FRAME_dgelft9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dgelft10, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t assassin_move_dodge_left = {6, assassin_frames_dodge_left, assassin_pause}; + +//============================================================================== + +// ASSASSIN DEATHS + +//============================================================================== + +/*---------------------------------------------------------------------- + assassin DeathA +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_deatha [] = +{ + FRAME_deatha1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha8, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_deatha9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha14, NULL, 0, 0, 0, NULL, 1, NULL +}; +animmove_t assassin_move_deatha = {14, assassin_frames_deatha, assassin_dead}; + +/*------------------------------------------------------------------------- + assassin Death B +-------------------------------------------------------------------------*/ +animframe_t assassin_frames_deathb [] = +{ + FRAME_deathb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb6, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_deathb7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb15, NULL, 0, 0, 0, NULL, 1, NULL +}; +animmove_t assassin_move_deathb = {15, assassin_frames_deathb, assassin_dead}; + +//============================================================================= + +// ASSASSIN PURSUING + +//============================================================================= + +/*---------------------------------------------------------------------- + assassin jump +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_jump [] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump7, assassinGoJump, 50, 500, 0, ai_charge, 0, assassingrowl, + FRAME_jump8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump11, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, +}; +animmove_t assassin_move_jump = {11, assassin_frames_jump, assassin_go_inair}; + +/*---------------------------------------------------------------------- + assassin forced jump +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_forcedjump [] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump7, assassin_sound, CHAN_VOICE, SND_JUMP, ATTN_NORM, ai_charge, 0, MG_ApplyJump, + FRAME_jump8, MG_InAirMove, 50, 0, 0, NULL, 0, NULL, + FRAME_jump9, MG_InAirMove, 50, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump10, MG_InAirMove, 50, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump11, MG_InAirMove, 50, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, +}; +animmove_t assassin_move_forcedjump = {11, assassin_frames_forcedjump, assassin_go_inair}; + + +/*---------------------------------------------------------------------- + assassin forced jump +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_fjump [] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump7, assassin_sound, CHAN_VOICE, SND_JUMP, ATTN_NORM, ai_charge, 0, MG_ApplyJump, + FRAME_jump8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump11, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, +}; +animmove_t assassin_move_fjump = {11, assassin_frames_fjump, assassin_go_evinair}; +//BACKFLIP +/*---------------------------------------------------------------------- + assassin backflipping +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_bfland [] = +{ + FRAME_bkflp14, assassin_sound, CHAN_BODY, SND_LAND, ATTN_NORM, NULL, 0, NULL, + FRAME_bkflp15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp16, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t assassin_move_bfland = {3, assassin_frames_bfland, assassin_pause}; + +/*---------------------------------------------------------------------- + assassin backflipping +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_bfinair [] = +{ + FRAME_bkflp13, NULL, 0, 0, 0, MG_CheckLanded, ANIM_BFLAND, NULL, +}; +animmove_t assassin_move_bfinair = {1, assassin_frames_bfinair, NULL}; + +/*---------------------------------------------------------------------- + assassin backflipping +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_backflip [] = +{ + FRAME_bkflp1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp6, assassinGoJump, -150, 400, 0, NULL, 0, assassingrowl, + FRAME_bkflp7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bkflp9, assassin_sound, CHAN_ITEM, SND_FLIP, ATTN_NORM, NULL, 0, NULL, + FRAME_bkflp10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_BFLAND, NULL, + FRAME_bkflp11, NULL, 0, 0, 0, MG_CheckLanded, ANIM_BFLAND, NULL, + FRAME_bkflp12, NULL, 0, 0, 0, MG_CheckLanded, ANIM_BFLAND, NULL, +}; +animmove_t assassin_move_backflip = {12, assassin_frames_backflip, assassin_go_bfinair}; + + +animframe_t assassin_frames_backspring [] = +{ + FRAME_newbackspring1, NULL, 0, 0, 0, ai_charge2, -4, assassingrowl, + FRAME_newbackspring2, NULL, 0, 0, 0, ai_charge2, -8, NULL, + FRAME_newbackspring3, NULL, 0, 0, 0, ai_charge2, -12, NULL, + FRAME_newbackspring4, NULL, 0, 0, 0, ai_charge2, -12, NULL, + FRAME_newbackspring5, NULL, 0, 0, 0, ai_charge2, -16, NULL, + FRAME_newbackspring6, NULL, 0, 0, 0, ai_charge2, -18, NULL, + FRAME_newbackspring7, NULL, 0, 0, 0, ai_charge2, -24, NULL, + FRAME_newbackspring8, NULL, 0, 0, 0, ai_charge2, -16, NULL, + FRAME_newbackspring9, NULL, 0, 0, 0, ai_charge2, -12, NULL, + FRAME_newbackspring10, NULL, 0, 0, 0, ai_charge2, -12, NULL, + FRAME_newbackspring11, NULL, 0, 0, 0, ai_charge2, -10, NULL, + FRAME_newbackspring12, NULL, 0, 0, 0, ai_charge2, -8, NULL, + FRAME_newbackspring13, NULL, 0, 0, 0, ai_charge2, -4, NULL, + FRAME_newbackspring14, NULL, 0, 0, 0, ai_charge2, -2, NULL, + FRAME_newbackspring15, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t assassin_move_backspring = {15, assassin_frames_backspring, assassin_pause}; + +//FRONT FLIP +/*---------------------------------------------------------------------- + assassin front flipping +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_ffland [] = +{ + FRAME_fntflp12, assassin_sound, CHAN_BODY, SND_LAND, ATTN_NORM, NULL, 0, NULL, + FRAME_fntflp13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp16, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_ffland = {5, assassin_frames_ffland, assassin_pause}; + +/*---------------------------------------------------------------------- + assassin front flipping +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_ffinair [] = +{ + FRAME_fntflp11, NULL, 0, 0, 0, MG_CheckLanded, ANIM_FFLAND, NULL, +}; +animmove_t assassin_move_ffinair = {1, assassin_frames_ffinair, NULL}; + +/*---------------------------------------------------------------------- + assassin front flipping +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_frontflip [] = +{ + FRAME_fntflp1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp6, assassinGoJump, 150, 400, 0, NULL, 0, assassingrowl, + FRAME_fntflp7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fntflp8, assassin_sound, CHAN_ITEM, SND_FLIP, ATTN_NORM, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_fntflp9, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_fntflp10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, +}; +animmove_t assassin_move_frontflip = {10, assassin_frames_frontflip, assassin_go_ffinair}; + + + + + + + + + +/*---------------------------------------------------------------------- + assassin Running - assassin running +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_run [] = +{//recalc movement values with new anim + FRAME_run1, NULL, 0, 0, 0, assassin_go_run, 20, assassingrowl, + FRAME_run2, NULL, 0, 0, 0, assassin_go_run, 18, assassin_pause, + FRAME_run3, NULL, 0, 0, 0, assassin_go_run, 12, assassin_pause, + FRAME_run4, NULL, 0, 0, 0, assassin_go_run, 16, assassin_pause, + FRAME_run5, NULL, 0, 0, 0, assassin_go_run, 24, assassin_pause, + FRAME_run6, NULL, 0, 0, 0, assassin_go_run, 18, assassin_pause, + FRAME_run7, NULL, 0, 0, 0, assassin_go_run, 16, assassin_pause, + FRAME_run8, NULL, 0, 0, 0, assassin_go_run, 12, assassin_pause, + FRAME_run9, NULL, 0, 0, 0, assassin_go_run, 18, assassin_pause, + FRAME_run10, NULL, 0, 0, 0, assassin_go_run, 26, assassin_pause +}; +animmove_t assassin_move_run = {10, assassin_frames_run, assassin_pause}; + +animframe_t assassin_frames_walk [] = +{ + FRAME_newwalk1, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_newwalk2, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_newwalk3, NULL, 0, 0, 0, ai_walk, 6, NULL, +}; +animmove_t assassin_move_walk = {3, assassin_frames_walk, assasin_walk_loop_go}; + +animframe_t assassin_frames_walk_loop [] = +{ + FRAME_newwalk4, NULL, 0, 0, 0, assassin_ai_walk, 8, assassingrowl, + FRAME_newwalk5, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, + FRAME_newwalk6, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, + FRAME_newwalk7, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, + FRAME_newwalk8, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, + FRAME_newwalk9, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, + FRAME_newwalk10, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, + FRAME_newwalk11, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, + FRAME_newwalk12, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, + FRAME_newwalk13, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, + FRAME_newwalk14, NULL, 0, 0, 0, assassin_ai_walk, 8, NULL, +}; +animmove_t assassin_move_walk_loop = {11, assassin_frames_walk_loop, assassin_pause}; + +//============================================================================= + +// ASSASSIN PAINS + +//============================================================================= + +/*---------------------------------------------------------------------- + assassin Pain - assassin gets hit +-----------------------------------------------------------------------*/ + +animframe_t assassin_frames_pain1 [] = +{ + FRAME_painb1, NULL, 0, 0, 0, ai_move, -16, assassinsqueal, +}; +animmove_t assassin_move_pain1 = {1, assassin_frames_pain1, assassin_post_pain}; + + +/*---------------------------------------------------------------------- + assassin Pain - assassin gets hit +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_pain2 [] = +{ + FRAME_painb1, NULL, 0, 0, 0, ai_move, -10, assassinsqueal, + FRAME_painb2, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_painb3, NULL, 0, 0, 0, ai_move, -6, NULL, + FRAME_painb4, NULL, 0, 0, 0, ai_move, -3, NULL, + FRAME_painb5, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t assassin_move_pain2 = {5, assassin_frames_pain2, assassin_post_pain}; + +//====================================================================== + +//ASSASSIN WAITING + +//======================================================================= +/*---------------------------------------------------------------------- + assassin chillin out +-----------------------------------------------------------------------*/ + +animframe_t assassin_frames_stand [] = +{ + FRAME_newidle1, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newidle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newidle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newidle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newidle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newidle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newidle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newidle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newidle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newidle10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newidle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newidle12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_stand = {12, assassin_frames_stand, assassin_pause}; + +animframe_t assassin_frames_delay [] = +{ + FRAME_newidle1, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle2, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle3, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle4, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle5, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle6, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle7, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle8, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle9, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle10, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle11, NULL, 0, 0, 0, NULL, 0, assassin_pause, + FRAME_newidle12, NULL, 0, 0, 0, NULL, 0, assassin_pause, +}; +animmove_t assassin_move_delay = {12, assassin_frames_delay, assassin_pause}; + +//crouches + +animframe_t assassin_frames_crouch_trans [] = +{ + FRAME_newcrchtrn1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchtrn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchtrn3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchtrn4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchtrn5, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_trans = {5, assassin_frames_crouch_trans, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_idle [] = +{ + FRAME_newcrouchidle1, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newcrouchidle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrouchidle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrouchidle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrouchidle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrouchidle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrouchidle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrouchidle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrouchidle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrouchidle10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrouchidle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrouchidle12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_idle = {12, assassin_frames_crouch_idle, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_look_right[] = +{ + FRAME_newcrchlkrit1, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newcrchlkrit2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_look_right = {12, assassin_frames_crouch_look_right, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_look_right_idle[] = +{ + FRAME_newcrhlkrtidle1, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newcrhlkrtidle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrhlkrtidle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrhlkrtidle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrhlkrtidle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrhlkrtidle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrhlkrtidle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrhlkrtidle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrhlkrtidle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrhlkrtidle10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrhlkrtidle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrhlkrtidle12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_look_right_idle = {12, assassin_frames_crouch_look_right_idle, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_look_l2r[] = +{ + FRAME_newcrchlklr1, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newcrchlklr2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_look_l2r = {12, assassin_frames_crouch_look_l2r, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_look_left[] = +{ + FRAME_newcrchlklft1, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newcrchlklft2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_look_left = {12, assassin_frames_crouch_look_left, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_look_left_idle[] = +{ + FRAME_newlkleftidle1, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newlkleftidle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newlkleftidle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newlkleftidle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newlkleftidle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newlkleftidle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newlkleftidle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newlkleftidle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newlkleftidle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newlkleftidle10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newlkleftidle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newlkleftidle12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_look_left_idle = {12, assassin_frames_crouch_look_left_idle, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_look_r2l[] = +{ + FRAME_newcrchlklr12, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newcrchlklr11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklr2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklr1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_look_r2l = {12, assassin_frames_crouch_look_r2l, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_look_r2c[] = +{ + FRAME_newcrchlkrit12, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newcrchlkrit11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlkrit2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlkrit1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_look_r2c = {12, assassin_frames_crouch_look_r2c, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_look_l2c[] = +{ + FRAME_newcrchlklft12, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_newcrchlklft11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchlklft2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_newcrchlklft1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_look_l2c = {12, assassin_frames_crouch_look_l2c, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_end[] = +{ + FRAME_newcrchtrn5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchtrn4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchtrn3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchtrn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newcrchtrn1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_end = {5, assassin_frames_crouch_end, assassin_crouch_idle_decision}; + +animframe_t assassin_frames_crouch_poke[] = +{ + FRAME_poke1, NULL, 0, 0, 0, ai_stand, 0, assassingrowl, + FRAME_poke2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke21, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poke23, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_poke24, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_crouch_poke = {24, assassin_frames_crouch_poke, assassin_crouch_idle_decision}; +/*---------------------------------------------------------------------- + assassin teleport - throws smoke bomb, then gone +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_teleport [] = +{ + FRAME_ataka3, NULL, 0, 0, 0, NULL, 0, assassinSkipFrameSkillCheck, + FRAME_ataka4, NULL, 0, 0, 0, NULL, 0, assassinSkipFrameSkillCheck, + FRAME_ataka5, NULL, 0, 0, 0, NULL, 0, assassinSkipFrameSkillCheck, + FRAME_ataka6, NULL, 0, 0, 0, NULL, 0, assassinSkipFrameSkillCheck, + FRAME_ataka7, NULL, 0, 0, 0, NULL, 0, assassinSkipFrameSkillCheck, + FRAME_ataka8, NULL, 0, 0, 0, NULL, 0, assassinSkipFrameSkillCheck, + FRAME_ataka9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka10, NULL, 0, 0, 0, NULL, 0, assassinReadyTeleport, + FRAME_ataka11, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_teleport = {9, assassin_frames_teleport, assassinGone}; + +animframe_t assassin_frames_cloak [] = +{ + FRAME_jump14, NULL, 0, 0, 0, NULL, 0, assassinSetCrouched, + FRAME_jump15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump16, NULL, 0, 0, 0, NULL, 0, assassinInitCloak, +}; +animmove_t assassin_move_cloak = {3, assassin_frames_cloak, assassinUnCrouch}; + + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +animframe_t assassin_frames_c_idle1 [] = +{ + FRAME_ataka1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t assassin_move_c_idle1 = {7, assassin_frames_c_idle1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + assassin Running - assassin running +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_c_run1 [] = +{ + FRAME_run1, ai_c_move, 20, 0, 0, NULL, 0, assassingrowl, + FRAME_run2, ai_c_move, 18, 0, 0, NULL, 0, NULL, + FRAME_run3, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_run4, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_run5, ai_c_move, 24, 0, 0, NULL, 0, NULL, + FRAME_run6, ai_c_move, 18, 0, 0, NULL, 0, NULL, + FRAME_run7, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_run8, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_run9, ai_c_move, 18, 0, 0, NULL, 0, NULL, + FRAME_run10, ai_c_move, 26, 0, 0, NULL, 0, NULL +}; +animmove_t assassin_move_c_run1 = {10, assassin_frames_c_run1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + assassin daggerL - assassin attacking left hand +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_c_attack1 [] = +{ + FRAME_ataka1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ataka14, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t assassin_move_c_attack1 = {14, assassin_frames_c_attack1,ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + assassin daggerR - assassin attacking right hand +-----------------------------------------------------------------------*/ +animframe_t assassin_frames_c_attack2 [] = +{ + FRAME_atakb1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb6, ai_c_move, 0, 0, 0, NULL, 0, NULL,//loop in from an attack, no windup + FRAME_atakb7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb8, ai_c_move, 0, 0, 0, NULL, 0, assassingrowl, + FRAME_atakb9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb13, ai_c_move, 0, 0, 0, NULL, 0, NULL,//check for loop to other attack + FRAME_atakb14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_atakb15, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t assassin_move_c_attack2 = {15, assassin_frames_c_attack2, ai_c_cycleend}; diff --git a/Toolkit/Programming/GameCode/game/m_assassin_anim.h b/Toolkit/Programming/GameCode/game/m_assassin_anim.h new file mode 100644 index 0000000..2e88600 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_assassin_anim.h @@ -0,0 +1,371 @@ +// R:\Art\models/monsters\assassin + +// This file generated by qdata - Do NOT Modify + +#define FRAME_prtfly 0 +#define FRAME_torsofly 1 +#define FRAME_ataka1 2 +#define FRAME_ataka2 3 +#define FRAME_ataka3 4 +#define FRAME_ataka4 5 +#define FRAME_ataka5 6 +#define FRAME_ataka6 7 +#define FRAME_ataka7 8 +#define FRAME_ataka8 9 +#define FRAME_ataka9 10 +#define FRAME_ataka10 11 +#define FRAME_ataka11 12 +#define FRAME_ataka12 13 +#define FRAME_ataka13 14 +#define FRAME_ataka14 15 +#define FRAME_atakb1 16 +#define FRAME_atakb2 17 +#define FRAME_atakb3 18 +#define FRAME_atakb4 19 +#define FRAME_atakb5 20 +#define FRAME_atakb6 21 +#define FRAME_atakb7 22 +#define FRAME_atakb8 23 +#define FRAME_atakb9 24 +#define FRAME_atakb10 25 +#define FRAME_atakb11 26 +#define FRAME_atakb12 27 +#define FRAME_atakb13 28 +#define FRAME_atakb14 29 +#define FRAME_atakb15 30 +#define FRAME_atakc1 31 +#define FRAME_atakc2 32 +#define FRAME_atakc3 33 +#define FRAME_atakc4 34 +#define FRAME_atakc5 35 +#define FRAME_atakc6 36 +#define FRAME_atakc7 37 +#define FRAME_atakc8 38 +#define FRAME_atakc9 39 +#define FRAME_atakc10 40 +#define FRAME_atakc11 41 +#define FRAME_atakc12 42 +#define FRAME_atakc13 43 +#define FRAME_atakc14 44 +#define FRAME_bkflp1 45 +#define FRAME_bkflp2 46 +#define FRAME_bkflp3 47 +#define FRAME_bkflp4 48 +#define FRAME_bkflp5 49 +#define FRAME_bkflp6 50 +#define FRAME_bkflp7 51 +#define FRAME_bkflp8 52 +#define FRAME_bkflp9 53 +#define FRAME_bkflp10 54 +#define FRAME_bkflp11 55 +#define FRAME_bkflp12 56 +#define FRAME_bkflp13 57 +#define FRAME_bkflp14 58 +#define FRAME_bkflp15 59 +#define FRAME_bkflp16 60 +#define FRAME_bkflp17 61 +#define FRAME_deatha1 62 +#define FRAME_deatha2 63 +#define FRAME_deatha3 64 +#define FRAME_deatha4 65 +#define FRAME_deatha5 66 +#define FRAME_deatha6 67 +#define FRAME_deatha7 68 +#define FRAME_deatha8 69 +#define FRAME_deatha9 70 +#define FRAME_deatha10 71 +#define FRAME_deatha11 72 +#define FRAME_deatha12 73 +#define FRAME_deatha13 74 +#define FRAME_deatha14 75 +#define FRAME_deathb1 76 +#define FRAME_deathb2 77 +#define FRAME_deathb3 78 +#define FRAME_deathb4 79 +#define FRAME_deathb5 80 +#define FRAME_deathb6 81 +#define FRAME_deathb7 82 +#define FRAME_deathb8 83 +#define FRAME_deathb9 84 +#define FRAME_deathb10 85 +#define FRAME_deathb11 86 +#define FRAME_deathb12 87 +#define FRAME_deathb13 88 +#define FRAME_deathb14 89 +#define FRAME_deathb15 90 +#define FRAME_dgelft1 91 +#define FRAME_dgelft2 92 +#define FRAME_dgelft3 93 +#define FRAME_dgelft4 94 +#define FRAME_dgelft5 95 +#define FRAME_dgelft6 96 +#define FRAME_dgelft7 97 +#define FRAME_dgelft8 98 +#define FRAME_dgelft9 99 +#define FRAME_dgelft10 100 +#define FRAME_dgelft11 101 +#define FRAME_dgelft12 102 +#define FRAME_dgert1 103 +#define FRAME_dgert2 104 +#define FRAME_dgert3 105 +#define FRAME_dgert4 106 +#define FRAME_dgert5 107 +#define FRAME_dgert6 108 +#define FRAME_dgert7 109 +#define FRAME_dgert8 110 +#define FRAME_dgert9 111 +#define FRAME_dgert10 112 +#define FRAME_fntflp1 113 +#define FRAME_fntflp2 114 +#define FRAME_fntflp3 115 +#define FRAME_fntflp4 116 +#define FRAME_fntflp5 117 +#define FRAME_fntflp6 118 +#define FRAME_fntflp7 119 +#define FRAME_fntflp8 120 +#define FRAME_fntflp9 121 +#define FRAME_fntflp10 122 +#define FRAME_fntflp11 123 +#define FRAME_fntflp12 124 +#define FRAME_fntflp13 125 +#define FRAME_fntflp14 126 +#define FRAME_fntflp15 127 +#define FRAME_fntflp16 128 +#define FRAME_jump1 129 +#define FRAME_jump2 130 +#define FRAME_jump3 131 +#define FRAME_jump4 132 +#define FRAME_jump5 133 +#define FRAME_jump6 134 +#define FRAME_jump7 135 +#define FRAME_jump8 136 +#define FRAME_jump9 137 +#define FRAME_jump10 138 +#define FRAME_jump11 139 +#define FRAME_jump12 140 +#define FRAME_jump13 141 +#define FRAME_jump14 142 +#define FRAME_jump15 143 +#define FRAME_jump16 144 +#define FRAME_jump17 145 +#define FRAME_lndatk1 146 +#define FRAME_lndatk2 147 +#define FRAME_lndatk3 148 +#define FRAME_lndatk4 149 +#define FRAME_lndatk5 150 +#define FRAME_lndatk6 151 +#define FRAME_lndatk7 152 +#define FRAME_lndatk8 153 +#define FRAME_lndatk9 154 +#define FRAME_lndatk10 155 +#define FRAME_lndatk11 156 +#define FRAME_newattackA1 157 +#define FRAME_newattackA2 158 +#define FRAME_newattackA3 159 +#define FRAME_newattackA4 160 +#define FRAME_newattackA5 161 +#define FRAME_newattackA6 162 +#define FRAME_newattackA7 163 +#define FRAME_newattackA8 164 +#define FRAME_newattackA9 165 +#define FRAME_newattackA10 166 +#define FRAME_newattackA11 167 +#define FRAME_newattackA12 168 +#define FRAME_newattackA13 169 +#define FRAME_newattackA14 170 +#define FRAME_newattackA15 171 +#define FRAME_newattackB1 172 +#define FRAME_newattackB2 173 +#define FRAME_newattackB3 174 +#define FRAME_newattackB4 175 +#define FRAME_newattackB5 176 +#define FRAME_newattackB6 177 +#define FRAME_newattackB7 178 +#define FRAME_newattackB8 179 +#define FRAME_newattackB9 180 +#define FRAME_newattackB10 181 +#define FRAME_newattackB11 182 +#define FRAME_newattackB12 183 +#define FRAME_newattackB13 184 +#define FRAME_newattackB14 185 +#define FRAME_newattackB15 186 +#define FRAME_newattackB16 187 +#define FRAME_newattackB17 188 +#define FRAME_newbackspring1 189 +#define FRAME_newbackspring2 190 +#define FRAME_newbackspring3 191 +#define FRAME_newbackspring4 192 +#define FRAME_newbackspring5 193 +#define FRAME_newbackspring6 194 +#define FRAME_newbackspring7 195 +#define FRAME_newbackspring8 196 +#define FRAME_newbackspring9 197 +#define FRAME_newbackspring10 198 +#define FRAME_newbackspring11 199 +#define FRAME_newbackspring12 200 +#define FRAME_newbackspring13 201 +#define FRAME_newbackspring14 202 +#define FRAME_newbackspring15 203 +#define FRAME_newcrchlklft1 204 +#define FRAME_newcrchlklft2 205 +#define FRAME_newcrchlklft3 206 +#define FRAME_newcrchlklft4 207 +#define FRAME_newcrchlklft5 208 +#define FRAME_newcrchlklft6 209 +#define FRAME_newcrchlklft7 210 +#define FRAME_newcrchlklft8 211 +#define FRAME_newcrchlklft9 212 +#define FRAME_newcrchlklft10 213 +#define FRAME_newcrchlklft11 214 +#define FRAME_newcrchlklft12 215 +#define FRAME_newcrchlklr1 216 +#define FRAME_newcrchlklr2 217 +#define FRAME_newcrchlklr3 218 +#define FRAME_newcrchlklr4 219 +#define FRAME_newcrchlklr5 220 +#define FRAME_newcrchlklr6 221 +#define FRAME_newcrchlklr7 222 +#define FRAME_newcrchlklr8 223 +#define FRAME_newcrchlklr9 224 +#define FRAME_newcrchlklr10 225 +#define FRAME_newcrchlklr11 226 +#define FRAME_newcrchlklr12 227 +#define FRAME_newcrchlkrit1 228 +#define FRAME_newcrchlkrit2 229 +#define FRAME_newcrchlkrit3 230 +#define FRAME_newcrchlkrit4 231 +#define FRAME_newcrchlkrit5 232 +#define FRAME_newcrchlkrit6 233 +#define FRAME_newcrchlkrit7 234 +#define FRAME_newcrchlkrit8 235 +#define FRAME_newcrchlkrit9 236 +#define FRAME_newcrchlkrit10 237 +#define FRAME_newcrchlkrit11 238 +#define FRAME_newcrchlkrit12 239 +#define FRAME_newcrchtrn1 240 +#define FRAME_newcrchtrn2 241 +#define FRAME_newcrchtrn3 242 +#define FRAME_newcrchtrn4 243 +#define FRAME_newcrchtrn5 244 +#define FRAME_newcrhlkrtidle1 245 +#define FRAME_newcrhlkrtidle2 246 +#define FRAME_newcrhlkrtidle3 247 +#define FRAME_newcrhlkrtidle4 248 +#define FRAME_newcrhlkrtidle5 249 +#define FRAME_newcrhlkrtidle6 250 +#define FRAME_newcrhlkrtidle7 251 +#define FRAME_newcrhlkrtidle8 252 +#define FRAME_newcrhlkrtidle9 253 +#define FRAME_newcrhlkrtidle10 254 +#define FRAME_newcrhlkrtidle11 255 +#define FRAME_newcrhlkrtidle12 256 +#define FRAME_newcrouchidle1 257 +#define FRAME_newcrouchidle2 258 +#define FRAME_newcrouchidle3 259 +#define FRAME_newcrouchidle4 260 +#define FRAME_newcrouchidle5 261 +#define FRAME_newcrouchidle6 262 +#define FRAME_newcrouchidle7 263 +#define FRAME_newcrouchidle8 264 +#define FRAME_newcrouchidle9 265 +#define FRAME_newcrouchidle10 266 +#define FRAME_newcrouchidle11 267 +#define FRAME_newcrouchidle12 268 +#define FRAME_newidle1 269 +#define FRAME_newidle2 270 +#define FRAME_newidle3 271 +#define FRAME_newidle4 272 +#define FRAME_newidle5 273 +#define FRAME_newidle6 274 +#define FRAME_newidle7 275 +#define FRAME_newidle8 276 +#define FRAME_newidle9 277 +#define FRAME_newidle10 278 +#define FRAME_newidle11 279 +#define FRAME_newidle12 280 +#define FRAME_newlkleftidle1 281 +#define FRAME_newlkleftidle2 282 +#define FRAME_newlkleftidle3 283 +#define FRAME_newlkleftidle4 284 +#define FRAME_newlkleftidle5 285 +#define FRAME_newlkleftidle6 286 +#define FRAME_newlkleftidle7 287 +#define FRAME_newlkleftidle8 288 +#define FRAME_newlkleftidle9 289 +#define FRAME_newlkleftidle10 290 +#define FRAME_newlkleftidle11 291 +#define FRAME_newlkleftidle12 292 +#define FRAME_newwalk1 293 +#define FRAME_newwalk2 294 +#define FRAME_newwalk3 295 +#define FRAME_newwalk4 296 +#define FRAME_newwalk5 297 +#define FRAME_newwalk6 298 +#define FRAME_newwalk7 299 +#define FRAME_newwalk8 300 +#define FRAME_newwalk9 301 +#define FRAME_newwalk10 302 +#define FRAME_newwalk11 303 +#define FRAME_newwalk12 304 +#define FRAME_newwalk13 305 +#define FRAME_newwalk14 306 +#define FRAME_painb1 307 +#define FRAME_painb2 308 +#define FRAME_painb3 309 +#define FRAME_painb4 310 +#define FRAME_painb5 311 +#define FRAME_poke1 312 +#define FRAME_poke2 313 +#define FRAME_poke3 314 +#define FRAME_poke4 315 +#define FRAME_poke5 316 +#define FRAME_poke6 317 +#define FRAME_poke7 318 +#define FRAME_poke8 319 +#define FRAME_poke9 320 +#define FRAME_poke10 321 +#define FRAME_poke11 322 +#define FRAME_poke12 323 +#define FRAME_poke13 324 +#define FRAME_poke14 325 +#define FRAME_poke15 326 +#define FRAME_poke16 327 +#define FRAME_poke17 328 +#define FRAME_poke18 329 +#define FRAME_run1 330 +#define FRAME_run2 331 +#define FRAME_run3 332 +#define FRAME_run4 333 +#define FRAME_run5 334 +#define FRAME_run6 335 +#define FRAME_run7 336 +#define FRAME_run8 337 +#define FRAME_run9 338 +#define FRAME_run10 339 +#define FRAME_poke19 340 +#define FRAME_poke20 341 +#define FRAME_poke21 342 +#define FRAME_poke22 343 +#define FRAME_poke23 344 +#define FRAME_poke24 345 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_DADDYNULL 0 +#define MESH__TORSOFT 1 +#define MESH__TORSOBK 2 +#define MESH__HEAD 3 +#define MESH__LKNIFE 4 +#define MESH__RKNIFE 5 +#define MESH__R4ARM 6 +#define MESH__L4ARM 7 +#define MESH__HIPS 8 +#define MESH__LCALF 9 +#define MESH__RCALF 10 +#define MESH__RTHIGH 11 +#define MESH__LTHIGH 12 +#define MESH__KNIFES 13 +#define MESH__LUPARM 14 +#define MESH__RUPARM 15 diff --git a/Toolkit/Programming/GameCode/game/m_beast.c b/Toolkit/Programming/GameCode/game/m_beast.c new file mode 100644 index 0000000..cb57227 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_beast.c @@ -0,0 +1,2804 @@ +/* +============================================================================== + +// m_tbeast.c +// +// Heretic II +// Copyright 1998 Raven Software + + +TBEAST + + +============================================================================== +*/ + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "p_anims2.h" +#include "p_anim_branch2.h" +#include "q_Physics.h" +#include "g_Physics.h" +#include "g_misc.h" +#include "m_beast.h" +#include "m_beast_anim.h" +#include "m_stats.h" + + +// ************************************* +// Definitions +// ************************************* + +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); +void BecomeDebris(edict_t *self); +qboolean clear_visible (edict_t *self, edict_t *other); +qboolean MG_MoveToGoal (edict_t *self, float dist); +trace_t MG_WalkMove (edict_t *self, float yaw, float dist, qboolean *succeeded); +int tbeast_inwalkframes(edict_t *self); + +static vec3_t GetLeftFootOffsetForFrameIndex[18] = +{// x y z + 160.00F, -64.00F, 0.00F, // 1 + 144.00F, -60.00F, 0.00F, // 2 + 96.00F, -56.00F, 0.00F, // 3 + 64.00F, -52.00F, 0.00F, // 4 + 16.00F, -48.00F, -2.00F, // 5 + -48.00F, -44.00F, -4.00F, // 6 + -80.00F, -40.00F, -2.00F, // 7 + -112.00F, -40.00F, 0.00F, // 8 + -160.00F, -40.00F, -4.00F, // 9 + -192.00F, -40.00F, 0.00F, // 10 + -120.00F, -42.00F, 2.00F, // 11 + -48.00F, -44.00F, 6.00F, // 12 + 0.00F, -44.00F, 14.00F, // 13 + 24.00F, -42.00F, 10.00F, // 14 + 28.00F, -48.00F, 16.00F, // 15 + 34.00F, -48.00F, 14.00F, // 16 + 110.00F, -58.00F, 0.00F, // 17 + 144.00F, -72.00F, 8.00F, // 18 +}; + +static vec3_t GetRightFootOffsetForFrameIndex[18] = +{// x y z + -160.00F, 32.00F, 0.00F, // 1 + -144.00F, 32.00F, 12.00F, // 2 + -96.00F, 28.00F, 14.00F, // 3 + -64.00F, 28.00F, 18.00F, // 4 + -16.00F, 28.00F, 22.00F, // 5 + 32.00F, 32.00F, 28.00F, // 6 + 64.00F, 38.00F, 28.00F, // 7 + 104.00F, 40.00F, 24.00F, // 8 + 160.00F, 48.00F, -4.00F, // 9 + 128.00F, 52.00F, -8.00F, // 10 + 112.00F, 54.00F, 0.00F, // 11 + 108.00F, 52.00F, 0.00F, // 12 + 72.00F, 48.00F, -2.00F, // 13 + 32.00F, 40.00F, 0.00F, // 14 + -4.00F, 36.00F, 0.00F, // 15 + -24.00F, 34.00F, 0.00F, // 16 + -80.00F, 32.00F, 2.00F, // 17 + -128.00F, 32.00F, -2.00F, // 18 +}; + +static animmove_t *animations[NUM_ANIMS] = +{ + &tbeast_move_biteup, + &tbeast_move_bitelow, + &tbeast_move_biteup2, + &tbeast_move_eating_twitch, + &tbeast_move_eating, + &tbeast_move_eatdown, + &tbeast_move_walk, + &tbeast_move_walkleft, + &tbeast_move_walkrt, + &tbeast_move_jump, + &tbeast_move_forced_jump, + &tbeast_move_inair, + &tbeast_move_land, + &tbeast_move_ginair, + &tbeast_move_gland, + &tbeast_move_stand, + &tbeast_move_delay, + &tbeast_move_die, + &tbeast_move_die_norm, + &tbeast_move_charge, + &tbeast_move_roar, + &tbeast_move_walkatk, + &tbeast_move_stun, + &tbeast_move_snatch, + &tbeast_move_ready_catch, + &tbeast_move_catch, + &tbeast_move_biteup_sfin, + &tbeast_move_bitelow_sfin, + &tbeast_move_biteup2_sfin, + &tbeast_move_quick_charge +}; + +static int sounds[NUM_SOUNDS]; + +static ClassResourceInfo_t resInfo; + +void tbeast_watch(edict_t *self, G_Message_t *msg); + + +qboolean visible_to_client (edict_t *self) +{ + edict_t *ent = NULL; + int i; + + for(i = 0; i <= game.maxclients; i++) + { + ent = &g_edicts[i]; + + if(ent->client) + { + edict_t *temp; + + temp = G_Spawn(); + + VectorSet(temp->s.origin, + ent->client->playerinfo.pcmd.camera_vieworigin[0] * 0.125, + ent->client->playerinfo.pcmd.camera_vieworigin[1] * 0.125, + ent->client->playerinfo.pcmd.camera_vieworigin[2] * 0.125); + + VectorSet(temp->s.angles, + SHORT2ANGLE(ent->client->playerinfo.pcmd.camera_viewangles[0]), + SHORT2ANGLE(ent->client->playerinfo.pcmd.camera_viewangles[1]), + SHORT2ANGLE(ent->client->playerinfo.pcmd.camera_viewangles[2])); + + if(infront_pos(temp, self->s.origin) && gi.inPVS(temp->s.origin, self->s.origin)) + { + G_FreeEdict(temp); + return true; + } + + G_FreeEdict(temp); + } + } + return false; +} + +qboolean shoulder_room_ahead (edict_t *self) +{ + vec3_t mins, maxs, endpos, angles, forward; + trace_t trace; + + VectorSet(angles, 0, self->s.angles[YAW], 0); + AngleVectors(angles, forward, NULL, NULL); + VectorMA(self->s.origin, 128, forward, endpos); + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + mins[2] = 0; + maxs[2] = 1; + + gi.trace(self->s.origin, mins, maxs, endpos, self, MASK_SOLID, &trace); + + if(trace.allsolid || trace.startsolid || trace.fraction < 1.0) + { +// gi.dprintf("No shoulder room ahead for beast to charge!\n"); + return (false); + } + + return (true); +} + +void tbeast_blocked (edict_t *self, trace_t *trace) +{//fake_touch does all the actual damage, this is just a check for the charge stuff + vec3_t dir, start, forward, end, mins, maxs; + float speed; + trace_t tr; + qboolean playsound = true; + qboolean stop = false; + edict_t *pillar = NULL; + + if(self->curAnimID==ANIM_CHARGE || (self->curAnimID==ANIM_QUICK_CHARGE && self->s.frame >= FRAME_charge1 && self->s.frame <= FRAME_charge10)) + { + if(trace->ent == world) + { + if(&trace->plane) + { + if(!Vec3IsZero(trace->plane.normal)) + { + if(trace->plane.normal[2]>0.7) + {//it's just a slope + playsound = false; + } + } + } + } + + if(playsound) + { + gi.sound(self, CHAN_ITEM, sounds[SND_SLAM], 1, ATTN_NORM, 0); + if(trace->ent) + { + if(!movable(trace->ent)&&!trace->ent->takedamage && trace->plane.normal[2] < 0.5) + stop = true; + } + } + + if(trace->ent && trace->ent->targetname && !stricmp(trace->ent->targetname, "pillar")) + pillar = trace->ent; + else + { + VectorCopy(self->s.origin, start); + AngleVectors(self->s.angles, forward, NULL, NULL); + start[2] = self->absmin[2] + self->size[2] * 0.8 + TB_UP_OFFSET; + VectorMA(start, self->maxs[0] * 0.8 + TB_FWD_OFFSET, forward, start); + VectorMA(start, 150, forward, end); + + VectorSet(mins, -24, -24, -1); + VectorSet(maxs, 24, 24, 1); + gi.trace(start, mins, maxs, end, self, MASK_SOLID,&tr); + if(tr.fraction<1.0 && tr.ent && tr.ent->targetname) + { + if(!stricmp(tr.ent->targetname, "pillar")) + pillar = tr.ent; + } + } + + if(pillar) + {//FIXME: In higher skills, less chance of breaking it? Or debounce time? +// gi.dprintf("Hit a Pillar!\n"); + + if(visible_to_client(self)) + { + self->red_rain_count++; + if(self->red_rain_count >= 2)//got both pillars, now die + { + //self->clipmask = 0; + self->solid = SOLID_NOT; + self->takedamage = DAMAGE_NO; + } + G_UseTargets (pillar, self); + pillar->targetname = "";//so we don't hit them again + pillar->target = "stop";//so it doesn't fire the target when it's broken later + + self->monsterinfo.attack_finished = level.time + 3; + } + + stop = true; + } + + if(stop) + { + gi.CreateEffect(&self->s, + FX_QUAKE, + 0, + vec3_origin, + "bbb", + 4, + 3, + 7); + + VectorCopy(self->velocity, dir); + speed = VectorNormalize(dir); + + self->velocity[0] = self->velocity[1] = 0; + self->sounds++; + if(self->sounds!=2 && irand(0, 1)) + SetAnim(self, ANIM_STUN); + } + } +} + +void tbeast_charge (edict_t *self, float force) +{ + vec3_t forward, enemy_dir; + float save_v2; + qboolean succeeded = false; + + if(!M_ValidTarget(self, self->enemy)) + { + SetAnim(self, ANIM_WALK); + return; + } + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorSubtract(self->enemy->s.origin, self->s.origin, enemy_dir); + VectorNormalize(enemy_dir); + + if(DotProduct(forward, enemy_dir) < 0.75)//enemy not generally ahead + ai_charge(self, 0); + + MG_WalkMove (self, self->s.angles[YAW], force, &succeeded); + + if(self->groundentity) + { + save_v2 = self->velocity[2]; + VectorScale(forward, force * 10 * 2, self->velocity); + self->velocity[2] = save_v2; + } +} + +//---------------------------------------------------------------------- +// TBeast Eat - decide which eating animations to use +//---------------------------------------------------------------------- +void tbeast_eat(edict_t *self, G_Message_t *msg) +{ + if(FindTarget(self)) + return; + + if(!irand(0,1)) + SetAnim(self, ANIM_EATING_TWITCH); + else + SetAnim(self, ANIM_EATING); +} + +/*---------------------------------------------------------------------- + TBeast Watch -decide which standing animations to use +-----------------------------------------------------------------------*/ +void tbeast_watch(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_STAND); +} + +/*---------------------------------------------------------------------- + TBeast Stand -decide which standing animations to use +-----------------------------------------------------------------------*/ +void tbeast_stand(edict_t *self, G_Message_t *msg) +{ + vec3_t v; + float len; + + if (self->ai_mood == AI_MOOD_DELAY) + { + SetAnim(self, ANIM_DELAY); + return; + } + + if (self->enemy) + { + if (clear_visible(self, self->enemy)) + return; + + VectorSubtract(self->enemy->s.origin, self->s.origin, v); + len = VectorNormalize(v); + + if (len < 200) + { + self->show_hostile = level.time + 1; // wake up other monsters + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + + return; + } + else if (len < 400) + { + if (!irand(0, 3)) + { + tbeast_growl(self); + } + } + + if (!irand(0, 3)) + { + tbeast_growl(self); + SetAnim(self, ANIM_STAND); + return; + } + else + { + if (self->monsterinfo.aiflags & AI_EATING) + SetAnim(self, ANIM_EATING); + + return; + } + } + + SetAnim(self, ANIM_STAND); +} + + +/*---------------------------------------------------------------------- + TBeast Walk -decide which walk animations to use +-----------------------------------------------------------------------*/ +void tbeast_walk(edict_t *self, G_Message_t *msg) +{ +// vec3_t v; +// float len; + float delta; + vec3_t targ_org; + + if(!MG_GetTargOrg(self, targ_org)) + return; + + + if (!self->enemy)//?goal? + { + SetAnim(self, ANIM_WALK); + return; + } + +/* if(clear_visible(self, self->enemy) && ahead(self, self->enemy)) + { + VectorSubtract (self->s.origin, targ_org, v); + len = VectorLength (v); + // targ_org is within range and far enough above or below to warrant a jump + if ((len > 40) && (len < 600) && ((self->s.origin[2] < targ_org[2] - 18) || + (self->s.origin[2] > targ_org[2] + 18))) + { + gi.dprintf("Jump from walk at enemy\n"); + SetAnim(self,ANIM_JUMP); + return; + } + }*/ + + delta = anglemod(self->s.angles[YAW] - self->ideal_yaw); + if (delta > 25 && delta <= 180) + { + SetAnim(self, ANIM_WALKRT); + } + else if (delta > 180 && delta < 335) + { + SetAnim(self, ANIM_WALKLEFT); + } + else + { + SetAnim(self, ANIM_WALK); + } +} + +void tbeast_init_charge (edict_t *self) +{ +// gi.dprintf("Beast CHARGE!\n"); + if(!ahead(self, self->enemy) || !irand(0,3)) + SetAnim(self, ANIM_QUICK_CHARGE); + else + SetAnim(self, ANIM_CHARGE); +} + +/*---------------------------------------------------------------------- + TBeast Melee - decide which melee animations to use +-----------------------------------------------------------------------*/ +void tbeast_melee(edict_t *self, G_Message_t *msg) +{ + vec3_t v, melee_point, forward, up; + float len, seperation; + float chance; + + if(!M_ValidTarget(self, self->enemy)) + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + return; + } + + AngleVectors(self->s.angles,forward, NULL, up); + VectorMA(self->s.origin, self->maxs[2]*0.5 + TB_UP_OFFSET, up, melee_point); + VectorMA(melee_point, 150 + TB_FWD_OFFSET, forward, melee_point); + + VectorSubtract (self->enemy->s.origin, melee_point, v); + len = VectorLength (v); + + seperation = self->enemy->maxs[0]; + + if ((len > 250 || !skill->value) && self->monsterinfo.attack_finished > level.time) + {//too soon to attack again + if (flrand(0, 1) < 0.9 && !skill->value) + SetAnim(self, ANIM_STAND); + else + SetAnim(self, ANIM_ROAR); + + return; + } + + //ok to attack + if(len - seperation < 100) + {//melee +// gi.dprintf("Biting: "); + chance = flrand(0, 1); + + if(self->enemy->absmin[2] > melee_point[2] + 128) + { +// gi.dprintf(" snatch extra high\n"); + SetAnim(self,ANIM_BITEUP2); + } + else if(self->enemy->absmin[2] > melee_point[2]) + { +// gi.dprintf(" snatch high\n"); + SetAnim(self,ANIM_BITEUP); + } + else + { +// gi.dprintf(" snatch low\n"); + SetAnim(self,ANIM_BITELOW); + } + + self->monsterinfo.attack_finished = level.time + flrand(2, 3); + return; + } + else if(len - seperation < self->melee_range && !irand(0,2)) + { +// gi.dprintf("walk attack\n"); + SetAnim(self,ANIM_WALKATK); + } + + if (self->enemy->classID != CID_TCHECKRIK && ((irand(0, 1) && infront(self, self->enemy)) || ahead(self, self->enemy)) && shoulder_room_ahead(self)) + { + tbeast_init_charge(self); + } + else + SetAnim(self, ANIM_WALK); +} + +void tbeast_start_charge(edict_t *self, G_Message_t *msg) +{ + MG_ChangeYaw(self); + if(self->enemy->classID != CID_TCHECKRIK && ((irand(0, 1) && infront(self, self->enemy)) || ahead(self, self->enemy)) && shoulder_room_ahead(self)) + { + tbeast_init_charge(self); + } + else + SetAnim(self, ANIM_WALK); +} + +#define TBEAST_SBAR_SIZE 3500 + +/*---------------------------------------------------------------------- + TBeast Run -decide which run animations to use +-----------------------------------------------------------------------*/ +void tbeast_run(edict_t *self, G_Message_t *msg) +{ + vec3_t v; + float len; + float delta; + qboolean enemy_vis; + vec3_t targ_org; + + if(!M_ValidTarget(self, self->enemy)) + return; + + if(!MG_GetTargOrg(self, targ_org)) + return; + + if(!self->dmg) + { + self->dmg = true; + SetAnim(self, ANIM_CHARGE); + return; + } + + VectorSubtract (self->s.origin, targ_org, v); + len = VectorLength (v); + + enemy_vis = clear_visible(self, self->enemy); +/* if(enemy_vis && ahead(self, self->enemy)) + { + // Enemy is within range and far enough above or below to warrant a jump + if ((len > 40) && (len < 600) && ((self->s.origin[2] < self->enemy->s.origin[2] - 40) || + (self->s.origin[2] > self->enemy->s.origin[2] + 40))) + { + if (abs(self->s.origin[2] - self->enemy->s.origin[2] - 40) < 200) // Can't jump more than 200 high + { + if (!irand(0, 2)) + { + gi.dprintf("Jump from run at enemy\n"); + SetAnim(self, ANIM_JUMP); + return; + } + } + } + }*/ + + if (self->enemy->classID != CID_TCHECKRIK && enemy_vis && ((irand(0, 1) && infront(self, self->enemy)) || ahead(self, self->enemy)) && shoulder_room_ahead(self)) + { + tbeast_init_charge(self); + } + else// if ((len < 200) && (self->monsterinfo.currframeindex == 0)) + { + delta = anglemod(self->s.angles[YAW] - self->ideal_yaw); + if (delta > 45 && delta <= 180) + { + SetAnim(self, ANIM_WALKRT); // Turn right + } + else if (delta > 180 && delta < 315) + { + SetAnim(self, ANIM_WALKLEFT); // Turn left + } + else + { + SetAnim(self, ANIM_WALK); // Run on + } + } +} + + +/*---------------------------------------------------------------------- + TBeast Pain - make the decision between pains 1, 2, or 3 +-----------------------------------------------------------------------*/ + +int tbeast_foot_damaged(edict_t *self, edict_t *attacker, float knockback, int take) +{ + QPostMessage(self->owner, MSG_PAIN, PRI_DIRECTIVE, "eeiii", self->owner, attacker, knockback, take, 0); + return false; +} + +void tbeast_pain(edict_t *self, G_Message_t *msg) +{ + edict_t *tempent; + int temp, damage; + qboolean force_pain; + + if(self->health < 1000) + return; + + if(!self->groundentity) + return; + + if(self->pain_debounce_time > level.time) + return; + + ParseMsgParms(msg, "eeiii", &tempent, &tempent, &force_pain, &damage, &temp); + + if(damage < irand(100, 200)) + return; + + self->pain_debounce_time = level.time + 10; + + if (!irand(0,1)) + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN2], 1, ATTN_NORM, 0); + + SetAnim(self, ANIM_STUN); +} + + +/*---------------------------------------------------------------------- + TBeast Die - choose death +-----------------------------------------------------------------------*/ +void tbeast_death(edict_t *self, G_Message_t *msg) +{ + self->msgHandler = DeadMsgHandler; + + if (self->deadflag == DEAD_DEAD) // Dead but still being hit + return; + + M_ShowLifeMeter(self, 0, 0); + // regular death + gi.sound(self, CHAN_VOICE, sounds[SND_DIE], 1, ATTN_NONE, 0); + self->deadflag = DEAD_DEAD; + self->takedamage = DAMAGE_YES; + + SetAnim(self, ANIM_DIE_NORM); +} + +void pitch_roll_for_slope (edict_t *forwhom, vec3_t *slope); +void tbeast_go_die (edict_t *self, edict_t *other, edict_t *activator) +{ + M_ShowLifeMeter(self, 0, 0); + + self->msgHandler = DeadMsgHandler; + gi.sound(self, CHAN_VOICE, sounds[SND_DIE], 1, ATTN_NONE, 0); + self->deadflag = DEAD_DEAD; + self->takedamage = DAMAGE_NO; + + self->solid = SOLID_NOT; + self->movetype = PHYSICSTYPE_NONE; + self->clipmask = 0; + VectorClear(self->mins); + VectorClear(self->maxs); + +// self->s.origin[2] += -8 - self->mins[2]; +// self->mins[2] = -8; +// self->maxs[2] = self->mins[2] + 24; +// self->svflags |= SVF_DEADMONSTER; + + self->health = 0; + self->post_think = NULL; + self->next_post_think = -1; + self->touch = NULL; + SetAnim(self, ANIM_DIE); + pitch_roll_for_slope(self, NULL); + G_UseTargets(self, activator); +} + + +/*---------------------------------------------------------------------- + + ACTION FUNCTIONS FOR THE MONSTER + +-----------------------------------------------------------------------*/ + +void tbeast_standorder (edict_t *self) +{ + if(tbeastCheckMood(self)) + return; + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void tbeast_walkorder (edict_t *self) +{ + if(tbeastCheckMood(self)) + return; + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); +} + +void tbeast_footstep (edict_t *self) +{ + vec3_t forward, right, pos, up, lfootoffset, rfootoffset, bottom; + int leg_check_index; + trace_t trace; + + AngleVectors(self->s.angles, forward, right, up); + + leg_check_index = tbeast_inwalkframes(self); + + if(leg_check_index > -1) + {//set up leg checks - only if in these frames + //left leg + if(leg_check_index < 6 || leg_check_index > 14) + { + VectorCopy(GetLeftFootOffsetForFrameIndex[leg_check_index], lfootoffset); + VectorMA(self->s.origin, lfootoffset[0] + TB_FWD_OFFSET, forward, pos); + VectorMA(pos, lfootoffset[1] + TB_RT_OFFSET, right, pos); + VectorMA(pos, lfootoffset[2] + TB_UP_OFFSET, up, pos); + } + else + {//right leg + VectorCopy(GetRightFootOffsetForFrameIndex[leg_check_index], rfootoffset); + VectorMA(self->s.origin, rfootoffset[0] + TB_FWD_OFFSET, forward, pos); + VectorMA(pos, rfootoffset[1] + TB_RT_OFFSET, right, pos); + VectorMA(pos, rfootoffset[2] + TB_UP_OFFSET, up, pos); + } + } + else + { + VectorCopy(self->s.origin, pos); + VectorMA(pos, self->maxs[0], forward, pos); + pos[2] += self->mins[2]; + + if(self->monsterinfo.currframeindex == FRAME_walk11 || + self->monsterinfo.currframeindex == FRAME_wlkrt11 || + self->monsterinfo.currframeindex == FRAME_wlklft11) + { + VectorMA(pos, -32, right, pos); + } + else + { + VectorMA(pos, 32, right, pos); + } + } + + VectorCopy(pos, bottom); + bottom[2]-=128; + gi.trace(pos, vec3_origin, vec3_origin, bottom, self, MASK_SOLID, &trace); + if(trace.fraction < 1.0) + VectorCopy(trace.endpos, pos); + + pos[2] += 10; + gi.CreateEffect(NULL, + FX_TB_EFFECTS, + 0, + pos, + "bv", + FX_TB_PUFF, + vec3_origin); + + VectorSet(up, flrand(-20, 20), flrand(-20, 20), flrand(20, 100)); + gi.CreateEffect(NULL, FX_OGLE_HITPUFF, 0, pos, "v", up); + + gi.CreateEffect(&self->s, + FX_QUAKE, + 0, + vec3_origin, + "bbb", + 3, + 1, + 2); + + if (!irand(0,1)) + gi.sound(self, CHAN_BODY, sounds[SND_STEP1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_BODY, sounds[SND_STEP2], 1, ATTN_NORM, 0); +} + +void tbeast_growl (edict_t *self) +{ + int chance; + + chance = irand(0, 200); + if (chance < 10) + gi.sound(self, CHAN_VOICE, sounds[SND_GROWL1], 1, ATTN_NORM, 0); + else if (chance < 20) + gi.sound(self, CHAN_VOICE, sounds[SND_GROWL2], 1, ATTN_NORM, 0); + else if (chance < 30) + gi.sound(self, CHAN_VOICE, sounds[SND_GROWL3], 1, ATTN_NORM, 0); +} + +void tbeast_snort (edict_t *self) +{ + int chance; + vec3_t forward, right, spot, spot2, vec; + + chance = irand(0, 20); + if (chance < 2) + { + if(!irand(0,1)) + gi.sound(self, CHAN_WEAPON, sounds[SND_SNORT1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_WEAPON, sounds[SND_SNORT2], 1, ATTN_NORM, 0); + //make snort effect from nose + AngleVectors(self->s.angles, forward, right, NULL); + + VectorCopy(self->s.origin, spot); + spot[2] += 36; + + VectorMA(spot, 100, forward, spot2); + + VectorMA(spot2, 64, right, spot2);//more than we want to get a nice vec + VectorSubtract(spot2, spot, vec); + VectorNormalize(vec); + VectorMA(spot2, -56, right, spot2);//back to + 8 + + gi.CreateEffect(NULL, FX_FLAMETHROWER, CEF_FLAG6|CEF_FLAG7, spot2, "df", vec, 100.0f); + + + Vec3ScaleAssign(-1, right); + + VectorMA(spot2, 72, right, spot2);//more than we want to get a nice vec + VectorSubtract(spot2, spot, vec); + VectorNormalize(vec); + VectorMA(spot2, -56, right, spot2);//back to +16 + + gi.CreateEffect(NULL, FX_FLAMETHROWER, CEF_FLAG6|CEF_FLAG7, spot2, "df", vec, 100.0f); + } +} + +qboolean tbeastCheckMood(edict_t *self) +{ + self->mood_think(self); + + if(self->ai_mood == AI_MOOD_NORMAL) + return false; + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + if(self->ai_mood_flags&AI_MOOD_FLAG_MISSILE) + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_PURSUE: + self->wait = 0; + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_NAVIGATE: + SetAnim(self, ANIM_WALK); + break; + + case AI_MOOD_STAND: + if (self->monsterinfo.aiflags & AI_EATING) + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_DELAY: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_EAT: + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + break; + + default : +#ifdef _DEVEL + gi.dprintf("beast: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } + + return true; +} + +/*---------------------------------------------------------------------- + TBeast Pause - decide what to do after attacking +-----------------------------------------------------------------------*/ +void tbeast_pause (edict_t *self) +{ + vec3_t v; + float len; + + if(self->enemy && self->enemy->classID != CID_TCHECKRIK && self->curAnimID == ANIM_STUN && self->pain_debounce_time > level.time + 7 && ahead(self, self->enemy)) + { + tbeast_init_charge(self); + return; + } + + if(tbeastCheckMood(self)) + return; + + if(!M_ValidTarget(self, self->enemy)) + return; + + if(clear_visible(self, self->enemy)) + { + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + } + else + len = 999999; + + if (len > 120) // Far enough to run after + { + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + } + else // Close enough to Attack or Hop + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + } +} + + +void tbeast_runorder (edict_t *self) +{ + if(tbeastCheckMood(self)) + return; + + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); +} + +void tbeastbite (edict_t *self, float ofsf, float ofsr, float ofsu) +{ + vec3_t v; + float damage; + float melee_range; + vec3_t temp, forward, right, up, melee_point, bite_endpos; + trace_t trace; + + if(self->ai_mood == AI_MOOD_NAVIGATE) + return; + + //fixme: do a checkenemy that checks oldenemy & posts messages + if(!M_ValidTarget(self, self->enemy)) + return; + + AngleVectors(self->s.angles,forward, right, up); + VectorMA(self->s.origin, ofsu + TB_UP_OFFSET, up, melee_point); + VectorMA(melee_point, ofsf + TB_FWD_OFFSET, forward, melee_point); + VectorMA(melee_point, ofsr, right, melee_point); + + melee_range = TBEAST_STD_MELEE_RNG;//give axtra range + VectorMA(melee_point, melee_range, forward, bite_endpos); + + //let's do this the right way + gi.trace(melee_point, vec3_origin, vec3_origin, bite_endpos, self, MASK_SHOT,&trace); + if (trace.fraction < 1 && !trace.startsolid && !trace.allsolid && trace.ent->takedamage)// A hit + { + gi.sound(self, CHAN_WEAPON, sounds[SND_CHOMP], 1, ATTN_NORM, 0); + + VectorCopy (self->enemy->s.origin, temp); + temp[2] += 5; + + VectorSubtract(self->enemy->s.origin, self->s.origin, v); + VectorNormalize(v); + + damage = irand(TB_DMG_BITE_MIN, TB_DMG_BITE_MAX); + T_Damage (self->enemy, self, self, forward, trace.endpos, v, damage, damage/2, DAMAGE_DISMEMBER,MOD_DIED); + } + else // A misssss + { + gi.sound(self, CHAN_WEAPON, sounds[SND_SNATCH], 1, ATTN_NORM, 0); + } +} + +void tbeast_dead(edict_t *self) +{ + self->movetype = PHYSICSTYPE_NONE; + self->deadState = DEAD_DEAD; + self->think = NULL; + self->nextthink = 0; + level.fighting_beast = false; + gi.linkentity (self); +} + +void tbeast_land(edict_t *self) +{ + vec3_t up, pos; + edict_t *found = NULL; + +// self->gravity = 1.0; + + gi.CreateEffect(&self->s, + FX_QUAKE, + 0, + vec3_origin, + "bbb", + 7, + 7, + 7); + + + VectorSet(up, flrand(-50,50), flrand(-50,50), flrand(50,300)); + + VectorCopy(self->s.origin, pos); + pos[0] += flrand(-50,50); + pos[1] += flrand(-50,50); + pos[2] += self->mins[2]; + gi.CreateEffect(NULL, FX_OGLE_HITPUFF, 0, pos, "v", up); + VectorCopy(self->s.origin, pos); + pos[0] += flrand(-50,50); + pos[1] += flrand(-50,50); + pos[2] += self->mins[2]; + gi.CreateEffect(NULL, FX_OGLE_HITPUFF, 0, pos, "v", up); + VectorCopy(self->s.origin, pos); + pos[0] += flrand(-50,50); + pos[1] += flrand(-50,50); + pos[2] += self->mins[2]; + gi.CreateEffect(NULL, FX_OGLE_HITPUFF, 0, pos, "v", up); + VectorCopy(self->s.origin, pos); + pos[0] += flrand(-50,50); + pos[1] += flrand(-50,50); + pos[2] += self->mins[2]; + gi.CreateEffect(NULL, FX_OGLE_HITPUFF, 0, pos, "v", up); + + gi.sound(self, CHAN_ITEM, sounds[SND_LAND], 1, ATTN_NORM, 0); + + while(found = findradius(found, self->s.origin, 512)) + { + if(found->client) + { + if(found->health > 0 && found->groundentity) + { + if(found->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + { + KnockDownPlayer(&found->client->playerinfo); + } + } + } + } +} + + +void tbeast_roar_knockdown(edict_t *self) +{ + edict_t *found = NULL; + + if(irand(0, 2)) + return; + + while(found = findradius(found, self->s.origin, 512)) + { + if(found->client && ahead(self, found)) + { + if(found->health > 0 && found->groundentity) + { + if(found->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + { + KnockDownPlayer(&found->client->playerinfo); + } + } + } + } +} + +void tbeast_roar(edict_t *self) +{ +/* vec3_t forward, endpos; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->s.origin, 128, forward, endpos); + gi.CreateEffect( NULL, FX_FLAMETHROWER, 0, endpos, "df", forward, 200);*/ + gi.sound(self, CHAN_VOICE, sounds[SND_ROAR2], 1, ATTN_NONE, 0); +} + +void tbeast_roar_short(edict_t *self) +{ + if(!self->delay) + { + self->monsterinfo.currframeindex = 25; + self->monsterinfo.nextframeindex = 26; + self->s.frame = FRAME_charge1; + self->delay = true; + } + else + gi.sound(self, CHAN_VOICE, sounds[SND_ROAR], 1, ATTN_NONE, 0); +} + +void tbeast_eatorder (edict_t *self) +{ + if(tbeastCheckMood(self)) + return; + + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); +} + +void tbeast_apply_jump (edict_t *self) +{ +// gi.dprintf("Jump from TB_CheckJump\n"); +// self->gravity = TB_JUMP_GRAV; + VectorCopy(self->movedir, self->velocity); + VectorNormalize(self->movedir); +} + + +qboolean CheckMoveFoot (edict_t *self, edict_t *foot, vec3_t dest) +{ + vec3_t dir; + trace_t trace; + + VectorSubtract(dest, foot->s.origin, dir); + VectorNormalize(dir); + + gi.trace(foot->s.origin, foot->mins, foot->maxs, dest, foot, MASK_MONSTERSOLID,&trace); + + if(trace.ent) + { + if(trace.ent->takedamage) + { + T_Damage(trace.ent, self, self, dir, trace.endpos, dir, 1000, 250, DAMAGE_DISMEMBER,MOD_DIED); + VectorCopy(foot->s.origin, foot->last_org); + VectorCopy(dest, foot->s.origin); +// VectorCopy(trace.endpos, foot->s.origin); + return true; + } +// else +// return false; + } + +// if(trace.allsolid||trace.startsolid) +// return false; + +// if(trace.fraction<0.9) +// return false; + + VectorCopy(foot->s.origin, foot->last_org); + VectorCopy(dest, foot->s.origin); +// VectorCopy(trace.endpos, foot->s.origin); + + return true; +} + +qboolean TB_CheckBottom (edict_t *self) +{ + vec3_t end; + trace_t trace; + vec3_t other_top, down, up; + + VectorCopy(self->s.origin, end); + end[2] -= 1; + gi.trace(self->s.origin, self->mins, self->maxs, end, self, MASK_ALL,&trace); + + if(trace.ent && stricmp(trace.ent->classname, "worldspawn")) + { + if(trace.ent->takedamage) + { + VectorCopy(trace.ent->s.origin, other_top); + other_top[2] += trace.ent->maxs[2]; + VectorSubtract(trace.ent->s.origin, self->s.origin, down); + VectorScale(down, -1, up); +// gi.dprintf("CheckBottom damaging %s\n", trace.ent->classname); +// T_Damage(trace.ent, self, self, down, other_top, up, 1000, 0, DAMAGE_DISMEMBER); + } + } + + if(trace.fraction < 1.0 || trace.startsolid || trace.allsolid) + { + /*if(&trace.plane) + { + if(!Vec3IsZero(trace.plane.normal)) + { + if(trace.plane.normal[2]>=0.5&&trace.plane.normal[2]<=1)//not a slope can go up + {//raise him up if on flat ground, lower is on slope - to keep feet on ground; + self->mins[2] = (1 - trace.plane.normal[2]) * 72 - 8 + TB_UP_OFFSET; + } + } + }*/ + self->groundentity = trace.ent; + return true; + } + return false; +} + +qboolean TB_CheckJump (edict_t *self)//, edict_t *other) +{ + vec3_t forward, start, end, start2, end2, mins, maxs; + trace_t trace; + float z_diff; + qboolean skiplow = false; + + if(self->enemy) + { + if(!ahead(self, self->enemy)) + return false; + + if(vhlen(self->enemy->s.origin, self->s.origin)<200) + { + z_diff = self->s.origin[2] + TB_HIBITE_U + TB_UP_OFFSET - self->enemy->s.origin[2]; + if(z_diff < -128) + { + SetAnim(self, ANIM_BITEUP2); + return true; + } + else if(Q_fabs(z_diff)<=32) + { + SetAnim(self, ANIM_BITEUP); + return true; + } + else if(z_diff < -32 && z_diff > -200) + skiplow = true; + else if(z_diff > 40 && z_diff < -24) + { + SetAnim(self, ANIM_BITELOW); + return true; + } + } + + if(self->enemy->s.origin[2] < self->s.origin[2]) + return false; + } + + if(self->monsterinfo.jump_time > level.time) + return false; + + VectorCopy(self->s.origin, start); + VectorCopy(start, end); + +//try a jump of 186 + end[2] += self->size[2]; + + if(!skiplow) + { + gi.trace(start, self->mins, self->maxs, end, self, MASK_SOLID,&trace); + + if(trace.fraction == 1.0 && !trace.startsolid && !trace.allsolid) + { + AngleVectors(self->s.angles, forward, NULL, NULL); + + VectorCopy(end, start2); + VectorMA(end, 64, forward, end2); + VectorScale(self->maxs, 0.5, maxs); + VectorCopy(self->mins, mins); + mins[0]*=0.5; + mins[1]*=0.5; + gi.trace(start2, self->mins, self->maxs, end2, self, MASK_SOLID,&trace); + if(trace.fraction == 1.0 && !trace.startsolid && !trace.allsolid) + { +// gi.dprintf("Beast blocked low jump!\n"); + VectorScale(forward, 250, self->movedir); + self->movedir[2] = 400; + self->monsterinfo.jump_time = level.time + 7; + SetAnim(self, ANIM_FJUMP); + return true; + } + } + } + +//try a jump of 372 + end[2] += self->size[2]; + + gi.trace(start, self->mins, self->maxs, end, self, MASK_SOLID,&trace); + + if(trace.fraction == 1.0 && !trace.startsolid && !trace.allsolid) + { + AngleVectors(self->s.angles, forward, NULL, NULL); + + VectorCopy(end, start2); + VectorMA(end, 64, forward, end2); + VectorScale(self->maxs, 0.5, maxs); + VectorCopy(self->mins, mins); + mins[0]*=0.5; + mins[1]*=0.5; + gi.trace(start2, self->mins, self->maxs, end2, self, MASK_SOLID,&trace); + if(trace.fraction == 1.0 && !trace.startsolid && !trace.allsolid) + { +// gi.dprintf("Beast blocked high jump!\n"); + VectorScale(forward, 300, self->movedir); + self->movedir[2] = 600; + self->monsterinfo.jump_time = level.time + 7; + SetAnim(self, ANIM_FJUMP); + return true; + } + } + return false; +} + +void MG_Pathfind(edict_t *self, qboolean check_clear_path); +void tbeast_run_think (edict_t *self, float dist) +{ + vec3_t angles, forward, start, end, mins; + trace_t trace; +/* + matrix3_t RotationMatrix; + vec3_t lfootoffset, rfootoffset, newlfootpos, newrfootpos; + vec3_t save_lf_org, save_rf_org, save_my_org; + float save_yaw;*/ + + if(!M_ValidTarget(self, self->enemy)) + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + return; + } + +//see if I'm on ground + TB_CheckBottom(self); + + if(self->monsterinfo.aiflags &AI_USING_BUOYS) + MG_Pathfind(self, false); + + if(!MG_MoveToGoal (self, dist)) + { + VectorSet(angles, 0, self->s.angles[YAW], 0); + AngleVectors(angles, forward, NULL, NULL); + + VectorCopy(self->s.origin, start); + VectorMA(start, 128, forward, end); + VectorCopy(self->mins, mins); + mins[2]+=54;//his step height + gi.trace(start, mins, self->maxs, end, self, MASK_SOLID,&trace); + if(trace.ent) + { + if(movable(trace.ent) || trace.ent->solid!=SOLID_BSP) + { + return; + } + } + if(trace.fraction == 1.0 || //nothing there - ledge + (&trace.plane && !Vec3IsZero(trace.plane.normal) && trace.plane.normal[2]<0.7))//not a slope can go up + { +#ifdef _DEVEL + if(TB_CheckJump(self)) + gi.dprintf("Enemy was ahead!\n"); +#else + TB_CheckJump(self); +#endif + } + } +} +/* +======================================== +TBEAST PICK UP AND GORE SOMETHING +======================================== +*/ +void tbeast_ready_catch (edict_t *self) +{ + float enemy_zdist, ok_zdist; + + if(!self->targetEnt) + return; + + ok_zdist = 128; + if(ok_zdist<48) + ok_zdist = 48; + + enemy_zdist = (self->targetEnt->s.origin[2] + self->targetEnt->mins[2]) - self->s.origin[2]; + if(enemy_zdist<=self->maxs[2] + ok_zdist && self->targetEnt->velocity[2]<=-60) + SetAnim(self,ANIM_CATCH); + else + SetAnim(self,ANIM_READY_CATCH); +} + +void tbeast_throw_toy(edict_t *self) +{ + if(!self->targetEnt) + return; + + self->targetEnt->flags &= ~FL_FLY; + self->targetEnt->velocity[0] = self->targetEnt->velocity[1] = 0; + self->targetEnt->velocity[2] = 500; + if(self->targetEnt->movetype>NUM_PHYSICSTYPES) + self->targetEnt->movetype = PHYSICSTYPE_STEP; + VectorRandomCopy(vec3_origin,self->targetEnt->avelocity,300); + + if(stricmp(self->targetEnt->classname,"player")) + QPostMessage(self->targetEnt, MSG_DEATH, PRI_DIRECTIVE, NULL); + + if(self->targetEnt->client) + gi.sound(self->targetEnt, CHAN_VOICE, sounds[SND_CORVUS_DIE], 1, ATTN_NORM, 0); +} + +void tbeast_toy_ofs(edict_t *self, float ofsf, float ofsr, float ofsu) +{ + vec3_t enemy_ofs, forward, right, up, blooddir, enemy_face; + + if(!self->enemy) + return; + + AngleVectors(self->s.angles, forward, right, up); + VectorMA(self->s.origin, ofsf + TB_FWD_OFFSET - 32, forward, enemy_ofs); + VectorMA(enemy_ofs, ofsr, right, enemy_ofs); + VectorMA(enemy_ofs, ofsu + TB_UP_OFFSET, up, self->targetEnt->s.origin); + VectorSubtract(self->targetEnt->s.origin, self->s.origin, blooddir); + + VectorScale(blooddir, -1, enemy_face); + enemy_face[2]/=10; + vectoangles(enemy_face, self->targetEnt->s.angles); + + switch(self->targetEnt->count) + { + case 1: + self->targetEnt->s.angles[PITCH]=anglemod(self->targetEnt->s.angles[PITCH]+90);//can't do roll? + break; + case 2: + self->targetEnt->s.angles[PITCH]=anglemod(self->targetEnt->s.angles[PITCH]-90);//can't do roll? + break; + case 3: + self->targetEnt->s.angles[ROLL]=anglemod(self->targetEnt->s.angles[ROLL]+90);//can't do roll? + break; + case 4: + self->targetEnt->s.angles[ROLL]=anglemod(self->targetEnt->s.angles[ROLL]-90);//can't do roll? + break; + default: + break; + } + + + VectorClear(self->targetEnt->velocity); + VectorClear(self->targetEnt->avelocity); + + if(flrand(0,1)<0.5) + { + if(self->targetEnt->materialtype == MAT_INSECT) + gi.CreateEffect(&self->targetEnt->s, FX_BLOOD, CEF_FLAG8, self->targetEnt->s.origin, "ub", blooddir, 200); + else + gi.CreateEffect(&self->targetEnt->s, FX_BLOOD, 0, self->targetEnt->s.origin, "ub", blooddir, 200); + } +} + +void tbeast_check_snatch(edict_t *self, float ofsf, float ofsr, float ofsu) +{ + float enemy_dist, ok_dist; + vec3_t forward, right, up, startpos, endpos; + edict_t *found = NULL; +// trace_t trace; + + if(!self->enemy) + return; + + ok_dist = 64; + + AngleVectors(self->s.angles,forward,right,up); + VectorMA(self->s.origin, ofsf + TB_FWD_OFFSET, forward, startpos); + VectorMA(startpos, ofsr, right, startpos); + VectorMA(startpos, ofsu + TB_UP_OFFSET, up, startpos); + + VectorSubtract(self->enemy->s.origin, startpos, endpos); + + enemy_dist = VectorLength(endpos); + if(enemy_dist>ok_dist || flrand(0, 50)>self->enemy->health) + {//if missed or health is low, just chomp it now + while(found = findradius(found, startpos, ok_dist)) + { + if(found->takedamage&&movable(found)) + { + if(found->health<=0) + T_Damage (found, self, self, endpos, found->s.origin, endpos, 2000, 300, DAMAGE_DISMEMBER,MOD_DIED); + else + break; + } + } + + if(!found) + { +// gi.dprintf("Snatch missed by %4.2f!\n", enemy_dist - ok_dist); + self->msgHandler = DefaultMsgHandler; + /* + if(!stricmp(self->enemy->classname,"player")) + { + if(self->oldenemy) + { + if(self->oldenemy->health>0) + { + self->oldenemy = NULL; + self->enemy = self->oldenemy; + } + } + }*/ + return; + } + } + else + found = self->enemy; + + self->msgHandler = DeadMsgHandler; +// gi.dprintf("SNAGGED!\n"); + + if(ofsu == TB_HIBITE_U + 128) + SetAnim(self, ANIM_BITEUP2_SFIN); + else if(ofsu == TB_HIBITE_U) + SetAnim(self, ANIM_BITEUP_SFIN); + else + SetAnim(self, ANIM_BITELOW_SFIN); + + self->targetEnt = found; + self->targetEnt->flags |= FL_FLY; + self->targetEnt->movetype = PHYSICSTYPE_FLY; + + if(!found->client) + { + found->monsterinfo.aiflags |= AI_DONT_THINK; + } + else + { + found->nextthink = level.time + 10;//stuck for 10 seconds. + if(found->health > 0) + { + if(found->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + { + KnockDownPlayer(&found->client->playerinfo); + } + } + gi.sound(found, CHAN_VOICE, sounds[irand(SND_CORVUS_SCREAM1, SND_CORVUS_SCREAM3)], 1, ATTN_NORM, 0); + } + + VectorClear(found->velocity); + VectorClear(found->avelocity); +} + +void tbeast_go_snatch (edict_t *self) +{ + SetAnim(self, ANIM_SNATCH); +} + +void tbeast_gore_toy(edict_t *self, float jumpht) +{ + float enemy_zdist, ok_zdist; + byte num_chunks; + vec3_t dir, forward; + + if(jumpht!=-1) + { + self->velocity[2] += jumpht; + if(self->groundentity) + { + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->velocity, -100, forward, self->velocity); + } + } + else + self->count = 0; + + if(!self->targetEnt) + return; + + if(self->targetEnt->health<0) + return; + + if(self->count) + return; + + ok_zdist = 128; + enemy_zdist = self->targetEnt->s.origin[2] - self->s.origin[2]; + if(enemy_zdist <= self->maxs[2] + ok_zdist || jumpht == -1) + {//FIXME: waits grabs it too low, waits too long + self->wait = self->targetEnt->materialtype; + + gi.sound(self, CHAN_WEAPON, sounds[SND_SNATCH], 1, ATTN_NORM, 0); + if(jumpht!=-1) + self->count = 1; + VectorCopy(self->velocity,dir); + VectorNormalize(dir); + num_chunks = (byte)(self->targetEnt->health/4); + if(num_chunks>15) + num_chunks = 15; + SprayDebris(self->targetEnt, self->targetEnt->s.origin, num_chunks, self->targetEnt->health*4);//self->enemy is thingtype wood?! + + if(stricmp(self->targetEnt->classname,"player")) + { + gi.sound(self->targetEnt, CHAN_WEAPON, sounds[SND_CATCH], 1, ATTN_NORM, 0); + BecomeDebris(self->targetEnt); + } + else + { + self->targetEnt->nextthink = level.time; + T_Damage (self->targetEnt, self, self, self->velocity, self->targetEnt->s.origin, dir, 2000, 300, DAMAGE_DISMEMBER|DAMAGE_NO_PROTECTION,MOD_DIED); + } + if(self->enemy == self->targetEnt) + self->enemy = NULL; + self->targetEnt = NULL; + } +} + +void tbeast_miss_sound (edict_t *self) +{ + gi.sound(self, CHAN_WEAPON, sounds[SND_SNATCH], 1, ATTN_NORM, 0); +} + +void tbeast_anger_sound (edict_t *self) +{ + byte chance; + + chance = irand(0,100); + if (chance < 10) + gi.sound(self, CHAN_WEAPON, sounds[SND_SNORT1], 1, ATTN_NORM, 0); + else if (chance < 20) + gi.sound(self, CHAN_WEAPON, sounds[SND_SNORT2], 1, ATTN_NORM, 0); + else if (chance < 30) + gi.sound(self, CHAN_ITEM, sounds[SND_TEAR1], 1, ATTN_NORM, 0); + else if (chance < 40) + gi.sound(self, CHAN_ITEM, sounds[SND_TEAR2], 1, ATTN_NORM, 0); + else if (chance < 50) + gi.sound(self, CHAN_WEAPON, sounds[SND_CHOMP], 1, ATTN_NORM, 0); + else if (chance < 60) + tbeast_growl(self); + + if(self->targetEnt) + { + chance = (byte)irand(1,3); + + SprayDebris(self->targetEnt, self->targetEnt->s.origin, chance, 100); + if(!self->targetEnt->client) + { + QPostMessage(self->targetEnt, MSG_DISMEMBER, PRI_DIRECTIVE, "ii", self->targetEnt->health*0.5, irand(1,13));//do I need last three if not sending them? + QPostMessage(self->targetEnt, MSG_PAIN, PRI_DIRECTIVE, "eeiii", self, self, true, 200, 0); + } + } +} + +void tbeast_gibs(edict_t *self) +{//FIXME: keep making gubs + vec3_t spot, mins, forward; + byte numchunks; + int flags = 0; + + if(!self->wait) + return; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->s.origin, 56, forward, spot); + spot[2] -= 8; + + if(self->wait == MAT_INSECT) + { + flags |= CEF_FLAG8; + flags |= CEF_FLAG7;//use male insect skin on chunks + } + + numchunks = (byte)(irand(3, 7)); + VectorSet(mins, -1, -1, -1); + gi.CreateEffect(NULL, + FX_FLESH_DEBRIS, + flags, + spot, + "bdb", + numchunks, self->mins, 16); + + tbeast_anger_sound (self); +} + +void tbeast_done_gore (edict_t *self) +{ + self->msgHandler = DefaultMsgHandler; + self->count = 0; + M_ValidTarget(self, self->enemy); + + self->monsterinfo.aiflags |= AI_EATING; + SetAnim(self, ANIM_EATDOWN); +} + +void tbeast_inair (edict_t *self) +{ + SetAnim(self, ANIM_INAIR); +} + +void tbeast_check_landed (edict_t *self) +{ + if(TB_CheckBottom(self)) + SetAnim(self, ANIM_LAND); +} + +void tbeast_ginair (edict_t *self) +{ + SetAnim(self, ANIM_GINAIR); +} + +void tbeast_gcheck_landed (edict_t *self) +{ + if(TB_CheckBottom(self)) + SetAnim(self, ANIM_GLAND); +} + +void tbeast_chomp(edict_t *self, float ofsf, float ofsr, float ofsu) +{ + float enemy_dist, ok_dist, damage; + vec3_t forward, right, up, startpos, endpos, v; + + if(!self->enemy) + return; + + ok_dist = 64; + + AngleVectors(self->s.angles,forward,right,up); + VectorMA(self->s.origin, ofsf + TB_FWD_OFFSET, forward, startpos); + VectorMA(startpos, ofsr, right, startpos); + VectorMA(startpos, ofsu + TB_UP_OFFSET, up, startpos); + + VectorSubtract(self->enemy->s.origin, startpos, endpos); + + enemy_dist = VectorLength(endpos); + if(enemy_dist>ok_dist) + {//if missed or health is low, just chomp it now +// gi.dprintf("Chomp missed by %4.2f!\n", enemy_dist - ok_dist); + if(enemy_dist - ok_dist < 64) + {//let them know it was close and we tried - spittle effect? + gi.sound(self, CHAN_WEAPON, sounds[SND_SNATCH], 1, ATTN_NORM, 0); + } + return; + } + gi.sound(self, CHAN_WEAPON, sounds[SND_CHOMP], 1, ATTN_NORM, 0); + VectorSubtract(self->enemy->s.origin, self->s.origin, v); + VectorNormalize(v); + damage = irand(TB_DMG_BITE_MIN, TB_DMG_BITE_MAX); + T_Damage (self->enemy, self, self, forward, endpos, v, damage, damage/2, DAMAGE_DISMEMBER,MOD_DIED); +} + +void tbeast_leap (edict_t *self, float fwdf, float rghtf, float upf) +{ + vec3_t forward, right, up, angles; + + if(!self->groundentity) + { + if(!TB_CheckBottom(self)) + return; + } + + if(self->s.frame == FRAME_jumpb7) + tbeast_chomp(self, 36, 0, 232); + +// self->gravity = TB_JUMP_GRAV; + VectorSet(angles, 0, self->s.angles[YAW], 0); + AngleVectors(angles, forward, right, up); + VectorScale(forward, fwdf, self->velocity); + VectorMA(self->velocity, rghtf, right, self->velocity); + VectorMA(self->velocity, upf, up, self->velocity); +} + +/*======================== + + Hacky Trial Beast fake collision and slope-standing code + + ========================*/ + +/* + + LerpAngleChange + + */ + +float LerpAngleChange (float curangle, float endangle, float step) +{ + float final, diff; + + curangle = anglemod(curangle); + endangle = anglemod(endangle); + + if(curangle>180) + curangle-=360; + else if(curangle<-180) + curangle+=360; + + if(endangle>180) + endangle-=360; + else if(endangle<-180) + endangle+=360; + + if(curangle == endangle) + return 0; + + diff = endangle - curangle; + + if(diff > 180) + diff -= 360; + else if(diff < -180) + diff += 360; + + final = anglemod(curangle + diff/step); + + if(final>180) + final-=360; + else if(final<-180) + final+=360; + + return final; +} + +int tbeast_inwalkframes(edict_t *self) +{ + if(self->curAnimID == ANIM_CHARGE||self->curAnimID==ANIM_QUICK_CHARGE) + { + switch(self->s.frame) + { + case FRAME_charge1: + return 2; + break; + case FRAME_charge2: + return 4; + break; + case FRAME_charge3: + return 6; + break; + case FRAME_charge4: + return 8; + break; + case FRAME_charge5: + return 9; + break; + case FRAME_charge6: + return 7; + break; + case FRAME_charge7: + return 13; + break; + case FRAME_charge8: + return 15; + break; + case FRAME_charge9: + return 1; + break; + case FRAME_charge10: + return 0; + break; + default: + return -1; + break; + } + } + + if(self->s.frame>=FRAME_walk1 && self->s.frame<=FRAME_walk18) + return self->monsterinfo.currframeindex; + + if(self->s.frame>=FRAME_wlklft1 && self->s.frame<=FRAME_wlklft18) + return self->monsterinfo.currframeindex; + + if(self->s.frame>=FRAME_wlkrt1 && self->s.frame<=FRAME_wlkrt18) + return self->monsterinfo.currframeindex; + + if(self->s.frame>=FRAME_wlkatk1 && self->s.frame<=FRAME_wlkatk18) + return self->monsterinfo.currframeindex; + + if(self->s.frame>=FRAME_wait1 && self->s.frame<=FRAME_wait14) + return 16; + + return -1; +} + +/* + + LevelToGround + + I'm a big guy, level me out + What slope am I on + ? +*/ +void LevelToGround (edict_t *self, float fscale, float rscale, qboolean z_adjust) +{ + vec3_t forward, right, backpos, frontpos, leftpos, rightpos, dir, angles, bottom1, bottom2; + vec3_t lfootoffset, rfootoffset, up; + trace_t trace; + qboolean right_front; + int leg_check_index; + int count = 0; + + AngleVectors(self->s.angles, forward, right, up); + + leg_check_index = tbeast_inwalkframes(self); + + if(leg_check_index > -1) + {//set up leg checks - only if in these frames + if(leg_check_index > 5 && leg_check_index < 15) + right_front = true; + else + right_front = false; + + //left leg + VectorCopy(GetLeftFootOffsetForFrameIndex[leg_check_index], lfootoffset); + VectorMA(self->s.origin, lfootoffset[0] + TB_FWD_OFFSET, forward, leftpos); + VectorMA(leftpos, lfootoffset[1] + TB_RT_OFFSET, right, leftpos); + VectorMA(leftpos, lfootoffset[2] + TB_UP_OFFSET, up, leftpos); + + //right leg + VectorCopy(GetRightFootOffsetForFrameIndex[leg_check_index], rfootoffset); + VectorMA(self->s.origin, rfootoffset[0] + TB_FWD_OFFSET, forward, rightpos); + VectorMA(rightpos, rfootoffset[1] + TB_RT_OFFSET, right, rightpos); + VectorMA(rightpos, rfootoffset[2] + TB_UP_OFFSET, up, rightpos); + + if(right_front) + {//this is also the front check + VectorCopy(rightpos, frontpos); + VectorCopy(leftpos, backpos); + } + else + { + VectorCopy(leftpos, frontpos); + VectorCopy(rightpos, backpos); + } + } + else return; + /*{ + VectorCopy(self->s.origin, backpos); + backpos[2] += self->mins[2] + 10; + + VectorMA(backpos, self->maxs[0] * fscale, forward, frontpos); + VectorMA(backpos, self->mins[0] * fscale, forward, backpos); + + VectorCopy(self->s.origin, leftpos); + leftpos[2] += self->mins[2] + 10; + + VectorMA(leftpos, self->maxs[0] * rscale, right, rightpos); + VectorMA(leftpos, self->mins[0] * rscale, right, leftpos); + }*/ + + VectorCopy(frontpos, bottom1); + bottom1[2] -= self->size[2] * 2; + gi.trace(frontpos, vec3_origin, vec3_origin, bottom1, self, MASK_SOLID,&trace); + if(trace.fraction == 1.0) + { + self->s.angles[PITCH] = LerpAngleChange (self->s.angles[PITCH], 0, 8); + } + else + { + VectorCopy(trace.endpos, bottom1); + + VectorCopy(backpos, bottom2); + bottom2[2] -= self->size[2] * 2; + gi.trace(backpos, vec3_origin, vec3_origin, bottom2, self, MASK_SOLID,&trace); + if(trace.fraction == 1.0) + { + self->s.angles[PITCH] = LerpAngleChange (self->s.angles[PITCH], 0, 8); + } + else + { + VectorCopy(trace.endpos, bottom2); + + VectorSubtract(bottom1, bottom2, dir); + vectoangles(dir, angles); + + self->s.angles[PITCH] = LerpAngleChange (self->s.angles[PITCH], angles[PITCH], 8); + } + } + + VectorCopy(rightpos, bottom1); + bottom1[2] -= self->size[2] * 2; + gi.trace(rightpos, vec3_origin, vec3_origin, bottom1, self, MASK_SOLID,&trace); + if(trace.fraction == 1.0) + { + self->s.angles[ROLL] = LerpAngleChange (self->s.angles[ROLL], 0, 8); + } + else + { + VectorCopy(trace.endpos, bottom1); + + VectorCopy(leftpos, bottom2); + bottom2[2] -= self->size[2] * 2; + gi.trace(leftpos, vec3_origin, vec3_origin, bottom2, self, MASK_SOLID,&trace); + if(trace.fraction == 1.0) + { + self->s.angles[ROLL] = LerpAngleChange (self->s.angles[ROLL], 0, 8); + } + else + { + VectorCopy(trace.endpos, bottom2); + + VectorSubtract(bottom1, bottom2, dir); + vectoangles(dir, angles); + + self->s.angles[ROLL] = LerpAngleChange (self->s.angles[ROLL], angles[PITCH], 8); + } + } + + /* + if(z_adjust) + { + if((gi.pointcontents(rightpos) & MASK_SOLID) || (gi.pointcontents(leftpos) & MASK_SOLID)) + { + gi.dprintf("Beast feet in ground, raising up\n"); + while(((gi.pointcontents(rightpos) & MASK_SOLID) || + (gi.pointcontents(leftpos) & MASK_SOLID)) && count < 10) + { + self->mins[2]++; + self->s.origin[2]++; + rightpos[2]++; + leftpos[2]++; + count++; + } + gi.linkentity(self); + } + else + { + leftpos[2] -= 4; + rightpos[2] -= 4; + if(!(gi.pointcontents(rightpos) & MASK_SOLID) && !(gi.pointcontents(leftpos) & MASK_SOLID)) + { + gi.dprintf("Beast feet not on ground, lowering\n"); + while(!(gi.pointcontents(rightpos) & MASK_SOLID) && + !(gi.pointcontents(leftpos) & MASK_SOLID) && count < 10) + { + self->mins[2]--; + self->s.origin[2]--; + rightpos[2]--; + leftpos[2]--; + count++; + } + gi.linkentity(self); + } + } + }*/ +} + +void DoImpactDamage(edict_t *self, trace_t *trace); +void tbeast_fake_impact(edict_t *self, trace_t *trace, qboolean crush) +{ + trace_t tr; + vec3_t dir, bottom; + qboolean throwthem = true; + + if(trace->ent->svflags & SVF_TOUCHED_BEAST) + return; + + if(trace->ent == self->targetEnt) + return; + + if(trace->ent->classID == CID_FUNC_DOOR) + return; + + if(trace->ent->classID == CID_TCHECKRIK) + return;//we want to pick up and eat insects + + if(trace->ent && trace->ent->movetype && trace->ent !=world && stricmp(trace->ent->classname, "worldspawn")) + { + if(trace->ent->client||trace->ent->svflags&SVF_MONSTER) + { + if(trace->ent->s.origin[2] > self->absmax[2] - 10) + {//FIXME: chance of throwing them off + trace->ent->s.origin[2] = self->absmax[2]; + trace->ent->velocity[2] = 0; + trace->ent->groundentity = self; + throwthem = false; + } + } + if(throwthem) + { + VectorCopy(self->s.origin, bottom); + bottom[2] += self->mins[2]; + VectorSubtract(trace->ent->s.origin, bottom, dir); + VectorNormalize(dir); + } + + if(movable(trace->ent) || trace->ent->takedamage) + { + if(throwthem) + VectorScale(dir, 200, trace->ent->velocity); + } + else if(Vec3NotZero(self->velocity) && trace->fraction < 0.7) + { + if(infront(self, trace->ent)) + { + if(trace->ent->targetname && !stricmp(trace->ent->targetname, "pillar")) + {//FIXME: In higher skills, less chance of breaking it? Or debounce time? + + if(visible_to_client(self)) + { +// gi.dprintf("Beast hit pillar!\n"); + G_UseTargets (trace->ent, self); + trace->ent->targetname = "";//so we don't hit them again + trace->ent->target = "stop";//so it doesn't fire the target when it's broken later + self->monsterinfo.attack_finished = level.time + 3; + + self->velocity[0] = self->velocity[1] = 0; + self->sounds++; + + self->red_rain_count++; + + if(self->red_rain_count >= 2)//got both pillars, now die + { + //self->clipmask = 0; + self->solid = SOLID_NOT; + self->takedamage = DAMAGE_NO; + } + } + gi.CreateEffect(&self->s, + FX_QUAKE, + 0, + vec3_origin, + "bbb", + 4, + 3, + 7); + + if(self->sounds!=2 && irand(0, 1)) + SetAnim(self, ANIM_STUN); + } + } + } + + if(trace->ent->touch&&trace->ent->solid!=SOLID_NOT) + trace->ent->touch (trace->ent, self, &trace->plane, trace->surface); + + if(trace->ent->isBlocked&&trace->ent->solid!=SOLID_NOT) + { + tr = *trace; + tr.ent = self; + trace->ent->isBlocked(trace->ent, &tr); + } + + if(throwthem && trace->ent->takedamage) + { + float damage; + + if(Vec3NotZero(self->velocity)) + { + if(trace->ent->client) + { + if(trace->ent->health > 30) + DoImpactDamage(self, trace); + + if(trace->ent->groundentity && trace->ent->health) + { + if(trace->ent->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + { + KnockDownPlayer(&trace->ent->client->playerinfo); + } + } + } + else + DoImpactDamage(self, trace); + } + else + { + if(trace->ent->client) + { + if(crush) + damage = flrand(20, 100); + else if(trace->ent->health > 30) + damage = flrand(10, 30) * skill->value/2; + else + damage = 0; + + if(!irand(0, 5) || (crush && !irand(0,1))) + { + if(trace->ent->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + KnockDownPlayer(&trace->ent->client->playerinfo); + } + if(damage) + T_Damage(trace->ent, self, self, dir, trace->endpos, dir, + flrand(TB_DMG_IMPACT_MIN, TB_DMG_IMPACT_MAX), TB_DMG_IMPACT_KB, 0,MOD_DIED); + } + else + { + if(crush) + damage = flrand(1000, 3000); + else + damage = flrand(20, 100); + T_Damage(trace->ent, self, self, dir, trace->endpos, dir, 1000, 250, 0,MOD_DIED); + } + } + } + else + { + if(trace->ent->client) + { + if(trace->ent->groundentity && trace->ent->health) + { + if(trace->ent->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + { + KnockDownPlayer(&trace->ent->client->playerinfo); + } + } + } + } + } +} + +qboolean boxes_overlap(vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2) +{ + if(mins1[0]>maxs2[0]) + return false; + + if(mins1[1]>maxs2[1]) + return false; + + if(mins1[2]>maxs2[2]) + return false; + + if(maxs1[0]s.angles, forward, right, up); + + //set up body check + VectorCopy(self->s.origin, start); + start[2] += 64 + TB_UP_OFFSET;//bottom of torso + start[2] += 61;//halfway up to the top of torso + VectorMA(start, 150 + TB_FWD_OFFSET, forward, end); + VectorMA(start, -120, forward, start);// + TB_FWD_OFFSET??? + VectorSet(mins, -50, -50, -61); + VectorSet(maxs, 50, 50, 70); + + leg_check_index = tbeast_inwalkframes(self); + + if(leg_check_index > -1) + {//set up leg checks - FIXME: trace from last footpos to current one + VectorSet(fmins, -8, -8, 0); + VectorSet(fmaxs, 8, 8, 1); + + //left leg + VectorCopy(GetLeftFootOffsetForFrameIndex[leg_check_index], lfootoffset); + VectorMA(self->s.origin, lfootoffset[0] + TB_FWD_OFFSET, forward, lend); + VectorMA(lend, lfootoffset[1] + TB_RT_OFFSET, right, lend); + VectorMA(lend, lfootoffset[2] + TB_UP_OFFSET, up, lend); + VectorCopy(lend, lstart); + lstart[2]+=63; + + VectorAdd(lend, fmins, lfootmins); + VectorCopy(lfootmins, lfootmaxs); + lfootmaxs[2] += 64; + + //right leg + VectorCopy(GetRightFootOffsetForFrameIndex[leg_check_index], rfootoffset); + VectorMA(self->s.origin, rfootoffset[0] + TB_FWD_OFFSET, forward, rend); + VectorMA(rend, rfootoffset[1] + TB_RT_OFFSET, right, rend); + VectorMA(rend, rfootoffset[2] + TB_UP_OFFSET, up, rend); + VectorCopy(rend, rstart); + rstart[2]+=63; + + VectorAdd(rend, fmins, rfootmins); + VectorCopy(rfootmins, rfootmaxs); + rfootmaxs[2] += 64; + } + +//BODY + //Fix me: continue the trace if less than 1.0 or save for next touch? + gi.trace(start, mins, maxs, end, self, MASK_MONSTERSOLID,&trace); + //Hey! Check and see if they're close to my mouth and chomp 'em! + tbeast_fake_impact(self, &trace, false); + + if(leg_check_index == -1) + { + VectorCopy(self->s.origin, end); + end[2] += self->mins[2]; + VectorCopy(end, start); + start[2] += 63; + VectorSet(mins, -32, -32, 0); + VectorSet(maxs, 32, 32, 1); + + gi.trace(start, mins, maxs, end, self, MASK_MONSTERSOLID,&trace); + tbeast_fake_impact(self, &trace, false); + return; + } + +//Do leg checks +//left leg + //Fix me: continue the trace if less than 1.0 or save for next touch? + gi.trace(lstart, fmins, fmaxs, lend, self, MASK_MONSTERSOLID,&trace); + tbeast_fake_impact(self, &trace, true); + +//right leg + //Fix me: continue the trace if less than 1.0 or save for next touch? + gi.trace(rstart, fmins, fmaxs, rend, self, MASK_MONSTERSOLID,&trace); + tbeast_fake_impact(self, &trace, true); +} + +void tbeast_fake_touch(edict_t *self) +{//Used by Trial Beast for Simulated Complex Bounding Box Collision + + vec3_t forward, right, up, start, end, dir, mins, maxs; + vec3_t lfootoffset, rfootoffset, omins, omaxs; + vec3_t lstart, lend, rstart, rend, lfootmins, lfootmaxs, rfootmins, rfootmaxs, fmins, fmaxs; + vec3_t melee_point; + int leg_check_index; + qboolean hitme = true; + qboolean hitother = false; + trace_t trace; + int osolid, ocm; + int i, num; + edict_t *touch[MAX_EDICTS], *other; + + num = gi.BoxEdicts (self->absmin, self->absmax, touch, MAX_EDICTS, AREA_SOLID); + // be careful, it is possible to have an entity in this + // list removed before we get to it (killtriggered) + + if(!touch[0]) + goto finish; + + AngleVectors(self->s.angles, forward, right, up); + + leg_check_index = tbeast_inwalkframes(self); + + if(leg_check_index > -1) + {//set up leg checks - FIXME: trace from last footpos to current one + + //Walking, Check melee point in front + VectorMA(self->s.origin, self->maxs[2]*0.5 + TB_UP_OFFSET, up, melee_point); + VectorMA(melee_point, 150 + TB_FWD_OFFSET, forward, melee_point); + + VectorSet(fmins, -8, -8, 0); + VectorSet(fmaxs, 8, 8, 1); + + //left leg + VectorCopy(GetLeftFootOffsetForFrameIndex[leg_check_index], lfootoffset); + VectorMA(self->s.origin, lfootoffset[0] + TB_FWD_OFFSET, forward, lend); + VectorMA(lend, lfootoffset[1] + TB_RT_OFFSET, right, lend); + VectorMA(lend, lfootoffset[2] + TB_UP_OFFSET, up, lend); + VectorCopy(lend, lstart); + lstart[2]+=63; + + VectorAdd(lend, fmins, lfootmins); + VectorCopy(lfootmins, lfootmaxs); + lfootmaxs[2] += 64; + + //right leg + VectorCopy(GetRightFootOffsetForFrameIndex[leg_check_index], rfootoffset); + VectorMA(self->s.origin, rfootoffset[0] + TB_FWD_OFFSET, forward, rend); + VectorMA(rend, rfootoffset[1] + TB_RT_OFFSET, right, rend); + VectorMA(rend, rfootoffset[2] + TB_UP_OFFSET, up, rend); + VectorCopy(rend, rstart); + rstart[2]+=63; + + VectorAdd(rend, fmins, rfootmins); + VectorCopy(rfootmins, rfootmaxs); + rfootmaxs[2] += 64; + } + + //set up body check + VectorCopy(self->s.origin, start); + start[2] += 64 + TB_UP_OFFSET;//bottom of torso + start[2] += 35;//halfway up to the top of torso + VectorMA(start, 150 + TB_FWD_OFFSET, forward, end); + VectorMA(start, -120, forward, start);// + TB_FWD_OFFSET??? + VectorSet(mins, -50, -50, -61); + VectorSet(maxs, 50, 50, 70); + + for (i=0 ; iinuse) + continue; + + if(other==self) + continue; + + if(!stricmp(other->classname, "worldspawn")) + continue; + + if(other == self->targetEnt) + continue; + + if(self->curAnimID != ANIM_CHARGE && self->curAnimID != ANIM_QUICK_CHARGE) + { + if(leg_check_index > -1 && other->takedamage && movable(other)) + {//Hey! Check and see if they're close to my mouth and chomp 'em! + if(vhlen (other->s.origin, melee_point) < 100) + { + self->oldenemy = self->enemy; + self->enemy = other; + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + goto finish; + } + } + } + + if(other->classID == CID_TCHECKRIK) + continue;//we want to pick up and eat insects + + //make other solid and size temp for trace + ocm = other->clipmask; + osolid = other->solid; + if(!Vec3IsZero(other->mins)) + VectorCopy(other->mins, omins); + else + { + VectorCopy(other->mins, omins); + VectorSet(other->mins, -1, -1, -1); + } + + if(!Vec3IsZero(other->maxs)) + VectorCopy(other->maxs, omaxs); + else + { + VectorCopy(other->maxs, omaxs); + VectorSet(other->maxs, 1, 1, 1); + } + + other->solid = SOLID_BBOX; + other->clipmask = MASK_ALL; +//BODY + //Fix me: continue the trace if less than 1.0 or save for next touch? + gi.trace(start, mins, maxs, end, self, MASK_MONSTERSOLID,&trace); + //put other back to normal + other->solid = osolid; + other->clipmask = ocm; + VectorCopy(omins, other->mins); + VectorCopy(omaxs, other->maxs); + + if(trace.ent==other)//hit something with BODY , touch it + hitother = true;//hit other! + + if(!hitother && other->absmin[2]>self->absmax[2] - 10) + { + if(!irand(0,10)) + { +// gi.dprintf("Jump to throw off something\n"); + SetAnim(self, ANIM_JUMP); + VectorSubtract(other->s.origin, self->s.origin, dir); + VectorNormalize(dir); + VectorScale(dir, 500, other->velocity); +// other->groundentity = NULL; + } + } + else + { + if(hitother) + hitme = true; + else + { + hitme = false; + if(leg_check_index > -1) + { + VectorAdd(other->s.origin, other->mins, omins); + VectorAdd(other->s.origin, other->maxs, omaxs); + if(boxes_overlap(omins, omaxs, lfootmins, lfootmaxs)) + hitme = true; + else if(boxes_overlap(omins, omaxs, rfootmins, rfootmaxs)) + hitme = true; + } + } + + if(hitme) + { + if(other->isBlocked&&other->solid!=SOLID_NOT) + { + gi.trace(other->s.origin, vec3_origin, vec3_origin, self->s.origin, other, MASK_ALL,&trace); + trace.ent = self; + VectorCopy(other->s.origin, trace.endpos); + other->isBlocked(other, &trace); + } + if(other->touch&&other->solid!=SOLID_NOT) + { + gi.trace(other->s.origin, vec3_origin, vec3_origin, self->s.origin, other, MASK_ALL,&trace); + trace.ent = self; + VectorCopy(other->s.origin, trace.endpos); + other->touch (other, self, &trace.plane, trace.surface); + } + if(other && other == trace.ent) + {//if other still valid, do my impact with it + tbeast_fake_impact(self, &trace, false); + other->svflags |= SVF_TOUCHED_BEAST;//so check_impacts doesn't do anything with it + } + } + } + } + +finish: + tbeast_check_impacts(self); + + for (i=0 ; isvflags &= ~SVF_TOUCHED_BEAST; + } + +} + +void tbeast_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + tbeast_fake_touch(self); +} + +void tbeast_post_think (edict_t *self) +{ + trace_t trace; + vec3_t end, mins, maxs; + float omins2; + qboolean go_jump = false; + + if(self->monsterinfo.awake) + { + if(self->volume < (float)(self->max_health)) + { + M_ShowLifeMeter(self, (int)(ceil(self->volume/self->max_health*TBEAST_SBAR_SIZE)), (int)(ceil(self->volume/self->max_health*TBEAST_SBAR_SIZE))); + self->volume += (float)(self->max_health) / 10; + } + else if(self->health > 0) + { + M_ShowLifeMeter(self, (int)(ceil((float)(self->health)/(float)(self->max_health)*TBEAST_SBAR_SIZE)), TBEAST_SBAR_SIZE); + } + } + + if(self->s.origin[0] != self->s.old_origin[0] || self->s.origin[1] != self->s.old_origin[1]) + LevelToGround(self, 0.5, 0.25, true); + + if(Q_fabs(self->s.angles[PITCH])>45 || Q_fabs(self->s.angles[ROLL])>45) + go_jump = true; + else + { + //raise him up if on flat ground, lower is on slope - to keep feet on ground! + //FIXME - use checkbottom plane instead? + + if(self->s.origin[0] != self->s.old_origin[0] || self->s.origin[1] != self->s.old_origin[1]) + { + omins2 = self->mins[2]; + self->mins[2] = ((Q_fabs(self->s.angles[PITCH]) + Q_fabs(self->s.angles[ROLL]))*0.5)/45 * 144 - 6 + TB_UP_OFFSET; + omins2 -= self->mins[2]; + if(omins2) + { + VectorCopy(self->s.origin, end); + end[2] += omins2; + gi.trace(self->s.origin, self->mins, self->maxs, end, self, MASK_SOLID,&trace); + VectorCopy(trace.endpos, self->s.origin); + } + gi.linkentity(self); + } + } + + VectorCopy(self->s.origin, self->s.old_origin); +// if(!TB_CheckBottom(self)) +// { +// gi.dprintf("Beast not on ground jump!\n"); +// SetAnim(self, ANIM_JUMP); +// } + + if(!irand(0, 10)) + { + if(self->curAnimID == ANIM_WALK || + self->curAnimID == ANIM_WALKLEFT || + self->curAnimID == ANIM_WALKRT || + self->curAnimID == ANIM_WALKATK) + { + VectorCopy(self->s.origin, end); + end[2] -= 64; + + VectorSet(mins, -8, -8, 0); + VectorSet(maxs, 8, 8, 2); + + gi.trace(self->s.origin, mins, maxs, end, self, MASK_SOLID,&trace); + if(trace.fraction == 1.0 && !trace.startsolid && !trace.allsolid) + go_jump = true; + } + } + + if(go_jump) + { +// gi.dprintf("Beast not on ground jump!\n"); + TB_CheckJump (self); + //SetAnim(self, ANIM_JUMP); + } + + tbeast_fake_touch(self); + + self->next_post_think = level.time + 0.1; +} + +edict_t *check_hit_beast(vec3_t start, vec3_t end) +{ + edict_t *found = NULL; + int i = 0; + vec3_t shot_dir, beast_dir, checkpos, diffvec; + float diff1, diff2; + + VectorSubtract(end, start, shot_dir); + diff1 = VectorNormalize(shot_dir); + + while(found = G_Find(found, FOFS(classname), "monster_trial_beast")) + { + VectorSubtract(found->s.origin, start, beast_dir); + diff2 = VectorLength(beast_dir) - 128; + + if(diff2 > diff1) + continue; + + //beast closer than trace endpos, let's do an incremental check + + VectorCopy(start, checkpos); + + for(i = 16; i < diff1; i+=16) + { + VectorMA(checkpos, 16, shot_dir, checkpos); + VectorSubtract(checkpos, found->s.origin, diffvec); + if(VectorLengthSquared(diffvec) < 16384)//128 squared + {//this spot is within 128 of beast origin, so you hit him, ok? + VectorCopy(checkpos, end); + return found; + } + } + } + + return NULL; +} + +void tbeast_go_charge (edict_t *self, edict_t *other, edict_t *activator) +{ + self->enemy = activator;//are we certain activator is client? + //do a FoundTarget(self, false);? + self->dmg = true; + SetAnim(self, ANIM_CHARGE); + self->use = tbeast_go_die; +} + +void TBeastStaticsInit() +{ + classStatics[CID_TBEAST].msgReceivers[MSG_STAND] = tbeast_stand; + classStatics[CID_TBEAST].msgReceivers[MSG_WALK] = tbeast_walk; + classStatics[CID_TBEAST].msgReceivers[MSG_RUN] = tbeast_run; + classStatics[CID_TBEAST].msgReceivers[MSG_EAT] = tbeast_eat; + classStatics[CID_TBEAST].msgReceivers[MSG_MELEE] = tbeast_melee; + classStatics[CID_TBEAST].msgReceivers[MSG_MISSILE] = tbeast_start_charge; + classStatics[CID_TBEAST].msgReceivers[MSG_WATCH] = tbeast_walk; + classStatics[CID_TBEAST].msgReceivers[MSG_PAIN] = tbeast_pain; + classStatics[CID_TBEAST].msgReceivers[MSG_DEATH] = tbeast_death; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/beast/tris.fm"); + + sounds[SND_ROAR] = gi.soundindex ("monsters/tbeast/roar.wav"); + sounds[SND_ROAR2] = gi.soundindex ("monsters/tbeast/roar2.wav"); + sounds[SND_SNORT1] = gi.soundindex ("monsters/tbeast/snort1.wav"); + sounds[SND_SNORT2] = gi.soundindex ("monsters/tbeast/snort2.wav"); + + sounds[SND_STEP1] = gi.soundindex ("monsters/tbeast/step1.wav"); + sounds[SND_STEP2] = gi.soundindex ("monsters/tbeast/step2.wav"); + sounds[SND_LAND] = gi.soundindex ("monsters/tbeast/land.wav"); + + sounds[SND_GROWL1] = gi.soundindex ("monsters/tbeast/growl1.wav"); + sounds[SND_GROWL2] = gi.soundindex ("monsters/tbeast/growl2.wav"); + sounds[SND_GROWL3] = gi.soundindex ("monsters/tbeast/growl3.wav"); + +// sounds[SND_SWIPE]= gi.soundindex ("monsters/tbeast/swipe.wav"); + sounds[SND_SLAM]= gi.soundindex ("monsters/tbeast/slam.wav"); + sounds[SND_SNATCH]= gi.soundindex ("monsters/tbeast/snatch.wav"); + sounds[SND_CHOMP]= gi.soundindex ("monsters/tbeast/chomp.wav"); + sounds[SND_TEAR1]= gi.soundindex ("monsters/tbeast/tear1.wav"); + sounds[SND_TEAR2]= gi.soundindex ("monsters/tbeast/tear2.wav"); + sounds[SND_THROW]= gi.soundindex ("monsters/tbeast/throw.wav"); + sounds[SND_CATCH]= gi.soundindex ("monsters/tbeast/catch.wav"); +// sounds[SND_SWALLOW]= gi.soundindex ("monsters/tbeast/swallow.wav"); + + sounds[SND_PAIN1]= gi.soundindex ("monsters/tbeast/pain1.wav"); + sounds[SND_PAIN2]= gi.soundindex ("monsters/tbeast/pain2.wav"); + sounds[SND_DIE]= gi.soundindex ("monsters/tbeast/die.wav"); + + sounds[SND_CORVUS_SCREAM1] = gi.soundindex ("corvus/bdeath1.wav"); + sounds[SND_CORVUS_SCREAM2] = gi.soundindex ("corvus/bdeath2.wav"); + sounds[SND_CORVUS_SCREAM3] = gi.soundindex ("corvus/bdeath3.wav"); + sounds[SND_CORVUS_DIE] = gi.soundindex ("player/falldeath1.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_TBEAST].resInfo = &resInfo; +} + + +/*QUAKED monster_trial_beast (1 .5 0) (-100 -100 -36) (100 100 150) ? + +The Trial Beastie + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 100 +melee_range = 400 (bite) +missile_range = 1500 (charge) +min_missile_range = 100 +bypass_missile_chance = 77 +jump_chance = 100 +wakeup_distance = 3000 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +void SP_monster_trial_beast (edict_t *self) +{ + // Generic Monster Initialization + if(deathmatch->value) + { + G_FreeEdict(self); + return; + } + + if (!walkmonster_start (self)) // Incomplete initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_TBEAST; + self->monsterinfo.aiflags |= AI_BRUTAL|AI_AGRESSIVE|AI_SHOVE; + self->monsterinfo.otherenemyname = "monster_tcheckrik_male"; + + self->health = TB_HEALTH * (skill->value + 1) / 3; + + self->mass = TB_MASS; + self->yaw_speed = 10; + self->isBlocked = tbeast_blocked; + self->bounced = tbeast_blocked; + + self->movetype=PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + //problem- staff won't work on him! + self->solid=SOLID_TRIGGER;//BBOX; + self->materialtype = MAT_FLESH; + +// VectorSet(self->mins, -116, -116, -4); +// VectorSet(self->maxs, 116, 116, 182); + VectorSet(self->mins, -100, -100, -36); + VectorSet(self->maxs, 100, 100, 150); + + self->viewheight = 104 + TB_UP_OFFSET; + + self->s.modelindex = classStatics[CID_TBEAST].resInfo->modelIndex; + + //Big guy can be stood on top of perhaps? + //self->touch = M_Touch; + + if(!self->wakeup_distance) + self->wakeup_distance = 3000; + + MG_InitMoods(self); + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + + self->dmg = false; + + self->svflags|=(SVF_BOSS|SVF_NO_AUTOTARGET); + +// self->monsterinfo.aiflags &= ~AI_USING_BUOYS; + + if(!irand(0,1)) + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + + self->monsterinfo.aiflags |= AI_NIGHTVISION; + + self->touch = tbeast_touch; + self->post_think = tbeast_post_think; + self->next_post_think = level.time + 0.1; + self->elasticity = ELASTICITY_SLIDE; + self->count = self->sounds = 0; + self->clipmask = CONTENTS_SOLID; + self->solid = SOLID_TRIGGER;//WHY IS HE BEING PUSHED BY BSP entities now???! + self->red_rain_count = 0;//pillar init + self->use = tbeast_go_charge; + self->delay = true; + + self->max_health = self->health; + self->volume = 0; + self->wait = 0; + + level.fighting_beast = true;//sorry, only one beast per level +} diff --git a/Toolkit/Programming/GameCode/game/m_beast.h b/Toolkit/Programming/GameCode/game/m_beast.h new file mode 100644 index 0000000..59eec29 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_beast.h @@ -0,0 +1,166 @@ + +typedef enum AnimID_e +{ + ANIM_BITEUP, + ANIM_BITELOW, + ANIM_BITEUP2, + ANIM_EATING_TWITCH, + ANIM_EATING, + ANIM_EATDOWN, + ANIM_WALK, + ANIM_WALKLEFT, + ANIM_WALKRT, + ANIM_JUMP, + ANIM_FJUMP, + ANIM_INAIR, + ANIM_LAND, + ANIM_GINAIR, + ANIM_GLAND, + ANIM_STAND, + ANIM_DELAY, + ANIM_DIE, + ANIM_DIE_NORM, + ANIM_CHARGE, + ANIM_ROAR, + ANIM_WALKATK, + ANIM_STUN, + ANIM_SNATCH, + ANIM_READY_CATCH, + ANIM_CATCH, + ANIM_BITEUP_SFIN, + ANIM_BITELOW_SFIN, + ANIM_BITEUP2_SFIN, + ANIM_QUICK_CHARGE, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_ROAR, + SND_ROAR2, + SND_SNORT1, + SND_SNORT2, + + SND_STEP1, + SND_STEP2, + SND_LAND, + + SND_GROWL1, + SND_GROWL2, + SND_GROWL3, + + SND_SWIPE, + SND_SLAM, + SND_SNATCH, + SND_CHOMP, + SND_TEAR1, + SND_TEAR2, + SND_THROW, + SND_CATCH, + SND_SWALLOW, + + SND_PAIN1, + SND_PAIN2, + SND_DIE, + + SND_CORVUS_SCREAM1, + SND_CORVUS_SCREAM2, + SND_CORVUS_SCREAM3, + SND_CORVUS_DIE, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t tbeast_move_biteup; +extern animmove_t tbeast_move_bitelow; +extern animmove_t tbeast_move_biteup2; +extern animmove_t tbeast_move_eating_twitch; +extern animmove_t tbeast_move_eating; +extern animmove_t tbeast_move_eatdown; +extern animmove_t tbeast_move_walk; +extern animmove_t tbeast_move_walkleft; +extern animmove_t tbeast_move_walkrt; +extern animmove_t tbeast_move_jump; +extern animmove_t tbeast_move_forced_jump; +extern animmove_t tbeast_move_inair; +extern animmove_t tbeast_move_land; +extern animmove_t tbeast_move_ginair; +extern animmove_t tbeast_move_gland; +extern animmove_t tbeast_move_stand; +extern animmove_t tbeast_move_delay; +extern animmove_t tbeast_move_die; +extern animmove_t tbeast_move_die_norm; +extern animmove_t tbeast_move_charge; +extern animmove_t tbeast_move_roar; +extern animmove_t tbeast_move_walkatk; +extern animmove_t tbeast_move_stun; +extern animmove_t tbeast_move_snatch; +extern animmove_t tbeast_move_ready_catch; +extern animmove_t tbeast_move_catch; +extern animmove_t tbeast_move_biteup_sfin; +extern animmove_t tbeast_move_bitelow_sfin; +extern animmove_t tbeast_move_biteup2_sfin; +extern animmove_t tbeast_move_quick_charge; + + +void tbeast_snort (edict_t *self); +void tbeast_growl (edict_t *self); +qboolean tbeastCheckMood(edict_t *self); +void tbeast_pause (edict_t *self); +void tbeastbite (edict_t *self, float ofsf, float ofsr, float ofsu); +void tbeast_land(edict_t *self); +void tbeast_roar(edict_t *self); +void tbeast_jump (edict_t *self); +void tbeast_apply_jump (edict_t *self); +void tbeast_ready_catch (edict_t *self); +void tbeast_throw_toy(edict_t *self); +void tbeast_toy_ofs(edict_t *self, float ofsf, float ofsr, float ofsu); +void tbeast_check_snatch(edict_t *self, float ofsf, float ofsr, float ofsu); +void tbeast_gore_toy(edict_t *self, float jumpht); +void tbeast_anger_sound (edict_t *self); +void tbeast_leap (edict_t *self, float fwdf, float rghtf, float upf); +void tbeast_eatorder (edict_t *self); +void tbeast_footstep (edict_t *self); +void tbeast_walkorder (edict_t *self); +void tbeast_standorder (edict_t *self); +void tbeast_dead(edict_t *self); +void tbeast_charge (edict_t *self, float force); +void tbeast_done_gore (edict_t *self); +void tbeast_run_think (edict_t *self, float dist); +float MG_ChangeYaw (edict_t *self); +qboolean MG_CheckBottom (edict_t *ent); +void tbeast_check_landed (edict_t *self); +void tbeast_inair (edict_t *self); +void tbeast_gcheck_landed (edict_t *self); +void tbeast_ginair (edict_t *self); +void tbeast_go_snatch (edict_t *self); +void tbeast_check_impacts(edict_t *self); +void tbeast_roar_knockdown(edict_t *self); +void tbeast_roar_short(edict_t *self); +void tbeast_gibs(edict_t *self); +edict_t *check_hit_beast(vec3_t start, vec3_t end); + +enum +{ + FX_TB_PUFF, + FX_TB_SNORT, +}; + +#define TB_HIBITE_F 150 +#define TB_HIBITE_R 0 +#define TB_HIBITE_U 108 + +#define TB_LOBITE_F 150 +#define TB_LOBITE_R 0 +#define TB_LOBITE_U 36 + +#define TB_WLKBITE_F 224 +#define TB_WLKBITE_U 72 + +#define TBEAST_STD_MELEE_RNG 128 +#define TBEAST_STD_MAXHOP_RNG 600 + +#define TB_JUMP_GRAV 0.8 + +#define TB_FWD_OFFSET -64//-32 +#define TB_UP_OFFSET -32 +#define TB_RT_OFFSET -24 diff --git a/Toolkit/Programming/GameCode/game/m_beast_anim.c b/Toolkit/Programming/GameCode/game/m_beast_anim.c new file mode 100644 index 0000000..ba16986 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_beast_anim.c @@ -0,0 +1,740 @@ +//============================================================================== +// +// m_tbeast_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_beast_anim.h" +#include "m_beast.h" + +#include "g_monster.h" + +void ai_charge2 (edict_t *self, float dist); + +/*---------------------------------------------------------------------- + TB bite way up +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_biteup2[] = +{ + FRAME_atkc1, NULL, 0, 0, 0, ai_charge2, 0, tbeast_growl, + FRAME_atkc2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atkc3, tbeast_check_snatch, TB_HIBITE_F - 32, TB_HIBITE_R, TB_HIBITE_U + 128, NULL, 0, NULL, + FRAME_atkc4, tbeastbite, TB_HIBITE_F - 32, TB_HIBITE_R, TB_HIBITE_U + 128, NULL, 0, NULL, + FRAME_atkc5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atkc6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atkc7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atkc8, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_biteup2 = {8, tbeast_frames_biteup2, tbeast_pause}; + +/*---------------------------------------------------------------------- + TB bite up +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_biteup[] = +{ + FRAME_atka1, NULL, 0, 0, 0, ai_charge2, 0, tbeast_growl, + FRAME_atka2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atka3, tbeast_check_snatch, TB_HIBITE_F, TB_HIBITE_R, TB_HIBITE_U, NULL, 0, NULL, + FRAME_atka4, tbeastbite, TB_HIBITE_F, TB_HIBITE_R, TB_HIBITE_U, NULL, 0, NULL, + FRAME_atka5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atka6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atka7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atka8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atka9, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_biteup = {9, tbeast_frames_biteup, tbeast_pause}; + +/*---------------------------------------------------------------------- + TB bite low +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_bitelow[] = +{ + FRAME_atkb1 , NULL, 0, 0, 0, ai_charge2, 0, tbeast_growl, + FRAME_atkb2 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atkb3 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atkb4 , tbeast_check_snatch, TB_LOBITE_F, TB_LOBITE_R, TB_LOBITE_U, NULL, 0, NULL, + FRAME_atkb5 , tbeastbite, TB_LOBITE_F, TB_LOBITE_R, TB_LOBITE_U, NULL, 0, NULL, + FRAME_atkb6 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atkb7 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atkb8 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atkb9 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atkb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_atkb11, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_bitelow = {11, tbeast_frames_bitelow, tbeast_pause}; + +/*---------------------------------------------------------------------- + TB eating twitch? +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_eating_twitch [] = +{ + FRAME_eatingb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb3, NULL, 0, 0, 0, NULL, 0, tbeast_snort, + FRAME_eatingb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb5, NULL, 0, 0, 0, NULL, 0, tbeast_gibs, + FRAME_eatingb6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb8, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_eating_twitch = {8, tbeast_frames_eating_twitch, tbeast_eatorder}; + +/*---------------------------------------------------------------------- + Gorgon Eat3 - pull back, then bend back down to eat +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_eating [] = +{ + FRAME_eatingc1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingc2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingc3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingc4, NULL, 0, 0, 0, NULL, 0, tbeast_gibs, + FRAME_eatingc5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingc6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_eating = {6, tbeast_frames_eating, tbeast_eatorder}; + + +/*---------------------------------------------------------------------- + TB bending down, eating +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_eatdown [] = +{ + FRAME_eatran1 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran2 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran3 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran4 , NULL, 0, 0, 0, NULL, 0, tbeast_snort, + FRAME_eatran5 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran6 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran7 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran8 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran9 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatran12, NULL, 0, 0, 0, NULL, 0, tbeast_gibs, + FRAME_eatran13, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_eatdown = {13, tbeast_frames_eatdown, tbeast_eatorder}; + +/*---------------------------------------------------------------------- + TB Walking +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_walk [] = +{ + FRAME_walk1 , NULL, 0, 0, 0, tbeast_run_think, 32, tbeast_footstep, + FRAME_walk2 , NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_walk3 , NULL, 0, 0, 0, tbeast_run_think, 32, NULL, + FRAME_walk4 , NULL, 0, 0, 0, tbeast_run_think, 24, NULL, + FRAME_walk5 , NULL, 0, 0, 0, tbeast_run_think, 20, NULL, + FRAME_walk6 , NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_walk7 , NULL, 0, 0, 0, tbeast_run_think, 20, tbeast_growl, + FRAME_walk8 , NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_walk9 , NULL, 0, 0, 0, tbeast_run_think, 20, NULL, + FRAME_walk10, NULL, 0, 0, 0, tbeast_run_think, 32, NULL, + FRAME_walk11, NULL, 0, 0, 0, tbeast_run_think, 28, tbeast_footstep, + FRAME_walk12, NULL, 0, 0, 0, tbeast_run_think, 12, NULL, + FRAME_walk13, NULL, 0, 0, 0, tbeast_run_think, 16, tbeast_snort, + FRAME_walk14, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_walk15, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_walk16, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_walk17, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_walk18, NULL, 0, 0, 0, tbeast_run_think, 24, NULL, +}; +animmove_t tbeast_move_walk = {18, tbeast_frames_walk, tbeast_walkorder}; + +/*---------------------------------------------------------------------- + TB Turning left while running +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_walkleft [] = +{ + FRAME_wlklft1 , NULL, 0, 0, 0, tbeast_run_think, 32, tbeast_footstep, + FRAME_wlklft2 , NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlklft3 , NULL, 0, 0, 0, tbeast_run_think, 32, NULL, + FRAME_wlklft4 , NULL, 0, 0, 0, tbeast_run_think, 24, NULL, + FRAME_wlklft5 , NULL, 0, 0, 0, tbeast_run_think, 20, tbeast_snort, + FRAME_wlklft6 , NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlklft7 , NULL, 0, 0, 0, tbeast_run_think, 20, NULL, + FRAME_wlklft8 , NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlklft9 , NULL, 0, 0, 0, tbeast_run_think, 20, NULL, + FRAME_wlklft10, NULL, 0, 0, 0, tbeast_run_think, 32, NULL, + FRAME_wlklft11, NULL, 0, 0, 0, tbeast_run_think, 28, tbeast_footstep, + FRAME_wlklft12, NULL, 0, 0, 0, tbeast_run_think, 12, NULL, + FRAME_wlklft13, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlklft14, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlklft15, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlklft16, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlklft17, NULL, 0, 0, 0, tbeast_run_think, 16, tbeast_growl, + FRAME_wlklft18, NULL, 0, 0, 0, tbeast_run_think, 24, NULL, +}; +animmove_t tbeast_move_walkleft = {18, tbeast_frames_walkleft, tbeast_walkorder}; + +/*---------------------------------------------------------------------- + TB Turning right while running +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_walkrt [] = +{ + FRAME_wlkrt1 , NULL, 0, 0, 0, tbeast_run_think, 32, tbeast_footstep, + FRAME_wlkrt2 , NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlkrt3 , NULL, 0, 0, 0, tbeast_run_think, 32, NULL, + FRAME_wlkrt4 , NULL, 0, 0, 0, tbeast_run_think, 24, NULL, + FRAME_wlkrt5 , NULL, 0, 0, 0, tbeast_run_think, 20, NULL, + FRAME_wlkrt6 , NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlkrt7 , NULL, 0, 0, 0, tbeast_run_think, 20, NULL, + FRAME_wlkrt8 , NULL, 0, 0, 0, tbeast_run_think, 16, tbeast_growl, + FRAME_wlkrt9 , NULL, 0, 0, 0, tbeast_run_think, 20, NULL, + FRAME_wlkrt10, NULL, 0, 0, 0, tbeast_run_think, 32, NULL, + FRAME_wlkrt11, NULL, 0, 0, 0, tbeast_run_think, 28, tbeast_footstep, + FRAME_wlkrt12, NULL, 0, 0, 0, tbeast_run_think, 12, NULL, + FRAME_wlkrt13, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlkrt14, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlkrt15, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlkrt16, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlkrt17, NULL, 0, 0, 0, tbeast_run_think, 16, NULL, + FRAME_wlkrt18, NULL, 0, 0, 0, tbeast_run_think, 24, tbeast_snort, +}; +animmove_t tbeast_move_walkrt = {18, tbeast_frames_walkrt, tbeast_walkorder}; + +animframe_t tbeast_frames_inair [] = +{ + FRAME_jumpb16, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, +}; +animmove_t tbeast_move_inair = {1, tbeast_frames_inair, NULL}; + +animframe_t tbeast_frames_land [] = +{ + FRAME_jumpb17, NULL, 0, 0, 0, NULL, 0, tbeast_land, + FRAME_jumpb18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb19, NULL, 0, 0, 0, NULL, 0, tbeast_snort, + FRAME_jumpb20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb23, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_land = {7, tbeast_frames_land, tbeast_pause}; +/*---------------------------------------------------------------------- + TB jump +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_jump [] = +{ + FRAME_jumpb1 , NULL, 0, 0, 0, NULL, 0, tbeast_growl, + FRAME_jumpb2 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb3 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb4 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb5 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb6 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb7 , tbeast_leap, 250, 0, 400, NULL, 0, NULL, + FRAME_jumpb8 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb9 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb11, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, + FRAME_jumpb12, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, + FRAME_jumpb13, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, + FRAME_jumpb14, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, + FRAME_jumpb15, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, +}; +animmove_t tbeast_move_jump = {15, tbeast_frames_jump, tbeast_inair}; + +/*---------------------------------------------------------------------- + TB jump +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_forced_jump [] = +{ + FRAME_jumpb1 , NULL, 0, 0, 0, NULL, 0, tbeast_growl, + FRAME_jumpb2 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb3 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb4 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb5 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb6 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb7 , NULL, 0, 0, 0, NULL, 0, tbeast_apply_jump, + FRAME_jumpb8 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb9 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb11, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, + FRAME_jumpb12, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, + FRAME_jumpb13, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, + FRAME_jumpb14, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, + FRAME_jumpb15, NULL, 0, 0, 0, NULL, 0, tbeast_check_landed, +}; +animmove_t tbeast_move_forced_jump = {15, tbeast_frames_forced_jump, tbeast_inair}; + +/*---------------------------------------------------------------------- + TB wait +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_stand [] = +{ + FRAME_wait1 , NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait2 , NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait3 , NULL, 0, 0, 0, ai_stand, 0, tbeast_snort, + FRAME_wait4 , NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait5 , NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait6 , NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait7 , NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait8 , NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait9 , NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait12, NULL, 0, 0, 0, ai_stand, 0, tbeast_snort, + FRAME_wait13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait14, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t tbeast_move_stand = {14, tbeast_frames_stand, tbeast_standorder}; + + +/*---------------------------------------------------------------------- + delay +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_delay [] = +{ + FRAME_wait1, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait2, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait3, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait4, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait5, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait6, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait7, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait8, NULL, 0, 0, 0, NULL, 0, tbeast_snort, + FRAME_wait9, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait10, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait11, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait12, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait13, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, + FRAME_wait14, NULL, 0, 0, 0, NULL, 0, tbeastCheckMood, +}; +animmove_t tbeast_move_delay = {14, tbeast_frames_delay, tbeast_pause}; + +animframe_t tbeast_frames_die [] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death20, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_die = {20, tbeast_frames_die, tbeast_dead}; + +animframe_t tbeast_frames_die_norm [] = +{ + FRAME_deatha1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha31, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_die_norm = {31, tbeast_frames_die_norm, tbeast_dead}; + +animframe_t tbeast_frames_charge [] = +{ + FRAME_roar1, NULL, 0, 0, 0, NULL, 0, tbeast_roar_short, + FRAME_roar3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar33, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar35, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar37, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar39, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar41, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar43, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar45, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar47, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar49, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_footstep, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 32, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 24, tbeast_growl, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 32, NULL, + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 28, tbeast_footstep, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 12, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 16, tbeast_growl, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 24, NULL,//18 + 0 = 17 + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_footstep,//1 + 17 = 18 + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 32, NULL, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 24, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 20, tbeast_growl, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_growl, + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 28, tbeast_footstep, + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 12, NULL, + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 16, tbeast_snort, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 24, NULL,//18 + 17 = 35 + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_footstep,//1 + 35 = 36 + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 32, NULL, + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 24, NULL, + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_growl, + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 28, tbeast_footstep, + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 12, NULL, + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 24, tbeast_walkorder,//18 + 35 = 53 +}; +animmove_t tbeast_move_charge = {75, tbeast_frames_charge, tbeast_walkorder}; + +animframe_t tbeast_frames_roar [] = +{ + FRAME_roar1, NULL, 0, 0, 0, NULL, 0, tbeast_roar, + FRAME_roar2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar10, NULL, 0, 0, 0, NULL, 0, tbeast_roar_knockdown, + FRAME_roar11, NULL, 0, 0, 0, NULL, 0, tbeast_roar_knockdown, + FRAME_roar12, NULL, 0, 0, 0, NULL, 0, tbeast_roar_knockdown, + FRAME_roar13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar14, NULL, 0, 0, 0, NULL, 0, tbeast_roar_knockdown, + FRAME_roar15, NULL, 0, 0, 0, NULL, 0, tbeast_roar_knockdown, + FRAME_roar16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar17, NULL, 0, 0, 0, NULL, 0, tbeast_roar_knockdown, + FRAME_roar18, NULL, 0, 0, 0, NULL, 0, tbeast_roar_knockdown, + FRAME_roar19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar20, NULL, 0, 0, 0, NULL, 0, tbeast_roar_knockdown, + FRAME_roar21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar23, NULL, 0, 0, 0, NULL, 0, tbeast_roar_knockdown, + FRAME_roar24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar32, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar33, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar34, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar35, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar36, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar37, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar38, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar39, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar40, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar41, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar42, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar43, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar44, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar45, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar46, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar47, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar48, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar49, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar50, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_roar = {50, tbeast_frames_roar, tbeast_pause}; + +animframe_t tbeast_frames_walkatk [] = +{ + FRAME_wlkatk1 , NULL, 0, 0, 0, tbeast_run_think, 36, tbeast_footstep, + FRAME_wlkatk2 , NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk3 , NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk4 , tbeastbite, TB_WLKBITE_F, -4, TB_WLKBITE_U, tbeast_run_think, 36, NULL, + FRAME_wlkatk5 , NULL, 0, 0, 0, tbeast_run_think, 36, tbeast_growl, + FRAME_wlkatk6 , NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk7 , NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk8 , NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk9 , NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk10, NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk11, NULL, 0, 0, 0, tbeast_run_think, 36, tbeast_footstep,//bite + FRAME_wlkatk12, NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk13, NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk14, tbeastbite, TB_WLKBITE_F, 16, TB_WLKBITE_U, tbeast_run_think, 36, NULL, + FRAME_wlkatk15, NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk16, NULL, 0, 0, 0, tbeast_run_think, 36, NULL, + FRAME_wlkatk17, NULL, 0, 0, 0, tbeast_run_think, 36, tbeast_growl, + FRAME_wlkatk18, NULL, 0, 0, 0, tbeast_run_think, 36, NULL, +}; +animmove_t tbeast_move_walkatk = {18, tbeast_frames_walkatk, tbeast_pause}; + +animframe_t tbeast_frames_stun [] = +{//FIXME: don't walk back so long + FRAME_walk18, NULL, 0, 0, 0, ai_move, -40, NULL, + FRAME_walk16, NULL, 0, 0, 0, ai_move, -32, NULL, + FRAME_walk14, NULL, 0, 0, 0, ai_move, -32, tbeast_snort, + FRAME_walk12, NULL, 0, 0, 0, ai_move, -12, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_move, -28, tbeast_footstep, + FRAME_walk10, NULL, 0, 0, 0, ai_move, -52, NULL, + FRAME_walk8 , NULL, 0, 0, 0, ai_move, -36, NULL, + FRAME_walk6 , NULL, 0, 0, 0, ai_move, -36, NULL, + FRAME_walk4 , NULL, 0, 0, 0, ai_move, -24, tbeast_snort, + FRAME_stun1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun3, NULL, 0, 0, 0, NULL, 0, tbeast_footstep, + FRAME_stun4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_stun19, NULL, 0, 0, 0, NULL, 0, tbeast_snort, +}; +animmove_t tbeast_move_stun = {28, tbeast_frames_stun, tbeast_pause}; + +//======================================================================== + +/*---------------------------------------------------------------------- + TB bite way up success finish +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_biteup2_sfin[] = +{ + FRAME_atkc4, tbeast_toy_ofs, 200, 0, 132, NULL, 0, tbeast_anger_sound, + FRAME_atkc5, tbeast_toy_ofs, 176, -4, 96, NULL, 0, NULL, + FRAME_atkc6, tbeast_toy_ofs, 160, -12, 80, NULL, 0, NULL, + FRAME_atkc7, tbeast_toy_ofs, 152, -4, 72, NULL, 0, NULL, +}; +animmove_t tbeast_move_biteup2_sfin = {4, tbeast_frames_biteup2_sfin, tbeast_go_snatch}; + +/*---------------------------------------------------------------------- + TB bite up success finish +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_biteup_sfin[] = +{ + FRAME_atka4, tbeast_toy_ofs, 200, 0, 132, NULL, 0, tbeast_anger_sound, + FRAME_atka5, tbeast_toy_ofs, 176, -4, 96, NULL, 0, NULL, + FRAME_atka6, tbeast_toy_ofs, 160, -12, 80, NULL, 0, NULL, + FRAME_atka7, tbeast_toy_ofs, 152, -4, 72, NULL, 0, NULL, +}; +animmove_t tbeast_move_biteup_sfin = {4, tbeast_frames_biteup_sfin, tbeast_go_snatch}; + +/*---------------------------------------------------------------------- + TB bite low success finish +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_bitelow_sfin[] = +{ + FRAME_atkb5 , tbeast_toy_ofs, 216, 0, 64, NULL, 0, NULL, + FRAME_atkb6 , tbeast_toy_ofs, 208, 0, 62, NULL, 0, tbeast_anger_sound, + FRAME_atkb7 , tbeast_toy_ofs, 196, 0, 56, NULL, 0, NULL, + FRAME_atkb8 , tbeast_toy_ofs, 184, 0, 54, NULL, 0, NULL, + FRAME_atkb9 , tbeast_toy_ofs, 176, 2, 60, NULL, 0, tbeast_anger_sound, + FRAME_atkb10, tbeast_toy_ofs, 178, 10, 64, NULL, 0, NULL, +}; +animmove_t tbeast_move_bitelow_sfin = {6, tbeast_frames_bitelow_sfin, tbeast_go_snatch}; + +/*---------------------------------------------------------------------- + TB snatch throw & catch +-----------------------------------------------------------------------*/ +animframe_t tbeast_frames_snatch [] = +{ +/* FRAME_eatinga1, tbeast_toy_ofs, 112, 32, -8, NULL, 0, NULL, + FRAME_eatinga2, tbeast_toy_ofs, 112, 18, 8, NULL, 0, NULL, + FRAME_eatinga3, tbeast_toy_ofs, 98, 0, 32, NULL, 0, tbeast_anger_sound, + FRAME_eatinga4, tbeast_toy_ofs, 128, 2, 36, NULL, 0, NULL, + FRAME_eatinga5, tbeast_toy_ofs, 152, 12, 64, NULL, 0, tbeast_anger_sound,*/ + FRAME_eatinga6, tbeast_toy_ofs, 164, -16, 94, NULL, 0, NULL, + FRAME_eatinga7, tbeast_toy_ofs, 152, -68, 60, NULL, 0, NULL, + FRAME_eatinga8, tbeast_toy_ofs, 112, -88, 56, NULL, 0, tbeast_anger_sound, + FRAME_eatinga9, tbeast_toy_ofs, 104, -80, 64, NULL, 0, NULL, + FRAME_eatinga10, tbeast_toy_ofs, 128, -64, 80, NULL, 0, NULL, + FRAME_eatinga11, tbeast_toy_ofs, 160, -16, 84, NULL, 0, NULL, + FRAME_eatinga12, tbeast_toy_ofs, 152, 104, 112, NULL, 0, tbeast_anger_sound, + FRAME_eatinga13, tbeast_toy_ofs, 128, 116, 128, NULL, 0, NULL, + FRAME_eatinga14, tbeast_toy_ofs, 136, 124, 132, NULL, 0, NULL, + FRAME_eatinga15, tbeast_toy_ofs, 160, 48, 124, NULL, 0, NULL, + FRAME_eatinga16, tbeast_toy_ofs, 168, -56, 98, NULL, 0, tbeast_anger_sound, + FRAME_eatinga17, tbeast_toy_ofs, 136, -100, 56, NULL, 0, NULL, + FRAME_eatinga18, tbeast_toy_ofs, 104, -96, 52, NULL, 0, NULL, + FRAME_eatinga19, tbeast_toy_ofs, 88, -92, 49, NULL, 0, NULL, + FRAME_eatinga20, tbeast_toy_ofs, 96, -88, 64, NULL, 0, tbeast_anger_sound, + FRAME_eatinga21, tbeast_toy_ofs, 126, -80, 64, NULL, 0, NULL, + FRAME_eatinga22, tbeast_toy_ofs, 142, -56, 53, NULL, 0, NULL, + FRAME_eatinga23, tbeast_toy_ofs, 146, -18, 34, NULL, 0, tbeast_anger_sound, + FRAME_eatinga24, tbeast_toy_ofs, 136, 24, 16, NULL, 0, NULL, + FRAME_eatinga25, tbeast_toy_ofs, 120, 48, -8, NULL, 0, NULL, + FRAME_jumpb21 , tbeast_toy_ofs, 96, -32, 8, NULL, 0, tbeast_anger_sound, + FRAME_jumpb20 , tbeast_toy_ofs, 128, -34, 12, NULL, 0, tbeast_anger_sound, + FRAME_jumpb19 , tbeast_toy_ofs, 164, 0, 128, NULL, 0, tbeast_anger_sound, + FRAME_jumpb18 , tbeast_toy_ofs, 148, 0, 216, NULL, 0, tbeast_throw_toy, + FRAME_jumpb19 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb1 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb2 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb3 , NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_snatch = {29, tbeast_frames_snatch, tbeast_ready_catch}; + +animframe_t tbeast_frames_ready_catch [] = +{ + FRAME_jumpb4 , NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_ready_catch = {1, tbeast_frames_ready_catch, tbeast_ready_catch}; + +animframe_t tbeast_frames_catch [] = +{ + FRAME_jumpb5 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb6 , NULL, 0, 0, 0, tbeast_gore_toy, 150, NULL, + FRAME_jumpb7 , NULL, 0, 0, 0, tbeast_gore_toy, 0, NULL, + FRAME_jumpb8 , NULL, 0, 0, 0, tbeast_gore_toy, 0, NULL, + FRAME_jumpb9 , NULL, 0, 0, 0, tbeast_gore_toy, 0, NULL, + FRAME_jumpb10, NULL, 0, 0, 0, tbeast_gore_toy, 0, NULL, + FRAME_jumpb11, NULL, 0, 0, 0, tbeast_gore_toy, -1, NULL, + FRAME_jumpb12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb15, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t tbeast_move_catch = {10, tbeast_frames_catch, tbeast_ginair}; + +animframe_t tbeast_frames_ginair [] = +{ + FRAME_jumpb16, NULL, 0, 0, 0, NULL, 0, tbeast_gcheck_landed, +}; +animmove_t tbeast_move_ginair = {1, tbeast_frames_ginair, NULL}; + +animframe_t tbeast_frames_gland [] = +{ + FRAME_jumpb17, NULL, 0, 0, 0, NULL, 0, tbeast_land, + FRAME_jumpb18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb19, NULL, 0, 0, 0, NULL, 0, tbeast_snort, + FRAME_jumpb20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb23, NULL, 0, 0, 0, NULL, 0, tbeast_done_gore, +}; +animmove_t tbeast_move_gland = {7, tbeast_frames_gland, tbeast_done_gore}; + +animframe_t tbeast_frames_quick_charge [] = +{ + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_footstep, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 32, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 24, tbeast_growl, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 32, NULL, + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 28, tbeast_footstep, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 12, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 16, tbeast_growl, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 24, NULL,//18 + 0 = 17 + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_footstep,//1 + 17 = 18 + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 32, NULL, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 24, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 20, tbeast_growl, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_growl, + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 28, tbeast_footstep, + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 12, NULL, + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 16, tbeast_snort, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 24, NULL,//18 + 17 = 35 + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_footstep,//1 + 35 = 36 + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 32, NULL, + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 24, NULL, + FRAME_charge1 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge2 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge3 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge4 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge5 , NULL, 0, 0, 0, tbeast_charge, 20, NULL, + FRAME_charge6 , NULL, 0, 0, 0, tbeast_charge, 32, tbeast_growl, + FRAME_charge7 , NULL, 0, 0, 0, tbeast_charge, 28, tbeast_footstep, + FRAME_charge8 , NULL, 0, 0, 0, tbeast_charge, 12, NULL, + FRAME_charge9 , NULL, 0, 0, 0, tbeast_charge, 16, NULL, + FRAME_charge10, NULL, 0, 0, 0, tbeast_charge, 24, tbeast_walkorder,//18 + 35 = 53 +}; +animmove_t tbeast_move_quick_charge = {50, tbeast_frames_quick_charge, tbeast_walkorder}; diff --git a/Toolkit/Programming/GameCode/game/m_beast_anim.h b/Toolkit/Programming/GameCode/game/m_beast_anim.h new file mode 100644 index 0000000..1d5e0e1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_beast_anim.h @@ -0,0 +1,329 @@ +// R:\Art\models/monsters\beast + +// This file generated by qdata - Do NOT Modify + +#define FRAME_atka1 0 +#define FRAME_atka2 1 +#define FRAME_atka3 2 +#define FRAME_atka4 3 +#define FRAME_atka5 4 +#define FRAME_atka6 5 +#define FRAME_atka7 6 +#define FRAME_atka8 7 +#define FRAME_atka9 8 +#define FRAME_atkb1 9 +#define FRAME_atkb2 10 +#define FRAME_atkb3 11 +#define FRAME_atkb4 12 +#define FRAME_atkb5 13 +#define FRAME_atkb6 14 +#define FRAME_atkb7 15 +#define FRAME_atkb8 16 +#define FRAME_atkb9 17 +#define FRAME_atkb10 18 +#define FRAME_atkb11 19 +#define FRAME_atkc1 20 +#define FRAME_atkc2 21 +#define FRAME_atkc3 22 +#define FRAME_atkc4 23 +#define FRAME_atkc5 24 +#define FRAME_atkc6 25 +#define FRAME_atkc7 26 +#define FRAME_atkc8 27 +#define FRAME_charge1 28 +#define FRAME_charge2 29 +#define FRAME_charge3 30 +#define FRAME_charge4 31 +#define FRAME_charge5 32 +#define FRAME_charge6 33 +#define FRAME_charge7 34 +#define FRAME_charge8 35 +#define FRAME_charge9 36 +#define FRAME_charge10 37 +#define FRAME_deatha1 38 +#define FRAME_deatha10 39 +#define FRAME_deatha11 40 +#define FRAME_deatha12 41 +#define FRAME_deatha13 42 +#define FRAME_deatha14 43 +#define FRAME_deatha15 44 +#define FRAME_deatha16 45 +#define FRAME_deatha17 46 +#define FRAME_deatha18 47 +#define FRAME_deatha19 48 +#define FRAME_deatha2 49 +#define FRAME_deatha20 50 +#define FRAME_deatha21 51 +#define FRAME_deatha22 52 +#define FRAME_deatha23 53 +#define FRAME_deatha24 54 +#define FRAME_deatha25 55 +#define FRAME_deatha26 56 +#define FRAME_deatha27 57 +#define FRAME_deatha28 58 +#define FRAME_deatha29 59 +#define FRAME_deatha3 60 +#define FRAME_deatha30 61 +#define FRAME_deatha31 62 +#define FRAME_deatha4 63 +#define FRAME_deatha5 64 +#define FRAME_deatha6 65 +#define FRAME_deatha7 66 +#define FRAME_deatha8 67 +#define FRAME_deatha9 68 +#define FRAME_death1 69 +#define FRAME_death2 70 +#define FRAME_death3 71 +#define FRAME_death4 72 +#define FRAME_death5 73 +#define FRAME_death6 74 +#define FRAME_death7 75 +#define FRAME_death8 76 +#define FRAME_death9 77 +#define FRAME_death10 78 +#define FRAME_death11 79 +#define FRAME_death12 80 +#define FRAME_death13 81 +#define FRAME_death14 82 +#define FRAME_death15 83 +#define FRAME_death16 84 +#define FRAME_death17 85 +#define FRAME_death18 86 +#define FRAME_death19 87 +#define FRAME_death20 88 +#define FRAME_eatinga1 89 +#define FRAME_eatinga2 90 +#define FRAME_eatinga3 91 +#define FRAME_eatinga4 92 +#define FRAME_eatinga5 93 +#define FRAME_eatinga6 94 +#define FRAME_eatinga7 95 +#define FRAME_eatinga8 96 +#define FRAME_eatinga9 97 +#define FRAME_eatinga10 98 +#define FRAME_eatinga11 99 +#define FRAME_eatinga12 100 +#define FRAME_eatinga13 101 +#define FRAME_eatinga14 102 +#define FRAME_eatinga15 103 +#define FRAME_eatinga16 104 +#define FRAME_eatinga17 105 +#define FRAME_eatinga18 106 +#define FRAME_eatinga19 107 +#define FRAME_eatinga20 108 +#define FRAME_eatinga21 109 +#define FRAME_eatinga22 110 +#define FRAME_eatinga23 111 +#define FRAME_eatinga24 112 +#define FRAME_eatinga25 113 +#define FRAME_eatingb1 114 +#define FRAME_eatingb2 115 +#define FRAME_eatingb3 116 +#define FRAME_eatingb4 117 +#define FRAME_eatingb5 118 +#define FRAME_eatingb6 119 +#define FRAME_eatingb7 120 +#define FRAME_eatingb8 121 +#define FRAME_eatingc1 122 +#define FRAME_eatingc2 123 +#define FRAME_eatingc3 124 +#define FRAME_eatingc4 125 +#define FRAME_eatingc5 126 +#define FRAME_eatingc6 127 +#define FRAME_eatran1 128 +#define FRAME_eatran2 129 +#define FRAME_eatran3 130 +#define FRAME_eatran4 131 +#define FRAME_eatran5 132 +#define FRAME_eatran6 133 +#define FRAME_eatran7 134 +#define FRAME_eatran8 135 +#define FRAME_eatran9 136 +#define FRAME_eatran10 137 +#define FRAME_eatran11 138 +#define FRAME_eatran12 139 +#define FRAME_eatran13 140 +#define FRAME_jumpb1 141 +#define FRAME_jumpb2 142 +#define FRAME_jumpb3 143 +#define FRAME_jumpb4 144 +#define FRAME_jumpb5 145 +#define FRAME_jumpb6 146 +#define FRAME_jumpb7 147 +#define FRAME_jumpb8 148 +#define FRAME_jumpb9 149 +#define FRAME_jumpb10 150 +#define FRAME_jumpb11 151 +#define FRAME_jumpb12 152 +#define FRAME_jumpb13 153 +#define FRAME_jumpb14 154 +#define FRAME_jumpb15 155 +#define FRAME_jumpb16 156 +#define FRAME_jumpb17 157 +#define FRAME_jumpb18 158 +#define FRAME_jumpb19 159 +#define FRAME_jumpb20 160 +#define FRAME_jumpb21 161 +#define FRAME_jumpb22 162 +#define FRAME_jumpb23 163 +#define FRAME_roar1 164 +#define FRAME_roar2 165 +#define FRAME_roar3 166 +#define FRAME_roar4 167 +#define FRAME_roar5 168 +#define FRAME_roar6 169 +#define FRAME_roar7 170 +#define FRAME_roar8 171 +#define FRAME_roar9 172 +#define FRAME_roar10 173 +#define FRAME_roar11 174 +#define FRAME_roar12 175 +#define FRAME_roar13 176 +#define FRAME_roar14 177 +#define FRAME_roar15 178 +#define FRAME_roar16 179 +#define FRAME_roar17 180 +#define FRAME_roar18 181 +#define FRAME_roar19 182 +#define FRAME_roar20 183 +#define FRAME_roar21 184 +#define FRAME_roar22 185 +#define FRAME_roar23 186 +#define FRAME_roar24 187 +#define FRAME_roar25 188 +#define FRAME_roar26 189 +#define FRAME_roar27 190 +#define FRAME_roar28 191 +#define FRAME_roar29 192 +#define FRAME_roar30 193 +#define FRAME_roar31 194 +#define FRAME_roar32 195 +#define FRAME_roar33 196 +#define FRAME_roar34 197 +#define FRAME_roar35 198 +#define FRAME_roar36 199 +#define FRAME_roar37 200 +#define FRAME_roar38 201 +#define FRAME_roar39 202 +#define FRAME_roar40 203 +#define FRAME_roar41 204 +#define FRAME_roar42 205 +#define FRAME_roar43 206 +#define FRAME_roar44 207 +#define FRAME_roar45 208 +#define FRAME_roar46 209 +#define FRAME_roar47 210 +#define FRAME_roar48 211 +#define FRAME_roar49 212 +#define FRAME_roar50 213 +#define FRAME_stun1 214 +#define FRAME_stun2 215 +#define FRAME_stun3 216 +#define FRAME_stun4 217 +#define FRAME_stun5 218 +#define FRAME_stun6 219 +#define FRAME_stun7 220 +#define FRAME_stun8 221 +#define FRAME_stun9 222 +#define FRAME_stun10 223 +#define FRAME_stun11 224 +#define FRAME_stun12 225 +#define FRAME_stun13 226 +#define FRAME_stun14 227 +#define FRAME_stun15 228 +#define FRAME_stun16 229 +#define FRAME_stun17 230 +#define FRAME_stun18 231 +#define FRAME_stun19 232 +#define FRAME_wait1 233 +#define FRAME_wait2 234 +#define FRAME_wait3 235 +#define FRAME_wait4 236 +#define FRAME_wait5 237 +#define FRAME_wait6 238 +#define FRAME_wait7 239 +#define FRAME_wait8 240 +#define FRAME_wait9 241 +#define FRAME_wait10 242 +#define FRAME_wait11 243 +#define FRAME_wait12 244 +#define FRAME_wait13 245 +#define FRAME_wait14 246 +#define FRAME_walk1 247 +#define FRAME_walk2 248 +#define FRAME_walk3 249 +#define FRAME_walk4 250 +#define FRAME_walk5 251 +#define FRAME_walk6 252 +#define FRAME_walk7 253 +#define FRAME_walk8 254 +#define FRAME_walk9 255 +#define FRAME_walk10 256 +#define FRAME_walk11 257 +#define FRAME_walk12 258 +#define FRAME_walk13 259 +#define FRAME_walk14 260 +#define FRAME_walk15 261 +#define FRAME_walk16 262 +#define FRAME_walk17 263 +#define FRAME_walk18 264 +#define FRAME_wlkatk1 265 +#define FRAME_wlkatk2 266 +#define FRAME_wlkatk3 267 +#define FRAME_wlkatk4 268 +#define FRAME_wlkatk5 269 +#define FRAME_wlkatk6 270 +#define FRAME_wlkatk7 271 +#define FRAME_wlkatk8 272 +#define FRAME_wlkatk9 273 +#define FRAME_wlkatk10 274 +#define FRAME_wlkatk11 275 +#define FRAME_wlkatk12 276 +#define FRAME_wlkatk13 277 +#define FRAME_wlkatk14 278 +#define FRAME_wlkatk15 279 +#define FRAME_wlkatk16 280 +#define FRAME_wlkatk17 281 +#define FRAME_wlkatk18 282 +#define FRAME_wlklft1 283 +#define FRAME_wlklft2 284 +#define FRAME_wlklft3 285 +#define FRAME_wlklft4 286 +#define FRAME_wlklft5 287 +#define FRAME_wlklft6 288 +#define FRAME_wlklft7 289 +#define FRAME_wlklft8 290 +#define FRAME_wlklft9 291 +#define FRAME_wlklft10 292 +#define FRAME_wlklft11 293 +#define FRAME_wlklft12 294 +#define FRAME_wlklft13 295 +#define FRAME_wlklft14 296 +#define FRAME_wlklft15 297 +#define FRAME_wlklft16 298 +#define FRAME_wlklft17 299 +#define FRAME_wlklft18 300 +#define FRAME_wlkrt1 301 +#define FRAME_wlkrt2 302 +#define FRAME_wlkrt3 303 +#define FRAME_wlkrt4 304 +#define FRAME_wlkrt5 305 +#define FRAME_wlkrt6 306 +#define FRAME_wlkrt7 307 +#define FRAME_wlkrt8 308 +#define FRAME_wlkrt9 309 +#define FRAME_wlkrt10 310 +#define FRAME_wlkrt11 311 +#define FRAME_wlkrt12 312 +#define FRAME_wlkrt13 313 +#define FRAME_wlkrt14 314 +#define FRAME_wlkrt15 315 +#define FRAME_wlkrt16 316 +#define FRAME_wlkrt17 317 +#define FRAME_wlkrt18 318 + +#define MODEL_SCALE 5.000000 + +#define NUM_MESH_NODES 1 + +#define MESH_NULL23 0 diff --git a/Toolkit/Programming/GameCode/game/m_bee.c b/Toolkit/Programming/GameCode/game/m_bee.c new file mode 100644 index 0000000..d548891 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_bee.c @@ -0,0 +1,110 @@ +//============================================================================== +// +// m_bee. +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "fx.h" +#include "g_HitLocation.h" +#include "g_misc.h" +#include "m_stats.h" + +static ClassResourceInfo_t resInfo; + +typedef enum SoundID_e +{ + SND_BUZZ1, + SND_BUZZ2, + SND_STING, + SND_GIB, + NUM_SOUNDS +} SoundID_t; + +static int sounds[NUM_SOUNDS]; +/* +========================================================== + + Bee Spawn functions + +========================================================== +*/ + +void BeeStaticsInit() +{ +// classStatics[CID_BEE].msgReceivers[MSG_STAND] = bee_stand1; +/* classStatics[CID_BEE].msgReceivers[MSG_RUN] = ogle_run1; + classStatics[CID_BEE].msgReceivers[MSG_MELEE] = ogle_melee; + classStatics[CID_BEE].msgReceivers[MSG_DISMEMBER] = ogle_dismember; + classStatics[CID_BEE].msgReceivers[MSG_DEATH] = ogle_death; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; */ + resInfo.modelIndex = gi.modelindex("models/monsters/bee/tris.fm"); + + sounds[SND_BUZZ1] = gi.soundindex ("monsters/bee/buzz1.wav"); + sounds[SND_BUZZ2] = gi.soundindex ("monsters/bee/buzz2.wav"); + sounds[SND_STING] = gi.soundindex ("monsters/bee/sting.wav"); + sounds[SND_GIB] = gi.soundindex ("monsters/bee/gib.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + +} + +/*QUAKED monster_bee (1 .5 0) (-16 -16 -24) (16 16 16) +The bee +*/ +void SP_monster_bee(edict_t *self) +{ + + self->s.modelindex = gi.modelindex("models/monsters/bee/tris.fm"); + + VectorSet(self->mins, -2, -2, -25); + VectorSet(self->maxs, 2, 2, 25); + + ObjectInit(self,40,40,MAT_WOOD,SOLID_BBOX); + + return; + +// walkmonster_start(self); + self->msgHandler = DefaultMsgHandler; + self->classID = CID_BEE; + + if (!self->health) + self->health = BEE_HEALTH; + + self->mass = BEE_MASS; + self->yaw_speed = 32; + +// self->movetype = PHYSICSTYPE_STEP; + self->solid=SOLID_BBOX; + + VectorSet(self->mins, -16, -16, -24); + VectorSet(self->maxs, 16, 16, 16); + + self->materialtype = MAT_INSECT; + + self->s.modelindex = classStatics[CID_BEE].resInfo->modelIndex; + self->s.skinnum=0; +/* + if (self->monsterinfo.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } +*/ + self->monsterinfo.otherenemyname = "monster_rat"; + +// AI_SpawnGuide(self); + +// self->use = ogle_use; + +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/m_chicken.c b/Toolkit/Programming/GameCode/game/m_chicken.c new file mode 100644 index 0000000..129bd51 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_chicken.c @@ -0,0 +1,455 @@ +//============================================================================== +// +// m_chicken.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// +// AI : +// +// STAND1 : Looking straight ahead +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" +#include "g_Physics.h" +#include "g_teleport.h" +#include "g_Skeletons.h" +#include "p_anims2.h" + +#include "m_chicken.h" +#include "m_chicken_anim.h" +#include "m_stats.h" + +extern void BecomeDebris(edict_t *self); +extern void ED_CallSpawn (edict_t *ent); + +/*---------------------------------------------------------------------- + Chicken Base Info +-----------------------------------------------------------------------*/ + +static animmove_t *animations[NUM_ANIMS] = +{ + &chicken_move_stand1, + &chicken_move_walk, + &chicken_move_run, + &chicken_move_cluck, + &chicken_move_attack, + &chicken_move_eat, + &chicken_move_jump, +}; + +static int sounds[NUM_SOUNDS]; + +static ClassResourceInfo_t resInfo; + +void ChickenStaticsInit() +{ + classStatics[CID_CHICKEN].msgReceivers[MSG_STAND] = chicken_stand; + classStatics[CID_CHICKEN].msgReceivers[MSG_WALK] = chicken_walk; + classStatics[CID_CHICKEN].msgReceivers[MSG_RUN] = chicken_run; + classStatics[CID_CHICKEN].msgReceivers[MSG_MELEE] = chicken_attack; + classStatics[CID_CHICKEN].msgReceivers[MSG_DEATH] = chicken_death; + classStatics[CID_CHICKEN].msgReceivers[MSG_WATCH] = chicken_cluck; + classStatics[CID_CHICKEN].msgReceivers[MSG_EAT] = chicken_eat; + classStatics[CID_CHICKEN].msgReceivers[MSG_JUMP] = chicken_jump; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/chicken2/tris.fm"); + + //for the cluck animation + sounds[SND_CLUCK1]= gi.soundindex ("monsters/chicken/cluck1.wav"); + sounds[SND_CLUCK2]= gi.soundindex ("monsters/chicken/cluck2.wav"); + + //for getting hit - even though right now, it dies immediately - they want this changed + sounds[SND_PAIN1]= gi.soundindex ("monsters/chicken/pain1.wav"); + sounds[SND_PAIN2]= gi.soundindex ("monsters/chicken/pain2.wav"); + + //for dying - we only ever get gibbed, so no other sound is required + sounds[SND_DIE]= gi.soundindex ("monsters/chicken/die.wav"); + + //for biting the player + sounds[SND_BITE1]= gi.soundindex ("monsters/chicken/bite1.wav"); + sounds[SND_BITE2]= gi.soundindex ("monsters/chicken/bite2.wav"); + + //for pecking the ground + sounds[SND_PECK1]= gi.soundindex ("monsters/chicken/peck1.wav"); + sounds[SND_PECK2]= gi.soundindex ("monsters/chicken/peck2.wav"); + + //and lastly, I thought it might be cool to have some cries for when the chicken jumps + sounds[SND_JUMP1]= gi.soundindex ("monsters/chicken/jump1.wav"); + sounds[SND_JUMP2]= gi.soundindex ("monsters/chicken/jump2.wav"); + sounds[SND_JUMP3]= gi.soundindex ("monsters/chicken/jump3.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_CHICKEN].resInfo = &resInfo; +} + +/*QUAKED monster_chicken (1 .5 0) (-16 -16 -0) (16 16 32) AMBUSH ASLEEP EATING + +The chicken + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +*/ +void SP_monster_chicken (edict_t *self) +{ + // Generic Monster Initialization + if (!monster_start(self)) // Failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_CHICKEN; + self->think = walkmonster_start_go; + self->materialtype = MAT_FLESH; + + self->health = CHICKEN_HEALTH; + self->mass = CHICKEN_MASS; + self->yaw_speed = 20; + + self->movetype = PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + VectorSet(self->mins,-12,-12,-16); + VectorSet(self->maxs,12,12,16); + + self->s.modelindex = classStatics[CID_CHICKEN].resInfo->modelIndex; + + self->s.skinnum = 0; + self->monsterinfo.scale = MODEL_SCALE; + + self->monsterinfo.otherenemyname = "obj_barrel"; + + //Spawn off the guide +// self->guide = AI_SpawnGuide(self); + MG_InitMoods(self); + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + + gi.linkentity(self); + +} + +void chicken_death(edict_t *self, G_Message_t *msg) +{ + self->msgHandler = DeadMsgHandler; + + // if we have a use, fire it off. +// monster_death_use (self); + + gi.sound (self, CHAN_BODY, sounds[SND_DIE], 1, ATTN_NORM, 0); + self->deadflag = DEAD_DEAD; + BecomeDebris(self); + gi.CreateEffect(&self->s, FX_CHICKEN_EXPLODE, CEF_OWNERS_ORIGIN, NULL, "" ); + +} + +// fade the original monster back in again +void MorphOriginalIn(edict_t *self) +{ + self->s.color.a += MORPH_TELE_FADE; + self->nextthink = level.time + FRAMETIME; + if (!(--self->morph_timer)) + { + self->think = self->oldthink; + } +} + +//Fade out the existing model till its gone +void MorphChickenOut(edict_t *self) +{ + edict_t *newent; + + self->s.color.a -= MORPH_TELE_FADE; + self->nextthink = level.time + FRAMETIME; + if (self->morph_timer < level.time) + { + // create the original bad guy + newent = G_Spawn(); + newent->classname = self->map; + VectorCopy(self->s.origin, newent->s.origin); + VectorCopy(self->s.angles, newent->s.angles); + newent->enemy = self->enemy; + ED_CallSpawn(newent); + newent->s.color.c = 0xffffff; + newent->oldthink = newent->think; + newent->think = MorphOriginalIn; + newent->morph_timer = MORPH_TELE_TIME; + newent->target = self->target; + + // make physics expand the bounding box for us, so the player doesn't get stuck inside the new bad guys box. + + // store the old mins max's + + VectorCopy(newent->mins,newent->intentMins); + VectorCopy(newent->maxs,newent->intentMaxs); + + VectorCopy(self->mins,newent->mins); + VectorCopy(self->maxs,newent->maxs); + + newent->physicsFlags |= PF_RESIZE; + + // do the teleport sound + gi.sound(newent,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + // do the teleport effect + gi.CreateEffect(&newent->s, FX_PLAYER_TELEPORT_IN, CEF_OWNERS_ORIGIN, NULL, "" ); + G_FreeEdict(self); + } +} + + +/*------------------------------------------------------------------------- + chicken checks to see if we are still a chicken, or is it time to return to + our original shape ? +-------------------------------------------------------------------------*/ +void chicken_check (edict_t *self) +{ + + // are we done yet ? + if (self->time > level.time) + return; + + // make that pretty effect around us + gi.CreateEffect(&self->s, FX_PLAYER_TELEPORT_OUT, CEF_OWNERS_ORIGIN, NULL, "" ); + + // deal with the existing chicken + self->think = MorphChickenOut; + self->nextthink = level.time + FRAMETIME; + self->touch = NULL; + self->morph_timer = MORPH_TELE_TIME; + VectorClear(self->velocity); + + // wipe out the guide, so we don't do anything else +// G_FreeEdict(self->guide); + +} + + + +/*------------------------------------------------------------------------- + chicken_bites you +-------------------------------------------------------------------------*/ +void chicken_bite (edict_t *self) +{ + vec3_t v, off, dir, org; + float len; + + // incase we try pecking at someone thats not there. + if (!self->enemy) + return; + + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + + // determine if we've actually bitten the player, or just missed + if (len <= (self->maxs[0] + self->enemy->maxs[0] + 24) ) // A hit + { + VectorSet(off, 20.0, 0.0, 5.0); + VectorGetOffsetOrigin(off, self->s.origin, self->s.angles[YAW], org); + // this is not apparently used for anything ? + VectorClear(dir); + // cause us some damage. + T_Damage (self->enemy, self, self, dir, org, vec3_origin, 1, 0, 0,MOD_DIED); + + if(!irand(0,1)) + gi.sound(self, CHAN_VOICE, sounds[SND_BITE1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_BITE2], 1, ATTN_NORM, 0); + } +} + +/*------------------------------------------------------------------------- + chicken_pause +-------------------------------------------------------------------------*/ +void chicken_pause (edict_t *self) +{ + vec3_t v; + float len; + int random_action; + + self->mood_think(self); + + if (self->ai_mood == AI_MOOD_NORMAL) + { + FindTarget(self); + + if(self->enemy) + { + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + + if ((len > 60) || (self->monsterinfo.aiflags & AI_FLEE)) // Far enough to run after + { + QPostMessage(self, MSG_RUN,PRI_DIRECTIVE, NULL); + } + else // Close enough to Attack + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + } + } + } + else + { + // decide if we will do a random action + random_action = (irand(0,10)); + // ok, if we can attack, then we do that, no question + if (self->ai_mood == AI_MOOD_ATTACK) + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + // else, one chance in a remote time, we will just go "cluck" + else if (!random_action) + // make us cluck + QPostMessage(self, MSG_WATCH, PRI_DIRECTIVE, NULL); + else + { + random_action--; + if (!random_action) + // make us peck + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + // otherwise run or track the player target + else + { + switch (self->ai_mood) + { + case AI_MOOD_PURSUE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_NAVIGATE: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_STAND: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_JUMP: + VectorCopy(self->movedir, self->velocity); + VectorNormalize(self->movedir); + SetAnim(self, ANIM_JUMP); + break; + case AI_MOOD_EAT: + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + break; + + default : +#ifdef _DEVEL + gi.dprintf("Chicken Unusable mood %d!\n", self->ai_mood); +#endif + break; + } + } + } + } +} + +/*------------------------------------------------------------------------- + chicken_eat again, possibly +-------------------------------------------------------------------------*/ +void chicken_eat_again (edict_t *self) +{ + // a one in three chance we will peck again :) + if (irand(0,2)) + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + else + chicken_pause(self); +} + +//---------------------------------------------------------------------- +// Chicken attack - peck us to death +//---------------------------------------------------------------------- +void chicken_attack(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_ATTACK); +} + +//---------------------------------------------------------------------- +// Chicken jump +//---------------------------------------------------------------------- +void chicken_jump(edict_t *self, G_Message_t *msg) +{ + if(!irand(0,2)) + gi.sound(self, CHAN_VOICE, sounds[SND_JUMP1], 1, ATTN_NORM, 0); + else if (!irand(0, 1)) + gi.sound(self, CHAN_VOICE, sounds[SND_JUMP2], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_JUMP3], 1, ATTN_NORM, 0); + SetAnim(self, ANIM_JUMP); +} + +//---------------------------------------------------------------------- +// Chicken Cluck +//---------------------------------------------------------------------- +void chicken_eat(edict_t *self, G_Message_t *msg) +{ + if (!irand(0, 1)) + gi.sound(self, CHAN_VOICE, sounds[SND_PECK1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_PECK2], 1, ATTN_NORM, 0); + SetAnim(self, ANIM_EAT); +} + +//---------------------------------------------------------------------- +// Chicken Cluck +//---------------------------------------------------------------------- +void chicken_cluck(edict_t *self, G_Message_t *msg) +{ + if (!irand(0, 1)) + gi.sound(self, CHAN_VOICE, sounds[SND_CLUCK1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_CLUCK2], 1, ATTN_NORM, 0); + + SetAnim(self, ANIM_CLUCK); +} + +//---------------------------------------------------------------------- +// Chicken Run - choose a run to use +//---------------------------------------------------------------------- +void chicken_run(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_RUN); +} + +//---------------------------------------------------------------------- +// Chicken Walk - choose a walk to use +//---------------------------------------------------------------------- +void chicken_walk(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_WALK); +} + +//---------------------------------------------------------------------- +// Chicken Stand -decide which standing animations to use +//---------------------------------------------------------------------- +void chicken_stand(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_STAND1); +} + +void chickensqueal (edict_t *self) +{ + if(!irand(0, 1)) + gi.sound (self, CHAN_WEAPON, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_PAIN2], 1, ATTN_NORM, 0); +} + +void ChickenGlide ( playerinfo_t *playerinfo ) +{ +} + +void chickenSound (edict_t *self, float channel, float sndindex, float atten) +{ + gi.sound(self, channel, sounds[(int)(sndindex)], 1, atten, 0); +} diff --git a/Toolkit/Programming/GameCode/game/m_chicken.h b/Toolkit/Programming/GameCode/game/m_chicken.h new file mode 100644 index 0000000..2adaf74 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_chicken.h @@ -0,0 +1,91 @@ +typedef enum AnimID_e +{ + ANIM_STAND1, + ANIM_WALK, + ANIM_RUN, + ANIM_CLUCK, + ANIM_ATTACK, + ANIM_EAT, + ANIM_JUMP, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + //for the cluck animation + SND_CLUCK1, + SND_CLUCK2, + + //for the foot falls + SND_CLAW, + + //for getting hit - even though right now, it dies immediately - they want this changed + SND_PAIN1, + SND_PAIN2, + + //for dying - we only ever get gibbed, so no other sound is required + SND_DIE, + + //for biting the player + SND_BITE1, + SND_BITE2, + SND_BITE3, + + //for pecking the ground + SND_PECK1, + SND_PECK2, + + //and lastly, I thought it might be cool to have some cries for when the chicken jumps + SND_JUMP1, + SND_JUMP2, + SND_JUMP3, + + NUM_SOUNDS +} SoundID_t; + +extern animmove_t chicken_move_stand1; +extern animmove_t chicken_move_walk; +extern animmove_t chicken_move_run; +extern animmove_t chicken_move_cluck; +extern animmove_t chicken_move_attack; +extern animmove_t chicken_move_eat; +extern animmove_t chicken_move_jump; + +//Dummy anim to catch sequence leaks +extern animmove_t chickenp_move_dummy; + +extern animmove_t chickenp_move_stand; +extern animmove_t chickenp_move_stand1; +extern animmove_t chickenp_move_stand2; +extern animmove_t chickenp_move_walk; +extern animmove_t chickenp_move_run; +extern animmove_t chickenp_move_back; +extern animmove_t chickenp_move_runb; +extern animmove_t chickenp_move_bite; +extern animmove_t chickenp_move_strafel; +extern animmove_t chickenp_move_strafer; +extern animmove_t chickenp_move_jump; +extern animmove_t chickenp_move_wjump; +extern animmove_t chickenp_move_wjumpb; +extern animmove_t chickenp_move_rjump; +extern animmove_t chickenp_move_rjumpb; +extern animmove_t chickenp_move_jump_loop; +extern animmove_t chickenp_move_attack; + +void chicken_stand(edict_t *self, G_Message_t *msg); +void chicken_walk(edict_t *self, G_Message_t *msg); +void chicken_run(edict_t *self, G_Message_t *msg); +void chicken_attack(edict_t *self, G_Message_t *msg); +void chicken_death(edict_t *self, G_Message_t *msg); +void player_chicken_death(edict_t *self, G_Message_t *msg); +void chicken_eat(edict_t *self, G_Message_t *msg); +void chicken_cluck(edict_t *self, G_Message_t *msg); +void chicken_jump(edict_t *self, G_Message_t *msg); + +void chicken_pause(edict_t *self); +void chicken_check(edict_t *self); +void chicken_eat_again(edict_t *self); +void chicken_bite (edict_t *self); + +int make_chicken_jump(edict_t *self); +void chickenSound (edict_t *self, float channel, float sndindex, float atten); diff --git a/Toolkit/Programming/GameCode/game/m_chicken_anim.c b/Toolkit/Programming/GameCode/game/m_chicken_anim.c new file mode 100644 index 0000000..ef37502 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_chicken_anim.c @@ -0,0 +1,164 @@ +//============================================================================== +// +// m_chicken_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_chicken_anim.h" +#include "m_chicken.h" + +#define ENEMY_WALK_SPEED 32 +#define ENEMY_RUN_SPEED 64 +#define PLAYER_WALK_SPEED 240 +#define PLAYER_STRAFE_SPEED 185 +#define PLAYER_RUN_SPEED 300 + +// FOR BAD GUYS ONLY +/*---------------------------------------------------------------------- + Chicken Standing - +-----------------------------------------------------------------------*/ +animframe_t chicken_frames_stand1 [] = +{ + FRAME_wait1, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_wait2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait4, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_wait5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait6, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t chicken_move_stand1 = {6, chicken_frames_stand1, chicken_pause}; + +/*---------------------------------------------------------------------- + Chicken running - +-----------------------------------------------------------------------*/ +animframe_t chicken_frames_run [] = +{ + FRAME_run1, NULL, 0, 0, 0, ai_run, ENEMY_RUN_SPEED, chicken_check, + FRAME_run2, NULL, 0, 0, 0, ai_run, ENEMY_RUN_SPEED, NULL, + FRAME_run3, chickenSound, CHAN_BODY, SND_CLAW, ATTN_NORM, ai_run, ENEMY_RUN_SPEED, NULL, + FRAME_run4, NULL, 0, 0, 0, ai_run, ENEMY_RUN_SPEED, chicken_check, + FRAME_run5, NULL, 0, 0, 0, ai_run, ENEMY_RUN_SPEED, NULL, + FRAME_run6, chickenSound, CHAN_BODY, SND_CLAW, ATTN_NORM, ai_run, ENEMY_RUN_SPEED, NULL, +}; +animmove_t chicken_move_run = {6, chicken_frames_run, chicken_pause}; + +/*---------------------------------------------------------------------- + Chicken walking - +-----------------------------------------------------------------------*/ +animframe_t chicken_frames_walk [] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_walk, ENEMY_WALK_SPEED, chicken_check, + FRAME_walk2, NULL, 0, 0, 0, ai_walk, ENEMY_WALK_SPEED, NULL, + FRAME_walk3, chickenSound, CHAN_BODY, SND_CLAW, ATTN_NORM, ai_walk, ENEMY_WALK_SPEED, chicken_check, + FRAME_walk4, NULL, 0, 0, 0, ai_walk, ENEMY_WALK_SPEED, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_walk, ENEMY_WALK_SPEED, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_walk, ENEMY_WALK_SPEED, NULL, + FRAME_walk7, chickenSound, CHAN_BODY, SND_CLAW, ATTN_NORM, ai_walk, ENEMY_WALK_SPEED, chicken_check, + FRAME_walk8, NULL, 0, 0, 0, ai_walk, ENEMY_WALK_SPEED, NULL, +}; +animmove_t chicken_move_walk = {8, chicken_frames_walk, chicken_pause}; + +/*---------------------------------------------------------------------- + Chicken cluck - +-----------------------------------------------------------------------*/ +animframe_t chicken_frames_cluck [] = +{ + FRAME_cluck1, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_cluck2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck4, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_cluck5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck7, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_cluck8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck10, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_cluck11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck13, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_cluck14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck16, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_cluck17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_cluck19, NULL, 0, 0, 0, ai_stand, 0, chicken_check, +}; +animmove_t chicken_move_cluck = {19, chicken_frames_cluck, chicken_eat_again}; + +/*---------------------------------------------------------------------- + Chicken attacking - +-----------------------------------------------------------------------*/ +animframe_t chicken_frames_attack [] = +{ + FRAME_attack1, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_attack2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_attack3, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_attack4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_attack5, NULL, 0, 0, 0, ai_stand, 0, chicken_bite, + FRAME_attack6, NULL, 0, 0, 0, ai_stand, 0, chicken_check +}; + +animmove_t chicken_move_attack = {6, chicken_frames_attack, chicken_pause}; + +/*---------------------------------------------------------------------- + Chicken eating - +-----------------------------------------------------------------------*/ +animframe_t chicken_frames_eat [] = +{ + FRAME_peck1, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck4, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck7, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck10, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck13, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck16, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck19, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck20, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck21, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck22, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck23, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck24, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck25, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck26, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck27, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_peck28, NULL, 0, 0, 0, ai_stand, 0, chicken_check, + FRAME_peck29, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; + +animmove_t chicken_move_eat = {29, chicken_frames_eat, chicken_eat_again}; + +/*---------------------------------------------------------------------- + Chicken jumping - +-----------------------------------------------------------------------*/ +animframe_t chicken_frames_jump [] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_jump6, NULL, 0, 0, 0, ai_walk, 8, NULL, +}; + +animmove_t chicken_move_jump = {6, chicken_frames_jump, chicken_pause}; diff --git a/Toolkit/Programming/GameCode/game/m_chicken_anim.h b/Toolkit/Programming/GameCode/game/m_chicken_anim.h new file mode 100644 index 0000000..1f90884 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_chicken_anim.h @@ -0,0 +1,204 @@ +// R:\Art\models/monsters\chicken2 + +// This file generated by qdata - Do NOT Modify + +#define FRAME__bodyparts1 0 +#define FRAME_attack1 1 +#define FRAME_attack2 2 +#define FRAME_attack3 3 +#define FRAME_attack4 4 +#define FRAME_attack5 5 +#define FRAME_attack6 6 +#define FRAME_cluck1 7 +#define FRAME_cluck2 8 +#define FRAME_cluck3 9 +#define FRAME_cluck4 10 +#define FRAME_cluck5 11 +#define FRAME_cluck6 12 +#define FRAME_cluck7 13 +#define FRAME_cluck8 14 +#define FRAME_cluck9 15 +#define FRAME_cluck10 16 +#define FRAME_cluck11 17 +#define FRAME_cluck12 18 +#define FRAME_cluck13 19 +#define FRAME_cluck14 20 +#define FRAME_cluck15 21 +#define FRAME_cluck16 22 +#define FRAME_cluck17 23 +#define FRAME_cluck18 24 +#define FRAME_cluck19 25 +#define FRAME_deathstand1 26 +#define FRAME_deathstand10 27 +#define FRAME_deathstand11 28 +#define FRAME_deathstand12 29 +#define FRAME_deathstand13 30 +#define FRAME_deathstand14 31 +#define FRAME_deathstand15 32 +#define FRAME_deathstand16 33 +#define FRAME_deathstand17 34 +#define FRAME_deathstand18 35 +#define FRAME_deathstand19 36 +#define FRAME_deathstand2 37 +#define FRAME_deathstand20 38 +#define FRAME_deathstand21 39 +#define FRAME_deathstand22 40 +#define FRAME_deathstand23 41 +#define FRAME_deathstand24 42 +#define FRAME_deathstand25 43 +#define FRAME_deathstand26 44 +#define FRAME_deathstand27 45 +#define FRAME_deathstand28 46 +#define FRAME_deathstand29 47 +#define FRAME_deathstand3 48 +#define FRAME_deathstand30 49 +#define FRAME_deathstand4 50 +#define FRAME_deathstand5 51 +#define FRAME_deathstand6 52 +#define FRAME_deathstand7 53 +#define FRAME_deathstand8 54 +#define FRAME_deathstand9 55 +#define FRAME_death1 56 +#define FRAME_death2 57 +#define FRAME_death3 58 +#define FRAME_death4 59 +#define FRAME_death5 60 +#define FRAME_death6 61 +#define FRAME_death7 62 +#define FRAME_death8 63 +#define FRAME_death9 64 +#define FRAME_death10 65 +#define FRAME_death11 66 +#define FRAME_death12 67 +#define FRAME_death13 68 +#define FRAME_death14 69 +#define FRAME_death15 70 +#define FRAME_death16 71 +#define FRAME_death17 72 +#define FRAME_death18 73 +#define FRAME_death19 74 +#define FRAME_death20 75 +#define FRAME_death21 76 +#define FRAME_death22 77 +#define FRAME_death23 78 +#define FRAME_death24 79 +#define FRAME_death25 80 +#define FRAME_death26 81 +#define FRAME_death27 82 +#define FRAME_death28 83 +#define FRAME_death29 84 +#define FRAME_death30 85 +#define FRAME_death31 86 +#define FRAME_death32 87 +#define FRAME_death33 88 +#define FRAME_death34 89 +#define FRAME_death35 90 +#define FRAME_death36 91 +#define FRAME_death37 92 +#define FRAME_death38 93 +#define FRAME_death39 94 +#define FRAME_death40 95 +#define FRAME_death41 96 +#define FRAME_death42 97 +#define FRAME_death43 98 +#define FRAME_death44 99 +#define FRAME_death45 100 +#define FRAME_death46 101 +#define FRAME_death47 102 +#define FRAME_death48 103 +#define FRAME_death49 104 +#define FRAME_death50 105 +#define FRAME_death51 106 +#define FRAME_death52 107 +#define FRAME_death53 108 +#define FRAME_death54 109 +#define FRAME_death55 110 +#define FRAME_jattack1 111 +#define FRAME_jattack2 112 +#define FRAME_jattack3 113 +#define FRAME_jattack4 114 +#define FRAME_jattack5 115 +#define FRAME_jump1 116 +#define FRAME_jump2 117 +#define FRAME_jump3 118 +#define FRAME_jump4 119 +#define FRAME_jump5 120 +#define FRAME_jump6 121 +#define FRAME_jump7 122 +#define FRAME_jump8 123 +#define FRAME_jump9 124 +#define FRAME_jump10 125 +#define FRAME_jump11 126 +#define FRAME_jump12 127 +#define FRAME_peck1 128 +#define FRAME_peck2 129 +#define FRAME_peck3 130 +#define FRAME_peck4 131 +#define FRAME_peck5 132 +#define FRAME_peck6 133 +#define FRAME_peck7 134 +#define FRAME_peck8 135 +#define FRAME_peck9 136 +#define FRAME_peck10 137 +#define FRAME_peck11 138 +#define FRAME_peck12 139 +#define FRAME_peck13 140 +#define FRAME_peck14 141 +#define FRAME_peck15 142 +#define FRAME_peck16 143 +#define FRAME_peck17 144 +#define FRAME_peck18 145 +#define FRAME_peck19 146 +#define FRAME_peck20 147 +#define FRAME_peck21 148 +#define FRAME_peck22 149 +#define FRAME_peck23 150 +#define FRAME_peck24 151 +#define FRAME_peck25 152 +#define FRAME_peck26 153 +#define FRAME_peck27 154 +#define FRAME_peck28 155 +#define FRAME_peck29 156 +#define FRAME_rattack1 157 +#define FRAME_rattack2 158 +#define FRAME_rattack3 159 +#define FRAME_rattack4 160 +#define FRAME_rattack5 161 +#define FRAME_rattack6 162 +#define FRAME_run1 163 +#define FRAME_run2 164 +#define FRAME_run3 165 +#define FRAME_run4 166 +#define FRAME_run5 167 +#define FRAME_run6 168 +#define FRAME_wait1 169 +#define FRAME_wait2 170 +#define FRAME_wait3 171 +#define FRAME_wait4 172 +#define FRAME_wait5 173 +#define FRAME_wait6 174 +#define FRAME_walk1 175 +#define FRAME_walk2 176 +#define FRAME_walk3 177 +#define FRAME_walk4 178 +#define FRAME_walk5 179 +#define FRAME_walk6 180 +#define FRAME_walk7 181 +#define FRAME_walk8 182 + +#define MODEL_SCALE 0.250000 + +#define NUM_MESH_NODES 12 + +#define MESH_BASE 0 +#define MESH__BODYCAP 1 +#define MESH__LWING 2 +#define MESH__LWINGCAP 3 +#define MESH__RLEG 4 +#define MESH__RLEGCAP 5 +#define MESH__HEAD 6 +#define MESH__HEADCAP 7 +#define MESH__LLEG 8 +#define MESH__LLEGCAP 9 +#define MESH__RWING 10 +#define MESH__RWINGCAP 11 diff --git a/Toolkit/Programming/GameCode/game/m_elf.h b/Toolkit/Programming/GameCode/game/m_elf.h new file mode 100644 index 0000000..70e5d3c --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_elf.h @@ -0,0 +1,356 @@ +// R:\base\models/player\elf + +// This file generated by qdata - Do NOT Modify + +#define FRAME_idle1 0 +#define FRAME_idle2 1 +#define FRAME_idle3 2 +#define FRAME_idle4 3 +#define FRAME_idle5 4 +#define FRAME_idle6 5 +#define FRAME_idle7 6 +#define FRAME_idle8 7 +#define FRAME_idle9 8 +#define FRAME_idle10 9 +#define FRAME_idle11 10 +#define FRAME_idle12 11 +#define FRAME_idle13 12 +#define FRAME_idle14 13 +#define FRAME_idle15 14 +#define FRAME_idle16 15 +#define FRAME_idle17 16 +#define FRAME_idle18 17 +#define FRAME_idle19 18 +#define FRAME_idle20 19 +#define FRAME_idle21 20 +#define FRAME_idle22 21 +#define FRAME_idle23 22 +#define FRAME_breathB1 23 +#define FRAME_breathB2 24 +#define FRAME_breathB3 25 +#define FRAME_breathB4 26 +#define FRAME_breathB5 27 +#define FRAME_breathB6 28 +#define FRAME_breathB7 29 +#define FRAME_breathB8 30 +#define FRAME_breathB9 31 +#define FRAME_breathB10 32 +#define FRAME_breathB11 33 +#define FRAME_breathB12 34 +#define FRAME_breathC1 35 +#define FRAME_breathC2 36 +#define FRAME_breathC3 37 +#define FRAME_breathC4 38 +#define FRAME_breathC5 39 +#define FRAME_breathC6 40 +#define FRAME_breathC7 41 +#define FRAME_breathC8 42 +#define FRAME_breathC9 43 +#define FRAME_breathC10 44 +#define FRAME_breathC11 45 +#define FRAME_breathC12 46 +#define FRAME_breathC13 47 +#define FRAME_breathC14 48 +#define FRAME_breathC15 49 +#define FRAME_breathC16 50 +#define FRAME_turnL1 51 +#define FRAME_turnL2 52 +#define FRAME_turnL3 53 +#define FRAME_turnL4 54 +#define FRAME_turnL5 55 +#define FRAME_turnL6 56 +#define FRAME_turnL7 57 +#define FRAME_turnL8 58 +#define FRAME_turnL9 59 +#define FRAME_turnL10 60 +#define FRAME_walk1 61 +#define FRAME_walk2 62 +#define FRAME_walk3 63 +#define FRAME_walk4 64 +#define FRAME_walk5 65 +#define FRAME_walk6 66 +#define FRAME_walk7 67 +#define FRAME_walk8 68 +#define FRAME_walk9 69 +#define FRAME_walk10 70 +#define FRAME_run1 71 +#define FRAME_run2 72 +#define FRAME_run3 73 +#define FRAME_run4 74 +#define FRAME_run5 75 +#define FRAME_run6 76 +#define FRAME_run7 77 +#define FRAME_run8 78 +#define FRAME_prejump1 79 +#define FRAME_prejump2 80 +#define FRAME_prejump3 81 +#define FRAME_prejump4 82 +#define FRAME_jump1 83 +#define FRAME_jump2 84 +#define FRAME_jump3 85 +#define FRAME_jump4 86 +#define FRAME_jump5 87 +#define FRAME_jump6 88 +#define FRAME_jump7 89 +#define FRAME_jump8 90 +#define FRAME_jump9 91 +#define FRAME_jump10 92 +#define FRAME_jump11 93 +#define FRAME_jump12 94 +#define FRAME_jump13 95 +#define FRAME_jump14 96 +#define FRAME_jump15 97 +#define FRAME_jump16 98 +#define FRAME_jumpup1 99 +#define FRAME_land1 100 +#define FRAME_land2 101 +#define FRAME_land3 102 +#define FRAME_roll1 103 +#define FRAME_roll2 104 +#define FRAME_roll3 105 +#define FRAME_roll4 106 +#define FRAME_roll5 107 +#define FRAME_roll6 108 +#define FRAME_roll7 109 +#define FRAME_roll8 110 +#define FRAME_roll9 111 +#define FRAME_roll10 112 +#define FRAME_roll11 113 +#define FRAME_fall1 114 +#define FRAME_fall2 115 +#define FRAME_fall3 116 +#define FRAME_fall4 117 +#define FRAME_grab1 118 +#define FRAME_grab2 119 +#define FRAME_grab3 120 +#define FRAME_pullup1 121 +#define FRAME_pullup2 122 +#define FRAME_pullup3 123 +#define FRAME_pullup4 124 +#define FRAME_pullup5 125 +#define FRAME_pullup6 126 +#define FRAME_pullup7 127 +#define FRAME_pullup8 128 +#define FRAME_pullup9 129 +#define FRAME_pullup10 130 +#define FRAME_pullup11 131 +#define FRAME_pullup12 132 +#define FRAME_pullup13 133 +#define FRAME_pullup14 134 +#define FRAME_pullup15 135 +#define FRAME_pullup16 136 +#define FRAME_pullup17 137 +#define FRAME_pullup18 138 +#define FRAME_pullup19 139 +#define FRAME_pullup20 140 +#define FRAME_spellA1 141 +#define FRAME_spellA2 142 +#define FRAME_spellA3 143 +#define FRAME_spellA4 144 +#define FRAME_spellA5 145 +#define FRAME_spellA6 146 +#define FRAME_spellA7 147 +#define FRAME_spellA8 148 +#define FRAME_spellA9 149 +#define FRAME_spellB1 150 +#define FRAME_spellB2 151 +#define FRAME_spellB3 152 +#define FRAME_spellB4 153 +#define FRAME_spellB5 154 +#define FRAME_spellB6 155 +#define FRAME_spellB7 156 +#define FRAME_spellB8 157 +#define FRAME_spellB9 158 +#define FRAME_spellB10 159 +#define FRAME_spellB11 160 +#define FRAME_spellB12 161 +#define FRAME_spellB13 162 +#define FRAME_spellB14 163 +#define FRAME_spellB15 164 +#define FRAME_recast1 165 +#define FRAME_recast2 166 +#define FRAME_recast3 167 +#define FRAME_recast4 168 +#define FRAME_relax1 169 +#define FRAME_relax2 170 +#define FRAME_relax3 171 +#define FRAME_relax4 172 +#define FRAME_BowOn1 173 +#define FRAME_BowOn2 174 +#define FRAME_BowOn3 175 +#define FRAME_BowOn4 176 +#define FRAME_BowOn5 177 +#define FRAME_BowOn6 178 +#define FRAME_BowOn7 179 +#define FRAME_BowOn8 180 +#define FRAME_BowOn9 181 +#define FRAME_BowOn10 182 +#define FRAME_BowOn11 183 +#define FRAME_Idlswm1 184 +#define FRAME_Idlswm2 185 +#define FRAME_Idlswm3 186 +#define FRAME_Idlswm4 187 +#define FRAME_Idlswm5 188 +#define FRAME_Idlswm6 189 +#define FRAME_Idlswm7 190 +#define FRAME_Idlswm8 191 +#define FRAME_Idlswm9 192 +#define FRAME_Idlswm10 193 +#define FRAME_Idlswm11 194 +#define FRAME_Idlswm12 195 +#define FRAME_Idlswm13 196 +#define FRAME_Idlswm14 197 +#define FRAME_Idlswm15 198 +#define FRAME_trnswm1 199 +#define FRAME_trnswm2 200 +#define FRAME_trnswm3 201 +#define FRAME_trnswm4 202 +#define FRAME_trnswm5 203 +#define FRAME_trnswm6 204 +#define FRAME_trnswm7 205 +#define FRAME_swmfor1 206 +#define FRAME_swmfor2 207 +#define FRAME_swmfor3 208 +#define FRAME_swmfor4 209 +#define FRAME_swmfor5 210 +#define FRAME_swmfor6 211 +#define FRAME_swmfor7 212 +#define FRAME_swmfor8 213 +#define FRAME_swmfor9 214 +#define FRAME_painA1 215 +#define FRAME_painA2 216 +#define FRAME_painA3 217 +#define FRAME_painA4 218 +#define FRAME_painA5 219 +#define FRAME_painB1 220 +#define FRAME_painB2 221 +#define FRAME_painB3 222 +#define FRAME_painB4 223 +#define FRAME_painB5 224 +#define FRAME_painB6 225 +#define FRAME_painB7 226 +#define FRAME_painB8 227 +#define FRAME_tbkswm1 228 +#define FRAME_tbkswm2 229 +#define FRAME_tbkswm3 230 +#define FRAME_tbkswm4 231 +#define FRAME_tbkswm5 232 +#define FRAME_tbkswm6 233 +#define FRAME_bckswm1 234 +#define FRAME_bckswm2 235 +#define FRAME_bckswm3 236 +#define FRAME_bckswm4 237 +#define FRAME_bckswm5 238 +#define FRAME_bckswm6 239 +#define FRAME_bckswm7 240 +#define FRAME_load1 241 +#define FRAME_load2 242 +#define FRAME_load3 243 +#define FRAME_load4 244 +#define FRAME_load5 245 +#define FRAME_load6 246 +#define FRAME_load7 247 +#define FRAME_load8 248 +#define FRAME_shoot1 249 +#define FRAME_shoot2 250 +#define FRAME_shoot3 251 +#define FRAME_shoot4 252 +#define FRAME_shoot5 253 +#define FRAME_shoot6 254 +#define FRAME_shoot7 255 +#define FRAME_shoot8 256 +#define FRAME_shoot9 257 +#define FRAME_shoot10 258 +#define FRAME_flnchL1 259 +#define FRAME_flnchL2 260 +#define FRAME_flnchL3 261 +#define FRAME_flnchL4 262 +#define FRAME_flnchL5 263 +#define FRAME_flnchL6 264 +#define FRAME_flnchL7 265 +#define FRAME_flnchR1 266 +#define FRAME_flnchR2 267 +#define FRAME_flnchR3 268 +#define FRAME_flnchR4 269 +#define FRAME_flnchR5 270 +#define FRAME_flnchR6 271 +#define FRAME_flnchR7 272 +#define FRAME_newspl1 273 +#define FRAME_newspl2 274 +#define FRAME_newspl3 275 +#define FRAME_newspl4 276 +#define FRAME_newspl5 277 +#define FRAME_newspl6 278 +#define FRAME_newspl7 279 +#define FRAME_newspl8 280 +#define FRAME_newspl9 281 +#define FRAME_newspl10 282 +#define FRAME_newspl11 283 +#define FRAME_newspl12 284 +#define FRAME_newspl13 285 +#define FRAME_newspl14 286 +#define FRAME_newspl15 287 +#define FRAME_newspl16 288 +#define FRAME_newspl17 289 +#define FRAME_newspl18 290 +#define FRAME_newspl19 291 +#define FRAME_newspl20 292 +#define FRAME_newspl21 293 +#define FRAME_newspl22 294 +#define FRAME_stopR1 295 +#define FRAME_stopR2 296 +#define FRAME_stopR3 297 +#define FRAME_stopR4 298 +#define FRAME_stopR5 299 +#define FRAME_stopR6 300 +#define FRAME_stopR7 301 +#define FRAME_stopR8 302 +#define FRAME_stopR9 303 +#define FRAME_stopR10 304 +#define FRAME_stopR11 305 +#define FRAME_stopR12 306 +#define FRAME_stopR13 307 +#define FRAME_stopR14 308 +#define FRAME_pestA1 309 +#define FRAME_pestA2 310 +#define FRAME_pestA3 311 +#define FRAME_pestA4 312 +#define FRAME_pestA5 313 +#define FRAME_pestA6 314 +#define FRAME_pestA7 315 +#define FRAME_pestA8 316 +#define FRAME_pestA9 317 +#define FRAME_pestA10 318 +#define FRAME_pestA11 319 +#define FRAME_pestA12 320 +#define FRAME_pestA13 321 +#define FRAME_pestA14 322 +#define FRAME_pestB1 323 +#define FRAME_pestB2 324 +#define FRAME_pestB3 325 +#define FRAME_pestB4 326 +#define FRAME_pestB5 327 +#define FRAME_pestB6 328 +#define FRAME_pestB7 329 +#define FRAME_pestB8 330 +#define FRAME_pestB9 331 +#define FRAME_pestB10 332 +#define FRAME_pestB11 333 +#define FRAME_pestB12 334 +#define FRAME_pestB13 335 +#define FRAME_pestB14 336 +#define FRAME_pestB15 337 +#define FRAME_pestB16 338 +#define FRAME_pestB17 339 +#define FRAME_pestB18 340 +#define FRAME_pestB19 341 +#define FRAME_pestB20 342 +#define FRAME_pestB21 343 +#define FRAME_pestB22 344 +#define FRAME_wlkoff1 345 +#define FRAME_wlkoff2 346 +#define FRAME_wlkoff3 347 +#define FRAME_wlkoff4 348 +#define FRAME_wlkoff5 349 + +#define MODEL_SCALE 1.000000 diff --git a/Toolkit/Programming/GameCode/game/m_elflord.c b/Toolkit/Programming/GameCode/game/m_elflord.c new file mode 100644 index 0000000..66cc10a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_elflord.c @@ -0,0 +1,852 @@ +//============================================================================== +// +// m_elflord.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" +#include "g_playstats.h" +#include "m_elflord.h" +#include "m_elflord_anims.h" +#include "g_monster.h" +#include "m_stats.h" +#include "g_HitLocation.h" + +/*QUAKED monster_elflord (1 .5 0) (-16 -16 -0) (16 16 32) +*/ + +//Mirrored on client side +enum +{ + CW_STAR, + CW_STAR_HIT, + CW_BEAM, + CW_METEOR, +} cwatcher_effect_id_t; + +void SpellCastSphereOfAnnihilation(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir, + float Value,qboolean *ReleaseFlagsPtr); + +/*---------------------------------------------------------------------- + Elf Lord Base Info +-----------------------------------------------------------------------*/ + +static animmove_t *animations[] = +{ + &elflord_move_idle, + &elflord_move_run, + &elflord_move_charge, + &elflord_move_charge_trans, + &elflord_move_floatback, + &elflord_move_dodgeright, + &elflord_move_dodgeleft, + &elflord_move_soa_begin, + &elflord_move_soa_loop, + &elflord_move_soa_end, + &elflord_move_ls, + &elflord_move_pain, + &elflord_move_death_btrans, + &elflord_move_death_loop, + &elflord_move_shield, + &elflord_move_attack, + &elflord_move_move, + &elflord_move_wait, + &elflord_move_come_to_life, +}; + +static int sounds[NUM_SOUNDS]; + +static ClassResourceInfo_t resInfo; + +/*----------------------------------------------- + elflord_projectile_blocked +-----------------------------------------------*/ + +void elflord_projectile_blocked( edict_t *self, trace_t *trace ) +{ + vec3_t vel; + + if ( (!stricmp(trace->ent->classname, "elflord_projectile")) || (trace->ent == self->owner) ) + return; + + VectorNormalize2(self->velocity, vel); + + if (trace->ent && trace->ent->takedamage) + { + T_Damage(trace->ent, self->owner, self->owner, vel, trace->endpos, trace->plane.normal, irand(ELFLORD_STAR_MIN_DAMAGE, ELFLORD_STAR_MAX_DAMAGE), 0, DAMAGE_NORMAL, MOD_DIED); + } + + //Create the star explosion + gi.CreateEffect( NULL, + FX_CWATCHER, + 0, + trace->endpos, + "bv", + CW_STAR_HIT, + trace->plane.normal); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + elford_Attack +-----------------------------------------------*/ + +void elford_Attack( edict_t *self ) +{ + edict_t *projectile; + vec3_t aim, vf, vr, ang, org; + float len, yaw_ofs = -20; + int i; + + if (!M_ValidTarget(self, self->enemy)) + return; + + for(i=0;i<3;i++) + { + projectile = G_Spawn(); + + projectile->classname = "elflord_projectile"; + projectile->solid = SOLID_BBOX; + projectile->movetype = PHYSICSTYPE_FLY; + projectile->clipmask = MASK_SHOT; + + AngleVectors(self->s.angles, vf, vr, NULL); + VectorCopy(self->s.origin, projectile->s.origin); + VectorMA(projectile->s.origin, 48, vf, projectile->s.origin); + VectorMA(projectile->s.origin, 16, vr, projectile->s.origin); + projectile->s.origin[2] += 8; + + VectorSet(projectile->mins, -2, -2, -2); + VectorSet(projectile->maxs, 2, 2, 2); + + projectile->owner = self; + projectile->svflags |= SVF_ALWAYS_SEND; + + VectorCopy(self->enemy->s.origin, org); + + M_PredictTargetPosition(self->enemy, self->enemy->velocity, skill->value * 2, org); + + org[2] += self->enemy->viewheight; + + VectorSubtract(org, projectile->s.origin, aim); + len = VectorNormalize(aim); + vectoangles(aim, ang); + ang[YAW] += yaw_ofs; + ang[PITCH] *= -1; + yaw_ofs += 20; + AngleVectors(ang, aim, NULL, NULL); + + VectorScale(aim, (600 + (skill->value * 100)), projectile->velocity); + + projectile->gravity = 0; + + gi.linkentity(projectile); + + gi.CreateEffect( &projectile->s, + FX_CWATCHER, + CEF_OWNERS_ORIGIN, + projectile->s.origin, + "bv", + CW_STAR, + self->s.origin); + + projectile->isBlocking = projectile->bounced = projectile->isBlocked = elflord_projectile_blocked; + } + + gi.sound(self, CHAN_WEAPON, sounds[SND_PROJ1], 1, ATTN_NORM, 0); +} + +/*----------------------------------------------- + elflord_StartBeam +-----------------------------------------------*/ + +void elflord_StartBeam(edict_t *self) +{ + edict_t *beam; + trace_t trace; + vec3_t endpos, ang, vr; + vec3_t mins = {-2, -2, -2}; + vec3_t maxs = { 2, 2, 2}; + + if (!M_ValidTarget(self, self->enemy)) + return; + + beam = G_Spawn(); + + VectorCopy(self->s.angles, ang); + ang[PITCH] *= -1; + AngleVectors(ang, self->pos1, vr, NULL); + + VectorMA(self->s.origin, 32, self->pos1, self->pos2); + self->pos2[2] -= 32; + + beam->classname = "elflord_Beam"; + beam->solid = SOLID_NOT; + beam->movetype = PHYSICSTYPE_NONE; + beam->owner = self; + beam->svflags |= SVF_ALWAYS_SEND; + + VectorMA(self->s.origin, 640, self->pos1, endpos); + gi.trace(self->s.origin, mins, maxs, endpos, self, MASK_SHOT, &trace); + + VectorCopy(trace.endpos, beam->s.origin); + + beam->pain_debounce_time = level.time + 5; + + gi.linkentity(beam); + + gi.CreateEffect( &beam->s, + FX_CWATCHER, + CEF_OWNERS_ORIGIN, + beam->s.origin, + "bv", + CW_BEAM, + self->pos2); + + gi.sound(self, CHAN_VOICE, sounds[SND_BEAM], 0.5, ATTN_NONE, 0); + + self->targetEnt = beam; +} + +/*----------------------------------------------- + elflord_EndBeam +-----------------------------------------------*/ + +void elflord_EndBeam(edict_t *self) +{ + self->targetEnt->think = G_FreeEdict; + self->targetEnt->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + elflord_decell +-----------------------------------------------*/ + +void elflord_decell(edict_t *self, float value) +{ + if (self->velocity[0] != 0.0 || self->velocity[1] != 0.0 || self->velocity[2] != 0.0) + { + self->velocity[0] *= value; + self->velocity[1] *= value; + self->velocity[2] *= value; + + if (abs(self->velocity[0]) < 1.0) + self->velocity[0] = 0.0; + if (abs(self->velocity[1]) < 1.0) + self->velocity[1] = 0.0; + if (abs(self->velocity[2]) < 1.0) + self->velocity[2] = 0.0; + } +} + +/*----------------------------------------------- + elflord_ai_stand +-----------------------------------------------*/ + +void elflord_ai_stand (edict_t *self, float dist) +{ + ai_stand(self, 0); + if (M_ValidTarget(self, self->enemy)) + { + return; + } +} + + +/**************************************/ + +/*----------------------------------------------- + elflord_finish_death +-----------------------------------------------*/ + +void elflord_finish_death(edict_t *self) +{ + SetAnim(self, ANIM_DIE_LOOP); +} + +/*----------------------------------------------- + elfLordGoCharge +-----------------------------------------------*/ + +void elfLordGoCharge(edict_t *self) +{ + SetAnim(self, ANIM_CHARGE); +} + +/*----------------------------------------------- + elflord_soa_loop +-----------------------------------------------*/ + +void elflord_soa_loop(edict_t *self) +{ + SetAnim(self, ANIM_ATTACK_SOA_LOOP); +} + +/*----------------------------------------------- + elflord_soa_end +-----------------------------------------------*/ + +void elflord_soa_end(edict_t *self) +{ + self->show_hostile = false; + gi.sound(self, CHAN_WEAPON, sounds[SND_SAFIRE], 1, ATTN_NORM, 0); + SetAnim(self, ANIM_ATTACK_SOA_END); +} + +/*----------------------------------------------- + elflord_stand +-----------------------------------------------*/ + +void elflord_stand(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_HOVER); +} + +/*----------------------------------------------- + elflord_flymove +-----------------------------------------------*/ + +void elflord_flymove (edict_t *self, float dist) +{ + vec3_t forward; + + if (!M_ValidTarget(self, self->enemy)) + return; + + VectorSubtract(self->enemy->s.origin, self->s.origin, forward); + + self->ideal_yaw = vectoyaw(forward); + + M_ChangeYaw(self); + + AngleVectors(self->s.angles, forward, NULL, NULL); + + VectorMA(self->velocity, dist, forward, self->velocity); + + self->velocity[2] = self->enemy->s.origin[2] + 100 - self->absmin[2]; + + if(!elfLordCheckAttack(self)) + MG_CheckEvade(self); +} + +/*----------------------------------------------- + elflordRandomRushSound +-----------------------------------------------*/ + +void elflordRandomRushSound(edict_t *self) +{ +} + +/*----------------------------------------------- + elflord_run +-----------------------------------------------*/ + +void elflord_run(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_FLOAT_FORWARD); +} + +/*----------------------------------------------- + elflord_soa_start +-----------------------------------------------*/ + +void elflord_soa_start(edict_t *self, G_Message_t *msg) +{ + vec3_t forward, startpos; + + if (!M_ValidTarget(self, self->enemy)) + return; + + gi.sound(self, CHAN_VOICE, sounds[SND_SACHARGE], 1, ATTN_NORM, 0); + self->show_hostile = true; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorCopy(self->s.origin, startpos); + SpellCastSphereOfAnnihilation(self, + startpos, + self->s.angles, //v_angle, + forward, + 0.0, + &self->show_hostile); + SetAnim(self, ANIM_ATTACK_SOA_BTRANS); +} + +/*----------------------------------------------- + elflord_soa_charge +-----------------------------------------------*/ + +void elflord_soa_charge(edict_t *self) +{ + gi.sound(self, CHAN_VOICE, sounds[SND_SACHARGE], 1, ATTN_NORM, 0); +} + +/*----------------------------------------------- + elflord_soa_go +-----------------------------------------------*/ + +void elflord_soa_go(edict_t *self) +{ + vec3_t forward; + + gi.sound(self, CHAN_VOICE, sounds[SND_SAFIRE], 1, ATTN_NORM, 0); + self->show_hostile = false; + + AngleVectors(self->s.angles, forward, NULL, NULL); + SpellCastSphereOfAnnihilation(self, + self->s.origin, + self->s.angles, //v_angle, + forward, + 0.0, + &self->show_hostile); +} + +/*----------------------------------------------- + elflord_death_start +-----------------------------------------------*/ + +void elflord_death_start(edict_t *self, G_Message_t *msg) +{ + //Turn off a beam if it's on + if (self->targetEnt) + G_FreeEdict(self->targetEnt); + + self->health = 0; + self->max_health = 0; + M_ShowLifeMeter( self, 0, 0); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + elflord_pain +-----------------------------------------------*/ + +void elflord_pain (edict_t *self, G_Message_t *msg) +{ + if (irand(0,9)) + return; + + if(!irand(0, 1)) + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN2], 1, ATTN_NORM, 0); +} + +/*----------------------------------------------- + elflordSound +-----------------------------------------------*/ + +void elflordSound(edict_t *self, float channel, float sndindex, float atten) +{ + gi.sound(self, channel, sounds[(int)(sndindex)], 1, atten, 0); +} + +/*----------------------------------------------- + elflord_FindMoveTarget +-----------------------------------------------*/ + +void elflord_FindMoveTarget (edict_t *self) +{ + edict_t *movetarg = NULL, *lastvalid = NULL; + vec3_t vel, target; + float len; + + while((movetarg = oldfindradius(movetarg, self->s.origin, 640)) != NULL) + { + //Must be a path_corner + if (strcmp(movetarg->classname, "path_corner")) + continue; + + //Must be a specified path_corner too + if (strcmp(movetarg->targetname, "elflord")) + continue; + + if (vhlen(movetarg->s.origin, self->s.origin) < 64) + continue; + + lastvalid = movetarg; + + if (irand(0,1)) + continue; + + //TODO: Determine a velocity to get us here + VectorCopy(movetarg->s.origin, target); + target[2] = self->s.origin[2]; + + VectorSubtract(target, self->s.origin, vel); + len = VectorNormalize(vel); + + len = ( ((len / 10) / FRAMETIME) * 2 ); + + VectorScale(vel, len, self->velocity); + + return; + } + + //We randomly skipped the last possible spot, so just use that + if (lastvalid) + { + VectorCopy(lastvalid->s.origin, target); + target[2] = self->s.origin[2]; + + VectorSubtract(target, self->s.origin, vel); + len = VectorNormalize(vel); + + len = ( ((len / 10) / FRAMETIME) * 2 ); + + VectorScale(vel, len, self->velocity); + } +} + +/*----------------------------------------------- + elflord_track +-----------------------------------------------*/ + +void elflord_track(edict_t *self) +{ + trace_t trace; + vec3_t dir, newdir, endpos; + vec3_t mins = {-2, -2, -2}; + vec3_t maxs = { 2, 2, 2}; + + if (!M_ValidTarget(self, self->enemy)) + { + //Remove the beam + self->targetEnt->think = G_FreeEdict; + self->targetEnt->nextthink = level.time + 0.1; + + //Don't finish what we were doing + SetAnim(self, ANIM_HOVER); + return; + } + + VectorSubtract(self->enemy->s.origin, self->pos2, dir); + VectorNormalize(dir); + + VectorScale(self->pos1, 3 - (skill->value * 0.5), newdir); + VectorAdd(newdir, dir, newdir); + VectorScale(newdir, 1 / ((3 - (skill->value * 0.5)) + 1), newdir); + + VectorNormalize(newdir); + + VectorMA(self->s.origin, 640, newdir, endpos); + + gi.trace(self->s.origin, mins, maxs, endpos, self, MASK_SHOT, &trace); + + if (trace.ent && trace.ent->takedamage) + { + T_Damage(trace.ent, self, self, newdir, trace.endpos, trace.plane.normal, irand(ELFLORD_BEAM_MIN_DAMAGE, ELFLORD_BEAM_MAX_DAMAGE), 0, DAMAGE_NORMAL, MOD_DIED); + } + + VectorCopy(trace.endpos, self->targetEnt->s.origin); + + vectoangles(newdir, self->s.angles); + + ai_charge2(self, 0); + + VectorCopy(newdir, self->pos1); +} + +/*----------------------------------------------- + elflord_FixAngles +-----------------------------------------------*/ + +void elflord_FixAngles(edict_t *self) +{ + self->s.angles[PITCH] = 0; +} + +/*----------------------------------------------- + elflord_MoveToFinalPosition +-----------------------------------------------*/ + +void elflord_MoveToFinalPosition( edict_t *self ) +{ + edict_t *movetarg = NULL; + vec3_t vel, target; + float len; + + while((movetarg = oldfindradius(movetarg, self->s.origin, 640)) != NULL) + { + //Must be a path_corner + if (strcmp(movetarg->classname, "path_corner")) + continue; + + //Must be a specified path_corner too + if (strcmp(movetarg->targetname, "elflord_final")) + continue; + + VectorCopy(movetarg->s.origin, target); + target[2] = self->s.origin[2]; + + VectorSubtract(target, self->s.origin, vel); + len = VectorNormalize(vel); + + len = ( ((len / 10) / FRAMETIME) * 2 ); + + VectorScale(vel, len, self->velocity); + + return; + } +} + +/*----------------------------------------------- + elfLordCheckAttack +-----------------------------------------------*/ + +qboolean elfLordCheckAttack (edict_t *self) +{ + int chance, + p_chance = 0, + soa_chance = 0, + beam_chance = 0, + move_chance = 0; + + if (!M_ValidTarget(self, self->enemy)) + { + SetAnim(self, ANIM_HOVER); + return false; + } + + elflord_decell(self, 0.8); + + if (self->count < self->max_health) + { + VectorClear(self->velocity); + SetAnim(self, ANIM_COME_TO_LIFE); + return false; + } + + if (self->health < self->max_health / 3) + {//Last stage + if (!self->dmg) + { + elflord_MoveToFinalPosition(self); + SetAnim(self, ANIM_MOVE); + self->dmg = 1; + return false; + } + + if (coop->value) + { + p_chance = 50; + soa_chance = 50; + beam_chance = 0; + } + else + { + p_chance = 5; + soa_chance = 5; + beam_chance = 90; + } + } + else if (self->health < self->max_health / 1.5) + {//Second stage + p_chance = 25; + soa_chance = 75; + beam_chance = 0; + } + else + {//First stage + p_chance = 90; + soa_chance = 0; + beam_chance = 0; + } + + chance = irand(0,100); + + if(irand(0,100) < p_chance) + { + SetAnim(self, ANIM_ATTACK); + return false; + } + else if(irand(0,100) < beam_chance) + { + SetAnim(self, ANIM_ATTACK_LS); + return false; + } + else if(irand(0,100) < soa_chance) + { + SetAnim(self, ANIM_ATTACK_SOA_BTRANS); + return false; + } + + if (!self->dmg) + { + elflord_FindMoveTarget(self); + SetAnim(self, ANIM_MOVE); + return false; + } + + return false; +} + +/*----------------------------------------------- + elfLordPause +-----------------------------------------------*/ + +void elfLordPause(edict_t *self) +{ + elfLordCheckAttack(self); +} + +/*----------------------------------------------- + elfLordWakeUp +-----------------------------------------------*/ + +void elfLordWakeUp (edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_COME_TO_LIFE); +} + +/*----------------------------------------------- + elflord_face +-----------------------------------------------*/ + +void elflord_face(edict_t *self) +{ + if (!M_ValidTarget(self, self->enemy)) + return; + + ai_charge2(self, 0); +} + +static ClassResourceInfo_t resInfo; + +/*----------------------------------------------- + elflord_SlideMeter +-----------------------------------------------*/ + +void elflord_SlideMeter( edict_t *self ) +{ + self->velocity[2] = 32; + + if (self->count < self->max_health) + { + M_ShowLifeMeter( self, self->count, self->count); + self->count += self->max_health / 20; + } +} + +/*----------------------------------------------- + elflord_PreThink +-----------------------------------------------*/ + +void elflord_PreThink( edict_t *self ) +{ + if (self->enemy && self->count >= self->max_health) + { + M_ShowLifeMeter( self, self->health, self->max_health); + } + + self->next_pre_think = level.time + 0.1; +} + +/*----------------------------------------------- + ElflordStaticsInit +-----------------------------------------------*/ + +void ElflordStaticsInit() +{ + classStatics[CID_ELFLORD].msgReceivers[MSG_STAND] = elflord_stand; + classStatics[CID_ELFLORD].msgReceivers[MSG_RUN] = elflord_run; + classStatics[CID_ELFLORD].msgReceivers[MSG_FLY] = elflord_run; + classStatics[CID_ELFLORD].msgReceivers[MSG_DEATH] = elflord_death_start; + classStatics[CID_ELFLORD].msgReceivers[MSG_MISSILE] = elflord_soa_start; + classStatics[CID_ELFLORD].msgReceivers[MSG_PAIN] = elflord_pain; + classStatics[CID_ELFLORD].msgReceivers[MSG_SIGHT] = elfLordWakeUp; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/elflord/tris.fm"); + + sounds[SND_PAIN1] = gi.soundindex ("monsters/elflord/pain1.wav"); + sounds[SND_PAIN2] = gi.soundindex ("monsters/elflord/pain2.wav"); + sounds[SND_DIE] = gi.soundindex ("monsters/elflord/death1.wav"); + + //use sphere sounds + sounds[SND_SACHARGE] = gi.soundindex ("weapons/SphereGrow.wav"); + sounds[SND_SAFIRE] = gi.soundindex ("weapons/SphereFire.wav"); + sounds[SND_SAHIT] = gi.soundindex ("weapons/SphereImpact.wav"); + + sounds[SND_PROJ1] = gi.soundindex ("monsters/elflord/shoot.wav"); + sounds[SND_BEAM] = gi.soundindex ("monsters/elflord/beam.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_ELFLORD].resInfo = &resInfo; +} + +/*QUAKED SP_monster_elflord (0.5 0.5 1) (-24 -24 -64) (24 24 16) + +Celestial Watcher + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +*/ +void SP_monster_elflord (edict_t *self) +{ + // Generic Monster Initialization + if (!flymonster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_ELFLORD; + + if (!self->health) + self->health = ELFLORD_HEALTH; + + self->max_health = self->health = MonsterHealth(self->health); + + self->mass = ELFLORD_MASS; + self->yaw_speed = 20; + + self->movetype=PHYSICSTYPE_STEP; + self->flags |= FL_FLY; + self->gravity = 0.0; + self->clipmask= MASK_MONSTERSOLID; + self->svflags |= SVF_ALWAYS_SEND|SVF_BOSS|SVF_TAKE_NO_IMPACT_DMG; + self->materialtype = MAT_FLESH; + self->solid=SOLID_BBOX; + + VectorSet(self->mins, -24, -24, -64); + VectorSet(self->maxs, 24, 24, 16); + + VectorClear(self->velocity); + + self->s.modelindex = classStatics[CID_ELFLORD].resInfo->modelIndex; + + self->dmg = 0; + self->pre_think = elflord_PreThink; + self->s.skinnum = 0; + self->monsterinfo.scale = 2.0; + + self->count = 1; + self->monsterinfo.otherenemyname = "player"; + + self->s.scale = 2.0; + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + + self->next_pre_think = level.time + 0.1; + + self->s.renderfx |= RF_GLOW; + + gi.linkentity(self); +} diff --git a/Toolkit/Programming/GameCode/game/m_elflord.h b/Toolkit/Programming/GameCode/game/m_elflord.h new file mode 100644 index 0000000..5d440d2 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_elflord.h @@ -0,0 +1,94 @@ +//Elf Lord header + +typedef enum AnimID_e +{ + ANIM_HOVER, //hover + ANIM_FLOAT_FORWARD, //float forward + ANIM_CHARGE, //charge forward + ANIM_CHARGE_BTRANS, //transition to charge + ANIM_FLOAT_BACK, //float backwards (w / attack) + ANIM_DODGE_RIGHT, //dodge right + ANIM_DODGE_LEFT, //dodge left + ANIM_ATTACK_SOA_BTRANS, //attack 1 (lightning sphere) beginning + ANIM_ATTACK_SOA_LOOP, //attack 1 (lightning sphere) loop + ANIM_ATTACK_SOA_END, //attack 1 (lightning sphere) ending + ANIM_ATTACK_LS, //attack 2 (light surge) + ANIM_PAIN1, //pain + ANIM_DIE_BTRANS, //death beginning + ANIM_DIE_LOOP, //death loop + ANIM_SHIELD, //shield + ANIM_ATTACK, + ANIM_MOVE, + ANIM_WAIT, + ANIM_COME_TO_LIFE, + NUM_ANIMS +} AnimID_t; + + +typedef enum SoundID_e +{ + SND_PAIN1, + SND_PAIN2, + SND_DIE, + + SND_SACHARGE, + SND_SAFIRE, + SND_SAHIT, + + SND_PROJ1, + SND_BEAM, + + NUM_SOUNDS +} SoundID_t; + +extern animmove_t elflord_move_idle; +extern animmove_t elflord_move_run; +extern animmove_t elflord_move_charge; +extern animmove_t elflord_move_charge_trans; +extern animmove_t elflord_move_floatback; +extern animmove_t elflord_move_dodgeright; +extern animmove_t elflord_move_dodgeleft; +extern animmove_t elflord_move_soa_begin; +extern animmove_t elflord_move_soa_loop; +extern animmove_t elflord_move_soa_end; +extern animmove_t elflord_move_ls; +extern animmove_t elflord_move_pain; +extern animmove_t elflord_move_death_btrans; +extern animmove_t elflord_move_death_loop; +extern animmove_t elflord_move_shield; +extern animmove_t elflord_move_attack; +extern animmove_t elflord_move_move; +extern animmove_t elflord_move_wait; +extern animmove_t elflord_move_come_to_life; + +qboolean elfLordCheckAttack (edict_t *self); + +void elflord_decell(edict_t *self, float value); +void elflord_decide_movement (edict_t *self); +void elflord_ai_stand (edict_t *self, float dist); +void elflord_stand(edict_t *self, G_Message_t *msg); +void elflord_run(edict_t *self, G_Message_t *msg); +void elflord_death_start(edict_t *self, G_Message_t *msg); +void elflord_soa_start(edict_t *self, G_Message_t *msg); +void elflordRandomRushSound(edict_t *self); +void elflordSound(edict_t *self, float channel, float sndindex, float atten); +void elflord_flymove (edict_t *self, float dist); +void elfLordPause(edict_t *self); +void elfLordGoCharge(edict_t *self); +void elflord_soa_loop(edict_t *self); +void elflord_soa_end(edict_t *self); + +void elflord_StartBeam(edict_t *self); +void elflord_EndBeam(edict_t *self); +void elford_Attack( edict_t *self ); + +void elflord_face(edict_t *self); +void elflord_track(edict_t *self); +void elflord_SlideMeter( edict_t *self ); +void elflord_soa_go(edict_t *self); +void elflord_soa_charge(edict_t *self); +void elflord_FixAngles(edict_t *self); + +void ai_charge2(edict_t *self, float dist); +float ai_face_goal(edict_t *self); +void MG_CheckEvade (edict_t *self); diff --git a/Toolkit/Programming/GameCode/game/m_elflord_anims.c b/Toolkit/Programming/GameCode/game/m_elflord_anims.c new file mode 100644 index 0000000..e456b4d --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_elflord_anims.c @@ -0,0 +1,423 @@ +//============================================================================== +// +// m_elflord_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "g_monster.h" +#include "m_elflord_anims.h" +#include "m_elflord.h" + +void elflord_finish_death(edict_t *self); +void elflord_soa_loop(edict_t *self); +void elflord_soa_end(edict_t *self); +void ai_charge2 (edict_t *self, float dist); + + +/*---------------------------------------------------------------------- + Idle - Sit and float +-----------------------------------------------------------------------*/ +animframe_t elflord_frames_idle [] = +{ + FRAME_idle1, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle16, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle17, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle19, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle20, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle21, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle22, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle23, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL, + FRAME_idle24, NULL, 0, 0, 0, elflord_ai_stand, 0, NULL +}; +animmove_t elflord_move_idle = {24, elflord_frames_idle, NULL}; + +animframe_t elflord_frames_run [] = +{ + FRAME_ftforwd1, NULL, 0, 0, 0, elflord_flymove, 7, NULL, + FRAME_ftforwd2, NULL, 0, 0, 0, elflord_flymove, 7, elflordRandomRushSound, + FRAME_ftforwd3, NULL, 0, 0, 0, elflord_flymove, 7, NULL, + FRAME_ftforwd4, NULL, 0, 0, 0, elflord_flymove, 8, NULL, + FRAME_ftforwd5, NULL, 0, 0, 0, elflord_flymove, 8, elflordRandomRushSound, + FRAME_ftforwd6, NULL, 0, 0, 0, elflord_flymove, 8, NULL, + FRAME_ftforwd7, NULL, 0, 0, 0, elflord_flymove, 8, NULL, + FRAME_ftforwd8, NULL, 0, 0, 0, elflord_flymove, 7, elflordRandomRushSound, + FRAME_ftforwd9, NULL, 0, 0, 0, elflord_flymove, 7, NULL, + FRAME_ftforwd10,NULL, 0, 0, 0, elflord_flymove, 7, elflordRandomRushSound, + FRAME_ftforwd11,NULL, 0, 0, 0, elflord_flymove, 7, NULL +}; +animmove_t elflord_move_run = {11, elflord_frames_run, NULL}; + +animframe_t elflord_frames_charge [] = +{ + FRAME_charge3, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge4, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge5, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge6, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge7, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge8, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge9, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge10, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge11, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge12, NULL, 0, 0, 0, elflord_flymove, 12, NULL, + FRAME_charge13, NULL, 0, 0, 0, elflord_flymove, 12, NULL, +}; +animmove_t elflord_move_charge = {11, elflord_frames_charge, elfLordPause}; + +animframe_t elflord_frames_charge_trans [] = +{ + FRAME_charge1, NULL, 0, 0, 0, elflord_flymove, 8, NULL, + FRAME_charge2, NULL, 0, 0, 0, elflord_flymove, 8, NULL, +}; +animmove_t elflord_move_charge_trans = {2, elflord_frames_charge_trans, elfLordGoCharge}; + +animframe_t elflord_frames_floatback[] = +{ + FRAME_ftback1, NULL, 0, 0, 0, elflord_flymove, -1, NULL, + FRAME_ftback2, NULL, 0, 0, 0, elflord_flymove, -2, NULL, + FRAME_ftback3, NULL, 0, 0, 0, elflord_flymove, -4, NULL, + FRAME_ftback4, NULL, 0, 0, 0, elflord_flymove, -8, NULL, + FRAME_ftback5, NULL, 0, 0, 0, elflord_flymove, -16, NULL, + FRAME_ftback6, NULL, 0, 0, 0, elflord_flymove, -24, NULL, + FRAME_ftback7, NULL, 0, 0, 0, elflord_flymove, -16, NULL, + FRAME_ftback8, NULL, 0, 0, 0, elflord_flymove, -8, NULL, + FRAME_ftback9, NULL, 0, 0, 0, elflord_flymove, -4, NULL, + FRAME_ftback10, NULL, 0, 0, 0, elflord_flymove, -2, NULL, + FRAME_ftback11, NULL, 0, 0, 0, elflord_flymove, -1, NULL +}; +animmove_t elflord_move_floatback = {11, elflord_frames_floatback, elfLordPause}; + +animframe_t elflord_frames_dodgeright[] = +{ + FRAME_dgrite1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgrite2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgrite3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgrite4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgrite5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgrite6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgrite7, NULL, 0, 0, 0, ai_charge2, 0, NULL +}; +animmove_t elflord_move_dodgeright = {7, elflord_frames_dodgeright, elfLordPause}; + +animframe_t elflord_frames_dodgeleft[] = +{ + FRAME_dgleft1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgleft2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgleft3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgleft4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgleft5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgleft6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_dgleft7, NULL, 0, 0, 0, ai_charge2, 0, NULL +}; +animmove_t elflord_move_dodgeleft = {7, elflord_frames_dodgeleft, elfLordPause}; + +animframe_t elflord_frames_soa_begin[] = +{ + FRAME_attkb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb4, NULL, 0, 0, 0, NULL, 0, elflord_soa_charge, + FRAME_attkb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb13, NULL, 0, 0, 0, NULL, 0, elflord_soa_go, + FRAME_attkb14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb20, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t elflord_move_soa_begin = {20, elflord_frames_soa_begin, elfLordPause}; + +animframe_t elflord_frames_soa_loop[] = +{ + FRAME_attka1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t elflord_move_soa_loop = {1, elflord_frames_soa_loop, elflord_soa_end}; + +animframe_t elflord_frames_soa_end[] = +{ + FRAME_attka1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t elflord_move_soa_end = {2, elflord_frames_soa_end, elfLordPause}; + +animframe_t elflord_frames_ls[] = +{ + FRAME_attkb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_StartBeam, +//Held for 3 seconds (30 frames) + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, +// + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, +// + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, + FRAME_attkb16, NULL, 0, 0, 0, NULL, 0, elflord_track, +// + FRAME_attkb17, NULL, 0, 0, 0, NULL, 0, elflord_FixAngles, + FRAME_attkb18, NULL, 0, 0, 0, NULL, 0, elflord_FixAngles, + FRAME_attkb19, NULL, 0, 0, 0, NULL, 0, elflord_EndBeam, + FRAME_attkb20, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t elflord_move_ls = {50, elflord_frames_ls, elfLordPause}; + +animframe_t elflord_frames_pain[] = +{ + FRAME_pain1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain7, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t elflord_move_pain = {7, elflord_frames_pain, elfLordPause}; + +animframe_t elflord_frames_death_btrans[] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, NULL, 0, 0, 0, NULL, 0, elflord_finish_death +}; +animmove_t elflord_move_death_btrans = {6, elflord_frames_death_btrans, NULL}; + +animframe_t elflord_frames_death_loop[] = +{ + FRAME_death7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death16, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t elflord_move_death_loop = {10, elflord_frames_death_loop, M_EndDeath}; + +animframe_t elflord_frames_shield[] = +{ + FRAME_shield1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shield23, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t elflord_move_shield = {23, elflord_frames_shield, elfLordPause}; + +animframe_t elflord_frames_attack[] = +{ + FRAME_newatk1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk7, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk8, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk9, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk10, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk11, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk12, NULL, 0, 0, 0, ai_charge2, 0, elford_Attack, + FRAME_newatk13, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk14, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk15, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newatk16, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t elflord_move_attack = {16, elflord_frames_attack, elfLordPause}; + +#define ELFLORD_DECELL 0.8 + +/*---------------------------------------------------------------------- + move - hover to a nearby waypoint +-----------------------------------------------------------------------*/ +animframe_t elflord_frames_move [] = +{ + FRAME_idle1, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle2, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle3, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle4, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle5, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle6, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle7, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle8, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle9, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle10, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle11, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle12, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle13, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle14, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle15, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle16, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle17, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle18, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle19, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle20, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle21, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle22, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle23, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face, + FRAME_idle24, NULL, 0, 0, 0, elflord_decell, ELFLORD_DECELL, elflord_face +}; +animmove_t elflord_move_move = {24, elflord_frames_move, elfLordPause}; + +/*---------------------------------------------------------------------- + Idle - Sit and float +-----------------------------------------------------------------------*/ +animframe_t elflord_frames_wait [] = +{ + FRAME_idle1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, ai_charge2, 0, elfLordCheckAttack, + FRAME_idle6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, ai_charge2, 0, elfLordCheckAttack, + FRAME_idle11, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, ai_charge2, 0, elfLordCheckAttack, + FRAME_idle16, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle17, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle19, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle20, NULL, 0, 0, 0, ai_charge2, 0, elfLordCheckAttack, + FRAME_idle21, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle22, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle23, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_idle24, NULL, 0, 0, 0, ai_charge2, 0, NULL +}; +animmove_t elflord_move_wait = {24, elflord_frames_wait, elfLordCheckAttack}; + +animframe_t elflord_frames_come_to_life [] = +{ + FRAME_attka1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, +//Charge + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, +// + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, + FRAME_attka12, NULL, 0, 0, 0, NULL, 0, elflord_SlideMeter, +// + FRAME_attka13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attka15, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t elflord_move_come_to_life = {35, elflord_frames_come_to_life, elfLordCheckAttack}; + diff --git a/Toolkit/Programming/GameCode/game/m_elflord_anims.h b/Toolkit/Programming/GameCode/game/m_elflord_anims.h new file mode 100644 index 0000000..463f915 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_elflord_anims.h @@ -0,0 +1,188 @@ +// R:\Art\models/monsters\elflord + +// This file generated by qdata - Do NOT Modify + +#define FRAME_attka1 0 +#define FRAME_attka2 1 +#define FRAME_attka3 2 +#define FRAME_attka4 3 +#define FRAME_attka5 4 +#define FRAME_attka6 5 +#define FRAME_attka7 6 +#define FRAME_attka8 7 +#define FRAME_attka9 8 +#define FRAME_attka10 9 +#define FRAME_attka11 10 +#define FRAME_attka12 11 +#define FRAME_attka13 12 +#define FRAME_attka14 13 +#define FRAME_attka15 14 +#define FRAME_attkb1 15 +#define FRAME_attkb2 16 +#define FRAME_attkb3 17 +#define FRAME_attkb4 18 +#define FRAME_attkb5 19 +#define FRAME_attkb6 20 +#define FRAME_attkb7 21 +#define FRAME_attkb8 22 +#define FRAME_attkb9 23 +#define FRAME_attkb10 24 +#define FRAME_attkb11 25 +#define FRAME_attkb12 26 +#define FRAME_attkb13 27 +#define FRAME_attkb14 28 +#define FRAME_attkb15 29 +#define FRAME_attkb16 30 +#define FRAME_attkb17 31 +#define FRAME_attkb18 32 +#define FRAME_attkb19 33 +#define FRAME_attkb20 34 +#define FRAME_charge1 35 +#define FRAME_charge2 36 +#define FRAME_charge3 37 +#define FRAME_charge4 38 +#define FRAME_charge5 39 +#define FRAME_charge6 40 +#define FRAME_charge7 41 +#define FRAME_charge8 42 +#define FRAME_charge9 43 +#define FRAME_charge10 44 +#define FRAME_charge11 45 +#define FRAME_charge12 46 +#define FRAME_charge13 47 +#define FRAME_cluster 48 +#define FRAME_death1 49 +#define FRAME_death2 50 +#define FRAME_death3 51 +#define FRAME_death4 52 +#define FRAME_death5 53 +#define FRAME_death6 54 +#define FRAME_death7 55 +#define FRAME_death8 56 +#define FRAME_death9 57 +#define FRAME_death10 58 +#define FRAME_death11 59 +#define FRAME_death12 60 +#define FRAME_death13 61 +#define FRAME_death14 62 +#define FRAME_death15 63 +#define FRAME_death16 64 +#define FRAME_dgleft1 65 +#define FRAME_dgleft2 66 +#define FRAME_dgleft3 67 +#define FRAME_dgleft4 68 +#define FRAME_dgleft5 69 +#define FRAME_dgleft6 70 +#define FRAME_dgleft7 71 +#define FRAME_dgrite1 72 +#define FRAME_dgrite2 73 +#define FRAME_dgrite3 74 +#define FRAME_dgrite4 75 +#define FRAME_dgrite5 76 +#define FRAME_dgrite6 77 +#define FRAME_dgrite7 78 +#define FRAME_ftback1 79 +#define FRAME_ftback2 80 +#define FRAME_ftback3 81 +#define FRAME_ftback4 82 +#define FRAME_ftback5 83 +#define FRAME_ftback6 84 +#define FRAME_ftback7 85 +#define FRAME_ftback8 86 +#define FRAME_ftback9 87 +#define FRAME_ftback10 88 +#define FRAME_ftback11 89 +#define FRAME_ftforwd1 90 +#define FRAME_ftforwd2 91 +#define FRAME_ftforwd3 92 +#define FRAME_ftforwd4 93 +#define FRAME_ftforwd5 94 +#define FRAME_ftforwd6 95 +#define FRAME_ftforwd7 96 +#define FRAME_ftforwd8 97 +#define FRAME_ftforwd9 98 +#define FRAME_ftforwd10 99 +#define FRAME_ftforwd11 100 +#define FRAME_idle1 101 +#define FRAME_idle2 102 +#define FRAME_idle3 103 +#define FRAME_idle4 104 +#define FRAME_idle5 105 +#define FRAME_idle6 106 +#define FRAME_idle7 107 +#define FRAME_idle8 108 +#define FRAME_idle9 109 +#define FRAME_idle10 110 +#define FRAME_idle11 111 +#define FRAME_idle12 112 +#define FRAME_idle13 113 +#define FRAME_idle14 114 +#define FRAME_idle15 115 +#define FRAME_idle16 116 +#define FRAME_idle17 117 +#define FRAME_idle18 118 +#define FRAME_idle19 119 +#define FRAME_idle20 120 +#define FRAME_idle21 121 +#define FRAME_idle22 122 +#define FRAME_idle23 123 +#define FRAME_idle24 124 +#define FRAME_pain1 125 +#define FRAME_pain2 126 +#define FRAME_pain3 127 +#define FRAME_pain4 128 +#define FRAME_pain5 129 +#define FRAME_pain6 130 +#define FRAME_pain7 131 +#define FRAME_poly 132 +#define FRAME_shield1 133 +#define FRAME_shield2 134 +#define FRAME_shield3 135 +#define FRAME_shield4 136 +#define FRAME_shield5 137 +#define FRAME_shield6 138 +#define FRAME_shield7 139 +#define FRAME_shield8 140 +#define FRAME_shield9 141 +#define FRAME_shield10 142 +#define FRAME_shield11 143 +#define FRAME_shield12 144 +#define FRAME_shield13 145 +#define FRAME_shield14 146 +#define FRAME_shield15 147 +#define FRAME_shield16 148 +#define FRAME_shield17 149 +#define FRAME_shield18 150 +#define FRAME_shield19 151 +#define FRAME_shield20 152 +#define FRAME_shield21 153 +#define FRAME_shield22 154 +#define FRAME_shield23 155 +#define FRAME_newatk1 156 +#define FRAME_newatk2 157 +#define FRAME_newatk3 158 +#define FRAME_newatk4 159 +#define FRAME_newatk5 160 +#define FRAME_newatk6 161 +#define FRAME_newatk7 162 +#define FRAME_newatk8 163 +#define FRAME_newatk9 164 +#define FRAME_newatk10 165 +#define FRAME_newatk11 166 +#define FRAME_newatk12 167 +#define FRAME_newatk13 168 +#define FRAME_newatk14 169 +#define FRAME_newatk15 170 +#define FRAME_newatk16 171 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 7 + +#define MESH_IDLE1 0 +#define MESH__BODY25 1 +#define MESH__LEFTARM25 2 +#define MESH__RIGHTARM25 3 +#define MESH__HEAD25 4 +#define MESH__THECAPE25 5 +#define MESH__LIGHT25 6 diff --git a/Toolkit/Programming/GameCode/game/m_fish.c b/Toolkit/Programming/GameCode/game/m_fish.c new file mode 100644 index 0000000..ccab656 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_fish.c @@ -0,0 +1,1139 @@ +//============================================================================== +// +// m_fish.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "m_fish.h" +#include "m_fish_anim.h" +#include "g_misc.h" +#include "m_stats.h" + +extern void M_MoveFrame (edict_t *self); +void fish_hunt(edict_t *self); +void fish_think(edict_t *self); + +#define WALK_TURN_ANGLE 40 +#define RUN_TURN_ANGLE 70 +#define BITE_DIST 32 +#define FISH_FAST 160 +#define FISH_HUNT (40 + FISH_FAST) +#define FISH_SLOW 100 +#define FISH_ACTIVATE_DIST 3000.0 +#define FISH_SKIN1 0 +#define FISH_SKIN2 2 + +/*---------------------------------------------------------------------- + Fish Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[NUM_ANIMS] = +{ + &fish_move_bite, + &fish_move_melee, + &fish_move_run1, + &fish_move_run2, + &fish_move_run3, + &fish_move_walk1, + &fish_move_walk2, + &fish_move_walk3, + &fish_move_stand1, + &fish_move_pain1, + &fish_move_death, +}; + +static int sounds[NUM_SOUNDS]; + +static ClassResourceInfo_t resInfo; + +void fish_dead_pain(edict_t *self, G_Message_t *msg); + +// bring all our movedir angles up positive again +void reset_fish_movedir(edict_t *self) +{ + while (self->movedir[0] > 360) + self->movedir[0] -= 360; + while (self->movedir[0] < 0) + self->movedir[0] += 360; + + while (self->movedir[1] > 360) + self->movedir[1] -= 360; + while (self->movedir[1] < 0) + self->movedir[1] += 360; + + while (self->movedir[2] > 360) + self->movedir[2] -= 360; + while (self->movedir[2] < 0) + self->movedir[2] += 360; +} + + +//---------------------------------------------------------------------- +// Fish Run - choose a run to use +//---------------------------------------------------------------------- +void fish_run(edict_t *self) +{ + float delta; + + delta = anglemod(self->s.angles[YAW] - self->movedir[YAW]); + if (delta > 70 && delta <= 180) // Look right + { + // tell the think function we are doing the turn, so don't play with the yaw + self->ai_mood_flags = 1; + self->best_move_yaw = -RUN_TURN_ANGLE; + SetAnim(self, ANIM_RUN3); + return; + } + else if (delta > 180 && delta < 290) // Look left + { + // tell the think function we are doing the turn, so don't play with the yaw + self->ai_mood_flags = 1; + self->best_move_yaw = RUN_TURN_ANGLE; + SetAnim(self, ANIM_RUN2); + return; + } + else + { + // tell the think function we are NOT doing the turn + self->ai_mood_flags = 0; + SetAnim(self, ANIM_RUN1); + return; + } +} + +//---------------------------------------------------------------------- +// Fish Walk - choose a walk to use +//---------------------------------------------------------------------- +void fish_walk(edict_t *self) +{ + float delta; + + delta = anglemod(self->s.angles[YAW] - self->movedir[YAW]); + if (delta > 40 && delta <= 180) // Look right + { + // tell the think function we are doing the turn, so don't play with the yaw + self->ai_mood_flags = 1; + self->best_move_yaw = -WALK_TURN_ANGLE; + SetAnim(self, ANIM_WALK3); + return; + } + else if (delta > 180 && delta < 20) // Look left + { + // tell the think function we are doing the turn, so don't play with the yaw + self->ai_mood_flags = 1; + self->best_move_yaw = WALK_TURN_ANGLE; + SetAnim(self, ANIM_WALK2); + return; + } + else + { + // tell the think function we are NOT doing the turn + self->ai_mood_flags = 0; + SetAnim(self, ANIM_WALK1); + return; + } +} + +// update the yaw on the first frame of a new animation -stop jittering +void fish_update_yaw(edict_t *self) +{ + self->s.angles[YAW] += self->best_move_yaw; + self->best_move_yaw = 0; +} + + +// generic 'decided on a new direction' reaction - make us select a new direction +void fish_new_direction(edict_t *self) +{ + if (!(irand(0,1))) + self->movedir[0] = flrand(-30.0, 30.0); + else + self->movedir[0] = 0; + self->movedir[1] += flrand(-45.0, 45.0); + // bring all our movedir angles up positive again + reset_fish_movedir(self); + + // if we change direction, we might hit the same poly we just last collided with + self->shrine_type = 0; + + // decide which animation to use + if (self->ai_mood == AI_MOOD_WANDER) + { + self->speed = FISH_FAST * self->old_yaw; + fish_run(self); + } + else + { + self->speed = FISH_SLOW * self->old_yaw; + fish_walk(self); + } +} + +// generic 'hit something' reaction - make us bounce off in a new direction +void fish_bounce_direction(edict_t *self) +{ + // reverse our direction with some randomness in the angles too + VectorCopy(self->s.angles, self->movedir); + // reverse our direction + self->movedir[YAW] += 180; + self->movedir[PITCH] = 0-self->movedir[PITCH]; + // give us some randomness to my return + self->movedir[YAW] += (irand(-15,15)); + self->movedir[PITCH] += (irand(-5,5)); + + // bring all our movedir angles up positive again + reset_fish_movedir(self); + + // decide which animation to use + if (self->ai_mood == AI_MOOD_WANDER) + { + self->speed = FISH_FAST * self->old_yaw; + fish_run(self); + } + else + { + self->speed = FISH_SLOW * self->old_yaw; + fish_walk(self); + } +} + +/* +=============== +M_ChangeFishYaw + +=============== +*/ +float M_ChangeFishYaw (edict_t *ent) +{ + float ideal; + float current; + float move; + float speed; + + current = anglemod(ent->s.angles[YAW]); + ideal = ent->movedir[YAW]; + + if (current == ideal) + return false; + + move = ideal - current; + speed = ent->yaw_speed; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + ent->s.angles[YAW] = anglemod (current + move); + return move; +} + +/* +=============== +M_ChangeFishPitch + +=============== +*/ +float M_ChangeFishPitch (edict_t *ent) +{ + float ideal; + float current; + float move; + float speed; + + current = anglemod(ent->s.angles[PITCH]); + ideal = ent->movedir[PITCH]; + + if (current == ideal) + return false; + + move = ideal - current; + speed = ent->dmg_radius; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + ent->s.angles[PITCH] = anglemod (current + move); + return move; +} + +// fish check to see if we are within ACTIVATE_DIST of the player +void fish_check_distance(edict_t *self) +{ + self->nextthink = level.time + 2.0; + + // determine if we are too far from the camera to warrant animating or ai + if (gi.CheckDistances(self->s.origin, FISH_ACTIVATE_DIST)) + { + self->nextthink = level.time + FRAMETIME; + self->think = fish_think; + } + +} + + +/*------------------------------------------------------------------------- + monster_think +-------------------------------------------------------------------------*/ +void fish_think (edict_t *self) +{ + vec3_t angles; + vec3_t top, bottom; + vec3_t dir; + trace_t trace; + byte angle_byte; + + self->nextthink = level.time + FRAMETIME; + + if(!self->enemy) + FindTarget(self); + + if(self->enemy) + {//let's not hunt things out of water! + if(!self->enemy->waterlevel) + self->enemy = NULL; + } + // determine if we are too far from the camera to warrant animating or ai + if (!gi.CheckDistances(self->s.origin, FISH_ACTIVATE_DIST)) + { + self->think = fish_check_distance; + VectorClear(self->velocity); + return; + } + + // animate us + M_MoveFrame (self); + + self->nextthink = level.time + FRAMETIME; + + // we are already dead or getting hit, we don't need to do anything + if ((self->deadflag & DEAD_DEAD) || (self->deadflag & DEAD_DYING) ) + return; + + M_CatagorizePosition(self); + + // did we break the surface ? + if (self->waterlevel < 3) + { + // if we break water - don't let us target anyone anymore + self->enemy = NULL; + self->ai_mood = AI_MOOD_WANDER; + self->dmg_radius = 10; + + // make us go down good sir ! + self->movedir[0] = flrand(-35.0, -15.0); + + // only allow one of these every second for this fish + if (!self->count) + { + // create a ripple + VectorCopy(self->s.origin, top); + VectorCopy(top, bottom); + top[2] += self->maxs[2] * 0.75; + bottom[2] += self->mins[2]; + + gi.trace(top, vec3_origin, vec3_origin, bottom, self, MASK_WATER,&trace); + + if(trace.fraction <= 1.0) + { + AngleVectors(self->s.angles,dir,NULL,NULL); + VectorScale(dir,200,dir); + angle_byte = Q_ftol(((self->s.angles[YAW] + DEGREE_180)/360.0) * 255.0); + + gi.CreateEffect(NULL, FX_WATER_WAKE, 0, trace.endpos, "sbv", self->s.number, + angle_byte, dir); + + gi.sound (self, CHAN_WEAPON, sounds[SND_SPLASH], 1, ATTN_NORM, 0); + self->count = 6; + } + } + } + else + { + self->count = 0; + self->dmg_radius = 4; + } + + // make sure that the movedir angles are between 0-359, or we are in trouble on the pitch and yaw routines + // messy, but the best way to be safe + if ((self->movedir[0] < 0 || self->movedir[0] > 360)|| + (self->movedir[1] < 0 || self->movedir[1] > 360)|| + (self->movedir[2] < 0 || self->movedir[2] > 360)) + reset_fish_movedir(self); + + // move us from one angle to another slowly - unless we are moving through the "turn" anims, + // which case, the anim takes care of the YAW + + // move us in pitch if we should + M_ChangeFishPitch(self); + + VectorDegreesToRadians(self->s.angles, angles); + + if (!self->ai_mood_flags) + { + // update Yaw + M_ChangeFishYaw(self); + // update velocity + DirFromAngles(angles, self->velocity); + Vec3ScaleAssign(self->speed, self->velocity); + } + else + { + // update velocity + DirFromAngles(angles, self->velocity); + // we aren't updating Yaw, remember ? - no updating yaw velocities + self->velocity[0] = 0; + self->velocity[1] = 0; + Vec3ScaleAssign(self->speed, self->velocity); + } + + // need this for rebounds + VectorCopy(self->velocity, self->pos1); + + M_WorldEffects(self); +} + + +void fish_under_water_wake (edict_t *self) +{ + gi.CreateEffect(&self->s, FX_M_EFFECTS, CEF_OWNERS_ORIGIN, self->s.origin, "bv", FX_UNDER_WATER_WAKE, vec3_origin); +} + +void fish_swim_sound (edict_t *self, float fast) +{ + if(fast) + { + if(irand(0, 1)) + return; + + if(irand(0,1)) + gi.sound (self, CHAN_BODY, sounds[SND_FAST_SWIM1], 0.75, ATTN_IDLE, 0); + else + gi.sound (self, CHAN_BODY, sounds[SND_FAST_SWIM2], 0.75, ATTN_IDLE, 0); + } + else + { + if(irand(0, 4)) + return; + + if(irand(0,1)) + gi.sound (self, CHAN_BODY, sounds[SND_SLOW_SWIM1], 0.5, ATTN_IDLE, 0); + else + gi.sound (self, CHAN_BODY, sounds[SND_SLOW_SWIM2], 0.5, ATTN_IDLE, 0); + } +} +/*------------------------------------------------------------------------- + The fish hit something +-------------------------------------------------------------------------*/ +void fish_blocked(edict_t *self, struct trace_s *trace) +{ + vec3_t v; + float len; + + // dead fish don't rebound off stuff. + if (self->deadflag == DEAD_DEAD) + return; + + // did we hit a monster or player ? + if(trace->ent && ((trace->ent->svflags & SVF_MONSTER) || (trace->ent->client))) + { + // hit another fish - send us on our way + if (trace->ent->classID == CID_FISH) + fish_bounce_direction(self); + //we didn't, shall we attack this entity ? + //we would be able to bite him, then sure, otherwise, just bounce us off and set him as the enemy + else + { + // first decide if this guy is dead + if (trace->ent->deadflag == DEAD_DEAD) + { + fish_bounce_direction(self); + self->enemy = NULL; + } + // nope, so lets BITE THE BASTARD :) + else + { + VectorSubtract (self->s.origin, trace->ent->s.origin, v); + len = VectorLength (v); + self->enemy = trace->ent; + + if ((len < (self->maxs[0] + self->enemy->maxs[0] + BITE_DIST + 50)) && (self->dmg_radius ==4)) // Within 20 of bounding box & not out of water + { + SetAnim(self, ANIM_BITE); + self->ai_mood = AI_MOOD_ATTACK; + } + else + { + fish_hunt(self); + } + } + } + + } + // we hit a wall, or something + // reverse our direction, and the randomise a cone of projection out from that, + // and send us on our way + else + { + // did we hit a model of some type ? + if (trace->ent) + fish_bounce_direction(self); + else + // did we hit the same wall as last time ? cos if we did, we already dealt with it + if ((int)trace->surface != (int)self->shrine_type) + { + self->shrine_type = (int)trace->surface; + fish_bounce_direction(self); + } + } +} + +/*------------------------------------------------------------------------- + The fish finished a swim cycle, shall we just randomly change direction + or perhaps target a player or a bad guy ? Or maybe just idle a bit +-------------------------------------------------------------------------*/ +void finished_swim(edict_t *self) +{ + int temp; + + if (self->ai_mood == AI_MOOD_PURSUE) + { + fish_hunt(self); + return; + } + + temp = irand(0,10); + if (temp <= 3) + { + // randomly, we might like to run somewhere + if (!(irand(0,3))) + self->ai_mood = AI_MOOD_WANDER; + else + self->ai_mood = AI_MOOD_STAND; + fish_new_direction(self); + } + else + if (temp <= 5) + { + self->speed = 20; + self->ai_mood = AI_MOOD_STAND; + SetAnim(self, ANIM_STAND1); + } +} + +/*------------------------------------------------------------------------- + The fish finished a swim cycle, shall we just randomly change direction + or perhaps target a player or a bad guy ? Or maybe just idle a bit +-------------------------------------------------------------------------*/ +void finished_fish_pain(edict_t *self) +{ + // run the hell away + self->ai_mood = AI_MOOD_WANDER; + self->deadflag = DEAD_NO; + + if(self->waterlevel == 3) + fish_hunt(self); +} + +/*------------------------------------------------------------------------- + The fish finished a run swim cycle, shall we just randomly change direction + or perhaps target a player or a bad guy ? Or maybe just idle a bit +-------------------------------------------------------------------------*/ +void finished_runswim(edict_t *self) +{ + int temp; + + if (self->ai_mood == AI_MOOD_PURSUE) + { + fish_hunt(self); + return; + } + + temp = irand(0,10); + if (temp <= 3) + { + // randomly, we might like to run somewhere + if (!(irand(0,3))) + self->ai_mood = AI_MOOD_STAND; + else + self->ai_mood = AI_MOOD_WANDER; + fish_new_direction(self); + } + else + if (temp <= 5) + { + self->speed = 20; + self->ai_mood = AI_MOOD_STAND; + SetAnim(self, ANIM_STAND1); + } +} + +//---------------------------------------------------------------------- +// Fish Idle - decide whether to stay idling, or go walking somewhere +//---------------------------------------------------------------------- +void fish_idle(edict_t *self) +{ + if (self->ai_mood != AI_MOOD_PURSUE) + { + if (!(irand(0,3))) + SetAnim(self, ANIM_STAND1); + else + fish_new_direction(self); + } + else + fish_hunt(self); +} + + +//---------------------------------------------------------------------- +// Fish Death - choose a death to use +//---------------------------------------------------------------------- +void fish_dead_pain(edict_t *self, G_Message_t *msg) +{ + if(self->health<-60) + BecomeDebris(self); +} + +void fish_death(edict_t *self, G_Message_t *msg) +{ + VectorClear(self->velocity); + self->deadflag = DEAD_DEAD; + if(self->health<-60) + { + gi.sound(self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + BecomeDebris(self); + return; + } + + gi.sound (self, CHAN_WEAPON, sounds[SND_DIE], 1, ATTN_NORM, 0); + + if(self->s.skinnum == FISH_SKIN1 || self->s.skinnum == FISH_SKIN2) + self->s.skinnum += 1; + + SetAnim(self, ANIM_DEATH1); +} + +//---------------------------------------------------------------------- +// Fish Pain - choose a pain to use +//---------------------------------------------------------------------- +void fish_pain(edict_t *self, G_Message_t *msg) +{ + int temp, damage; + qboolean force_pain; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_pain, &damage, &temp); + + if(!force_pain) + if(!flrand(0,3)) + return; + + + SetAnim(self, ANIM_PAIN1); + VectorClear(self->velocity); + self->deadflag = DEAD_DYING; + + if(!irand(0,2)) + if(self->s.skinnum == FISH_SKIN1 || self->s.skinnum == FISH_SKIN2) + self->s.skinnum += 1; + + if (irand(0, 1)) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + } + else + { + gi.sound (self, CHAN_WEAPON, sounds[SND_PAIN2], 1, ATTN_NORM, 0); + } + +} + + +//---------------------------------------------------------------------- +// Fish Melee - choose a melee to use +//---------------------------------------------------------------------- +void fish_melee(edict_t *self, G_Message_t *msg) +{ + + if (self->enemy->health <= 0) + { + if (!FindTarget(self)) + { + SetAnim(self, ANIM_STAND1); + return; + } + } + + SetAnim(self, ANIM_MELEE); +} + +/*---------------------------------------------------------------------- + + ACTION FUNCTIONS FOR THE FISH + + Death stuff + +-----------------------------------------------------------------------*/ +//---------------------------------------------------------------------- +// Fish Deadbob - (not really sure I like the name of this one) +//---------------------------------------------------------------------- +void fish_deadbob(edict_t *self) +{ + + if (self->velocity[2] > 0) + { + if (self->s.origin[2] > self->monsterinfo.misc_debounce_time + flrand(3.0, 6.0)) // So it doesn't always go to the same height + self->velocity[2] = flrand(-7.0, -2.0); + } + else + { + if (self->s.origin[2] < self->monsterinfo.misc_debounce_time) + self->velocity[2] = flrand(2.0, 7.0); + } + + self->think = fish_deadbob; + self->nextthink = level.time + .2; +} + +//---------------------------------------------------------------------- +// Fish float - make the fish float to the surface +//---------------------------------------------------------------------- + + +void fish_deadfloat(edict_t *self) +{ + self->think = fish_deadfloat; + self->nextthink = level.time + .1; + + M_CatagorizePosition(self); + + if(self->waterlevel == 3) + { + if(self->velocity[2]<10) + self->velocity[2]+=10; + else + self->velocity[2] = 20; // Just in case somethimg blocked it going up + } + else if(self->waterlevel < 2) + { + if(self->velocity[2] > -150) + self->velocity[2] -= 50; // Fall back in now! + else + self->velocity[2] = -200; + } + else + { + self->monsterinfo.misc_debounce_time = self->s.origin[2]; + self->think = fish_deadbob; + self->nextthink = level.time + .1; + } +} + +//---------------------------------------------------------------------- +// Fish Dead - he's dead, figure how far it is to the top of the water so he can float +//---------------------------------------------------------------------- +void fish_dead(edict_t *self) +{ + self->deadflag = DEAD_DEAD; + self->takedamage = DAMAGE_YES; + + VectorClear(self->velocity); + + self->think = fish_deadfloat; + self->nextthink = level.time + 0.1; + + // stop the fish making bubbles + gi.RemoveEffects(&self->s, FX_WATER_BUBBLE); + gi.RemovePersistantEffect(self->PersistantCFX); + self->PersistantCFX = 0; + + gi.linkentity (self); +} + +// he bit the player - decide what to do +void fishbite (edict_t *self) +{ + vec3_t v; + float scale; + float len; + + if (!self->enemy) + return; + + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + + if (len < (self->maxs[0] + self->enemy->maxs[0] + BITE_DIST)) // Within 20 of bounding box + { + if (irand(0, 1)) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEHIT1], 1, ATTN_NORM, 0); + } + else + { + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEHIT2], 1, ATTN_NORM, 0); + } + + scale = -3; + VectorScale(v, scale, v); + VectorAdd (self->enemy->velocity, v, self->enemy->velocity); + + T_Damage (self->enemy, self, self, vec3_origin, self->enemy->s.origin, vec3_origin, irand(FISH_DMG_BITE_MIN, FISH_DMG_BITE_MAX) , 0, DAMAGE_DISMEMBER,MOD_DIED); + + } + else // A misssss + { + if (irand(0, 1)) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEMISS1], 1, ATTN_NORM, 0); + } + else + { + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEMISS2], 1, ATTN_NORM, 0); + } + } +} + +void fish_target(edict_t *self) +{ + vec3_t dir; + + if (self->enemy) + { + // figure out the vector from the fish to the target + VectorSubtract(self->enemy->s.origin, self->s.origin, dir); + // normalise it + Vec3Normalize(dir); + if(Vec3IsZero(dir)) + return; + // figure out the angles we want + AnglesFromDir(dir, self->movedir); + VectorRadiansToDegrees (self->movedir, self->movedir); + } +} + +// figure out where our prey is, and go get him +void fish_hunt(edict_t *self) +{ + + // make sure we still have a target - bouncing off stuff tends to clear it out + if (!self->enemy) + { + FindTarget(self); + // if we can't find one, let him just swim on alone.. + if (!self->enemy) + { + if(self->curAnimID == ANIM_PAIN1) + { + self->speed = 20; + self->ai_mood = AI_MOOD_STAND; + SetAnim(self, ANIM_STAND1); + } + return; + } + } + + fish_target(self); + // set movement type + self->ai_mood = AI_MOOD_PURSUE; + // make us run after it + self->speed = FISH_HUNT * self->old_yaw; + fish_run(self); +} + +// we are done attacking.. what do we do now ? attack again ? +void fish_pause (edict_t *self) +{ + vec3_t v; + float len; + + FindTarget(self); + + // is the target either not there or already dead ? + if (!self->enemy || self->enemy->deadflag == DEAD_DEAD) + { + self->enemy = NULL; + self->ai_mood = AI_MOOD_WANDER; + fish_bounce_direction(self); + return;//right? crashes if not! + } + + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + + // we are close enough to bite + if (len < (self->maxs[0] + self->enemy->maxs[0] + BITE_DIST)) // Within BITE_DIST of bounding box + { + VectorClear(self->velocity); + // if he's low on health, eat the bastard.. + if (self->enemy->health < (self->enemy->max_health / 2)) + { + SetAnim(self, ANIM_MELEE); + self->ai_mood = AI_MOOD_ATTACK; + } + // other wise a quick bite + else + { + // randomly swim off anyway + if (!irand(0,4)) + { + self->ai_mood = AI_MOOD_ATTACK; + SetAnim(self, ANIM_BITE); + } + else + { + self->enemy = NULL; + self->ai_mood = AI_MOOD_WANDER; + fish_bounce_direction(self); + } + } + } + + else + { + if (len < 120) // close enough to just zoom in on + { + fish_hunt(self); + } + else // far enough that I break off.. + { + self->enemy = NULL; + self->ai_mood = AI_MOOD_WANDER; + fish_bounce_direction(self); + } + } +} + + + +// shall we chase after someone ? +void fish_chase(edict_t *self) +{ + + // shall we hunt someone ? + if (irand(0,1)) + return; + + // find a target to chase after + FindTarget(self); + + // if we got one.. + if (self->enemy) + fish_hunt(self); +} + +/*---------------------------------------------------------------------- + + SOUND FUNCTIONS FOR THE FISH + +-----------------------------------------------------------------------*/ + +// random growl +void fish_growl (edict_t *self) +{ + int chance; + + return; + chance = irand(0, 200); + + if (chance > 60) + { + } + else if (chance < 20 ) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_GROWL1], 1, ATTN_NORM, 0); + } + else if (chance < 40) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_GROWL2], 1, ATTN_NORM, 0); + } + else + { + gi.sound (self, CHAN_WEAPON, sounds[SND_GROWL3], 1, ATTN_NORM, 0); + } +} + + +void FishStaticsInit() +{ + classStatics[CID_FISH].msgReceivers[MSG_PAIN] = fish_pain; + classStatics[CID_FISH].msgReceivers[MSG_DEATH] = fish_death; + classStatics[CID_FISH].msgReceivers[MSG_DEATH_PAIN] = fish_dead_pain; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/fish/tris.fm"); + + sounds[SND_PAIN1] = gi.soundindex ("monsters/fish/pain1.wav"); + sounds[SND_PAIN2] = gi.soundindex ("monsters/fish/pain2.wav"); + sounds[SND_DIE] = gi.soundindex ("monsters/fish/death1.wav"); + sounds[SND_GIB] = gi.soundindex ("monsters/fish/gib.wav"); + sounds[SND_BITEHIT1] = gi.soundindex ("monsters/fish/meleehit1.wav"); + sounds[SND_BITEHIT2] = gi.soundindex ("monsters/fish/meleehit2.wav"); + sounds[SND_BITEMISS1] = gi.soundindex ("monsters/fish/meleemiss1.wav"); + sounds[SND_BITEMISS2] = gi.soundindex ("monsters/fish/meleemiss2.wav"); + sounds[SND_GROWL1] = gi.soundindex ("monsters/fish/growl1.wav"); + sounds[SND_GROWL2] = gi.soundindex ("monsters/fish/growl2.wav"); + sounds[SND_GROWL3] = gi.soundindex ("monsters/fish/growl3.wav"); + sounds[SND_SPLASH] = gi.soundindex("player/breaststroke.wav"); + + sounds[SND_SLOW_SWIM1] = gi.soundindex("monsters/fish/fishmov3.wav"); + sounds[SND_SLOW_SWIM2] = gi.soundindex("monsters/fish/fishmov4.wav"); + sounds[SND_FAST_SWIM1] = gi.soundindex("monsters/fish/fishmov1.wav"); + sounds[SND_FAST_SWIM2] = gi.soundindex("monsters/fish/fishmov2.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_FISH].resInfo = &resInfo; +} + +/*QUAKED monster_fish (1 .5 0) (-25 -25 -14) (25 25 14) + +The fish + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) +*/ + +void SP_monster_fish (edict_t *self) +{ + level.total_monsters++; + + if (deathmatch->value == 1) + { + G_FreeEdict (self); + return; + } + + // Generic Monster Initialization + + if (!self->health) + self->health = MonsterHealth(FISH_HEALTH); + + //Apply to the end result (whether designer set or not) + self->health = MonsterHealth(self->health); + + self->nextthink = level.time + FRAMETIME; + self->svflags |= SVF_MONSTER | SVF_TAKE_NO_IMPACT_DMG | SVF_DO_NO_IMPACT_DMG; + self->svflags &= ~SVF_DEADMONSTER; + self->s.renderfx |= RF_FRAMELERP; + self->takedamage = DAMAGE_AIM; + self->max_health = self->health; + self->clipmask = MASK_MONSTERSOLID; + self->materialtype = MAT_FLESH; + self->flags |= FL_SWIM|FL_NO_KNOCKBACK; + + self->s.effects|=EF_CAMERA_NO_CLIP; + + // random skin of three + if(irand(0, 1)) + self->s.skinnum = FISH_SKIN1; + else + self->s.skinnum = FISH_SKIN2; + + self->deadflag = DEAD_NO; + self->isBlocked = fish_blocked; + self->ai_mood = AI_MOOD_STAND; + self->ai_mood_flags = 0; + self->gravity = self->best_move_yaw = 0; + self->wakeup_distance = 1024; + self->monsterinfo.aiflags |= AI_NIGHTVISION; + + self->monsterinfo.aiflags |= AI_NO_ALERT;//pay no attention to alert ents + + VectorCopy (self->s.origin, self->s.old_origin); + VectorCopy (self->s.angles, self->movedir); + + if (!self->mass) + self->mass = FISH_MASS; + + self->s.frame = 0; + + self->oldenemy_debounce_time = -1; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_FISH; + self->think = fish_check_distance; + self->nextthink = level.time + FRAMETIME; + + self->yaw_speed = 11; + self->dmg_radius = 4; + // random(ish) speed + self->old_yaw = flrand(0.65,1.0); + + self->movetype=PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + self->s.modelindex = classStatics[CID_FISH].resInfo->modelIndex; + + self->shrine_type = 0; + + if (self->s.scale == 1) + self->s.scale = self->monsterinfo.scale = MODEL_SCALE * flrand(0.5,1.0); + + VectorSet(self->mins, -16, -16, -8); + VectorSet(self->maxs, 16, 16, 8); + + // scale the max's and mins according to scale of model + Vec3ScaleAssign(self->s.scale, self->mins); + Vec3ScaleAssign(self->s.scale, self->maxs); + + // give us the bubble spawner + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, + FX_WATER_BUBBLE, + CEF_OWNERS_ORIGIN | CEF_BROADCAST, + NULL, + ""); + + SetAnim(self, ANIM_STAND1); + + gi.linkentity(self); + + M_CatagorizePosition(self); +} diff --git a/Toolkit/Programming/GameCode/game/m_fish.h b/Toolkit/Programming/GameCode/game/m_fish.h new file mode 100644 index 0000000..fe4864e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_fish.h @@ -0,0 +1,70 @@ +typedef enum AnimID_e +{ + ANIM_BITE, + ANIM_MELEE, + ANIM_RUN1, + ANIM_RUN2, + ANIM_RUN3, + ANIM_WALK1, + ANIM_WALK2, + ANIM_WALK3, + ANIM_STAND1, + ANIM_PAIN1, + ANIM_DEATH1, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PAIN1, + SND_PAIN2, + SND_DIE, + SND_GIB, + SND_BITEHIT1, + SND_BITEHIT2, + SND_BITEMISS1, + SND_BITEMISS2, + SND_GROWL1, + SND_GROWL2, + SND_GROWL3, + SND_SPLASH, + SND_SLOW_SWIM1, + SND_SLOW_SWIM2, + SND_FAST_SWIM1, + SND_FAST_SWIM2, + NUM_SOUNDS +} SoundID_t; + + +extern animmove_t fish_move_bite; +extern animmove_t fish_move_melee; +extern animmove_t fish_move_run1; +extern animmove_t fish_move_run2; +extern animmove_t fish_move_run3; +extern animmove_t fish_move_walk1; +extern animmove_t fish_move_walk2; +extern animmove_t fish_move_walk3; +extern animmove_t fish_move_stand1; +extern animmove_t fish_move_pain1; +extern animmove_t fish_move_death; + +void fish_pain(edict_t *self, G_Message_t *msg); +void fish_death(edict_t *self, G_Message_t *msg); + +void fish_dead(edict_t *self); +void fish_growl (edict_t *self); +void fishbite (edict_t *self); +void fish_idle(edict_t *self); +void finished_swim(edict_t *self); +void finished_runswim(edict_t *self); +void fish_walk(edict_t *self); +void fish_run(edict_t *self); +void finished_fish_pain(edict_t *self); +void fish_update_yaw(edict_t *self); +void fish_pause(edict_t *self); +void fish_chase(edict_t *self); +void fish_target(edict_t *self); +void fish_swim_sound (edict_t *self, float fast); +void fish_under_water_wake (edict_t *self); + + diff --git a/Toolkit/Programming/GameCode/game/m_fish_anim.c b/Toolkit/Programming/GameCode/game/m_fish_anim.c new file mode 100644 index 0000000..b65766e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_fish_anim.c @@ -0,0 +1,279 @@ +//============================================================================== +// +// m_fish.c +// +// Heretic II +// Copyright 1998 Raven Software +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_fish_anim.h" +#include "m_fish.h" + +#define FISH_WALK_SPEED 3 +#define FISH_RUN_SPEED 7 +#define FISH_FLEE_SPEED 9 + + +/*---------------------------------------------------------------------- + Fish Melee1 - +-----------------------------------------------------------------------*/ +animframe_t fish_frames_melee [] = +{ + FRAME_attfrnzy1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_attfrnzy2, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy3, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy4, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy5, NULL, 0, 0, 0, NULL, 0, fishbite, + FRAME_attfrnzy6, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy7, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy8, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy9, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy10, NULL, 0, 0, 0, NULL, 0, fishbite, + FRAME_attfrnzy11, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy12, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy13, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attfrnzy14, NULL, 0, 0, 0, NULL, 0, fish_target, +}; + +animmove_t fish_move_melee = {14, fish_frames_melee, fish_pause}; + + +/*---------------------------------------------------------------------- + Fish bite - +-----------------------------------------------------------------------*/ +animframe_t fish_frames_bite [] = +{ + FRAME_attbite1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_attbite2, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attbite3, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attbite4, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attbite5, NULL, 0, 0, 0, NULL, 0, fish_target, + FRAME_attbite6, NULL, 0, 0, 0, NULL, 0, fishbite, + FRAME_attbite7, NULL, 0, 0, 0, NULL, 0, fish_target, +}; + +animmove_t fish_move_bite = {7, fish_frames_bite, fish_pause}; + +/*---------------------------------------------------------------------- + Fish Run1 - +-----------------------------------------------------------------------*/ +animframe_t fish_frames_run1 [] = +{ + FRAME_swim1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_swim2, NULL, 0, 0, 0, NULL, 0, fish_under_water_wake, + FRAME_swim3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swim4, NULL, 0, 0, 0, fish_swim_sound, 1, fish_growl, + FRAME_swim5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swim6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swim7, NULL, 0, 0, 0, NULL, 0, fish_growl, + FRAME_swim8, NULL, 0, 0, 0, fish_swim_sound, 1, fish_chase, +}; + +animmove_t fish_move_run1 = {8, fish_frames_run1, finished_runswim}; + +/*---------------------------------------------------------------------- + Fish Run2 - +-----------------------------------------------------------------------*/ +animframe_t fish_frames_run2 [] = +{ + FRAME_swimLEFT1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_swimLEFT2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimLEFT3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimLEFT4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimLEFT5, NULL, 0, 0, 0, fish_swim_sound, 1, NULL, + FRAME_swimLEFT6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimLEFT7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimLEFT8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimLEFT9, NULL, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t fish_move_run2 = {9, fish_frames_run2, fish_run}; + +/*---------------------------------------------------------------------- + Fish Run3 - +-----------------------------------------------------------------------*/ +animframe_t fish_frames_run3 [] = +{ + FRAME_swimRIGHT1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_swimRIGHT2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimRIGHT3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimRIGHT4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimRIGHT5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimRIGHT6, NULL, 0, 0, 0, fish_swim_sound, 1, NULL, + FRAME_swimRIGHT7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimRIGHT8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swimRIGHT9, NULL, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t fish_move_run3 = {9, fish_frames_run3, fish_run}; + +/*---------------------------------------------------------------------- + Fish Walk1 - +-----------------------------------------------------------------------*/ +animframe_t fish_frames_walk1 [] = +{ + FRAME_fishpat1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_fishpat2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat7, NULL, 0, 0, 0, NULL, 0, fish_growl, + FRAME_fishpat8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat9, NULL, 0, 0, 0, fish_swim_sound, 0, NULL, + FRAME_fishpat10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat11, NULL, 0, 0, 0, NULL, 0, fish_chase, + FRAME_fishpat12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat19, NULL, 0, 0, 0, NULL, 0, fish_growl, + FRAME_fishpat20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat21, NULL, 0, 0, 0, fish_swim_sound, 0, NULL, + FRAME_fishpat22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fishpat24, NULL, 0, 0, 0, NULL, 0, fish_chase +}; + +animmove_t fish_move_walk1 = {24, fish_frames_walk1, finished_swim}; + + + +/*---------------------------------------------------------------------- + Fish Walk2 - swim to the left +-----------------------------------------------------------------------*/ +animframe_t fish_frames_walk2 [] = +{ + FRAME_slowturnl1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_slowturnl2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnl3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnl4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnl5, NULL, 0, 0, 0, fish_swim_sound, 0, NULL, + FRAME_slowturnl6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnl7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnl8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnl9, NULL, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t fish_move_walk2 = {9, fish_frames_walk2, fish_walk}; + +/*---------------------------------------------------------------------- + Fish Walk3 - Swim to the right +-----------------------------------------------------------------------*/ +animframe_t fish_frames_walk3 [] = +{ + FRAME_slowturnr1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_slowturnr2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnr3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnr4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnr5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnr6, NULL, 0, 0, 0, fish_swim_sound, 0, NULL, + FRAME_slowturnr7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnr8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slowturnr9, NULL, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t fish_move_walk3 = {9, fish_frames_walk3, fish_walk}; + +/*---------------------------------------------------------------------- + Fish Stand1 - +-----------------------------------------------------------------------*/ +animframe_t fish_frames_stand1 [] = +{ + + FRAME_fishpat1, NULL, 0, 0, 0, ai_stand, 0, fish_update_yaw, + FRAME_fishpat2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat9, NULL, 0, 0, 0, fish_swim_sound, 0, NULL, + FRAME_fishpat10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat20, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat21, NULL, 0, 0, 0, fish_swim_sound, 0, NULL, + FRAME_fishpat22, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat23, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fishpat24, NULL, 0, 0, 0, ai_stand, 0, fish_chase, + +}; + +animmove_t fish_move_stand1 = {24, fish_frames_stand1, fish_idle }; + + +/*---------------------------------------------------------------------- + Fish Pain1 - +-----------------------------------------------------------------------*/ +animframe_t fish_frames_pain1 [] = +{ + FRAME_pain1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_pain2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain7, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t fish_move_pain1 = {7, fish_frames_pain1, finished_fish_pain }; + +/*---------------------------------------------------------------------- + Fish Death1 - +-----------------------------------------------------------------------*/ +animframe_t fish_frames_death [] = +{ + FRAME_Death1, NULL, 0, 0, 0, NULL, 0, fish_update_yaw, + FRAME_Death2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death32, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Death33, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t fish_move_death = {33, fish_frames_death, fish_dead}; + diff --git a/Toolkit/Programming/GameCode/game/m_fish_anim.h b/Toolkit/Programming/GameCode/game/m_fish_anim.h new file mode 100644 index 0000000..3611de4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_fish_anim.h @@ -0,0 +1,155 @@ +// R:\Art\models/monsters\fish + +// This file generated by qdata - Do NOT Modify + +#define FRAME_attbite1 0 +#define FRAME_attbite2 1 +#define FRAME_attbite3 2 +#define FRAME_attbite4 3 +#define FRAME_attbite5 4 +#define FRAME_attbite6 5 +#define FRAME_attbite7 6 +#define FRAME_attfrnzy1 7 +#define FRAME_attfrnzy2 8 +#define FRAME_attfrnzy3 9 +#define FRAME_attfrnzy4 10 +#define FRAME_attfrnzy5 11 +#define FRAME_attfrnzy6 12 +#define FRAME_attfrnzy7 13 +#define FRAME_attfrnzy8 14 +#define FRAME_attfrnzy9 15 +#define FRAME_attfrnzy10 16 +#define FRAME_attfrnzy11 17 +#define FRAME_attfrnzy12 18 +#define FRAME_attfrnzy13 19 +#define FRAME_attfrnzy14 20 +#define FRAME_attfrnzy15 21 +#define FRAME_attfrnzy16 22 +#define FRAME_attfrnzy17 23 +#define FRAME_attfrnzy18 24 +#define FRAME_Death1 25 +#define FRAME_Death2 26 +#define FRAME_Death3 27 +#define FRAME_Death4 28 +#define FRAME_Death5 29 +#define FRAME_Death6 30 +#define FRAME_Death7 31 +#define FRAME_Death8 32 +#define FRAME_Death9 33 +#define FRAME_Death10 34 +#define FRAME_Death11 35 +#define FRAME_Death12 36 +#define FRAME_Death13 37 +#define FRAME_Death14 38 +#define FRAME_Death15 39 +#define FRAME_Death16 40 +#define FRAME_Death17 41 +#define FRAME_Death18 42 +#define FRAME_Death19 43 +#define FRAME_Death20 44 +#define FRAME_Death21 45 +#define FRAME_Death22 46 +#define FRAME_Death23 47 +#define FRAME_Death24 48 +#define FRAME_Death25 49 +#define FRAME_Death26 50 +#define FRAME_Death27 51 +#define FRAME_Death28 52 +#define FRAME_Death29 53 +#define FRAME_Death30 54 +#define FRAME_Death31 55 +#define FRAME_Death32 56 +#define FRAME_Death33 57 +#define FRAME_fishpat1 58 +#define FRAME_fishpat2 59 +#define FRAME_fishpat3 60 +#define FRAME_fishpat4 61 +#define FRAME_fishpat5 62 +#define FRAME_fishpat6 63 +#define FRAME_fishpat7 64 +#define FRAME_fishpat8 65 +#define FRAME_fishpat9 66 +#define FRAME_fishpat10 67 +#define FRAME_fishpat11 68 +#define FRAME_fishpat12 69 +#define FRAME_fishpat13 70 +#define FRAME_fishpat14 71 +#define FRAME_fishpat15 72 +#define FRAME_fishpat16 73 +#define FRAME_fishpat17 74 +#define FRAME_fishpat18 75 +#define FRAME_fishpat19 76 +#define FRAME_fishpat20 77 +#define FRAME_fishpat21 78 +#define FRAME_fishpat22 79 +#define FRAME_fishpat23 80 +#define FRAME_fishpat24 81 +#define FRAME_pain1 82 +#define FRAME_pain2 83 +#define FRAME_pain3 84 +#define FRAME_pain4 85 +#define FRAME_pain5 86 +#define FRAME_pain6 87 +#define FRAME_pain7 88 +#define FRAME_partfly 89 +#define FRAME_swim1 90 +#define FRAME_swim2 91 +#define FRAME_swim3 92 +#define FRAME_swim4 93 +#define FRAME_swim5 94 +#define FRAME_swim6 95 +#define FRAME_swim7 96 +#define FRAME_swim8 97 +#define FRAME_swimLEFT1 98 +#define FRAME_swimLEFT2 99 +#define FRAME_swimLEFT3 100 +#define FRAME_swimLEFT4 101 +#define FRAME_swimLEFT5 102 +#define FRAME_swimLEFT6 103 +#define FRAME_swimLEFT7 104 +#define FRAME_swimLEFT8 105 +#define FRAME_swimLEFT9 106 +#define FRAME_swimRIGHT1 107 +#define FRAME_swimRIGHT2 108 +#define FRAME_swimRIGHT3 109 +#define FRAME_swimRIGHT4 110 +#define FRAME_swimRIGHT5 111 +#define FRAME_swimRIGHT6 112 +#define FRAME_swimRIGHT7 113 +#define FRAME_swimRIGHT8 114 +#define FRAME_swimRIGHT9 115 +#define FRAME_slowturnr1 116 +#define FRAME_slowturnr2 117 +#define FRAME_slowturnr3 118 +#define FRAME_slowturnr4 119 +#define FRAME_slowturnr5 120 +#define FRAME_slowturnr6 121 +#define FRAME_slowturnr7 122 +#define FRAME_slowturnr8 123 +#define FRAME_slowturnr9 124 +#define FRAME_slowturnl1 125 +#define FRAME_slowturnl2 126 +#define FRAME_slowturnl3 127 +#define FRAME_slowturnl4 128 +#define FRAME_slowturnl5 129 +#define FRAME_slowturnl6 130 +#define FRAME_slowturnl7 131 +#define FRAME_slowturnl8 132 +#define FRAME_slowturnl9 133 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 12 + +#define MESH_BASEBIN 0 +#define MESH__JAW 1 +#define MESH__FRFINLFT 2 +#define MESH__FRFINRT 3 +#define MESH__DORSALFIN 4 +#define MESH__SECFINLFT 5 +#define MESH__SECFINRT 6 +#define MESH__BODY 7 +#define MESH__TAILFIN 8 +#define MESH__HEAD 9 +#define MESH__UPTEETH 10 +#define MESH__LOWTEETH 11 diff --git a/Toolkit/Programming/GameCode/game/m_gkrokon.c b/Toolkit/Programming/GameCode/game/m_gkrokon.c new file mode 100644 index 0000000..ea2c6a5 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_gkrokon.c @@ -0,0 +1,1186 @@ +//============================================================================== +// +// m_gkrokon.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" +#include "decals.h" +#include "g_playstats.h" +#include "m_gkrokon.h" +#include "m_gkrokon_anim.h" +#include "m_stats.h" +#include "g_HitLocation.h" + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + +static animmove_t *Animations[NUM_ANIMS] = +{ + &GkrokonMoveStand1, + &GkrokonMoveStand2, + &GkrokonMoveStand3, + &GkrokonMoveStand4, + &GkrokonMoveCrouch1, + &GkrokonMoveCrouch2, + &GkrokonMoveCrouch3, + &GkrokonMoveWalk1, + &GkrokonMoveRun1, + &GkrokonMoveRun2, + &GkrokonMoveJump1, + &GkrokonMoveForcedJump, + &GkrokonMoveMeleeAttack1, + &GkrokonMoveMeleeAttack2, + &GkrokonMoveMissileAttack1, + &GkrokonMoveEat1, + &GkrokonMoveEat2, + &GkrokonMoveEat3, + &GkrokonMovePain1, + &GkrokonMoveDeath1, + &GkrokonMoveHop1, + &GkrokonMoveRunAway, + &GkrokonMoveMissileAttack2, + &GkrokonMoveDelay +}; + +void ThrowBodyPart(edict_t *self, vec3_t *spot, int BodyPart, float damage, int frame); +/* + + Spoo functions + +*/ + +/*----------------------------------------------- + create_gkrokon_spoo +-----------------------------------------------*/ + +void create_gkrokon_spoo(edict_t *Spoo) +{ + Spoo->movetype=PHYSICSTYPE_FLY; + Spoo->solid=SOLID_BBOX; + Spoo->classname="Gkrokon_Spoo"; + Spoo->touch=GkrokonSpooTouch; + Spoo->isBlocked=GkrokonSpooTouch2; + Spoo->dmg=1.0; + Spoo->clipmask = MASK_SHOT; + Spoo->nextthink = level.time + FRAMETIME; + VectorSet(Spoo->mins,-1.0,-1.0,-1.0); + VectorSet(Spoo->maxs,1.0,1.0,1.0); + Spoo->s.effects = EF_CAMERA_NO_CLIP; +} + +/*----------------------------------------------- + reflect_spoo +-----------------------------------------------*/ + +void reflect_spoo(edict_t *self, edict_t *Spoo) +{ + create_gkrokon_spoo(Spoo); + + Spoo->enemy=self->enemy; + Spoo->owner=self->owner; + Spoo->s.scale=self->s.scale; + Spoo->dmg = self->dmg; + + VectorCopy(self->s.origin, Spoo->s.origin); + Create_rand_relect_vect(self->velocity, Spoo->velocity); + Vec3ScaleAssign(GKROKON_SPOO_SPEED/2,Spoo->velocity); + vectoangles(Spoo->velocity, Spoo->s.angles); + + gi.linkentity(Spoo); + + gi.CreateEffect(&Spoo->s, + FX_SPOO, + CEF_OWNERS_ORIGIN, + Spoo->s.origin, + ""); + + Spoo->reflect_debounce_time = self->reflect_debounce_time -1; +} + +/*----------------------------------------------- + GkrokonSpooTouch2 +-----------------------------------------------*/ + +void GkrokonSpooTouch2(edict_t *self,trace_t *trace) +{ + GkrokonSpooTouch(self,trace->ent,(cplane_t *)&trace->plane,(csurface_t *)trace->surface); +} + +/*----------------------------------------------- + GkrokonSpooTouch +-----------------------------------------------*/ + +void GkrokonSpooTouch(edict_t *self,edict_t *Other,cplane_t *Plane,csurface_t *Surface) +{ + vec3_t Origin, ScorchOrigin, planeDir; + edict_t *Spoo; + + if(Surface&&(Surface->flags&SURF_SKY)) + { + G_FreeEdict(self); + return; + } + + // are we reflecting ? + if (EntReflecting(Other, true, true) && self->reflect_debounce_time) + { + Spoo = G_Spawn(); + reflect_spoo(self, Spoo); + G_SetToFree(self); + return; + } + + // Calculate the position for the explosion entity. + VectorMA(self->s.origin,-16,self->velocity,Origin); + + if(Other->takedamage) + { + self->dmg = irand(GKROKON_DMG_SPOO_MIN, GKROKON_DMG_SPOO_MAX); + T_Damage(Other,self,self->owner,self->movedir,Other->s.origin,Plane->normal,self->dmg,self->dmg,0,MOD_DIED); + } + else + { + VectorMA(self->s.origin,-16.0,self->movedir,self->s.origin); + } + + T_DamageRadius(self, self->owner, self, 5.0, + self->dmg, self->dmg/4, DAMAGE_NO_KNOCKBACK|DAMAGE_ATTACKER_IMMUNE,MOD_DIED); + + gi.RemoveEffects(&self->s, 0); + + if(IsDecalApplicable(self, Other, self->s.origin, Surface, Plane, planeDir)) + { + VectorCopy(self->s.origin, ScorchOrigin); + gi.CreateEffect(NULL, + FX_SCORCHMARK, + 0, + ScorchOrigin, + "d", + planeDir); + } + // Splatter some spoo over the surface. + VectorCopy(self->s.origin, ScorchOrigin); + + gi.CreateEffect(NULL, + FX_SPOO_SPLAT, + 0, + ScorchOrigin, + "d", + planeDir); + + gi.sound(self,CHAN_WEAPON,gi.soundindex("monsters/rat/gib.wav"),1,ATTN_NORM,0); + + G_SetToFree(self); +} + +/*----------------------------------------------- + GkrokonSpoo +-----------------------------------------------*/ + +void GkrokonSpoo(edict_t *self) +{ + vec3_t Forward, up, vf; + edict_t *Spoo; + float edist; + + if(!self->enemy) + return; + + // Spawn the spoo globbit. + Spoo = G_Spawn(); + + create_gkrokon_spoo(Spoo); + Spoo->reflect_debounce_time = MAX_REFLECT; + + Spoo->s.scale = 0.5; + Spoo->enemy=self->enemy; + Spoo->owner=self; + AngleVectors(self->s.angles,Forward,NULL,up); + VectorCopy(self->s.origin,Spoo->s.origin); + VectorMA(Spoo->s.origin,-16,Forward,Spoo->s.origin); + Spoo->s.origin[2]+=12.0; + VectorCopy(self->movedir,Spoo->movedir); + vectoangles(Forward,Spoo->s.angles); + + VectorSubtract(self->enemy->s.origin, self->s.origin, vf); + edist = VectorNormalize(vf); + + if (DotProduct(vf, Forward) < 0.5) + return; + + VectorScale(vf,GKROKON_SPOO_SPEED,Spoo->velocity); + Spoo->velocity[2] += GKROKON_SPOO_ARC; + Spoo->velocity[2] += (edist - 256); + vectoangles(Spoo->velocity, Spoo->s.angles); + + gi.linkentity(Spoo); + + gi.sound(Spoo,CHAN_WEAPON,sounds[SND_SPOO],1,ATTN_NORM,0); + + gi.CreateEffect(&Spoo->s, + FX_SPOO, + CEF_OWNERS_ORIGIN, + Spoo->s.origin, + ""); + + + self->monsterinfo.misc_debounce_time = level.time + flrand(0.5, 3); +} + +/* + + Gkrokon Helper Functions + +*/ + +/*----------------------------------------------- + SkitterAway +-----------------------------------------------*/ + +void SkitterAway(edict_t *self) +{ + if (irand(0,10) < 2 && self->monsterinfo.attack_finished < level.time) + { + self->monsterinfo.attack_finished = level.time + 5; + SetAnim(self, ANIM_SNEEZE); + } + else + SetAnim(self, ANIM_RUNAWAY); +} + +/*----------------------------------------------- + GkrokonBite +-----------------------------------------------*/ + +void GkrokonBite(edict_t *self, float value) +{ + trace_t trace; + edict_t *victim; + vec3_t soff, eoff, mins, maxs, bloodDir, direction; + int damage = irand(GKROKON_DMG_BITE_MIN, GKROKON_DMG_BITE_MAX); + + VectorSet(mins, -2, -2, -2); + VectorSet(maxs, 2, 2, 2); + + //From the right side + if (value) + { + VectorSet(soff, 32, 48, 32); + VectorSet(eoff, 32, 16, 24); + } + else + { + VectorSet(soff, 32, -24, 32); + VectorSet(eoff, 24, 32, 24); + } + + VectorSubtract(soff, eoff, bloodDir); + VectorNormalize(bloodDir); + + victim = M_CheckMeleeLineHit(self, soff, eoff, mins, maxs, &trace, direction); + + if (victim) + { + if (victim == self) + { + //Create a puff effect + //gi.CreateEffect(NULL, FX_SPARKS, 0, hitPos, "db", vec3_origin, irand(1,3)); + if (irand(0,1)) + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEMISS1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEMISS2], 1, ATTN_NORM, 0); + } + else + { + //Hurt whatever we were whacking away at + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, + damage, damage, DAMAGE_NORMAL,MOD_DIED); + + if (irand(0,1)) + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEHIT1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEHIT2], 1, ATTN_NORM, 0); + } + } + else + { + //Play swoosh sound? + if (irand(0,1)) + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEMISS1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEMISS2], 1, ATTN_NORM, 0); + } +} + +/*----------------------------------------------- + gkrokonSound +-----------------------------------------------*/ + +void gkrokonSound(edict_t *self, float channel, float sndindex, float atten) +{ + gi.sound(self, channel, sounds[(int)(sndindex)], 1, atten, 0); +} + +/*----------------------------------------------- + gkrokonRandomWalkSound +-----------------------------------------------*/ + +void gkrokonRandomWalkSound (edict_t *self) +{ + if (irand(0,3)) + return; + + if(!irand(0,1)) + gkrokonSound(self, CHAN_BODY, SND_WALK1, ATTN_NORM); + else + gkrokonSound(self, CHAN_BODY, SND_WALK2, ATTN_NORM); +} + +/*----------------------------------------------- + GkrokonDead +-----------------------------------------------*/ + +void GkrokonDead(edict_t *self) +{ + M_EndDeath(self); +} + +/*----------------------------------------------- + beetle_ai_stand +-----------------------------------------------*/ + +void beetle_ai_stand(edict_t *self, float dist) +{ + if (M_ValidTarget(self, self->enemy)) + { + MG_FaceGoal(self, true); + } +} + +/*----------------------------------------------- + beetle_idle_sound +-----------------------------------------------*/ + +void beetle_idle_sound(edict_t *self) +{ + int chance = irand(0,20); + + switch (chance) + { + case 0: + gkrokonSound(self, CHAN_BODY, SND_IDLE1, ATTN_NORM); + break; + + case 1: + gkrokonSound(self, CHAN_BODY, SND_IDLE2, ATTN_NORM); + break; + + default: + break; + } +} + +/* + + Message Handlers + +*/ + +/*----------------------------------------------- + beetle_skitter +-----------------------------------------------*/ + +void beetle_skitter(edict_t *self, G_Message_t *Msg) +{ + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SkitterAway(self); +} + +/*----------------------------------------------- + beetle_check_mood +-----------------------------------------------*/ + +void beetle_check_mood (edict_t *self, G_Message_t *msg) +{ + ParseMsgParms(msg, "i", &self->ai_mood); + + GkrokonPause(self); +} + +/*----------------------------------------------- + beetle_walk +-----------------------------------------------*/ + +void beetle_walk(edict_t *self,G_Message_t *Msg) +{ + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_STAND3); + else + SetAnim(self,ANIM_WALK1); +} + +/*----------------------------------------------- + beetle_run +-----------------------------------------------*/ + +void beetle_run(edict_t *self, G_Message_t *Msg) +{ + int chance; + float dist; + + //Make sure we're not getting up from laying down without the proper animations + if(self->ai_mood == AI_MOOD_FLEE) + { + if(irand(0,1)) + SetAnim(self, ANIM_RUN1); + else + SetAnim(self, ANIM_RUN2); + + return; + } + + if (self->curAnimID == ANIM_STAND1) + { + SetAnim(self, ANIM_STAND2); + return; + } + + if (M_ValidTarget(self, self->enemy)) + { + dist = M_DistanceToTarget(self, self->enemy); + + chance = irand(0,100); + + if (dist < 300) + { + if (chance < 5) + SetAnim(self, ANIM_STAND3); + else if (chance < 20) + SetAnim(self, ANIM_RUN2); + else + SetAnim(self, ANIM_RUN1); + } + else + { + SetAnim(self, ANIM_RUN1); + } + + return; + } + + //If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +/*----------------------------------------------- + beetle_stand +-----------------------------------------------*/ + +void beetle_stand(edict_t *self,G_Message_t *Msg) +{ + if (self->spawnflags & MSF_EXTRA1) + SetAnim(self, ANIM_STAND1); + else + SetAnim(self, ANIM_STAND3); +} + +/*----------------------------------------------- + beetle_melee +-----------------------------------------------*/ + +void beetle_missile(edict_t *self,G_Message_t *Msg) +{ + int chance; + float dist; + + chance = irand(0,100); + + if(self->enemy) + { + if(self->monsterinfo.misc_debounce_time < level.time) + { + dist = M_DistanceToTarget(self, self->enemy); + + if(self->spawnflags&MSF_FIXED) + { + if (dist < self->missile_range) + SetAnim(self, ANIM_MISSILE1); + else if(self->curAnimID == ANIM_CROUCH1 && !irand(0, 2)) + SetAnim(self, ANIM_CROUCH2);//go into stand + else if(self->curAnimID == ANIM_STAND3 && !irand(0, 10)) + SetAnim(self, ANIM_CROUCH3);//go into a crouch + else + SetAnim(self, ANIM_DELAY);//stand around + } + else if (dist < 64) + { + if (chance < 10) + SetAnim(self, ANIM_MISSILE1); + else if (chance < 30) + { + SetAnim(self, ANIM_RUNAWAY); + self->monsterinfo.flee_finished = level.time + 1; + } + else + { + if (irand(0,1)) + SetAnim(self, ANIM_MELEE1); + else + SetAnim(self, ANIM_MELEE2); + } + } + else if ((dist > 64) && (dist < 200)) + { + if (chance < 40) + SetAnim(self, ANIM_MISSILE1); + else if ((self->monsterinfo.flee_finished < level.time) && (dist > 100)) + SetAnim(self, ANIM_RUN2); + else + SetAnim(self, ANIM_STAND3); + } + else if (dist < 300) + { + if (chance < 5) + SetAnim(self, ANIM_STAND3); + else if (chance < 20) + SetAnim(self, ANIM_RUN2); + else + SetAnim(self, ANIM_RUN1); + } + else + { + SetAnim(self, ANIM_RUN1); + } + } + else if (irand(0,10) < 6) + { + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + } + else + { + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SkitterAway(self); + } + return; + } + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void beetle_melee(edict_t *self,G_Message_t *Msg) +{ + beetle_missile(self, Msg); +} + +/*----------------------------------------------- + beetle_pain +-----------------------------------------------*/ + +void beetle_pain(edict_t *self,G_Message_t *Msg) +{ + int temp, damage; + int force_damage; + + ParseMsgParms(Msg, "eeiii", &temp, &temp, &force_damage, &damage, &temp); + + //Weighted random based on health compared to the maximum it was at + if (force_damage||((flrand(0, self->max_health+50) > self->health) && irand(0,2))) + { + if(irand(0,1)) + gi.sound (self, CHAN_WEAPON, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_PAIN2], 1, ATTN_NORM, 0); + + SetAnim(self, ANIM_PAIN1); + } + + if (!irand(0,2)) + { + self->monsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + 15; + } +} + +/*----------------------------------------------- + beetle_eat +-----------------------------------------------*/ + +void beetle_eat(edict_t *self,G_Message_t *Msg) +{ + int chance = irand(0,2); + + switch (chance) + { + case 0: + SetAnim(self, ANIM_EAT1); + break; + case 1: + SetAnim(self, ANIM_EAT2); + break; + case 2: + SetAnim(self, ANIM_EAT3); + break; + } +} + +/*----------------------------------------------- + beetle_death +-----------------------------------------------*/ + +void beetle_death(edict_t *self,G_Message_t *Msg) +{ + edict_t *targ, *inflictor, *attacker; + float damage; + + ParseMsgParms(Msg, "eeei", &targ, &inflictor, &attacker, &damage); + + M_StartDeath(self, ANIM_DIE1); + + if (self->health < -80) + { + BecomeDebris(self); + return; + } + else + { + if(self->health < -10) + { + vec3_t forward; + int i, num_limbs; + + num_limbs = irand(3, 10); + for(i = 0; i < num_limbs; i++) + { + if(self->svflags&SVF_MONSTER) + self->monsterinfo.dismember(self, flrand(80, 160), irand(hl_Head, hl_LegLowerRight) | hl_MeleeHit); + } + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->velocity, -400, forward, self->velocity); + self->velocity[2] += 150; + } + SetAnim(self, ANIM_DIE1); + } + + gi.sound (self, CHAN_BODY, sounds[SND_DIE], 1, ATTN_NORM, 0); +} + +int Bit_for_MeshNode_gk [NUM_MESH_NODES] = +{ + BIT_WAIT1, + BIT_SHELLA_P1, + BIT_SPIKE_P1, + BIT_HEAD_P1, + BIT_RPINCHERA_P1, + BIT_RPINCHERB_P1, + BIT_LPINCHERA_P1, + BIT_LPINCHERB_P1, + BIT_LARM_P1, + BIT_RARM_P1, + BIT_ABDOMEN_P1, + BIT_LTHIGH_P1, + BIT_RTHIGH_P1, + BIT_SHELLB_P1, +}; + +qboolean canthrownode_gk (edict_t *self, int BP, int *throw_nodes) +{//see if it's on, if so, add it to throw_nodes + //turn it off on thrower + if(!(self->s.fmnodeinfo[BP].flags & FMNI_NO_DRAW)) + { + *throw_nodes |= Bit_for_MeshNode_gk[BP]; + self->s.fmnodeinfo[BP].flags |= FMNI_NO_DRAW; + return true; + } + return false; +} + +void beetle_dismember(edict_t *self, int damage, int HitLocation) +{ + int throw_nodes = 0; + vec3_t gore_spot, right; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; + + VectorClear(gore_spot); + switch(HitLocation) + { + case hl_Head: + if(self->s.fmnodeinfo[MESH__SHELLB_P1].flags & FMNI_NO_DRAW) + break; + self->s.fmnodeinfo[MESH__SHELLB_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__SHELLB_P1].skin = self->s.skinnum + 1; + break; + + case hl_TorsoFront://split in half? + if(!(self->s.fmnodeinfo[MESH__HEAD_P1].flags & FMNI_USE_SKIN)) + { + if(irand(0, 4)) + { + self->s.fmnodeinfo[MESH__HEAD_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__HEAD_P1].skin = self->s.skinnum+1; + } + } + else if(canthrownode_gk(self, MESH__HEAD_P1, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + T_Damage(self, self->enemy, self->enemy, vec3_origin, vec3_origin, vec3_origin, 9999, 200, DAMAGE_NORMAL,MOD_DIED); + return; + } + + if(!(self->s.fmnodeinfo[MESH__SPIKE_P1].flags & FMNI_USE_SKIN)) + { + if(irand(0, 4)) + { + self->s.fmnodeinfo[MESH__SPIKE_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__SPIKE_P1].skin = self->s.skinnum+1; + } + } + else if(canthrownode_gk(self, MESH__SPIKE_P1, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + + if(!(self->s.fmnodeinfo[MESH__RPINCHERA_P1].flags & FMNI_USE_SKIN)) + { + if(irand(0, 4)) + { + self->s.fmnodeinfo[MESH__RPINCHERA_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RPINCHERA_P1].skin = self->s.skinnum+1; + } + } + else if(canthrownode_gk(self, MESH__RPINCHERA_P1, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + + if(!(self->s.fmnodeinfo[MESH__LPINCHERA_P1].flags & FMNI_USE_SKIN)) + { + if(irand(0, 4)) + { + self->s.fmnodeinfo[MESH__LPINCHERA_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LPINCHERA_P1].skin = self->s.skinnum+1; + } + } + else if(canthrownode_gk(self, MESH__LPINCHERA_P1, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + + if(!(self->s.fmnodeinfo[MESH__RPINCHERB_P1].flags & FMNI_USE_SKIN)) + { + if(irand(0, 4)) + { + self->s.fmnodeinfo[MESH__RPINCHERB_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RPINCHERB_P1].skin = self->s.skinnum+1; + } + } + else if(canthrownode_gk(self, MESH__RPINCHERB_P1, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + + if(!(self->s.fmnodeinfo[MESH__LPINCHERB_P1].flags & FMNI_USE_SKIN)) + { + if(irand(0, 4)) + { + self->s.fmnodeinfo[MESH__LPINCHERB_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LPINCHERB_P1].skin = self->s.skinnum+1; + } + } + else if(canthrownode_gk(self, MESH__LPINCHERB_P1, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + case hl_TorsoBack://split in half? + if(self->s.fmnodeinfo[MESH__ABDOMEN_P1].flags & FMNI_NO_DRAW) + break; + self->s.fmnodeinfo[MESH__ABDOMEN_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__ABDOMEN_P1].skin = self->s.skinnum+1; + break; + + case hl_ArmLowerLeft://left arm + case hl_ArmUpperLeft: + if(self->s.fmnodeinfo[MESH__LARM_P1].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__LARM_P1].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + } + else + { + self->s.fmnodeinfo[MESH__LARM_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LARM_P1].skin = self->s.skinnum+1; + } + break; + + case hl_ArmUpperRight: + case hl_ArmLowerRight://right arm + if(self->s.fmnodeinfo[MESH__RARM_P1].flags & FMNI_NO_DRAW) + break; + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + } + else + { + self->s.fmnodeinfo[MESH__RARM_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RARM_P1].skin = self->s.skinnum+1; + } + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft://left leg + if(self->health>0) + { + if(self->s.fmnodeinfo[MESH__LTHIGH_P1].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__LTHIGH_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LTHIGH_P1].skin = self->s.skinnum+1; + break; + } + else + { + if(self->s.fmnodeinfo[MESH__LTHIGH_P1].flags & FMNI_NO_DRAW) + break; + if(canthrownode_gk(self, MESH__LTHIGH_P1, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + case hl_LegUpperRight: + case hl_LegLowerRight://right leg + if(self->health>0) + { + if(self->s.fmnodeinfo[MESH__RTHIGH_P1].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__RTHIGH_P1].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RTHIGH_P1].skin = self->s.skinnum+1; + } + else + { + if(self->s.fmnodeinfo[MESH__RTHIGH_P1].flags & FMNI_NO_DRAW) + break; + if(canthrownode_gk(self, MESH__RTHIGH_P1, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + } + break; + default: + break; + } + + if(self->s.fmnodeinfo[MESH__SPIKE_P1].flags&FMNI_NO_DRAW) + { + self->monsterinfo.aiflags |= AI_COWARD; + self->monsterinfo.aiflags |= AI_NO_MELEE; + self->monsterinfo.aiflags |= AI_NO_MISSILE; + } +} + +void beetle_dead_pain (edict_t *self, G_Message_t *msg) +{ + if(self->health<=-80) + { + // We get gibbed. + gi.sound(self,CHAN_BODY,sounds[SND_GIB],1,ATTN_NORM,0); + + self->think = BecomeDebris; + self->nextthink = level.time + FRAMETIME; + + return; + } + + if(msg) + if(!(self->svflags & SVF_PARTS_GIBBED)) + MG_parse_dismember_msg(self, msg); +} + +// **************************************************************************** +// GkrokonStaticsInit - +// **************************************************************************** + +void GkrokonStaticsInit(void) +{ + classStatics[CID_GKROKON].msgReceivers[MSG_STAND]=beetle_stand; + classStatics[CID_GKROKON].msgReceivers[MSG_RUN]=beetle_run; + classStatics[CID_GKROKON].msgReceivers[MSG_DEATH_PAIN] = beetle_dead_pain; + classStatics[CID_GKROKON].msgReceivers[MSG_CHECK_MOOD] = beetle_check_mood; + classStatics[CID_GKROKON].msgReceivers[MSG_FALLBACK] = beetle_skitter; + classStatics[CID_GKROKON].msgReceivers[MSG_MELEE]=beetle_melee; + classStatics[CID_GKROKON].msgReceivers[MSG_MISSILE]=beetle_missile; + classStatics[CID_GKROKON].msgReceivers[MSG_PAIN]=beetle_pain; + classStatics[CID_GKROKON].msgReceivers[MSG_EAT]=beetle_eat; + classStatics[CID_GKROKON].msgReceivers[MSG_DEATH]=beetle_death; + classStatics[CID_GKROKON].msgReceivers[MSG_DEATH_PAIN] = beetle_dead_pain; + classStatics[CID_GKROKON].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + + resInfo.numAnims=NUM_ANIMS; + resInfo.animations=Animations; + resInfo.modelIndex=gi.modelindex("models/monsters/gkrokon/tris.fm"); + + sounds[SND_PAIN1]=gi.soundindex("monsters/beetle/pain1.wav"); + sounds[SND_PAIN2]=gi.soundindex("monsters/beetle/pain2.wav"); + sounds[SND_DIE]=gi.soundindex("monsters/beetle/death.wav"); + sounds[SND_GIB]=gi.soundindex("monsters/insect/gib.wav"); + sounds[SND_SPOO]=gi.soundindex("monsters/beetle/spoo.wav"); + sounds[SND_IDLE1]=gi.soundindex("monsters/beetle/idle1.wav"); + sounds[SND_IDLE2]=gi.soundindex("monsters/beetle/idle2.wav"); + sounds[SND_SIGHT]=gi.soundindex("monsters/beetle/sight.wav"); + sounds[SND_WALK1]=gi.soundindex("monsters/beetle/walk1.wav"); + sounds[SND_WALK2]=gi.soundindex("monsters/beetle/walk2.wav"); + sounds[SND_FLEE]=gi.soundindex("monsters/beetle/flee.wav"); + sounds[SND_ANGRY]=gi.soundindex("monsters/beetle/angry.wav"); + sounds[SND_EATING]=gi.soundindex("monsters/beetle/eating.wav"); + sounds[SND_BITEHIT1]=gi.soundindex("monsters/beetle/meleehit1.wav"); + sounds[SND_BITEHIT2]=gi.soundindex("monsters/beetle/meleehit2.wav"); + sounds[SND_BITEMISS1]=gi.soundindex("monsters/beetle/meleemiss1.wav"); + sounds[SND_BITEMISS2]=gi.soundindex("monsters/beetle/meleemiss2.wav"); + + resInfo.numSounds=NUM_SOUNDS; + resInfo.sounds=sounds; + + classStatics[CID_GKROKON].resInfo=&resInfo; +} + +// **************************************************************************** +// SP_Monster_Gkrokon - The Gkrokon's spawn function. +// **************************************************************************** + +/*QUAKED monster_gkrokon (1 .5 0) (-20 -20 -0) (20 20 32) AMBUSH ASLEEP EATING 8 16 32 64 FIXED WANDER MELEE_LEAD STALK COWARD RESTING EXTRA2 EXTRA3 EXTRA4 + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +EATING - Chomp chomp... chewie chomp + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will try to cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 12 +melee_range = 0 +missile_range = 256 +min_missile_range = 48 +bypass_missile_chance = 0 +jump_chance = 100 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ + +void SP_Monster_Gkrokon(edict_t *self) +{ + if (!walkmonster_start(self)) // Failed initialization + return; + + self->msgHandler=DefaultMsgHandler; + self->classID=CID_GKROKON; + + if (!self->health) + self->health=GKROKON_HEALTH; + + self->materialtype = MAT_INSECT; + self->mass=GKROKON_MASS; + self->yaw_speed=20; + self->movetype=PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + self->solid=SOLID_BBOX; + self->monsterinfo.dismember = beetle_dismember; + + self->s.renderfx |= RF_FRAMELERP; + + self->touch = M_Touch; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + self->monsterinfo.attack_finished = level.time; + + self->s.modelindex=classStatics[CID_GKROKON].resInfo->modelIndex; + + self->s.skinnum = (irand(0, 1)) ? 0 : 2; + + self->monsterinfo.otherenemyname = ""; + + self->timestamp = 0; + + self->monsterinfo.searchType = SEARCH_COMMON; + + MG_InitMoods(self); + + // Check our spawnflags to see what our initial behaviour should be. + if(self->spawnflags & MSF_EATING) + { + self->monsterinfo.aiflags|=AI_EATING; + QPostMessage(self,MSG_EAT,PRI_DIRECTIVE,NULL); + } + else + QPostMessage(self,MSG_STAND,PRI_DIRECTIVE,NULL); + + self->count = 0; +} + + +void GkrokonPause(edict_t *self) +{ + if(self->spawnflags & MSF_FIXED && self->curAnimID == ANIM_DELAY && self->enemy) + { + self->monsterinfo.searchType = SEARCH_COMMON; + MG_FaceGoal(self, true); + } + + self->mood_think(self); + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_PURSUE: + case AI_MOOD_NAVIGATE: + case AI_MOOD_FLEE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_WALK: + case AI_MOOD_WANDER: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_BACKUP: + QPostMessage(self, MSG_FALLBACK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_STAND: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_JUMP: + if(self->spawnflags&MSF_FIXED || self->jump_chance<=0) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_FJUMP); + break; + + case AI_MOOD_EAT: + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + break; + + default : +#ifdef _DEVEL + gi.dprintf("Unusable mood %d for Gkrokon\n", self->ai_mood); +#endif + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + } +} + +void beetle_to_stand (edict_t *self) +{ + SetAnim(self, ANIM_STAND3); + GkrokonPause(self); +} + +void beetle_to_crouch (edict_t *self) +{ + SetAnim(self, ANIM_CROUCH1); + GkrokonPause(self); +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/m_gkrokon.h b/Toolkit/Programming/GameCode/game/m_gkrokon.h new file mode 100644 index 0000000..66ebf14 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_gkrokon.h @@ -0,0 +1,142 @@ +//============================================================================== +// +// m_gkrokon.h +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#define GKROKON_JUMP_VELOCITY 300.0 +#define GKROKON_HOP_VELOCITY 128.0 + +#define GKROKON_SPOO_SPEED 450.0 +#define GKROKON_SPOO_ARC 150.0 + +// **************************************************************************** +// The Gkrokon's animations. +// **************************************************************************** + +typedef enum AnimID_e +{ + ANIM_STAND1, + ANIM_STAND2, + ANIM_STAND3, + ANIM_STAND4, + ANIM_CROUCH1, + ANIM_CROUCH2, + ANIM_CROUCH3, + ANIM_WALK1, + ANIM_RUN1, + ANIM_RUN2, + ANIM_JUMP1, + ANIM_FJUMP, + ANIM_MELEE1, + ANIM_MELEE2, + ANIM_MISSILE1, + ANIM_EAT1, + ANIM_EAT2, + ANIM_EAT3, + ANIM_PAIN1, + ANIM_DIE1, + ANIM_HOP, + ANIM_RUNAWAY, + ANIM_SNEEZE, + ANIM_DELAY, + NUM_ANIMS +} AnimID_t; + +// **************************************************************************** +// The Gkrokon's sounds. +// **************************************************************************** + +typedef enum SoundID_e +{ + SND_PAIN1, + SND_PAIN2, + SND_DIE, + SND_GIB, + SND_SPOO, + SND_IDLE1, + SND_IDLE2, + SND_SIGHT, + SND_WALK1, + SND_WALK2, + SND_FLEE, + SND_ANGRY, + SND_EATING, + SND_BITEHIT1, + SND_BITEHIT2, + SND_BITEMISS1, + SND_BITEMISS2, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t GkrokonMoveStand1; +extern animmove_t GkrokonMoveStand2; +extern animmove_t GkrokonMoveStand3; +extern animmove_t GkrokonMoveStand4; +extern animmove_t GkrokonMoveCrouch1; +extern animmove_t GkrokonMoveCrouch2; +extern animmove_t GkrokonMoveCrouch3; +extern animmove_t GkrokonMoveWalk1; +extern animmove_t GkrokonMoveRun1; +extern animmove_t GkrokonMoveRun2; +extern animmove_t GkrokonMoveRunAway; +extern animmove_t GkrokonMoveJump1; +extern animmove_t GkrokonMoveForcedJump; +extern animmove_t GkrokonMoveMeleeAttack1; +extern animmove_t GkrokonMoveMeleeAttack2; +extern animmove_t GkrokonMoveMissileAttack1; +extern animmove_t GkrokonMoveMissileAttack2; +extern animmove_t GkrokonMoveEat1; +extern animmove_t GkrokonMoveEat2; +extern animmove_t GkrokonMoveEat3; +extern animmove_t GkrokonMovePain1; +extern animmove_t GkrokonMoveDeath1; +//extern animmove_t GkrokonMoveDeath_hold; +extern animmove_t GkrokonMoveHop1; +extern animmove_t GkrokonMoveDelay; + +void GkrokonSpooTouch2(edict_t *self,trace_t *trace); + +void GkrokonPause(edict_t *self); +void gkrokonSound(edict_t *self, float channel, float sndindex, float atten); +void gkrokonRandomWalkSound (edict_t *self); +void GkrokonSpoo(edict_t *self); +void GkrokonDead(edict_t *self); + +void extrapolateFiredir (edict_t *self,vec3_t p1,float pspeed,edict_t *targ,float accept,vec3_t vec2); + +void create_gkrokon_spoo(edict_t *Spoo); +void BecomeDebris(edict_t *self); + +void GkrokonSpooThink(edict_t *self); +void GkrokonSpooTouch(edict_t *self,edict_t *Other,cplane_t *Plane,csurface_t *Surface); + +trace_t trace_dir(edict_t *self, vec3_t source, vec3_t angles, float dist); + +void GkrokonStaticsInit(void); +void GkrokonInit(void); + +void beetle_ai_stand(edict_t *self, float dist); +float MG_FaceGoal (edict_t *self, qboolean doturn); +void beetle_idle_sound(edict_t *self); +void beetle_to_stand (edict_t *self); +void beetle_to_crouch (edict_t *self); +void GkrokonBite(edict_t *self, float value); + +#define BIT_WAIT1 0 +#define BIT_SHELLA_P1 1 +#define BIT_SPIKE_P1 2 +#define BIT_HEAD_P1 4 +#define BIT_RPINCHERA_P1 8 +#define BIT_RPINCHERB_P1 16 +#define BIT_LPINCHERA_P1 32 +#define BIT_LPINCHERB_P1 64 +#define BIT_LARM_P1 128 +#define BIT_RARM_P1 256 +#define BIT_ABDOMEN_P1 512 +#define BIT_LTHIGH_P1 1024 +#define BIT_RTHIGH_P1 2048 +#define BIT_SHELLB_P1 4096 diff --git a/Toolkit/Programming/GameCode/game/m_gkrokon_anim.c b/Toolkit/Programming/GameCode/game/m_gkrokon_anim.c new file mode 100644 index 0000000..4bb8d16 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_gkrokon_anim.c @@ -0,0 +1,446 @@ +//============================================================================== +// +// m_gkrokon_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_gkrokon_anim.h" +#include "m_gkrokon.h" +#include "random.h" + +// **************************************************************************** +// Stand1 - Laid down, resting, still on the floor. +// **************************************************************************** + +animframe_t GkrokonFramesStand1[]= +{ + FRAME_bwait1, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait2, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait3, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait4, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait5, NULL, 0, 0, 0, beetle_ai_stand, 0, beetle_idle_sound, + FRAME_bwait6, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait7, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait8, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait9, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait10, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait11, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait12, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait13, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait14, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, +}; +animmove_t GkrokonMoveStand1={14,GkrokonFramesStand1, GkrokonPause};//GkrokonOrderStand}; + +// **************************************************************************** +// Stand2 - Getting up off the floor. +// **************************************************************************** + +animframe_t GkrokonFramesStand2[]= +{ + FRAME_birth1, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth2, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth3, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth4, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth5, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth6, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth7, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth8, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth9, NULL, 0, 0, 0, beetle_ai_stand, 0, beetle_idle_sound, + FRAME_birth10, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth11, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth12, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, +}; + +animmove_t GkrokonMoveStand2={12,GkrokonFramesStand2, GkrokonPause};//GkrokonOrderStand}; + +// **************************************************************************** +// Stand3 - Standing fairly still, waiting. +// **************************************************************************** + +animframe_t GkrokonFramesStand3[]= +{ + FRAME_wait1, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_wait2, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_wait3, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_wait4, NULL, 0, 0, 0, beetle_ai_stand, 0, beetle_idle_sound, + FRAME_wait5, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_wait6, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_wait7, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_wait8, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, +}; + +animmove_t GkrokonMoveStand3={8,GkrokonFramesStand3, GkrokonPause};//GkrokonOrderStand}; + +// **************************************************************************** +// Stand4 - Settling down onto the floor. +// **************************************************************************** + +animframe_t GkrokonFramesStand4[]= +{ + FRAME_birth5, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth4, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth3, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_birth2, NULL, 0, 0, 0, beetle_ai_stand, 0, beetle_idle_sound, + FRAME_birth1, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, +}; + +animmove_t GkrokonMoveStand4={5,GkrokonFramesStand4, GkrokonPause};//GkrokonOrderStand}; + +// **************************************************************************** +// Crouch1 - Crouched down on the floor (stalking enemy). +// **************************************************************************** + +animframe_t GkrokonFramesCrouch1[]= +{ + FRAME_bwait1, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait2, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait3, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait4, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait5, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait6, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait7, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait8, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait9, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait10, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait11, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait12, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait13, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, + FRAME_bwait14, NULL, 0, 0, 0, beetle_ai_stand, 0, NULL, +}; + +animmove_t GkrokonMoveCrouch1={14,GkrokonFramesCrouch1, GkrokonPause};//GkrokonOrderCrouch}; + +// **************************************************************************** +// Crouch2 - Getting up off the floor from crouching (stalking enemy). +// **************************************************************************** + +animframe_t GkrokonFramesCrouch2[]= +{ + FRAME_birth1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth4, NULL, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t GkrokonMoveCrouch2={4,GkrokonFramesCrouch2, beetle_to_stand};//GkrokonOrderCrouch}; + +// **************************************************************************** +// Crouch3 - Settling down into crouching position (stalking enemy). +// **************************************************************************** + +animframe_t GkrokonFramesCrouch3[]= +{ + FRAME_birth4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth1, NULL, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t GkrokonMoveCrouch3={4,GkrokonFramesCrouch3, beetle_to_crouch};//GkrokonOrderCrouch}; + +// **************************************************************************** +// Walk1 - A leisurely ambling gait. +// **************************************************************************** + +animframe_t GkrokonFramesWalk1[]= +{ + FRAME_walkB1, NULL, 0, 0, 0, beetle_ai_stand, 6, NULL, + FRAME_walkB2, NULL, 0, 0, 0, beetle_ai_stand, 7, NULL, + FRAME_walkB3, NULL, 0, 0, 0, beetle_ai_stand, 5, NULL, + FRAME_walkB4, NULL, 0, 0, 0, beetle_ai_stand, 8, NULL, + FRAME_walkB5, NULL, 0, 0, 0, beetle_ai_stand, 7, NULL, + FRAME_walkB6, NULL, 0, 0, 0, beetle_ai_stand, 6, gkrokonRandomWalkSound, + FRAME_walkB7, NULL, 0, 0, 0, beetle_ai_stand, 5, NULL, + FRAME_walkB8, NULL, 0, 0, 0, beetle_ai_stand, 8, NULL, +}; + +animmove_t GkrokonMoveWalk1={8,GkrokonFramesWalk1,GkrokonPause}; + +// **************************************************************************** +// Run1 - A galloping run. +// **************************************************************************** + +animframe_t GkrokonFramesRun1[]= +{ + FRAME_gallop1, NULL, 0, 0, 0, ai_run, 16, NULL, + FRAME_gallop2, NULL, 0, 0, 0, ai_run, 24, NULL, + FRAME_gallop3, NULL, 0, 0, 0, ai_run, 22, NULL, + FRAME_gallop4, NULL, 0, 0, 0, ai_run, 18, gkrokonRandomWalkSound, + FRAME_gallop5, NULL, 0, 0, 0, ai_run, 16, NULL, + FRAME_gallop6, NULL, 0, 0, 0, ai_run, 24, NULL, +}; + +animmove_t GkrokonMoveRun1={6,GkrokonFramesRun1, GkrokonPause};//GkrokonOrderRun}; + +// **************************************************************************** +// Run2 - A skittering, insectlike run. +// **************************************************************************** + +animframe_t GkrokonFramesRun2[]= +{ + FRAME_skittr1, NULL, 0, 0, 0, ai_run, 12, NULL, + FRAME_skittr2, NULL, 0, 0, 0, ai_run, 12, NULL, + FRAME_skittr3, NULL, 0, 0, 0, ai_run, 12, gkrokonRandomWalkSound, + FRAME_skittr4, NULL, 0, 0, 0, ai_run, 12, NULL, +}; + +animmove_t GkrokonMoveRun2={4,GkrokonFramesRun2, GkrokonPause};//GkrokonOrderRun}; + +animframe_t GkrokonFramesRunAway[]= +{ + FRAME_skittr4, gkrokonSound, CHAN_VOICE, SND_FLEE, ATTN_NORM, ai_run, -14, NULL, + FRAME_skittr3, NULL, 0, 0, 0, ai_run, -16, NULL, + FRAME_skittr2, NULL, 0, 0, 0, ai_run, -14, gkrokonRandomWalkSound, + FRAME_skittr1, NULL, 0, 0, 0, ai_run, -12, NULL, + FRAME_skittr4, NULL, 0, 0, 0, ai_run, -14, NULL, + FRAME_skittr3, NULL, 0, 0, 0, ai_run, -16, NULL, + FRAME_skittr2, NULL, 0, 0, 0, ai_run, -14, gkrokonRandomWalkSound, + FRAME_skittr1, NULL, 0, 0, 0, ai_run, -12, NULL, +}; + +animmove_t GkrokonMoveRunAway={8,GkrokonFramesRunAway, GkrokonPause};//GkrokonOrderRun}; + +// **************************************************************************** +// Jump1 - Jumping. +// **************************************************************************** + +animframe_t GkrokonFramesJump1[]= +{ + FRAME_jump1, gkrokonSound, CHAN_VOICE, SND_ANGRY, ATTN_NORM, NULL, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, NULL, 0, /*GkrokonJump*/NULL, + FRAME_jump6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump20, NULL, 0, 0, 0, NULL, 0, /*GkrokonBite*/NULL, + FRAME_jump22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump23, NULL, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t GkrokonMoveJump1={12,GkrokonFramesJump1, GkrokonPause}; //GkrokonOrderRun}; + +animframe_t GkrokonFramesForcedJump[]= +{ + FRAME_jump1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, NULL, 0, /*GkrokonJump*/NULL, + FRAME_jump6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump20, NULL, 0, 0, 0, NULL, 0, /*GkrokonBite*/NULL, + FRAME_jump22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump23, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t GkrokonMoveForcedJump={12,GkrokonFramesForcedJump, GkrokonPause}; //GkrokonOrderRun}; + +// **************************************************************************** +// GkrokonFramesMeleeAttack1 - A bite attack on my enemy. +// **************************************************************************** + +animframe_t GkrokonFramesMeleeAttack1[]= +{ + FRAME_latack1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_latack2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_latack3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_latack4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_latack5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_latack6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_latack7, NULL, 0, 0, 0, GkrokonBite, 0, NULL, + FRAME_latack8, NULL, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t GkrokonMoveMeleeAttack1={8,GkrokonFramesMeleeAttack1, GkrokonPause};//GkrokonOrderStand}; + +animframe_t GkrokonFramesMeleeAttack2[]= +{ + FRAME_ratack1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_ratack2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_ratack3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_ratack4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_ratack5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_ratack6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_ratack7, NULL, 0, 0, 0, GkrokonBite, 1, NULL, + FRAME_ratack8, NULL, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t GkrokonMoveMeleeAttack2={8,GkrokonFramesMeleeAttack2, GkrokonPause};//GkrokonOrderStand}; + +// **************************************************************************** +// GkrokonFramesMissileAttack1 - Firing spoo-goo from spoo launcher. +// **************************************************************************** + +animframe_t GkrokonFramesMissileAttack1[]= +{ + FRAME_spoo1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spoo2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spoo3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spoo4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spoo5, NULL, 0, 0, 0, ai_charge, 0, GkrokonSpoo, +}; +animmove_t GkrokonMoveMissileAttack1={5,GkrokonFramesMissileAttack1, GkrokonPause};//GkrokonOrderRun}; + +animframe_t GkrokonFramesMissileAttack2[]= +{ + FRAME_spoo1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spoo2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spoo3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spoo4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spoo5, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; + +animmove_t GkrokonMoveMissileAttack2={5,GkrokonFramesMissileAttack2, GkrokonPause};//GkrokonOrderRun}; + +// **************************************************************************** +// GkrokonFramesEat1 - Going from ready to eating. +// **************************************************************************** + +animframe_t GkrokonFramesEat1[]= +{ + FRAME_eat1, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_eat2, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_eat3, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_eat4, NULL, 0, 0, 0, ai_eat, 0, NULL, +}; + +animmove_t GkrokonMoveEat1={4,GkrokonFramesEat1, GkrokonPause};//GkrokonOrderEat}; + +// **************************************************************************** +// GkrokonFramesEat2 - The eat cycle. +// **************************************************************************** + +animframe_t GkrokonFramesEat2[]= +{ + FRAME_eat5, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_eat6, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_eat7, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_eat8, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_eat9, NULL, 0, 0, 0, ai_eat, 0, NULL, +}; + +animmove_t GkrokonMoveEat2={5,GkrokonFramesEat2, GkrokonPause};//GkrokonOrderEat}; + +// **************************************************************************** +// GkrokonFramesEat3 - Going from eating to ready. +// **************************************************************************** + +animframe_t GkrokonFramesEat3[]= +{ + FRAME_EATTRANS1, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_EATTRANS2, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_EATTRANS3, NULL, 0, 0, 0, ai_eat, 0, NULL, + FRAME_EATTRANS4, NULL, 0, 0, 0, ai_eat, 0, NULL, +}; + +animmove_t GkrokonMoveEat3={4,GkrokonFramesEat3, GkrokonPause};//GkrokonOrderEat}; + +// **************************************************************************** +// Pain1 - +// **************************************************************************** + +animframe_t GkrokonFramesPain1[]= +{ + FRAME_pain1, NULL, 0, 0, 0, ai_charge, -1, NULL, + FRAME_pain2, NULL, 0, 0, 0, ai_charge, -1, NULL, + FRAME_pain3, NULL, 0, 0, 0, ai_charge, -1, NULL, + FRAME_pain4, NULL, 0, 0, 0, ai_charge, -1, NULL, + FRAME_pain5, NULL, 0, 0, 0, ai_charge, -1, NULL, + FRAME_pain6, NULL, 0, 0, 0, ai_charge, -1, NULL, + FRAME_pain7, NULL, 0, 0, 0, ai_charge, -1, NULL, + FRAME_pain8, NULL, 0, 0, 0, ai_charge, -1, NULL, +}; + +animmove_t GkrokonMovePain1={8,GkrokonFramesPain1, GkrokonPause};//GkrokonOrderRun}; + +// **************************************************************************** +// Death1 - +// **************************************************************************** + +/* +animframe_t GkrokonFramesDeath_hold[]= +{ + FRAME_deathb19, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t GkrokonMoveDeath_hold={1,GkrokonFramesDeath_hold,NULL}; + +*/ + animframe_t GkrokonFramesDeath1[]= +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death16, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death17, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death18, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death19, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death20, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death21, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death22, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death23, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death24, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death25, NULL, 0, 0, 0, ai_move, 2, NULL, + FRAME_death26, NULL, 0, 0, 0, ai_move, 2, NULL, +}; +animmove_t GkrokonMoveDeath1={26,GkrokonFramesDeath1,GkrokonDead}; + +animframe_t GkrokonStartHop[]= +{ + FRAME_birth5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth6, NULL, 0, 0, 0, NULL, 0, /*gkrokon_hopdown*/NULL, + FRAME_birth7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth10, NULL, 0, 0, 0, NULL, 0, gkrokonRandomWalkSound, + FRAME_birth11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_birth12, NULL, 0, 0, 0, NULL, 0, /*gkrokon_donehop*/NULL, +}; + +animmove_t GkrokonMoveHop1={10,GkrokonStartHop,GkrokonPause}; + +animframe_t GkrokonFramesDelay[]= +{ + FRAME_bwait1, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait2, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait3, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait4, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait5, gkrokonSound, CHAN_VOICE, SND_IDLE1, ATTN_NORM, NULL, 0, GkrokonPause, + FRAME_bwait6, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait7, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait8, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait9, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait10, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait11, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait12, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait13, NULL, 0, 0, 0, NULL, 0, GkrokonPause, + FRAME_bwait14, NULL, 0, 0, 0, NULL, 0, GkrokonPause, +}; +animmove_t GkrokonMoveDelay={14,GkrokonFramesDelay, GkrokonPause};//GkrokonOrderStand}; diff --git a/Toolkit/Programming/GameCode/game/m_gkrokon_anim.h b/Toolkit/Programming/GameCode/game/m_gkrokon_anim.h new file mode 100644 index 0000000..b3fa903 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_gkrokon_anim.h @@ -0,0 +1,166 @@ +// R:\Art\models/monsters\gkrokon + +// This file generated by qdata - Do NOT Modify + +#define FRAME_birth1 0 +#define FRAME_birth2 1 +#define FRAME_birth3 2 +#define FRAME_birth4 3 +#define FRAME_birth5 4 +#define FRAME_birth6 5 +#define FRAME_birth7 6 +#define FRAME_birth8 7 +#define FRAME_birth9 8 +#define FRAME_birth10 9 +#define FRAME_birth11 10 +#define FRAME_birth12 11 +#define FRAME_bwait1 12 +#define FRAME_bwait2 13 +#define FRAME_bwait3 14 +#define FRAME_bwait4 15 +#define FRAME_bwait5 16 +#define FRAME_bwait6 17 +#define FRAME_bwait7 18 +#define FRAME_bwait8 19 +#define FRAME_bwait9 20 +#define FRAME_bwait10 21 +#define FRAME_bwait11 22 +#define FRAME_bwait12 23 +#define FRAME_bwait13 24 +#define FRAME_bwait14 25 +#define FRAME_EATTRANS1 26 +#define FRAME_EATTRANS2 27 +#define FRAME_EATTRANS3 28 +#define FRAME_EATTRANS4 29 +#define FRAME_eat1 30 +#define FRAME_eat2 31 +#define FRAME_eat3 32 +#define FRAME_eat4 33 +#define FRAME_eat5 34 +#define FRAME_eat6 35 +#define FRAME_eat7 36 +#define FRAME_eat8 37 +#define FRAME_eat9 38 +#define FRAME_gallop1 39 +#define FRAME_gallop2 40 +#define FRAME_gallop3 41 +#define FRAME_gallop4 42 +#define FRAME_gallop5 43 +#define FRAME_gallop6 44 +#define FRAME_jump1 45 +#define FRAME_jump2 46 +#define FRAME_jump3 47 +#define FRAME_jump4 48 +#define FRAME_jump5 49 +#define FRAME_jump6 50 +#define FRAME_jump7 51 +#define FRAME_jump8 52 +#define FRAME_jump9 53 +#define FRAME_jump10 54 +#define FRAME_jump11 55 +#define FRAME_jump12 56 +#define FRAME_jump13 57 +#define FRAME_jump14 58 +#define FRAME_jump15 59 +#define FRAME_jump16 60 +#define FRAME_jump17 61 +#define FRAME_jump18 62 +#define FRAME_jump19 63 +#define FRAME_jump20 64 +#define FRAME_jump21 65 +#define FRAME_jump22 66 +#define FRAME_jump23 67 +#define FRAME_pain1 68 +#define FRAME_pain2 69 +#define FRAME_pain3 70 +#define FRAME_pain4 71 +#define FRAME_pain5 72 +#define FRAME_pain6 73 +#define FRAME_pain7 74 +#define FRAME_pain8 75 +#define FRAME_skittr1 76 +#define FRAME_skittr2 77 +#define FRAME_skittr3 78 +#define FRAME_skittr4 79 +#define FRAME_spoo1 80 +#define FRAME_spoo2 81 +#define FRAME_spoo3 82 +#define FRAME_spoo4 83 +#define FRAME_spoo5 84 +#define FRAME_wait1 85 +#define FRAME_wait2 86 +#define FRAME_wait3 87 +#define FRAME_wait4 88 +#define FRAME_wait5 89 +#define FRAME_wait6 90 +#define FRAME_wait7 91 +#define FRAME_wait8 92 +#define FRAME_walkB1 93 +#define FRAME_walkB2 94 +#define FRAME_walkB3 95 +#define FRAME_walkB4 96 +#define FRAME_walkB5 97 +#define FRAME_walkB6 98 +#define FRAME_walkB7 99 +#define FRAME_walkB8 100 +#define FRAME_latack1 101 +#define FRAME_latack2 102 +#define FRAME_latack3 103 +#define FRAME_latack4 104 +#define FRAME_latack5 105 +#define FRAME_latack6 106 +#define FRAME_latack7 107 +#define FRAME_latack8 108 +#define FRAME_ratack1 109 +#define FRAME_ratack2 110 +#define FRAME_ratack3 111 +#define FRAME_ratack4 112 +#define FRAME_ratack5 113 +#define FRAME_ratack6 114 +#define FRAME_ratack7 115 +#define FRAME_ratack8 116 +#define FRAME_death1 117 +#define FRAME_death2 118 +#define FRAME_death3 119 +#define FRAME_death4 120 +#define FRAME_death5 121 +#define FRAME_death6 122 +#define FRAME_death7 123 +#define FRAME_death8 124 +#define FRAME_death9 125 +#define FRAME_death10 126 +#define FRAME_death11 127 +#define FRAME_death12 128 +#define FRAME_death13 129 +#define FRAME_death14 130 +#define FRAME_death15 131 +#define FRAME_death16 132 +#define FRAME_death17 133 +#define FRAME_death18 134 +#define FRAME_death19 135 +#define FRAME_death20 136 +#define FRAME_death21 137 +#define FRAME_death22 138 +#define FRAME_death23 139 +#define FRAME_death24 140 +#define FRAME_death25 141 +#define FRAME_death26 142 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 14 + +#define MESH_WAIT1 0 +#define MESH__SHELLA_P1 1 +#define MESH__SPIKE_P1 2 +#define MESH__HEAD_P1 3 +#define MESH__RPINCHERA_P1 4 +#define MESH__RPINCHERB_P1 5 +#define MESH__LPINCHERA_P1 6 +#define MESH__LPINCHERB_P1 7 +#define MESH__LARM_P1 8 +#define MESH__RARM_P1 9 +#define MESH__ABDOMEN_P1 10 +#define MESH__LTHIGH_P1 11 +#define MESH__RTHIGH_P1 12 +#define MESH__SHELLB_P1 13 diff --git a/Toolkit/Programming/GameCode/game/m_gorgon.c b/Toolkit/Programming/GameCode/game/m_gorgon.c new file mode 100644 index 0000000..ba7111e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_gorgon.c @@ -0,0 +1,2401 @@ +/* +============================================================================== + +// m_gorgon.c +// +// Heretic II +// Copyright 1998 Raven Software + + +GORGON + + AI : + + STANDING 1 : Looking straight ahead + STANDING 2 : Looking to left + STANDING 3 : Looking to the right + + WALK : a normal straight line + WALK RIGHT : if turning to the right while walking + WALK LEFT : if turning to the left while walking + + RUN1 : Running + RUN2 : Turning left while running + RUN3 : Turning right while running + + MELEE1 : Attack Left + MELEE2 : Attack Right + MELEE3 : Attack Up + MELEE4 : Attack Pullback + MELEE5 : Running attack + MELEE6 : Hop left + MELEE7 : Hop right + MELEE8 : Hop forward + MELEE9 : Hop backward + + PAIN1 : step back and bow head down + PAIN2 : bow head to the left + PAIN3 : bow head to the right + + DIE1 : take a few steps backwards and keel over + DIE2 : fly backwards and slide to a stop + +============================================================================== +*/ + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "g_misc.h" +#include "m_gorgon.h" +#include "m_gorgon_anim.h" +#include "m_stats.h" +#include "p_anim_branch2.h" +#include "p_anims2.h" +#include "g_HitLocation.h" + + +// ************************************* +// Definitions +// ************************************* + +void BecomeDebris(edict_t *self); +qboolean ai_have_enemy (edict_t *self); +qboolean clear_visible (edict_t *self, edict_t *other); +qboolean EqualAngle(float angle1, float angle2, float leniency); +qboolean ok_to_wake (edict_t *monster, qboolean gorgon_roar, qboolean ignore_ambush); +float MG_ChangeWhichYaw (edict_t *self, qboolean ideal_yaw); +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); +qboolean gorgon_check_jump (edict_t *self); + +#define TRYSTEP_OK 0 +#define TRYSTEP_ALLSOLID 1 +#define TRYSTEP_STARTSOLID 2 +#define TRYSTEP_OFFEDGE 3 +#define TRYSTEP_NOSUPPORT 4 +#define TRYSTEP_INWATER 5 +#define GORGON_STD_MELEE_RNG 48 +#define GORGON_STD_MAXHOP_RNG 200 + +static animmove_t *animations[NUM_ANIMS] = +{ + &gorgon_move_stand1, + &gorgon_move_stand2, + &gorgon_move_stand3, + &gorgon_move_stand4, + &gorgon_move_walk, + &gorgon_move_walk2, + &gorgon_move_walk3, + &gorgon_move_melee1, + &gorgon_move_melee2, + &gorgon_move_melee3, + &gorgon_move_melee4, + &gorgon_move_melee5, + &gorgon_move_melee6, + &gorgon_move_melee7, + &gorgon_move_melee8, + &gorgon_move_melee9, + &gorgon_move_melee10, + &gorgon_move_fjump, + &gorgon_move_run1, + &gorgon_move_run2, + &gorgon_move_run3, + &gorgon_move_pain1, + &gorgon_move_pain2, + &gorgon_move_pain3, + &gorgon_move_die1, + &gorgon_move_die2, + &gorgon_move_snatch, + &gorgon_move_catch, + &gorgon_move_miss, + &gorgon_move_readycatch, + &gorgon_move_snatchhi, + &gorgon_move_snatchlow, + &gorgon_move_slip, + &gorgon_move_slip_pain, + &gorgon_move_delay, + &gorgon_move_roar, + &gorgon_move_roar2, + &gorgon_move_land2, + &gorgon_move_land, + &gorgon_move_inair, + &gorgon_move_to_swim, + &gorgon_move_swim, + &gorgon_move_swim_bite_a, + &gorgon_move_swim_bite_a, + &gorgon_move_outwater, + &gorgon_move_eat_down, + &gorgon_move_eat_up, + &gorgon_move_eat_loop, + &gorgon_move_eat_tear, + &gorgon_move_eat_pullback, + &gorgon_move_look_around, + &gorgon_move_eat_left, + &gorgon_move_eat_right, + &gorgon_move_eat_snap, + &gorgon_move_eat_react +}; + +static int sounds[NUM_SOUNDS]; + +static ClassResourceInfo_t resInfo; + +void gorgon_watch(edict_t *self, G_Message_t *msg); +void gorgon_death_pain(edict_t *self, G_Message_t *msg); + +void gorgon_blocked (edict_t *self, trace_t *trace) +{ + vec3_t dir; + + if(self->velocity[2]>=0) + return; + + if(trace->ent->s.origin[2] + trace->ent->maxs[2] > self->s.origin[2] + self->mins[2]) + return; + + if(!trace->ent->takedamage) + return; + + VectorCopy(self->velocity,dir); + VectorNormalize(dir); + T_Damage (trace->ent, self, self, self->velocity, trace->ent->s.origin, dir, flrand(5, 15), 50, DAMAGE_EXTRA_KNOCKBACK,MOD_DIED); + if(trace->ent->health>0) + { + if(trace->ent->client) + { + if(!irand(0, 2)) + { + if(trace->ent->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + { + if(infront(trace->ent, self)) + { + KnockDownPlayer(&trace->ent->client->playerinfo); + } + } + } + } + } +} + +void gorgon_roar_sound (edict_t *self) +{ + int chance; + + chance = irand(0, 100); + if (chance < 20) + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else if (chance < 40) + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN2], 1, ATTN_NORM, 0); + else if (chance < 60) + gi.sound(self, CHAN_VOICE, sounds[SND_DIE], 1, ATTN_NORM, 0); + else + gorgon_growl(self); +} + + +void gorgon_roar_response_go (edict_t *self) +{ + self->pre_think = NULL; + self->next_pre_think = -1; + + if(self->ai_mood == AI_MOOD_EAT) + self->ai_mood = AI_MOOD_PURSUE; + + SetAnim(self, ANIM_ROAR2); + + self->nextthink = level.time + 0.1; +} + +void gorgon_roar_response (edict_t *self, G_Message_t *msg) +{//respond to call + if(!irand(0, 3)) + return;//25% don't roar back + + self->pre_think = gorgon_roar_response_go; + self->next_pre_think = level.time + flrand (0.5, 2); + self->nextthink = level.time + 10; +} + +void gorgonRoar (edict_t *self) +{//finds gorgons in immediate vicinity and wakes them up + edict_t *found = NULL; + + if(!self->enemy) + return; + + while(found = findradius(found, self->s.origin, GORGON_ALERT_DIST)) + { + if(found->health>0) + { + if(!found->enemy) + { + if(found->svflags & SVF_MONSTER) + { + if(found->classID == CID_GORGON) + { + if(!found->monsterinfo.roared) + { + if(gi.inPHS(self->s.origin, found->s.origin)) + {//make sure they can hear me + if(ok_to_wake(found, true, true)) + { + found->monsterinfo.roared = true; + found->enemy = self->enemy; + FoundTarget(found, false); + QPostMessage(found, MSG_VOICE_POLL, PRI_DIRECTIVE, ""); + } + } + } + } + } + } + } + } +//Not just an alert monsters since we want to wake up gorgons only + // AlertMonsters(self, self->enemy, 5, 1); +} + +qboolean gorgonFindAsleepGorgons (edict_t *self) +{//sees if there are any gorgons in range that aren't awake + edict_t *found = NULL; + + while(found = findradius(found, self->s.origin, GORGON_ALERT_DIST)) + { + if(found!=self) + { + if(found->health>0) + { + if(!found->enemy) + { + if(found->svflags & SVF_MONSTER) + { + if(found->classID == CID_GORGON) + { + if(!found->monsterinfo.roared) + { + return true; + } + } + } + } + } + } + } + return false; +} +//---------------------------------------------------------------------- +// Gorgon Eat - decide which eating animations to use +//---------------------------------------------------------------------- +void gorgon_eat(edict_t *self, G_Message_t *msg) +{ + int chance; + + chance = irand(0, 100); + if (chance < 90) // Eating + { + if (chance < 80) + SetAnim(self, ANIM_EAT_LOOP); + else + SetAnim(self, ANIM_EAT_PULLBACK); + } + else + { + SetAnim(self, ANIM_EAT_TEAR); + } + + self->monsterinfo.misc_debounce_time = level.time + 5; +} + +/*---------------------------------------------------------------------- + Gorgon Watch -decide which standing animations to use +-----------------------------------------------------------------------*/ +void gorgon_watch(edict_t *self, G_Message_t *msg) +{ + int chance; + + chance = irand(0, 100); + if (chance < 10) + SetAnim(self, ANIM_STAND2); + else if (chance < 20) + SetAnim(self, ANIM_STAND3); + else + SetAnim(self, ANIM_STAND1); +} + +qboolean gorgon_check_attack(edict_t *self) +{ + vec3_t v, vr, vf; + float dot, dot2, len; + int chance; + + if(!M_ValidTarget(self, self->enemy)) + return false; + + if (!clear_visible(self, self->enemy)) + return false; + + VectorSubtract(self->enemy->s.origin, self->s.origin, v); + len = VectorNormalize(v); + + if (len < 200) + { + self->show_hostile = level.time + 1; // wake up other monsters + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + + return true; + } + else if (len < 400) + { + if (!irand(0, 3)) + { + gorgon_growl(self); + return true; + } + } + + if (!irand(0, 3)) + { + AngleVectors(self->s.angles, vf, vr, NULL); + dot = DotProduct(vf, v); + dot2 = DotProduct(vr, v); + + if (dot > -0.85 && dot < -0.25) //Behind and aesthetically correct + { + gorgon_growl(self); + + if (dot2 > 0) //to the right + SetAnim(self, ANIM_STAND3); + else //to the left + SetAnim(self, ANIM_STAND2); + + return true; + } + return false; + } + else + { + if (self->monsterinfo.aiflags & AI_EATING) + { + chance = irand(0, 100); + if (chance < 10) + SetAnim(self, ANIM_EAT_TEAR); + else if (chance < 20) + SetAnim(self, ANIM_EAT_PULLBACK); + else + SetAnim(self, ANIM_EAT_LOOP); + return true; + } + + return false; + } +} +/*---------------------------------------------------------------------- + Gorgon Stand -decide which standing animations to use +-----------------------------------------------------------------------*/ +void gorgon_stand(edict_t *self, G_Message_t *msg) +{ + int chance; + + if (self->ai_mood == AI_MOOD_DELAY) + { + SetAnim(self, ANIM_DELAY); + return; + } + + if(gorgon_check_attack(self)) + return; + + if (self->monsterinfo.aiflags & AI_EATING) + { + chance = irand(0, 100); + if (chance < 10) + SetAnim(self, ANIM_EAT_TEAR); + else if (chance < 20) + SetAnim(self, ANIM_EAT_PULLBACK); + else + SetAnim(self, ANIM_EAT_LOOP); + } + else + { + chance = irand(0, 100); + if (chance < 10) + SetAnim(self, ANIM_STAND2); + else if (chance < 20) + SetAnim(self, ANIM_STAND3); + else + SetAnim(self, ANIM_STAND1); + } + + self->monsterinfo.misc_debounce_time = level.time + 5; +} + + +/*---------------------------------------------------------------------- + Gorgon Walk -decide which walk animations to use +-----------------------------------------------------------------------*/ +void gorgon_walk(edict_t *self, G_Message_t *msg) +{ + vec3_t v; + float len; + float delta; + vec3_t targ_org; + + if(!MG_GetTargOrg(self, targ_org)) + return; + + + if (!self->enemy)//?goal? + { + SetAnim(self, ANIM_WALK1); + return; + } + + if (self->spawnflags & MSF_COWARD) + { + VectorSubtract (self->s.origin, targ_org, v); + len = VectorLength (v); + self->ideal_yaw = vectoyaw(v); + M_ChangeYaw(self); + + if (len < 200) + { + self->monsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + flrand(4.0, 7.0); + SetAnim(self, ANIM_RUN1); + return; + } + } + + if(clear_visible(self, self->enemy) && infront(self, self->enemy)) + { + VectorSubtract (self->s.origin, targ_org, v); + len = VectorLength (v); + // targ_org is within range and far enough above or below to warrant a jump + if ((len > 40) && (len < 600) && ((self->s.origin[2] < targ_org[2] - 18) || + (self->s.origin[2] > targ_org[2] + 18))) + { + if(gorgon_check_jump(self)) + { + SetAnim(self, ANIM_FJUMP); + return; + } + } + } + + delta = anglemod(self->s.angles[YAW] - self->ideal_yaw); + if (delta > 25 && delta <= 180) + { + SetAnim(self, ANIM_WALK3); + } + else if (delta > 180 && delta < 335) + { + SetAnim(self, ANIM_WALK2); + } + else + { + SetAnim(self, ANIM_WALK1); + } +} + +/*---------------------------------------------------------------------- + Gorgon Melee - decide which melee animations to use +-----------------------------------------------------------------------*/ +void gorgon_melee(edict_t *self, G_Message_t *msg) +{ + trace_t trace; + vec3_t v, source, melee_point, forward, up; + float len, seperation, melee_range, max_hop_range; + float chance; + + if(self->ai_mood == AI_MOOD_NAVIGATE) + return; + + if(!ai_have_enemy(self)) + return; + + AngleVectors(self->s.angles,forward, NULL, up); + VectorMA(self->s.origin, self->maxs[2]*0.5, up, melee_point); + VectorMA(melee_point, self->maxs[0], forward, melee_point); + + VectorSubtract (self->enemy->s.origin, melee_point, v); + len = VectorLength (v); + + seperation = self->enemy->maxs[0]; + melee_range = self->melee_range; + + + if (self->monsterinfo.attack_finished > level.time) + {//too soon to attack again +// gi.dprintf("Waiting for next attack\n"); + chance = flrand(0, 1); + if (chance < 0.6) + SetAnim(self, ANIM_STAND4); + else if (chance < 0.7) + SetAnim(self, ANIM_MELEE6); // Hop left + else if (chance < 0.8) + SetAnim(self, ANIM_MELEE7); // Hop right + else + SetAnim(self, ANIM_MELEE9); // Hop backward + + return; + } + + //ok to attack + if(len - seperation < melee_range) + {//melee +// gi.dprintf("Biting: "); + chance = flrand(0, 1); + + if(!stricmp(self->enemy->classname,"monster_rat")) + { + if(self->enemy->s.origin[2] > self->s.origin[2]) + { +// gi.dprintf(" snatch high\n"); + SetAnim(self,ANIM_SNATCHHI); + } + else + { +// gi.dprintf(" snatch low\n"); + SetAnim(self,ANIM_SNATCHLOW); + } + } + else if (chance < 0.25) + { +// gi.dprintf(" melee1\n"); + SetAnim(self, ANIM_MELEE1); // Attack left + } + else if (chance < 0.5) + { +// gi.dprintf(" melee2\n"); + SetAnim(self, ANIM_MELEE2); // Attack right + } + else if (chance < 0.75) + { +// gi.dprintf(" melee3\n"); + SetAnim(self, ANIM_MELEE3); // Attack Up + } + else + { +// gi.dprintf(" melee4\n"); + SetAnim(self, ANIM_MELEE4); // Pull back + } + + self->monsterinfo.attack_finished = level.time + flrand(0, 3 - skill->value); + return; + } + + //Out of melee range + if (len < 150)// && enemy_vis) + { + SetAnim(self, ANIM_MELEE5); + return; + } + max_hop_range = self->s.scale * GORGON_STD_MAXHOP_RNG; + if (len < max_hop_range) // Hop forward + {//cheacks ahead to see if can hop at it +// gi.dprintf(" too far\n"); + //Setup the trace +// gi.dprintf("Hopping forward\n"); + VectorCopy(self->s.origin, source); + VectorMA(source, 64 * self->s.scale, forward, source); + + gi.trace (self->s.origin, self->mins, self->maxs, source, self, MASK_SHOT,&trace); + + if (trace.ent == self->enemy || trace.fraction == 1) + SetAnim(self, ANIM_MELEE8); + else + { + VectorCopy(self->s.origin, source); + VectorMA(source, 32 * self->s.scale, forward, source); + + gi.trace (self->s.origin, self->mins, self->maxs, source, self, MASK_SHOT,&trace); + + if (trace.fraction == 1) + SetAnim(self, ANIM_MELEE7); + else + SetAnim(self, ANIM_MELEE6); + } + } +} + + +/*---------------------------------------------------------------------- + Gorgon Run -decide which run animations to use +-----------------------------------------------------------------------*/ +void gorgon_run(edict_t *self, G_Message_t *msg) +{ + vec3_t v; + float len; + float delta; + qboolean enemy_vis; + vec3_t targ_org; + + if(!ai_have_enemy(self)) + return; + + if(!MG_GetTargOrg(self, targ_org)) + return; + + if(self->flags & FL_INWATER) + { + gorgonGoSwim(self); + return; + } + + VectorSubtract (self->s.origin, targ_org, v); + len = VectorLength (v); + if(self->ai_mood == AI_MOOD_PURSUE) + { +// gi.dprintf("Running gorgon after player...\n"); + enemy_vis = clear_visible(self, self->enemy); + } + else + enemy_vis = clear_visible_pos(self, self->monsterinfo.nav_goal); + + if(enemy_vis) + {//JUMP + if(self->enemy && irand(0, 4) && self->damage_debounce_time < level.time && !self->monsterinfo.roared) + {//should we do this the first time we see player? + if(infront(self, self->enemy)) + { + if(gorgonFindAsleepGorgons(self)) + { + self->damage_debounce_time = level.time + 10; + SetAnim(self, ANIM_ROAR);//threaten, brings other monsters + return; + } + else if (!self->dmg_radius) + {//make a wakeup roar + self->dmg_radius = true; + SetAnim(self, ANIM_ROAR2); + } + } + } + // Enemy is within range and far enough above or below to warrant a jump + if(infront_pos(self, targ_org)) + { + if ((len > 40) && (len < 600) && ((self->s.origin[2] < targ_org[2] - 24) || + (self->s.origin[2] > targ_org[2] + 24))) + { + if (abs(self->s.origin[2] - targ_org[2] - 24) < 200) // Can't jump more than 200 high + { + if (!irand(0, 2)) + { + if(self->ai_mood == AI_MOOD_PURSUE||!irand(0, 4)) + {//20% chance to jump at a buoy + if(gorgon_check_jump(self)) + { + SetAnim(self, ANIM_FJUMP); + return; + } + } + } + } + } + } + } + + delta = anglemod(self->s.angles[YAW] - self->ideal_yaw); + if (delta > 45 && delta <= 180) + { + SetAnim(self, ANIM_RUN3); // Turn right + } + else if (delta > 180 && delta < 315) + { + SetAnim(self, ANIM_RUN2); // Turn left + } + else + { + SetAnim(self, ANIM_RUN1); // Run on + } +} + + +/*---------------------------------------------------------------------- + Gorgon Pain - make the decision between pains 1, 2, or 3 or slip +-----------------------------------------------------------------------*/ +qboolean gorgonCheckSlipGo (edict_t *self, qboolean frompain); +void gorgon_pain(edict_t *self, G_Message_t *msg) +{ + edict_t *tempent; + int chance, temp, damage; + qboolean force_pain; + + ParseMsgParms(msg, "eeiii", &tempent, &tempent, &force_pain, &damage, &temp); + + if(!force_pain) + { + if(!irand(0, 2)||!self->groundentity) + return; + + if(self->pain_debounce_time > level.time) + return; + } + + self->pain_debounce_time = level.time + 0.5; + + chance = irand(0, 100); + if (chance < 50) + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN2], 1, ATTN_NORM, 0); + + if(!irand(0, 4)) + self->s.skinnum = GORGON_PAIN_SKIN; + + if(skill->value > 1.0 || !gorgonCheckSlipGo(self, true)) + { + if (chance < 33) + SetAnim(self, ANIM_PAIN1); + else if (chance < 66) + SetAnim(self, ANIM_PAIN2); + else + SetAnim(self, ANIM_PAIN3); + } +} + + +/*---------------------------------------------------------------------- + Gorgon Die - choose death +-----------------------------------------------------------------------*/ +void gorgon_death_pain(edict_t *self, G_Message_t *msg) +{ + if (self->health <= -80) + { + gi.sound(self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + self->deadflag = DEAD_DEAD; + BecomeDebris(self); + return; + } +} + +void gorgon_death(edict_t *self, G_Message_t *msg) +{ + if(self->monsterinfo.aiflags&AI_DONT_THINK) + { + gi.sound(self, CHAN_VOICE, sounds[SND_DIE], 1, ATTN_NORM, 0); + if (irand(0,10) < 5) // Big enough death to be thrown back + SetAnim(self, ANIM_DIE2); + else + SetAnim(self, ANIM_DIE1); + return; + } + self->msgHandler = DeadMsgHandler; + + // check for gib + if (self->health <= -80) + { + gi.sound(self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + self->deadflag = DEAD_DEAD; + BecomeDebris(self); + return; + } + + if (self->deadflag == DEAD_DEAD) // Dead but still being hit + return; + + self->pre_think = NULL; + self->next_pre_think = -1; + + self->gravity = 1.0f; + self->svflags |= SVF_TAKE_NO_IMPACT_DMG | SVF_DO_NO_IMPACT_DMG; + // regular death + self->s.skinnum = GORGON_PAIN_SKIN; + gi.sound(self, CHAN_VOICE, sounds[SND_DIE], 1, ATTN_NORM, 0); + self->deadflag = DEAD_DEAD; + self->takedamage = DAMAGE_YES; + + if (self->health <= -10) // Big enough death to be thrown back + SetAnim(self, ANIM_DIE2); + else + SetAnim(self, ANIM_DIE1); +} + + + +/*---------------------------------------------------------------------- + + ACTION FUNCTIONS FOR THE MONSTER + +-----------------------------------------------------------------------*/ + +void gorgon_footstep (edict_t *self) +{ + int chance; + + chance = irand(0, 100); + if (chance < 25) + gi.sound(self, CHAN_BODY, sounds[SND_STEP1], 1, ATTN_NORM, 0); + else if (chance < 50) + gi.sound(self, CHAN_BODY, sounds[SND_STEP2], 1, ATTN_NORM, 0); + else if (chance < 75) + gi.sound(self, CHAN_BODY, sounds[SND_STEP3], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_BODY, sounds[SND_STEP4], 1, ATTN_NORM, 0); +} + +void gorgon_growl (edict_t *self) +{ + int chance; + + chance = irand(0, 100); + if (chance < 10) + gi.sound(self, CHAN_WEAPON, sounds[SND_GROWL1], 1, ATTN_NORM, 0); + else if (chance < 20) + gi.sound(self, CHAN_WEAPON, sounds[SND_GROWL2], 1, ATTN_NORM, 0); + else if (chance < 30) + gi.sound(self, CHAN_WEAPON, sounds[SND_GROWL3], 1, ATTN_NORM, 0); +} + +void gorgon_prethink (edict_t *self); +qboolean gorgonCheckMood(edict_t *self) +{ + self->pre_think = gorgon_prethink; + self->next_pre_think = level.time + 0.1; + + self->mood_think(self); + + if(self->ai_mood == AI_MOOD_NORMAL) + return false; + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK://melee and missile the same + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_PURSUE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_WALK: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_NAVIGATE: + if(self->flags & FL_INWATER) + { + gorgonGoSwim(self); + return true; + } + if(self->curAnimID == ANIM_RUN1 || + self->curAnimID == ANIM_RUN2|| + self->curAnimID == ANIM_RUN3) + return true; + else + SetAnim(self, ANIM_RUN1); + break; + case AI_MOOD_STAND: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_DELAY: + SetAnim(self, ANIM_DELAY); + break; + case AI_MOOD_WANDER: + case AI_MOOD_FLEE: + if(self->flags & FL_INWATER) + { + gorgonGoSwim(self); + return true; + } + if(self->curAnimID == ANIM_RUN1 || + self->curAnimID == ANIM_RUN2|| + self->curAnimID == ANIM_RUN3) + return true; + else + SetAnim(self, ANIM_RUN1); + break; + case AI_MOOD_JUMP: + if(self->jump_chance < irand(0, 100)) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_FJUMP); + break; + case AI_MOOD_EAT://FIXME: this is not neccessary? + gorgon_ai_eat(self, 0); + //QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + break; + default : +#ifdef _DEVEL + gi.dprintf("gorgon: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } + + return true; +} + +void gorgon_check_mood (edict_t *self, G_Message_t *msg) +{ + ParseMsgParms(msg, "i", &self->ai_mood); + + gorgonCheckMood(self); +} + +void gorgonbite (edict_t *self) +{ + vec3_t v; + float damage; + float melee_range; + vec3_t temp, forward, up, melee_point, bite_endpos; + trace_t trace; + + if(self->ai_mood == AI_MOOD_NAVIGATE) + return; + + //fixme: do a checkenemy that checks oldenemy & posts messages + if(!ai_have_enemy(self)) + return; + + AngleVectors(self->s.angles,forward, NULL, up); + VectorMA(self->s.origin, self->maxs[2]*0.5, up, melee_point); + VectorMA(melee_point, self->maxs[0], forward, melee_point); + + melee_range = self->s.scale * GORGON_STD_MELEE_RNG * 1.25;//give axtra range + VectorMA(melee_point, melee_range, forward, bite_endpos); + + //let's do this the right way + gi.trace(melee_point, vec3_origin, vec3_origin, bite_endpos, self, MASK_SHOT,&trace); + if (trace.fraction < 1 && !trace.startsolid && !trace.allsolid && trace.ent->takedamage)// A hit + { + if (irand(0, 1)) + gi.sound(self, CHAN_WEAPON, sounds[SND_MELEEHIT1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_WEAPON, sounds[SND_MELEEHIT2], 1, ATTN_NORM, 0); + + VectorCopy (self->enemy->s.origin, temp); + temp[2] += 5; + + VectorSubtract(self->enemy->s.origin, self->s.origin, v); + VectorNormalize(v); + + damage = irand(GORGON_DMG_MIN, GORGON_DMG_MAX) * self->monsterinfo.scale; + T_Damage (self->enemy, self, self, forward, trace.endpos, v, damage, damage/2, DAMAGE_EXTRA_BLOOD,MOD_DIED); + } + else // A misssss + { + if (irand(0, 1)) + gi.sound(self, CHAN_WEAPON, sounds[SND_MELEEMISS1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_WEAPON, sounds[SND_MELEEMISS2], 1, ATTN_NORM, 0); + } +} + +void gorgon_dead(edict_t *self) +{ + self->pre_think = NULL; + self->next_pre_think = -1; + self->deadState = DEAD_DEAD; + self->svflags |= SVF_DEADMONSTER; + M_EndDeath(self); +} + +void gorgon_land(edict_t *self) +{ + gi.sound(self, CHAN_WEAPON, sounds[SND_LAND], 1, ATTN_NORM, 0); +} + +void gorgon_eatorder (edict_t *self) +{ + if(gorgon_check_attack(self)) + return; + + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); +} + +#define JUMP_SCALE 1.5 + +void gorgon_hop (edict_t *self) +{ + vec3_t forward,right; + vec3_t temp; + + if (self->s.frame == FRAME_hop8) + { + self->movetype = PHYSICSTYPE_STEP; + self->velocity[2] = -10; + } + else + { + if (self->monsterinfo.currentmove == &gorgon_move_melee6) // hop left + { + VectorCopy (self->s.angles, temp); + temp[YAW] -= 15; + AngleVectors (temp, NULL, right, NULL); + VectorScale (right, -40*JUMP_SCALE, self->velocity); + } + else if (self->monsterinfo.currentmove == &gorgon_move_melee7) // hop right + { + VectorCopy (self->s.angles, temp); + temp[YAW] += 15; + AngleVectors (temp, NULL, right, NULL); + VectorScale (right, 40*JUMP_SCALE, self->velocity); + } + else if (self->monsterinfo.currentmove == &gorgon_move_melee8) // hop forward + { + VectorCopy (self->s.angles, temp); + AngleVectors (temp, forward, NULL, NULL); + + VectorScale (forward, 50*JUMP_SCALE, self->velocity); + } + else if (self->monsterinfo.currentmove == &gorgon_move_melee9) // hop backward + { + VectorCopy (self->s.angles, temp); + AngleVectors (temp, forward, NULL, NULL); + VectorScale (forward, -50*JUMP_SCALE, self->velocity); + } + + //self->movetype = PHYSICSTYPE_TOSS; + //self->groundentity = self; + self->velocity[2] += 175; + } +} + +void gorgonApplyJump (edict_t *self) +{ + if(Vec3IsZero(self->movedir)) + { + vec3_t forward; + +// gi.dprintf("Gorgon in FJump with no movedir!!!!\n"); + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->velocity, flrand(200, 400), forward, self->velocity); + self->velocity[2] = flrand(100, 200); + } + else + { + self->jump_time = level.time + 0.5; + VectorCopy(self->movedir, self->velocity); + VectorClear(self->movedir); + } +} + +void gorgonJumpOutWater (edict_t *self) +{ + vec3_t endpos, forward; + + if(!self->enemy) + VectorCopy(self->enemy->s.origin, endpos); + else + { + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->s.origin, 100, forward, endpos); + } + + endpos[2] += 30; + VectorSubtract(endpos, self->s.origin, self->velocity); + self->velocity[2] += 200; +} + +void gorgonForward (edict_t *self, float dist) +{ + vec3_t forward, fdir; + float dot; + + AngleVectors(self->s.angles, forward, NULL, NULL); + + VectorCopy(self->velocity, fdir); + VectorNormalize(fdir); + + dot = DotProduct(fdir, forward); + + dist *= (1 - dot); + + if(dist) + VectorMA(self->velocity, dist, forward, self->velocity); +} + +void gorgonFixPitch (edict_t *self) +{ + MG_ChangePitch(self, 0, 10); +} + +void gorgonZeroPitch (edict_t *self) +{ + self->s.angles[PITCH] = 0; +} + +void gorgonGoSwim (edict_t *self) +{ + SetAnim(self, ANIM_SWIM); +} + +void gorgonCheckInWater (edict_t *self) +{ + trace_t trace; + vec3_t endpos; + + VectorCopy(self->s.origin, endpos); + endpos[2] -= 32; + + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&trace); + if(trace.fraction < 1.0) + { + if(trace.contents & CONTENTS_SOLID || trace.contents & CONTENTS_MONSTER) + SetAnim(self, ANIM_INAIR); + } +} + +void gorgon_check_landed (edict_t *self) +{ + vec3_t pos; + float save_yspeed; + int contents; + + save_yspeed = self->yaw_speed; + self->yaw_speed *= 0.33; + self->best_move_yaw = vectoyaw(self->velocity); + MG_ChangeWhichYaw(self, false);//turn toward best_move_yaw, 1/3 as fast as if on ground + self->yaw_speed = save_yspeed; + + if(self->groundentity) + { + if(irand(0, 1)) + SetAnim(self, ANIM_LAND2); + else + SetAnim(self, ANIM_LAND); + } + else if(self->velocity[2]<0) + { + VectorCopy(self->s.origin, pos); + pos[2] += self->mins[2]; + VectorMA(pos, 0.5, self->velocity, pos); + contents = gi.pointcontents(pos); + if(contents&CONTENTS_SOLID) + { + if(irand(0, 1)) + SetAnim(self, ANIM_LAND2); + else + SetAnim(self, ANIM_LAND); + } + else if(contents&CONTENTS_WATER) + SetAnim(self, ANIM_TO_SWIM); + } +} + +void gorgon_go_inair (edict_t *self) +{ + SetAnim(self, ANIM_INAIR); +} + +qboolean gorgon_check_jump (edict_t *self) +{ + vec3_t forward, right, up; + vec3_t landing_spot,arc_spot, test_spot; + vec3_t angles , v, landing_spot_angles; + float hold; + float len; + trace_t trace; + + if(self->jump_chance < irand(0, 100)) + return false; + + if(!MG_GetTargOrg(self, landing_spot)) + { + return false; + } + + if(!infront_pos(self, landing_spot)) + return false; + + VectorSubtract(self->s.origin, landing_spot, v); + len = VectorLength(v); + + if(len > 400) + { + return false; + } + + if(self->enemy) + VectorSet(angles, 0, anglemod(-self->enemy->s.angles[YAW]), 0); + else + VectorCopy(self->s.angles, angles); + + //incorporate scale? + + // JUMPING + // Calculate landing spot behind enemy to jump to + // Caclulate arc spot to jump at which will arc the monster to the landing spot + // Calculate velocity to make monster jump to hit arc spot + + // choose landing spot behind enemy + AngleVectors (angles, forward, right, up); + + VectorMA (landing_spot, 60, forward, landing_spot); + + VectorCopy(landing_spot, test_spot); + test_spot[2] -= 1024; + + gi.trace(landing_spot, self->mins, self->maxs, test_spot, self, MASK_MONSTERSOLID|MASK_WATER,&trace); + + if (trace.fraction == 1.0) + { + return false; + } + else + { + if (!(trace.contents & CONTENTS_SOLID) && !(trace.contents & CONTENTS_WATER)) + { + return false; + } + } + +/* if (trace.startsolid || trace.allsolid) + { + if(trace.ent != self->enemy) + return; + }*/ + + self->jump_time = level.time + 0.5; + + // calculate arc spot (the top of his jump arc) which will land monster at landing spot + VectorSubtract (self->s.origin, landing_spot, v); + landing_spot_angles[PITCH] = 0; + landing_spot_angles[ROLL] = 0; + landing_spot_angles[YAW] = vectoyaw(v); + + AngleVectors (landing_spot_angles, forward, right, up); + + VectorMA (landing_spot, 20, forward, arc_spot); + VectorMA (landing_spot, 180, up, arc_spot); + + AngleVectors (self->s.angles, forward, right, up); + + // Calculate velocity to make monster jump to hit arc spot + VectorSubtract (arc_spot,self->s.origin, v); // Face monster to arc spot + vectoangles(v,angles); + self->best_move_yaw = angles[YAW]; + + len = VectorLength (v); + + hold = len / 200; + + AngleVectors (angles, forward, right, up); + VectorScale (forward, 300 * hold, self->movedir); + + self->movedir[2] = 200 * hold; + + self->monsterinfo.jump_time = level.time + 3; + return true; +} + +void gorgon_jump (edict_t *self) +{ + vec3_t forward, right, up; + vec3_t landing_spot,arc_spot, test_spot; + vec3_t angles , v, landing_spot_angles; + float hold; + float len; + trace_t trace; + + if(!MG_GetTargOrg(self, landing_spot)) + { + if(!irand(0,3)) + SetAnim(self, ANIM_ROAR2); + else + SetAnim(self, ANIM_RUN1); + return; + } + + VectorSubtract(self->s.origin, landing_spot, v); + len = VectorLength(v); + + if(len > 400) + { + if(!irand(0,3)) + SetAnim(self, ANIM_ROAR2); + else + SetAnim(self, ANIM_RUN1); + return; + } + + if(self->enemy) + VectorSet(angles, 0, anglemod(-self->enemy->s.angles[YAW]), 0); + else + VectorCopy(self->s.angles, angles); + + //incorporate scale? + + // JUMPING + // Calculate landing spot behind enemy to jump to + // Caclulate arc spot to jump at which will arc the monster to the landing spot + // Calculate velocity to make monster jump to hit arc spot + + // choose landing spot behind enemy + AngleVectors (angles, forward, right, up); + + VectorMA (landing_spot, 60, forward, landing_spot); + + VectorCopy(landing_spot, test_spot); + test_spot[2] -= 1024; + + gi.trace(landing_spot, self->mins, self->maxs, test_spot, self, MASK_MONSTERSOLID|MASK_WATER,&trace); + + if (trace.fraction == 1.0) + { + return; + } + else + { + if (!(trace.contents & CONTENTS_SOLID) && !(trace.contents & CONTENTS_WATER)) + { + return; + } + } + +/* if (trace.startsolid || trace.allsolid) + { + if(trace.ent != self->enemy) + return; + }*/ + + self->jump_time = level.time + 0.5; + + // calculate arc spot (the top of his jump arc) which will land monster at landing spot + VectorSubtract (self->s.origin, landing_spot, v); + landing_spot_angles[PITCH] = 0; + landing_spot_angles[ROLL] = 0; + landing_spot_angles[YAW] = vectoyaw(v); + + AngleVectors (landing_spot_angles, forward, right, up); + + VectorMA (landing_spot, 20, forward, arc_spot); + VectorMA (landing_spot, 180, up, arc_spot); + + AngleVectors (self->s.angles, forward, right, up); + + // Calculate velocity to make monster jump to hit arc spot + VectorSubtract (arc_spot,self->s.origin, v); // Face monster to arc spot + vectoangles(v,angles); + self->best_move_yaw = angles[YAW]; + + len = VectorLength (v); + + hold = len / 200; + + AngleVectors (angles, forward, right, up); + VectorScale (forward, 300 * hold, self->velocity); + + self->velocity[2] = 200 * hold; + + self->monsterinfo.jump_time = level.time + 3; +} + +//Gorgon Evasion! + +void gorgon_evade (edict_t *self, G_Message_t *msg) +{ + edict_t *projectile; + HitLocation_t HitLocation; + int duck_chance, dodgeleft_chance, dodgeright_chance, jump_chance, backflip_chance, frontflip_chance; + int chance; + float eta; + + ParseMsgParms(msg, "eif", &projectile, &HitLocation, &eta); + + if(eta<0.3) + return;//needs a .3 seconds to respond, minimum + + switch(HitLocation) + { + case hl_Head: + duck_chance = 30; + dodgeleft_chance = 50; + dodgeright_chance = 50; + jump_chance = 0; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_TorsoFront://split in half? + duck_chance = 20; + dodgeleft_chance = 40; + dodgeright_chance = 40; + jump_chance = 0; + backflip_chance = 80; + frontflip_chance = 0; + break; + case hl_TorsoBack://split in half? + duck_chance = 20; + dodgeleft_chance = 40; + dodgeright_chance = 40; + jump_chance = 0; + backflip_chance = 0; + frontflip_chance = 80; + break; + case hl_ArmUpperLeft: + duck_chance = 10; + dodgeleft_chance = 0; + dodgeright_chance = 90; + jump_chance = 0; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_ArmLowerLeft://left arm + duck_chance = 0; + dodgeleft_chance = 0; + dodgeright_chance = 80; + jump_chance = 30; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_ArmUpperRight: + duck_chance = 20; + dodgeleft_chance = 90; + dodgeright_chance = 0; + jump_chance = 0; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_ArmLowerRight://right arm + duck_chance = 0; + dodgeleft_chance = 80; + dodgeright_chance = 0; + jump_chance = 30; + backflip_chance = 20; + frontflip_chance = 20; + break; + case hl_LegUpperLeft: + duck_chance = 0; + dodgeleft_chance = 0; + dodgeright_chance = 60; + jump_chance = 50; + backflip_chance = 30; + frontflip_chance = 30; + break; + case hl_LegLowerLeft://left leg + duck_chance = 0; + dodgeleft_chance = 0; + dodgeright_chance = 30; + jump_chance = 90; + backflip_chance = 60; + frontflip_chance = 60; + break; + case hl_LegUpperRight: + duck_chance = 0; + dodgeleft_chance = 60; + dodgeright_chance = 0; + jump_chance = 50; + backflip_chance = 30; + frontflip_chance = 30; + break; + case hl_LegLowerRight://right leg + duck_chance = 0; + dodgeleft_chance = 30; + dodgeright_chance = 0; + jump_chance = 90; + backflip_chance = 30; + frontflip_chance = 30; + break; + default: + duck_chance = 5; + dodgeleft_chance = 10; + dodgeright_chance = 10; + jump_chance = 10; + backflip_chance = 10; + frontflip_chance = 10; + break; + } + if(self->jump_chance < 0) + jump_chance = -1; + + chance = irand(0, 100); + if(chance < frontflip_chance) + { + SetAnim(self, ANIM_MELEE8);//hop forward + return; + } + + chance = irand(0, 100); + if(chance < backflip_chance) + { + if(self->curAnimID == ANIM_RUN1&&irand(0,10)<8)//running, do the front jump + { + SetAnim(self, ANIM_MELEE10);//jump forward + } + else + { + SetAnim(self, ANIM_MELEE9);//hop forward + } + return; + } + + chance = irand(0, 100); + if(chance < dodgeleft_chance) + { + SetAnim(self, ANIM_MELEE6);//hop left + return; + } + + chance = irand(0, 100); + if(chance < dodgeright_chance) + { + SetAnim(self, ANIM_MELEE7);//hop left + return; + } + + chance = irand(0, 100); + if(chance < jump_chance) + { + SetAnim(self, ANIM_MELEE10);//jump forward + return; + } + + chance = irand(0, 100); + if(chance < duck_chance) + { + SetAnim(self, ANIM_PAIN1);//jump forward + return; + } +} + +/* +======================================== +GORGON PICK UP AND GORE SOMETHING +======================================== +*/ +void gorgon_ready_catch (edict_t *self) +{ + float enemy_zdist, ok_zdist; + + if(!ai_have_enemy(self)) + { + SetAnim(self,ANIM_CATCH); + return; + } + + ok_zdist = 128 * (self->s.scale*0.5/2.5); + if(ok_zdist<48) + ok_zdist = 48; + + enemy_zdist = self->enemy->absmin[2] - self->absmax[2]; + + if(enemy_zdist <= 0 || (enemy_zdist <= ok_zdist && self->enemy->velocity[2] <= -60)) + SetAnim(self,ANIM_CATCH); + else + SetAnim(self,ANIM_READY_CATCH); +} + +void gorgon_throw_toy(edict_t *self) +{ + if(!self->enemy) + return; + + self->enemy->flags &= ~FL_FLY; + self->enemy->velocity[0] = self->enemy->velocity[1] = 0; + self->enemy->velocity[2] = 500; + if(self->enemy->movetype>NUM_PHYSICSTYPES) + self->enemy->movetype = PHYSICSTYPE_STEP; + VectorRandomCopy(vec3_origin,self->enemy->avelocity,300); + + if(stricmp(self->enemy->classname,"player")) + QPostMessage(self->enemy, MSG_DEATH, PRI_DIRECTIVE, NULL); + + //FIXME: What if I miss? Set the monster's touch to + // something that restores it's angles and normal thinking (AI_FLEE) +/* if(!stricmp(self->enemy->classname,"player")) + { + PlayerAnimSetUpperSeq(self->enemy, 92); + PlayerAnimSetLowerSeq(&self->enemy->client->playerinfo, 92); + }*/ +} + +void gorgon_toy_ofs(edict_t *self, float ofsf, float ofsr, float ofsu) +{ + vec3_t enemy_ofs, forward, right, up, blooddir, enemy_face; + + if(!self->enemy) + return; + + //adjust for scale + ofsf *= self->s.scale*0.5/2.5; + ofsr *= self->s.scale*0.5/2.5; + ofsu += self->mins[2];//because origin moved up since those were calced + ofsu *= self->s.scale*0.25/2.5; + + AngleVectors(self->s.angles, forward, right, up); + VectorMA(self->s.origin, ofsf, forward, enemy_ofs); + VectorMA(enemy_ofs, ofsr, right, enemy_ofs); + VectorMA(enemy_ofs, ofsu, up, self->enemy->s.origin); + VectorSubtract(self->enemy->s.origin, self->s.origin, blooddir); + + VectorScale(blooddir, -1, enemy_face); + enemy_face[2]/=10; + vectoangles(enemy_face, self->enemy->s.angles); + + switch(self->enemy->count) + { + case 1: + self->enemy->s.angles[PITCH]=anglemod(self->enemy->s.angles[PITCH]+90);//can't do roll? + break; + case 2: + self->enemy->s.angles[PITCH]=anglemod(self->enemy->s.angles[PITCH]-90);//can't do roll? + break; + case 3: + self->enemy->s.angles[ROLL]=anglemod(self->enemy->s.angles[ROLL]+90);//can't do roll? + break; + case 4: + self->enemy->s.angles[ROLL]=anglemod(self->enemy->s.angles[ROLL]-90);//can't do roll? + break; + default: + break; + } + + + VectorClear(self->enemy->velocity); + VectorClear(self->enemy->avelocity); + + if(flrand(0,1)<0.5) + { + if(self->enemy->materialtype == MAT_INSECT) + gi.CreateEffect(&self->enemy->s, FX_BLOOD, CEF_FLAG8, self->enemy->s.origin, "ub", blooddir, 200); + else + gi.CreateEffect(&self->enemy->s, FX_BLOOD, 0, self->enemy->s.origin, "ub", blooddir, 200); + } +} + +void gorgon_check_snatch(edict_t *self, float ofsf, float ofsr, float ofsu) +{ + float enemy_dist, ok_zdist; + vec3_t forward, right, up, startpos, endpos; + trace_t trace; + + //adjust for scale + ok_zdist = 64 * (self->s.scale*0.5/2.5); + if(ok_zdist<24) + ok_zdist = 24; + + AngleVectors(self->s.angles,forward,right,up); + VectorMA(self->s.origin, self->maxs[0], forward, startpos); + VectorMA(startpos, self->maxs[2]*0.5, up, startpos); + VectorCopy(startpos, endpos); + VectorMA(endpos, ofsf, forward, endpos); + VectorMA(endpos, ofsr, right, endpos); + VectorMA(endpos, ofsu, up, endpos); + gi.trace(startpos,vec3_origin,vec3_origin,endpos, self, MASK_SHOT,&trace); + VectorCopy(trace.endpos,endpos); + + VectorSubtract(self->enemy->s.origin, endpos, endpos); + enemy_dist = VectorLength(endpos); + if(enemy_dist>ok_zdist) + { +// gi.dprintf("Snatch missed (%4.2f)\n", enemy_dist); + self->msgHandler = DefaultMsgHandler; + if(!stricmp(self->enemy->classname,"player")) + if(self->oldenemy) + if(self->oldenemy->health>0) + { + self->oldenemy = NULL; + self->enemy = self->oldenemy; + } + + if(self->curAnimID == ANIM_SNATCHLOW) + SetAnim(self,ANIM_MISS); + else + SetAnim(self,ANIM_MELEE2);//? + return; + } +// gi.dprintf("SNAGGED!\n"); + //FIXME: if health is low, just chomp it now + self->enemy->flags |= FL_FLY; + if(self->enemy->movetype>NUM_PHYSICSTYPES) + self->enemy->movetype = PHYSICSTYPE_FLY; + + if(stricmp(self->enemy->classname,"player")) + { + self->enemy->monsterinfo.aiflags |= AI_DONT_THINK; + self->enemy->count = irand(1,5); + } + else + self->enemy->nextthink = level.time + 10;//stuck for 10 seconds. + + VectorClear(self->enemy->velocity); + VectorClear(self->enemy->avelocity); +} + +void gorgon_gore_toy(edict_t *self, float jumpht) +{ + float enemy_zdist, ok_zdist; + byte num_chunks; + vec3_t dir, forward; + + if(jumpht!=-1) + {//not getting here + self->velocity[2] += jumpht; + if(self->groundentity) + { + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->velocity, -100, forward, self->velocity); + } + } + else + self->count = 0; + + if(!self->enemy) + return; + + if(self->enemy->health<0) + return; + + if(self->count) + return; + + ok_zdist = 56 * (self->s.scale*0.5/2.5); + if(ok_zdist<36) + ok_zdist = 36; + enemy_zdist = self->enemy->s.origin[2] - self->s.origin[2]; + if(enemy_zdist <= self->maxs[2] + ok_zdist || jumpht == -1) + { + gi.sound(self, CHAN_WEAPON, sounds[SND_MELEEMISS2], 1, ATTN_NORM, 0); + if(jumpht!=-1) + self->count = 1; + VectorCopy(self->velocity,dir); + VectorNormalize(dir); + if(self->enemy->materialtype != MAT_FLESH)//foo + self->enemy->materialtype = MAT_FLESH; + num_chunks = (byte)(self->enemy->health/4); + if(num_chunks>15) + num_chunks = 15; + SprayDebris(self->enemy, self->enemy->s.origin, num_chunks, self->enemy->health*4);//self->enemy is thingtype wood?! + + if(stricmp(self->enemy->classname,"player")) + { + gi.sound(self->enemy, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + BecomeDebris(self->enemy); + } + else + { + self->enemy->nextthink = level.time; + T_Damage (self->enemy, self, self, self->velocity, self->enemy->s.origin, dir, 2000, 300, 0,MOD_DIED); + } + } +} + +void gorgon_miss_sound (edict_t *self) +{ + if (irand(0, 1)) + gi.sound(self, CHAN_WEAPON, sounds[SND_MELEEMISS1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_WEAPON, sounds[SND_MELEEMISS2], 1, ATTN_NORM, 0); +} + +void gorgon_anger_sound (edict_t *self) +{ + byte chance; + vec3_t spot; + + chance = irand(0,100); + if (chance < 10) + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else if (chance < 20) + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN2], 1, ATTN_NORM, 0); + else if (chance < 30) + gi.sound(self, CHAN_WEAPON, sounds[SND_MELEEHIT1], 1, ATTN_NORM, 0); + else if (chance < 40) + gi.sound(self, CHAN_WEAPON, sounds[SND_MELEEHIT2], 1, ATTN_NORM, 0); + else if (chance < 50) + gi.sound(self, CHAN_VOICE, sounds[SND_DIE], 1, ATTN_NORM, 0); + else if (chance < 60) + gorgon_growl(self); + + if(self->enemy) + { + chance = (byte)irand(1,3); + VectorCopy(self->enemy->s.origin, spot); + + QPostMessage(self->enemy,MSG_DISMEMBER,PRI_DIRECTIVE,"ii", self->enemy->health*0.5, irand(1,13));//do I need last three if not sending them? + QPostMessage(self->enemy,MSG_PAIN,PRI_DIRECTIVE,"ii", self->enemy, self);//do I need last three if not sending them? + } +} + +void gorgon_go_snatch (edict_t *self) +{ + SetAnim(self,ANIM_SNATCH); +} + +void gorgon_done_gore (edict_t *self) +{ + self->msgHandler = DefaultMsgHandler; + self->count = 0; + if(self->oldenemy) + { + if(self->oldenemy->health>0) + { + self->enemy = self->oldenemy; + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + return; + } + } + SetAnim(self,ANIM_EAT_LOOP); +} + +/* ======================================== +Trip and fall if making too tight a turn, wont work until origin is in center +========================================== */ + +void gorgonRoll (edict_t *self, float rollangle) +{//FIXME: cannot interrupt!!! + self->s.angles[ROLL] = anglemod(rollangle); +} + +void gorgonLerpOff (edict_t *self) +{ + self->s.renderfx &= ~RF_FRAMELERP; +} + +void gorgonLerpOn (edict_t *self) +{ + self->s.renderfx |= RF_FRAMELERP; +} + +qboolean gorgonCheckSlipGo (edict_t *self, qboolean frompain) +{ + vec3_t v, right; + + if(!self->enemy) + return false; + + VectorSubtract (self->enemy->s.origin, self->s.origin, v); + VectorNormalize(v); + AngleVectors(self->s.angles, NULL, right, NULL); + if(DotProduct(right, v) > 0.3 && irand(0, 1)) + {//fall down, go boom + if(frompain) + { + SetAnim(self, ANIM_SLIP_PAIN); + return true; + } + else if(self->monsterinfo.misc_debounce_time < level.time && !irand(0, 4)) + { + self->monsterinfo.misc_debounce_time = level.time + 7; + SetAnim(self, ANIM_SLIP); + return true; + } + } + + return false; +} + +void gorgonCheckSlip (edict_t *self) +{ + if(!(self->spawnflags & MSF_GORGON_SPEEDY) && self->s.scale > 0.75) + { + gorgonCheckMood(self); + return; + } + + if(!gorgonCheckSlipGo (self, false)) + gorgonCheckMood(self); +} + +void gorgonSlide (edict_t *self, float force) +{ + vec3_t right; + + if(!self->groundentity) + return;//already in air + + if(force == 0) + { + self->friction = 1.0; + return; + } + + AngleVectors(self->s.angles, NULL, right, NULL); + VectorMA(self->velocity, force, right, self->velocity); + self->velocity[2] = 50; + self->friction = 0.2; +} + +void gorgonChooseDeath (edict_t *self) +{ + if(irand(0, 1)) + gorgon_death2twitch(self); +} + +void gorgon_ai_swim (edict_t *self, float dist) +{ + vec3_t dir = {0, 0, 0}; + vec3_t vec, angles; + + gorgon_prethink(self); + self->pre_think = gorgon_prethink; + self->next_pre_think = level.time + 0.1; + + self->mood_think(self); +// MG_Pathfind(self, false); + + MG_SetNormalizeVelToGoal(self, dir); + + if(Vec3IsZero(dir)) + { +// gi.dprintf("swimming gorgon couldn't find a target\n"); + Vec3ScaleAssign(0.8, self->velocity); + return; + } + + self->ideal_yaw = vectoyaw(dir); + MG_ChangeYaw(self); + + if(dist == -1) + Vec3ScaleAssign(150, dir); + else + Vec3ScaleAssign(dist * 3, dir); + + VectorAdd(self->velocity, dir, self->velocity); + VectorNormalize(self->velocity); + Vec3ScaleAssign(200, self->velocity); + + if(!self->enemy) + return; + + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + vectoangles(vec, angles); + MG_ChangePitch(self, angles[PITCH], 10); + + //MG_ChangePitchForZVel(self, 10, dist * 3, 60); + + if(dist != -1) + {//-1 = charge + if(self->monsterinfo.attack_finished < level.time) + { + if(M_ValidTarget(self, self->enemy)) + { + if(clear_visible(self, self->enemy)) + { + if(infront(self, self->enemy)) + { + VectorSubtract(self->enemy->s.origin, self->s.origin, dir); + dist = VectorLength(dir); + + if(dist < self->melee_range + VectorLength(self->velocity) * 0.1) + { + if(irand(0, 1)) + SetAnim(self, ANIM_SWIM_BITE_A); + else + SetAnim(self, ANIM_SWIM_BITE_B); + self->monsterinfo.attack_finished = level.time + flrand(0, 3 - skill->value); + } + else if(self->monsterinfo.jump_time < level.time) + { + if(!(self->enemy->flags & FL_INWATER)) + { + if(dist < GORGON_STD_MAXHOP_RNG * 2) + SetAnim(self, ANIM_OUT_WATER); + } + } + } + } + } + } + } +} + +void gorgon_prethink (edict_t *self) +{//also make wake on surface of water? + if(self->flags & FL_INWATER) + { + self->gravity = 0.0f; + self->svflags |= SVF_TAKE_NO_IMPACT_DMG | SVF_DO_NO_IMPACT_DMG; + + if(!self->wait) + { + gi.CreateEffect(NULL, FX_WATER_ENTRYSPLASH, 0, + self->s.origin, "bd", 128|96, vec3_up); + self->wait = true; + } + + if(self->curAnimID == ANIM_INAIR) + SetAnim(self, ANIM_TO_SWIM); + } + else + { + gi.RemoveEffects (&self->s, FX_M_EFFECTS); + self->gravity = 1.0f; + self->svflags &= ~SVF_TAKE_NO_IMPACT_DMG; + if(self->s.scale>0.5) + self->svflags &= ~SVF_DO_NO_IMPACT_DMG; + + if(self->wait) + { + gi.CreateEffect(NULL, FX_WATER_ENTRYSPLASH, 0, + self->s.origin, "bd", 128|96, vec3_up); + self->wait = false; + } + + if(self->curAnimID == ANIM_SWIM || + self->curAnimID == ANIM_SWIM_BITE_A || + self->curAnimID == ANIM_SWIM_BITE_B) + SetAnim(self, ANIM_RUN1); + + gorgonFixPitch(self); + } + self->next_pre_think = level.time + 0.1; +} + +void gorgon_ai_eat(edict_t *self, float crap) +{//fixme: crap will be a yaw mod for view_ofs looking around + vec3_t forward, right, v; + float edist, fdot, rdot; + + if(self->enemy) + { + VectorSubtract(self->enemy->s.origin, self->s.origin, v); + edist = VectorNormalize(v); + if(edistwakeup_distance) + { + if(visible(self, self->enemy)) + { + self->spawnflags &= ~MSF_EATING; + self->monsterinfo.aiflags &= ~AI_EATING; + FoundTarget(self, true); + return; + } + } + else if(self->curAnimID == ANIM_EAT_LOOP && !irand(0, 5)) + { + if(visible(self, self->enemy)) + { + AngleVectors(self->s.angles, forward, right, NULL); + fdot = DotProduct(v, forward); + rdot = DotProduct(v, right); + if(fdot < 0) + { + if(rdot > 0.3) + SetAnim(self, ANIM_EAT_RIGHT); + if(rdot < -0.3) + SetAnim(self, ANIM_EAT_LEFT); + else + SetAnim(self, ANIM_EAT_UP); + return; + } + } + } + } + else + FindTarget(self); + + + if(crap != -1) + return; + + switch(self->curAnimID) + { + case ANIM_EAT_DOWN: + SetAnim(self, ANIM_EAT_LOOP); + break; + + case ANIM_EAT_UP: + SetAnim(self, ANIM_LOOK_AROUND); + break; + + case ANIM_EAT_LOOP: + if(irand(0, 1)) + SetAnim(self, ANIM_EAT_LOOP); + else if(irand(0, 1)) + SetAnim(self, ANIM_EAT_PULLBACK); + else if(irand(0, 1)) + SetAnim(self, ANIM_EAT_TEAR); + else if(irand(0, 1))//fixme- check gorgon to right + SetAnim(self, ANIM_EAT_SNAP); + else if(irand(0, 1))//fixme- check if gorgon to left snapped + SetAnim(self, ANIM_EAT_REACT); + else if(irand(0, 1))//fixme- check enemy + SetAnim(self, ANIM_EAT_LEFT); + else//fixme- check enemy + SetAnim(self, ANIM_EAT_RIGHT); + break; + + case ANIM_EAT_TEAR: + SetAnim(self, ANIM_EAT_LOOP); + break; + + case ANIM_EAT_PULLBACK: + SetAnim(self, ANIM_EAT_LOOP); + break; + + case ANIM_LOOK_AROUND: + SetAnim(self, ANIM_EAT_DOWN); + break; + + case ANIM_EAT_LEFT: + SetAnim(self, ANIM_EAT_LOOP); + break; + + case ANIM_EAT_RIGHT: + SetAnim(self, ANIM_EAT_LOOP); + break; + + case ANIM_EAT_SNAP: + SetAnim(self, ANIM_EAT_LOOP); + break; + + case ANIM_EAT_REACT: + SetAnim(self, ANIM_EAT_LOOP); + break; + } +} + +void gorgon_jump_msg (edict_t *self, G_Message_t *msg) +{ + if(self->jump_chance < irand(0, 100)) + return; + SetAnim(self, ANIM_FJUMP); +} + +void GorgonStaticsInit() +{ + classStatics[CID_GORGON].msgReceivers[MSG_STAND] = gorgon_stand; + classStatics[CID_GORGON].msgReceivers[MSG_WALK] = gorgon_walk; + classStatics[CID_GORGON].msgReceivers[MSG_RUN] = gorgon_run; + classStatics[CID_GORGON].msgReceivers[MSG_EAT] = gorgon_eat; + classStatics[CID_GORGON].msgReceivers[MSG_MELEE] = gorgon_melee; + classStatics[CID_GORGON].msgReceivers[MSG_MISSILE] = gorgon_melee; + classStatics[CID_GORGON].msgReceivers[MSG_WATCH] = gorgon_walk; + classStatics[CID_GORGON].msgReceivers[MSG_PAIN] = gorgon_pain; + classStatics[CID_GORGON].msgReceivers[MSG_DEATH] = gorgon_death; + classStatics[CID_GORGON].msgReceivers[MSG_JUMP]=gorgon_jump_msg; + classStatics[CID_GORGON].msgReceivers[MSG_DEATH_PAIN] = gorgon_death_pain; + classStatics[CID_GORGON].msgReceivers[MSG_CHECK_MOOD] = gorgon_check_mood; + classStatics[CID_GORGON].msgReceivers[MSG_VOICE_POLL] = gorgon_roar_response; + classStatics[CID_GORGON].msgReceivers[MSG_EVADE] = gorgon_evade; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/gorgon/tris.fm"); + + sounds[SND_PAIN1]= gi.soundindex ("monsters/gorgon/pain1.wav"); + sounds[SND_PAIN2]= gi.soundindex ("monsters/gorgon/pain2.wav"); + sounds[SND_DIE]= gi.soundindex ("monsters/gorgon/death1.wav"); + sounds[SND_GURGLE]= gi.soundindex ("monsters/gorgon/gurgle.wav"); //what is this for? + sounds[SND_GIB]= gi.soundindex ("monsters/gorgon/gib.wav"); + + sounds[SND_MELEEHIT1]= gi.soundindex ("monsters/gorgon/meleehit1.wav"); + sounds[SND_MELEEHIT2] = gi.soundindex ("monsters/gorgon/meleehit2.wav"); + sounds[SND_MELEEMISS1] = gi.soundindex ("monsters/gorgon/meleemiss1.wav"); + sounds[SND_MELEEMISS2] = gi.soundindex ("monsters/gorgon/meleemiss2.wav"); + + sounds[SND_STEP1] = gi.soundindex ("monsters/gorgon/footstep1.wav"); + sounds[SND_STEP2] = gi.soundindex ("monsters/gorgon/footstep2.wav"); + sounds[SND_STEP3] = gi.soundindex ("monsters/gorgon/footstep3.wav"); + sounds[SND_STEP4] = gi.soundindex ("monsters/gorgon/footstep4.wav"); + + sounds[SND_GROWL1] = gi.soundindex ("monsters/gorgon/growl1.wav"); + sounds[SND_GROWL2] = gi.soundindex ("monsters/gorgon/growl2.wav"); + sounds[SND_GROWL3] = gi.soundindex ("monsters/gorgon/growl3.wav"); + + sounds[SND_LAND] = gi.soundindex ("monsters/gorgon/land.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_GORGON].resInfo = &resInfo; +} + +/*QUAKED monster_gorgon_leader (1 .5 0) (-16 -16 -0) (16 16 32) AMBUSH ASLEEP EATING 8 16 32 64 128 + +The gorgon leader + +*/ +void SP_monster_gorgon_leader (edict_t *self) +{ + float scale; + + G_SetToFree(self); + return; + // Generic Monster Initialization + if (!monster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_GORGON; + self->think = walkmonster_start_go; + self->monsterinfo.aiflags |= AI_BRUTAL|AI_AGRESSIVE|AI_SHOVE; + + if (!self->health) + self->health = GORGON_LEADER_HEALTH; + + self->mass = GORGON_LEADER_MASS; + self->yaw_speed = 10; + self->isBlocked = gorgon_blocked; + + self->movetype=PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + self->materialtype = MAT_FLESH; + + VectorSet(self->mins,-42,-42,0);//-48,-48,0 + VectorSet(self->maxs,42,42,56);//48,48,64 + self->viewheight = self->maxs[2]*0.8; + + self->s.modelindex = classStatics[CID_GORGON].resInfo->modelIndex; + + //Big guy can be stood on top of perhaps? + //self->touch = M_Touch; + + self->s.skinnum = GORGON_SKIN; + + scale = 2;//flrand(0.9, 1.4); + + if (!self->s.scale) + { + self->monsterinfo.scale = self->s.scale = scale; + } + + self->monsterinfo.aiflags |= AI_NIGHTVISION; + + VectorScale(self->mins, scale, self->mins); + VectorScale(self->maxs, scale, self->maxs); + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + + MG_InitMoods(self); + self->svflags |= SVF_WAIT_NOTSOLID; +} + + +/*QUAKED monster_gorgon (1 .5 0) (-16 -16 0) (16 16 32) AMBUSH ASLEEP EATING SPEEDY 16 32 64 128 WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +The gorgon + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +EATING - Chomp chomp... chewie chomp (wakeup_distance will default to 300) + +SPEEDY - generally faster gorgon + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 20 +melee_range = 48 +missile_range = 0 +min_missile_range = 0 +bypass_missile_chance = 0 +jump_chance = 80 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +void SP_monster_gorgon (edict_t *self) +{ + //fix some spawnflags + if (self->spawnflags & MSF_GORGON_COWARD) + { + self->spawnflags &= ~MSF_GORGON_COWARD; + self->spawnflags |= MSF_COWARD; + } + + // Generic Monster Initialization + if (!walkmonster_start(self)) // Failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_GORGON; + self->materialtype = MAT_FLESH; + self->touch = M_Touch; + + self->mass = GORGON_MASS; + if(self->spawnflags & MSF_GORGON_SPEEDY) + self->yaw_speed = 30; + else + self->yaw_speed = 15; + self->dmg = 0;//used for slight turn during run + + self->movetype=PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + self->solid=SOLID_BBOX; + + if(irand(0, 1)) + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + self->s.modelindex = classStatics[CID_GORGON].resInfo->modelIndex; + + self->s.skinnum = GORGON_SKIN; + + self->monsterinfo.otherenemyname = "monster_rat"; + + + if (self->spawnflags & MSF_COWARD) + { + if(!self->health) + self->health = GORGON_HEALTH/2; + + self->monsterinfo.aiflags |= AI_COWARD; + self->monsterinfo.scale = self->s.scale = 0.5; + } + else + { + if (!self->health) + self->health = GORGON_HEALTH; + + if (!self->s.scale) + self->s.scale = flrand(GORGON_SCALE_MIN, GORGON_SCALE_MAX); + self->monsterinfo.scale = self->s.scale; + } + + if (self->spawnflags & MSF_EATING) + { + self->monsterinfo.aiflags |= AI_EATING; + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + if(!self->wakeup_distance) + self->wakeup_distance = 300; + } + else + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } + + MG_InitMoods(self); + + self->svflags |= SVF_WAIT_NOTSOLID; + self->flags |= FL_AMPHIBIAN; + self->monsterinfo.aiflags |= AI_SWIM_OK; + + self->monsterinfo.roared = false; + + if(!irand(0, 2))//33% chance of not making a wakeup roar + self->dmg_radius = true; + else + self->dmg_radius = false; + + self->pre_think = gorgon_prethink; + self->next_pre_think = level.time + 0.1; +} diff --git a/Toolkit/Programming/GameCode/game/m_gorgon.h b/Toolkit/Programming/GameCode/game/m_gorgon.h new file mode 100644 index 0000000..5244187 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_gorgon.h @@ -0,0 +1,198 @@ +typedef enum AnimID_e +{ + ANIM_STAND1, + ANIM_STAND2, + ANIM_STAND3, + ANIM_STAND4, + ANIM_WALK1, + ANIM_WALK2, + ANIM_WALK3,//10 + ANIM_MELEE1, + ANIM_MELEE2, + ANIM_MELEE3, + ANIM_MELEE4, + ANIM_MELEE5, + ANIM_MELEE6, + ANIM_MELEE7, + ANIM_MELEE8, + ANIM_MELEE9, + ANIM_MELEE10,//20 + ANIM_FJUMP, + ANIM_RUN1, + ANIM_RUN2, + ANIM_RUN3, + ANIM_PAIN1, + ANIM_PAIN2, + ANIM_PAIN3, + ANIM_DIE1, + ANIM_DIE2, + ANIM_SNATCH,//30 + ANIM_CATCH, + ANIM_MISS, + ANIM_READY_CATCH, + ANIM_SNATCHHI, + ANIM_SNATCHLOW, + ANIM_SLIP, + ANIM_SLIP_PAIN, + ANIM_DELAY, + ANIM_ROAR, + ANIM_ROAR2,//40 + ANIM_LAND2, + ANIM_LAND, + ANIM_INAIR, + + ANIM_TO_SWIM, + ANIM_SWIM, + ANIM_SWIM_BITE_A, + ANIM_SWIM_BITE_B, + ANIM_OUT_WATER, + + ANIM_EAT_DOWN, + ANIM_EAT_UP,//50 + ANIM_EAT_LOOP,//51 + ANIM_EAT_TEAR,//52 + ANIM_EAT_PULLBACK,//53 + ANIM_LOOK_AROUND,//54 + ANIM_EAT_LEFT,//55 + ANIM_EAT_RIGHT,//56 + ANIM_EAT_SNAP,//57 + ANIM_EAT_REACT, + + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PAIN1, + SND_PAIN2, + SND_GURGLE, + SND_DIE, + SND_GIB, + SND_MELEEHIT1, + SND_MELEEHIT2, + SND_MELEEMISS1, + SND_MELEEMISS2, + SND_STEP1, + SND_STEP2, + SND_STEP3, + SND_STEP4, + SND_GROWL1, + SND_GROWL2, + SND_GROWL3, + SND_LAND, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t gorgon_move_stand1; +extern animmove_t gorgon_move_stand2; +extern animmove_t gorgon_move_stand3; +extern animmove_t gorgon_move_stand4; +extern animmove_t gorgon_move_walk; +extern animmove_t gorgon_move_walk2; +extern animmove_t gorgon_move_walk3; +extern animmove_t gorgon_move_melee1; +extern animmove_t gorgon_move_melee2; +extern animmove_t gorgon_move_melee3; +extern animmove_t gorgon_move_melee4; +extern animmove_t gorgon_move_melee5; +extern animmove_t gorgon_move_melee6; +extern animmove_t gorgon_move_melee7; +extern animmove_t gorgon_move_melee8; +extern animmove_t gorgon_move_melee9; +extern animmove_t gorgon_move_melee10; +extern animmove_t gorgon_move_fjump; +extern animmove_t gorgon_move_run1; +extern animmove_t gorgon_move_run2; +extern animmove_t gorgon_move_run3; +extern animmove_t gorgon_move_pain1; +extern animmove_t gorgon_move_pain2; +extern animmove_t gorgon_move_pain3; +extern animmove_t gorgon_move_die1; +extern animmove_t gorgon_move_die2; +extern animmove_t gorgon_move_jump; +extern animmove_t gorgon_move_catch; +extern animmove_t gorgon_move_snatch; +extern animmove_t gorgon_move_miss; +extern animmove_t gorgon_move_readycatch; +extern animmove_t gorgon_move_snatchhi; +extern animmove_t gorgon_move_snatchlow; +extern animmove_t gorgon_move_slip; +extern animmove_t gorgon_move_slip_pain; +extern animmove_t gorgon_move_delay; +extern animmove_t gorgon_move_roar; +extern animmove_t gorgon_move_roar2; +extern animmove_t gorgon_move_land2; +extern animmove_t gorgon_move_land; +extern animmove_t gorgon_move_inair; + +extern animmove_t gorgon_move_to_swim; +extern animmove_t gorgon_move_swim; +extern animmove_t gorgon_move_swim_bite_a; +extern animmove_t gorgon_move_swim_bite_a; +extern animmove_t gorgon_move_outwater; + +extern animmove_t gorgon_move_eat_down; +extern animmove_t gorgon_move_eat_up; +extern animmove_t gorgon_move_eat_loop; +extern animmove_t gorgon_move_eat_tear; +extern animmove_t gorgon_move_eat_pullback; +extern animmove_t gorgon_move_look_around; +extern animmove_t gorgon_move_eat_left; +extern animmove_t gorgon_move_eat_right; +extern animmove_t gorgon_move_eat_snap; +extern animmove_t gorgon_move_eat_react; + + +void gorgon_eat(edict_t *self, G_Message_t *msg); +void gorgon_stand(edict_t *self, G_Message_t *msg); +void gorgon_walk(edict_t *self, G_Message_t *msg); +void gorgon_melee(edict_t *self, G_Message_t *msg); +void gorgon_run(edict_t *self, G_Message_t *msg); +void gorgon_pain(edict_t *self, G_Message_t *msg); +void gorgon_death(edict_t *self, G_Message_t *msg); +void gorgonbite (edict_t *self); +void gorgon_footstep (edict_t *self); +void gorgon_eatorder (edict_t *self); +void gorgon_dead(edict_t *self); +void gorgon_hop (edict_t *self); +void gorgon_growl (edict_t *self); +void gorgon_jump (edict_t *self); +void gorgon_ready_catch (edict_t *self); +void gorgon_throw_toy(edict_t *self); +void gorgon_toy_ofs(edict_t *self, float ofsf, float ofsr, float ofsu); +void gorgon_check_snatch(edict_t *self, float ofsf, float ofsr, float ofsu); +void gorgon_gore_toy(edict_t *self, float jumpht); +void gorgon_miss_sound (edict_t *self); +void gorgon_anger_sound (edict_t *self); +void gorgon_go_snatch (edict_t *self); +void gorgon_done_gore (edict_t *self); +void gorgon_blocked (edict_t *self, trace_t *trace); +void gorgonRoll (edict_t *self, float rollangle); +void gorgonLerpOff (edict_t *self); +void gorgonLerpOn (edict_t *self); +void gorgonCheckSlip (edict_t *self); +void gorgonSlide (edict_t *self, float force); +qboolean gorgonCheckMood (edict_t *self); +void ai_goal_charge (edict_t *self, float dist); +void gorgonApplyJump (edict_t *self); +void gorgonRoar (edict_t *self); +void gorgon_roar_sound (edict_t *self); +void gorgon_go_inair (edict_t *self); +void gorgon_check_landed (edict_t *self); +void gorgonJumpOutWater (edict_t *self); +void gorgonGoSwim (edict_t *self); +void gorgonCheckInWater (edict_t *self); +void gorgon_ai_swim (edict_t *self, float dist); +void gorgonForward (edict_t *self, float dist); +void gorgonFixPitch (edict_t *self); +void gorgonZeroPitch (edict_t *self); +void gorgon_death2twitch (edict_t *self); +void gorgonChooseDeath (edict_t *self); +void gorgon_ai_eat(edict_t *self, float crap); + +float MG_ChangePitchForZVel(edict_t *self, float speed, float cap_vel, float max_angle); +void MG_SetNormalizeVelToGoal(edict_t *self, vec3_t vec); +float MG_ChangeYaw (edict_t *self); +void MG_Pathfind(edict_t *self, qboolean check_clear_path); +float MG_ChangePitch(edict_t *self, float ideal, float speed); +void fish_under_water_wake (edict_t *self); diff --git a/Toolkit/Programming/GameCode/game/m_gorgon_anim.c b/Toolkit/Programming/GameCode/game/m_gorgon_anim.c new file mode 100644 index 0000000..494bcab --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_gorgon_anim.c @@ -0,0 +1,1321 @@ +//============================================================================== +// +// m_gorgon_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_gorgon_anim.h" +#include "m_gorgon.h" + +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "m_stats.h" + + +void gorgon_land(edict_t *self); +void M_movetoside (edict_t *self,float yaw, float dist); +void ai_charge2 (edict_t *self, float dist); +float MG_FaceGoal (edict_t *self, qboolean doturn); +void ai_moveright (edict_t *self, float dist); + +#define GORGON_STEPS 20//number of steps for whole swerve +#define GORGON_STEPS_INT1 (GORGON_STEPS/4) +#define GORGON_STEPS_INT2 (GORGON_STEPS/2) +#define GORGON_STEPS_INT3 (GORGON_STEPS - GORGON_STEPS_INT1) +#define GORGON_STEPS_INT4 GORGON_STEPS + +#define GORGON_SWERVE 20//degree of swerve +#define GORGON_SWERVE_INT1 (GORGON_SWERVE/4) +#define GORGON_SWERVE_INT2 (GORGON_SWERVE/2) +#define GORGON_SWERVE_INT3 (GORGON_SWERVE - GORGON_SWERVE_INT1) +#define GORGON_SWERVE_INT4 GORGON_SWERVE + +#define GORGON_SWERVE_MULT (GORGON_SWERVE/GORGON_STEPS_INT1) + +void gorgon_ai_run (edict_t *self, float dist) +{ + float offset; + + MG_FaceGoal(self, false); + + if(self->monsterinfo.idle_time != -1 && self->monsterinfo.idle_time < level.time) + { + self->dmg++; + if(self->dmgdmg) * GORGON_SWERVE_MULT;//0->5 * 4 = 0->20 + else if(self->dmgdmg) - GORGON_SWERVE_INT1) * GORGON_SWERVE_MULT);//20 - ((0->10 - 5) * 4) = 20->0 + else if(self->dmgdmg) - GORGON_SWERVE_INT2) * GORGON_SWERVE_MULT); + else if(self->dmgdmg) - GORGON_SWERVE_INT3) * GORGON_SWERVE_MULT)); + else + self->dmg = 0; + + if(self->dmg) + { + self->ideal_yaw = anglemod(self->ideal_yaw + offset); + } + } + + if(self->spawnflags & MSF_GORGON_SPEEDY) + ai_run(self, dist*1.25); + else + ai_run(self, dist*0.75); +} + +/*---------------------------------------------------------------------- + STAND3 - Gorgon Standing and looking right +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_stand3 [] = +{ + FRAME_painc1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_painc2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_painc3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_painc4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_painc5, NULL, 0, 0, 0, ai_stand, 0, NULL +}; +animmove_t gorgon_move_stand3 = {5, gorgon_frames_stand3, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + STAND2 - Gorgon Standing and looking left +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_stand2 [] = +{ + FRAME_painb1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_painb2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_painb3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_painb4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_painb5, NULL, 0, 0, 0, ai_stand, 0, NULL +}; +animmove_t gorgon_move_stand2 = {5, gorgon_frames_stand2, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + STAND1 - Gorgon Standing and wagging it's tail +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_stand1 [] = +{ + FRAME_wait1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait8, NULL, 0, 0, 0, ai_stand, 0, NULL +}; +animmove_t gorgon_move_stand1 = {8, gorgon_frames_stand1, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + STAND1 - Gorgon Standing and wagging it's tail +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_stand4 [] = +{ + FRAME_wait1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_wait8, NULL, 0, 0, 0, ai_stand, 0, NULL +}; +animmove_t gorgon_move_stand4 = {8, gorgon_frames_stand4, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + Gorgon Turning right while running +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_walk3 [] = +{ + FRAME_wlkrt1, NULL, 0, 0, 0, ai_walk, 8, gorgon_footstep, + FRAME_wlkrt2, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlkrt3, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlkrt4, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlkrt5, NULL, 0, 0, 0, ai_walk, 8, gorgon_footstep, + FRAME_wlkrt6, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlkrt7, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlkrt8, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlkrt9, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlkrt10, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlkrt11, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlkrt12, NULL, 0, 0, 0, ai_walk, 8, NULL +}; + +animmove_t gorgon_move_walk3 = {12, gorgon_frames_walk3, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + Gorgon Turning left while running +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_walk2 [] = +{ + FRAME_wlklft1,NULL, 0, 0, 0, ai_walk, 8, gorgon_footstep, + FRAME_wlklft2,NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlklft3,NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlklft4,NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlklft5,NULL, 0, 0, 0, ai_walk, 8, gorgon_footstep, + FRAME_wlklft6,NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlklft7,NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlklft8,NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlklft9,NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlklft10,NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlklft11,NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_wlklft12,NULL, 0, 0, 0, ai_walk, 8, NULL +}; + +animmove_t gorgon_move_walk2 = {12, gorgon_frames_walk2, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + Gorgon Walking +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_walk [] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_walk, 7, gorgon_footstep, + FRAME_walk2, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_walk, 6, gorgon_footstep, + FRAME_walk7, NULL, 0, 0, 0, ai_walk, 7, NULL, + FRAME_walk8, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk9, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk10, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk12, NULL, 0, 0, 0, ai_walk, 6, gorgon_growl +}; + +animmove_t gorgon_move_walk = {12, gorgon_frames_walk, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + Gorgon Melee while Running +-----------------------------------------------------------------------*/ +void gorgon_melee5check (edict_t *self) +{ + if (self->monsterinfo.currframeindex == 0) + { + gorgon_footstep(self); + } + else if (self->monsterinfo.currframeindex == 4) + gorgon_footstep(self); +} + + +void gorgon_ai_charge2 (edict_t *self, float dist) +{ + if(!visible(self, self->enemy)) + return; + + ai_charge2(self, dist); +} + +/*---------------------------------------------------------------------- + Forced Jump - jump from a buoy +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_fjump [] = +{ + FRAME_jumpb1,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb2,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb3,NULL, 0, 0, 0, NULL, 0, gorgon_growl, + FRAME_jumpb4,NULL, 0, 0, 0, NULL, 0, gorgonApplyJump, + FRAME_jumpb5,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpb6,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpb7,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpb8,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpb9,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpb10,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpb11,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpb12,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpb13,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpb14,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, +}; +animmove_t gorgon_move_fjump = {14, gorgon_frames_fjump, gorgon_go_inair}; + +/*---------------------------------------------------------------------- + land 1 +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_land [] = +{ + FRAME_jumpa15,NULL, 0, 0, 0, NULL, 0, gorgon_land, + FRAME_jumpa16,NULL, 0, 0, 0, NULL, 0, gorgon_growl, + FRAME_jumpa17,NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t gorgon_move_land = {3, gorgon_frames_land, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + land 2 +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_land2 [] = +{ + FRAME_jumpa15,NULL, 0, 0, 0, NULL, 0, gorgon_land, + FRAME_jumpa16,NULL, 0, 0, 0, NULL, 0, gorgon_growl, + FRAME_jumpa17,NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t gorgon_move_land2 = {3, gorgon_frames_land2, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + in air +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_inair [] = +{ + FRAME_jumpa14,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, +}; +animmove_t gorgon_move_inair = {1, gorgon_frames_inair, NULL}; + +/*---------------------------------------------------------------------- + MELEE10 - jump up at player +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee10 [] = +{ + FRAME_jumpa1,NULL, 0, 0, 0, gorgon_ai_charge2, 0, NULL, + FRAME_jumpa2,NULL, 0, 0, 0, gorgon_ai_charge2, 0, NULL, + FRAME_jumpa3,NULL, 0, 0, 0, gorgon_ai_charge2, 0, gorgon_growl, + FRAME_jumpa4,NULL, 0, 0, 0, NULL, 0, gorgon_jump, + FRAME_jumpa5,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpa6,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpa7,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpa8,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpa9,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpa10,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpa11,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpa12,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpa13,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, + FRAME_jumpa14,NULL, 0, 0, 0, NULL, 0, gorgon_check_landed, +}; +animmove_t gorgon_move_melee10 = {14, gorgon_frames_melee10, gorgon_go_inair}; + + +/*---------------------------------------------------------------------- + MELEE9 - hop backward +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee9 [] = +{ + FRAME_hop1, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop2, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop3, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop4, NULL, 0, 0, 0, ai_goal_charge, 0, gorgon_hop, + FRAME_hop5, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop6, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop7, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop8, NULL, 0, 0, 0, ai_goal_charge, 0, gorgon_hop, + FRAME_hop9, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop10, NULL, 0, 0, 0, ai_goal_charge, 0, NULL +}; +animmove_t gorgon_move_melee9 = {10, gorgon_frames_melee9, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + MELEE8 - hop forward +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee8 [] = +{ + FRAME_hop1, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop2, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop3, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop4, NULL, 0, 0, 0, ai_goal_charge, 0, gorgon_hop, + FRAME_hop5, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop6, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop7, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop8, NULL, 0, 0, 0, ai_goal_charge, 0, gorgon_hop, + FRAME_hop9, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop10, NULL, 0, 0, 0, ai_goal_charge, 0, NULL +}; +animmove_t gorgon_move_melee8 = {10, gorgon_frames_melee8, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + MELEE7 - hop right +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee7 [] = +{ + FRAME_hop1, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop2, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop3, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop4, NULL, 0, 0, 0, ai_goal_charge, 0, gorgon_hop, + FRAME_hop5, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop6, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop7, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop8, NULL, 0, 0, 0, ai_goal_charge, 0, gorgon_hop, + FRAME_hop9, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop10, NULL, 0, 0, 0, ai_goal_charge, 0, NULL +}; +animmove_t gorgon_move_melee7 = {10, gorgon_frames_melee7, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + MELEE6 - hop left +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee6 [] = +{ + FRAME_hop1, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop2, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop3, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop4, NULL, 0, 0, 0, ai_goal_charge, 0, gorgon_hop, + FRAME_hop5, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop6, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop7, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop8, NULL, 0, 0, 0, ai_goal_charge, 0, gorgon_hop, + FRAME_hop9, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_hop10, NULL, 0, 0, 0, ai_goal_charge, 0, NULL +}; +animmove_t gorgon_move_melee6 = {10, gorgon_frames_melee6, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + Melee5 - running attack +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee5 [] = +{ + FRAME_runatk1, NULL, 0, 0, 0, ai_goal_charge, 20, gorgon_melee5check, + FRAME_runatk2, NULL, 0, 0, 0, ai_goal_charge, 20, NULL, + FRAME_runatk3, NULL, 0, 0, 0, ai_goal_charge, 22, NULL, + FRAME_runatk4, NULL, 0, 0, 0, ai_goal_charge, 21, gorgonbite, + FRAME_runatk5, NULL, 0, 0, 0, ai_goal_charge, 20, gorgon_melee5check, + FRAME_runatk6, NULL, 0, 0, 0, ai_goal_charge, 20, NULL, + FRAME_runatk7, NULL, 0, 0, 0, ai_goal_charge, 22, NULL, + FRAME_runatk8, NULL, 0, 0, 0, ai_goal_charge, 21, gorgonCheckMood +}; + + +animmove_t gorgon_move_melee5 = {8, gorgon_frames_melee5, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + Melee4 - Gorgon Attack Pullback +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee4 [] = +{ + FRAME_atkc1, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_atkc2, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_atkc3, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_atkc4, NULL, 0, 0, 0, ai_goal_charge, 0, NULL +}; +animmove_t gorgon_move_melee4 = {4, gorgon_frames_melee4, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + Melee3 - Gorgon Attack Up +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee3 [] = +{ + FRAME_atkd1, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_atkd2, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_atkd3, NULL, 0, 0, 0, ai_goal_charge, 0, gorgonbite, + FRAME_atkd4, NULL, 0, 0, 0, ai_goal_charge, 0, NULL +}; + +animmove_t gorgon_move_melee3 = {4, gorgon_frames_melee3, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + Melee2 - Gorgon Attack Right +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee2 [] = +{ + FRAME_atkb1, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_atkb2, NULL, 0, 0, 0, ai_goal_charge, 0, gorgonbite, + FRAME_atkb3, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_atkb4, NULL, 0, 0, 0, ai_goal_charge, 0, NULL +}; + +animmove_t gorgon_move_melee2 = {4, gorgon_frames_melee2, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + Melee1 - Gorgon Attack Left +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_melee1 [] = +{ + FRAME_atka1, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_atka2, NULL, 0, 0, 0, ai_goal_charge, 0, gorgonbite, + FRAME_atka3, NULL, 0, 0, 0, ai_goal_charge, 0, NULL, + FRAME_atka4, NULL, 0, 0, 0, ai_goal_charge, 0, NULL +}; + +animmove_t gorgon_move_melee1 = {4, gorgon_frames_melee1, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + RUN3 - Turning right while running +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_run3 [] = +{ + FRAME_wlkrt1, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgon_footstep, + FRAME_wlkrt2, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt3, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt4, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt5, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt6, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt7, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt8, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt9, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt10, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt11, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckSlip, + FRAME_wlkrt12, NULL, 0, 0, 0, gorgon_ai_run, 16, gorgon_growl +}; + +animmove_t gorgon_move_run3 = {12, gorgon_frames_run3, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + RUN2 - Turning left while running +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_run2 [] = +{ + FRAME_wlklft1,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgon_footstep, + FRAME_wlklft2,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckMood, + FRAME_wlklft3,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckMood, + FRAME_wlklft4,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckMood, + FRAME_wlklft5,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgon_footstep, + FRAME_wlklft6,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckMood, + FRAME_wlklft7,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckMood, + FRAME_wlklft8,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckMood, + FRAME_wlklft9,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckMood, + FRAME_wlklft10,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckMood, + FRAME_wlklft11,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgonCheckMood, + FRAME_wlklft12,NULL, 0, 0, 0, gorgon_ai_run, 16, gorgon_growl +}; + +animmove_t gorgon_move_run2 = {12, gorgon_frames_run2, gorgonCheckMood}; + + + +/*---------------------------------------------------------------------- + Gorgon Running +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_run1 [] = +{ + FRAME_run1, NULL, 0, 0, 0, gorgon_ai_run, 30, gorgon_footstep, + FRAME_run2, NULL, 0, 0, 0, gorgon_ai_run, 31, gorgonCheckMood, + FRAME_run3, NULL, 0, 0, 0, gorgon_ai_run, 32, gorgonCheckMood, + FRAME_run4, NULL, 0, 0, 0, gorgon_ai_run, 34, gorgonCheckMood, + FRAME_run5, NULL, 0, 0, 0, gorgon_ai_run, 30, gorgon_footstep, + FRAME_run6, NULL, 0, 0, 0, gorgon_ai_run, 31, gorgonCheckMood, + FRAME_run7, NULL, 0, 0, 0, gorgon_ai_run, 32, gorgonCheckMood, + FRAME_run8, NULL, 0, 0, 0, gorgon_ai_run, 34, gorgon_growl +}; + +animmove_t gorgon_move_run1 = {8, gorgon_frames_run1, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + Gorgon Pain1 - step back while bending head down +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_pain1 [] = +{ + FRAME_pain1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain9, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t gorgon_move_pain1 = {9, gorgon_frames_pain1, gorgonCheckMood}; + + +/*---------------------------------------------------------------------- + Gorgon Pain2 - bend head to the left +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_pain2 [] = +{ + FRAME_painb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painb5, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t gorgon_move_pain2 = {5, gorgon_frames_pain2, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + Gorgon Pain3 - bend head to the right +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_pain3 [] = +{ + FRAME_painc1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painc2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painc3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painc4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painc5, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t gorgon_move_pain3 = {5, gorgon_frames_pain3, gorgonCheckMood}; + + + + + +void gorgon_smoke(edict_t *self) +{ + //CL_SmokeAndFlash(self->s.origin); + gorgon_land(self); + //gi.sound(self, CHAN_WEAPON, sounds[SND_GROWL3], 1, ATTN_NORM, 0); +} + +void gorgondeath1_fall (edict_t *self) +{ +// vec3_t forward,right, up,hold_angles; + +// if (self->s.frame == FRAME_deatha11) +// carnasaur_noshadow(self); + + if (self->s.frame == FRAME_deatha13) + gorgon_smoke(self); + + M_movetoside(self,flrand(180, 345), flrand(0, -8)); +} + +animframe_t gorgon_frames_die1 [] = +{ + FRAME_deatha1, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deatha2, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deatha3, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deatha4, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deatha5, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deatha6, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deatha7, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deatha8, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deatha9, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deatha10, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, + FRAME_deatha11, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha12, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha13, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha14, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha15, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deatha16, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deatha17, NULL, 0, 0, 0, ai_move, 0, NULL, //carnasaur_drip, + FRAME_deatha18, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deatha19, NULL, 0, 0, 0, ai_move, 0, NULL +}; + +animmove_t gorgon_move_die1 = {19, gorgon_frames_die1, gorgon_dead}; + +/*---------------------------------------------------------------------- + Gorgon Death2 - fly backwards and twitch +-----------------------------------------------------------------------*/ +void gorgon_starttwitch(edict_t *self) +{ + self->monsterinfo.thinkinc = MONSTER_THINK_INC;//FRAMETIME; +} + +void gorgon_nexttwitch(edict_t *self) +{ + self->monsterinfo.thinkinc = FRAMETIME * 4 + flrand(0.0, 4.0); +} + +animframe_t gorgon_frames_death2twitch [] = +{ + FRAME_twitch, NULL, 0, 0, 0, NULL, 0, gorgon_starttwitch, + FRAME_twitch_1,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_twitch_2,NULL, 0, 0, 0, NULL, 0, gorgon_nexttwitch +}; + +animmove_t gorgon_move_death2twitch = {3, gorgon_frames_death2twitch, NULL}; + +void gorgon_death2twitch (edict_t *self) +{ + VectorSet(self->mins,-24,-24,0); + VectorSet(self->maxs,24,24,18); + VectorScale(self->mins, self->s.scale, self->mins); + VectorScale(self->maxs, self->s.scale, self->maxs); + self->monsterinfo.currentmove = &gorgon_move_death2twitch; + self->monsterinfo.nextframeindex = 0; +} + + +animframe_t gorgon_frames_death2slide [] = +{ + FRAME_slide1, NULL, 0, 0, 0, ai_move, -16, NULL, + FRAME_slide2, NULL, 0, 0, 0, ai_move, -14, NULL, + FRAME_slide3, NULL, 0, 0, 0, ai_move, -12, NULL, + FRAME_slide4, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_slide5, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_slide6, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_slide7, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_slide8, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_slide9, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_slide10, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_slide11, NULL, 0, 0, 0, ai_move, -4, NULL, + FRAME_slide12, NULL, 0, 0, 0, ai_move, -2, NULL, + FRAME_slide13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide14, NULL, 0, 0, 0, NULL, 0, NULL,//gorgonChooseDeath, + FRAME_slide15, NULL, 0, 0, 0, ai_moveright, -2, NULL, + FRAME_slide16, NULL, 0, 0, 0, ai_moveright, -4, NULL, + FRAME_slide17, NULL, 0, 0, 0, ai_moveright, -2, NULL, + FRAME_slide18, NULL, 0, 0, 0, ai_moveright, -6, NULL, + FRAME_slide19, NULL, 0, 0, 0, ai_moveright, -2, NULL, + FRAME_slide20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_slide31, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t gorgon_move_death2slide = {31, gorgon_frames_death2slide, gorgon_dead}; + +void gorgon_death2_slide (edict_t *self) +{ + + self->monsterinfo.currentmove = &gorgon_move_death2slide; + self->monsterinfo.nextframeindex = 0; +} + +void gorgon_death2throw (edict_t *self) +{ + vec3_t forward; + + AngleVectors (self->s.angles, forward, NULL, NULL); + + VectorScale (forward, -375, self->velocity); + self->velocity[2] = 200; +// self->movetype= MOVETYPE_BOUNCE;//elasticity? +} + +void gorgon_death2 (edict_t *self) +{ + +// self->movetype= MOVETYPE_STEP; + self->velocity[2] = -120; +} + +animframe_t gorgon_frames_die2 [] = +{ + FRAME_hit1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hit3, NULL, 0, 0, 0, NULL, 0, gorgon_death2throw, + FRAME_hit5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hit7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hit9, NULL, 0, 0, 0, NULL, 0, gorgon_death2, + FRAME_hit11, NULL, 0, 0, 0, NULL, 0, NULL, +}; + +animmove_t gorgon_move_die2 = {6, gorgon_frames_die2, gorgon_death2_slide}; + + +/* +CHOMP! +*/ + +/*---------------------------------------------------------------------- + Melee3 - Gorgon Attack Up +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_catch [] = +{ + FRAME_jumpb5,NULL, 0, 0, 0, gorgon_gore_toy, 150, NULL, + FRAME_jumpb6,NULL, 0, 0, 0, gorgon_gore_toy, 0, NULL, + FRAME_jumpb7,NULL, 0, 0, 0, gorgon_gore_toy, 0, NULL, + FRAME_jumpb8,NULL, 0, 0, 0, gorgon_gore_toy, 0, NULL, + FRAME_jumpb9,NULL, 0, 0, 0, gorgon_gore_toy, 0, NULL, + FRAME_jumpb10,NULL, 0, 0, 0, gorgon_gore_toy, -1, NULL, + FRAME_jumpb11,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb12,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb13,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb14,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb15,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb16,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb17,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb18,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb19,NULL, 0, 0, 0, NULL, 0, gorgon_anger_sound, +}; +animmove_t gorgon_move_catch = {15, gorgon_frames_catch, gorgon_done_gore}; + +/*---------------------------------------------------------------------- + Gorgon Eat3 - pull back, then bend back down to eat +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_miss [] = +{ + FRAME_eatinga4, NULL, 0, 0, 0, NULL, 0, gorgon_miss_sound, + FRAME_eatinga3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatinga2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatinga1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t gorgon_move_miss = {4, gorgon_frames_miss, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + Shake and toss up toy + + Chance of throwing it to left or right, maybe carry away? +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_snatch [] = +{ + FRAME_eatingb5, gorgon_toy_ofs, 70, 0, 66, NULL, 0, gorgon_anger_sound, + FRAME_eatingb6, gorgon_toy_ofs, 68, -44, 66, NULL, 0, NULL, + FRAME_eatingb7, gorgon_toy_ofs, 56, -64, 66, NULL, 0, NULL, + FRAME_eatingb8, gorgon_toy_ofs, 60, -56, 66, NULL, 0, gorgon_anger_sound, + FRAME_eatingb9, gorgon_toy_ofs, 68, -24, 66, NULL, 0, NULL, + FRAME_eatingb10, gorgon_toy_ofs, 72, 40, 66, NULL, 0, NULL, + FRAME_eatingb11, gorgon_toy_ofs, 60, 70, 66, NULL, 0, NULL, + FRAME_eatingb12, gorgon_toy_ofs, 70, 48, 66, NULL, 0, gorgon_anger_sound, + FRAME_eatingb13, gorgon_toy_ofs, 74, -32, 66, NULL, 0, NULL, + FRAME_eatingb14, gorgon_toy_ofs, 64, -70, 66, NULL, 0, NULL, + FRAME_eatingb15, gorgon_toy_ofs, 40, -72, 66, NULL, 0, NULL, + FRAME_eatingb16, gorgon_toy_ofs, 42, -70, 66, NULL, 0, gorgon_anger_sound, + FRAME_eatingb17, gorgon_toy_ofs, 60, -60, 62, NULL, 0, NULL, + FRAME_eatingb18, gorgon_toy_ofs, 66, -40, 56, NULL, 0, NULL, + FRAME_eatingb19, gorgon_toy_ofs, 72, -10, 32, NULL, 0, NULL, + FRAME_eatingb20, gorgon_toy_ofs, 62, 16, 12, NULL, 0, gorgon_anger_sound, + FRAME_eatingb21, gorgon_toy_ofs, 56, 32, 0, NULL, 0, NULL, + FRAME_eatinga4, gorgon_toy_ofs, 48, 16, 64, NULL, 0, NULL, + FRAME_eatinga3, gorgon_toy_ofs, 50, 14, 96, NULL, 0, gorgon_anger_sound, + FRAME_eatinga2, gorgon_toy_ofs, 80, 8, 80, NULL, 0, NULL, + FRAME_eatinga1, gorgon_toy_ofs, 96, 0, 76, NULL, 0, NULL, + FRAME_jumpa1, gorgon_toy_ofs, 100, 8, 78, NULL, 0, gorgon_anger_sound, + FRAME_jumpa2, gorgon_toy_ofs, 90, 6, 64, NULL, 0, NULL, + FRAME_jumpa3, gorgon_toy_ofs, 76, 4, 48, NULL, 0, NULL, + FRAME_jumpa4, gorgon_toy_ofs, 96, 6, 140, NULL, 0, gorgon_anger_sound, + FRAME_jumpa5, gorgon_toy_ofs, 90, 6, 208, NULL, 0, gorgon_throw_toy, + FRAME_jumpb4, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t gorgon_move_snatch = {27, gorgon_frames_snatch, gorgon_ready_catch}; + +/*---------------------------------------------------------------------- + Gorgon Eat3 - pull back, then bend back down to eat +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_readycatch [] = +{ + FRAME_jumpb4, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t gorgon_move_readycatch = {1, gorgon_frames_readycatch, gorgon_ready_catch}; + +/*---------------------------------------------------------------------- + Gorgon +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_snatchhi [] = +{ + FRAME_atkd1, NULL, 0, 0, 0, gorgon_ai_charge2, 10, NULL, + FRAME_atkd2, NULL, 0, 0, 0, gorgon_ai_charge2, 10, NULL, + FRAME_atkd3, gorgon_check_snatch, 96, 0, 56, NULL, 0, NULL, + FRAME_atkd4, gorgon_toy_ofs, 96, 16, 160, NULL, 0, NULL +}; +animmove_t gorgon_move_snatchhi = {4, gorgon_frames_snatchhi, gorgon_go_snatch}; + +/*---------------------------------------------------------------------- + Gorgon +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_snatchlow [] = +{ + FRAME_eatinga1, NULL, 0, 0, 0, gorgon_ai_charge2, 10, NULL, + FRAME_eatinga2, NULL, 0, 0, 0, gorgon_ai_charge2, 10, NULL, + FRAME_eatinga3, NULL, 0, 0, 0, gorgon_ai_charge2, 10, NULL, + FRAME_eatinga4, NULL, 0, 0, 0, gorgon_ai_charge2, 10, NULL, + FRAME_eatinga5, gorgon_check_snatch, 64, 0, -48, NULL, 0, NULL, + FRAME_eatingb1, gorgon_toy_ofs, 48, -32, 0, NULL, 0, gorgon_anger_sound, + FRAME_eatingb2, gorgon_toy_ofs, 48, 10, 10, NULL, 0, NULL, + FRAME_eatingb3, gorgon_toy_ofs, 48, 0, 20, NULL, 0, gorgon_anger_sound, + FRAME_eatingb4, gorgon_toy_ofs, 56, 0, 24, NULL, 0, NULL, +}; +animmove_t gorgon_move_snatchlow = {9, gorgon_frames_snatchlow, gorgon_go_snatch}; + + + +/*---------------- +? +-----------------------*/ +animframe_t gorgon_frames_slip [] = +{ + FRAME_deatha1, NULL, 0, 0, 0, gorgonSlide, -200, NULL, + FRAME_deatha2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha10, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, + FRAME_deatha11, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha12, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha13, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha14, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha15, NULL, 0, 0, 0, gorgonRoll, -60, NULL, + FRAME_deatha16, NULL, 0, 0, 0, gorgonRoll, -120, NULL, + FRAME_deatha17, NULL, 0, 0, 0, gorgonRoll, -180, NULL, //carnasaur_drip, + FRAME_deatha18, NULL, 0, 0, 0, gorgonRoll, -240, NULL, + FRAME_deatha19, NULL, 0, 0, 0, gorgonRoll, -300, gorgonLerpOff, + FRAME_eatingb1, NULL, 0, 0, 0, gorgonRoll, 0, NULL, + FRAME_eatingb3, NULL, 0, 0, 0, NULL, 0, gorgonLerpOn, + FRAME_eatingb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb11, NULL, 0, 0, 0, NULL, 0, NULL, // carnasaur_fall, + FRAME_eatingb13, NULL, 0, 0, 0, NULL, 0, NULL, // carnasaur_fall, + FRAME_eatingb15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatinga4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatinga3, NULL, 0, 0, 0, NULL, 0, gorgon_anger_sound, + FRAME_eatinga2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatinga1, NULL, 0, 0, 0, gorgonSlide, 0, NULL, +}; +animmove_t gorgon_move_slip = {36, gorgon_frames_slip, gorgonCheckMood}; + +/*---------------- +? +-----------------------*/ +animframe_t gorgon_frames_slip_pain [] = +{ + FRAME_deatha11, NULL, 0, 0, 0, gorgonSlide, -200, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha12, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha13, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_deatha14, NULL, 0, 0, 0, NULL, 0, gorgondeath1_fall, // carnasaur_fall, + FRAME_rollover1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rollover2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rollover3, NULL, 0, 0, 0, NULL, 0, NULL, //carnasaur_drip, + FRAME_rollover4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rollover5, NULL, 0, 0, 0, NULL, 0, gorgonLerpOff, + FRAME_eatingb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb3, NULL, 0, 0, 0, NULL, 0, gorgonLerpOn, + FRAME_eatingb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb11, NULL, 0, 0, 0, NULL, 0, NULL, // carnasaur_fall, + FRAME_eatingb13, NULL, 0, 0, 0, NULL, 0, NULL, // carnasaur_fall, + FRAME_eatingb15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatingb21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatinga4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatinga3, NULL, 0, 0, 0, NULL, 0, gorgon_anger_sound, + FRAME_eatinga2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_eatinga1, NULL, 0, 0, 0, gorgonSlide, 0, NULL, +}; +animmove_t gorgon_move_slip_pain = {26, gorgon_frames_slip_pain, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + delay +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_delay [] = +{ + FRAME_wait1, NULL, 0, 0, 0, NULL, 0, gorgonCheckMood, + FRAME_wait2, NULL, 0, 0, 0, NULL, 0, gorgonCheckMood, + FRAME_wait3, NULL, 0, 0, 0, NULL, 0, gorgonCheckMood, + FRAME_wait4, NULL, 0, 0, 0, NULL, 0, gorgonCheckMood, + FRAME_wait5, NULL, 0, 0, 0, NULL, 0, gorgonCheckMood, + FRAME_wait6, NULL, 0, 0, 0, NULL, 0, gorgonCheckMood, + FRAME_wait7, NULL, 0, 0, 0, NULL, 0, gorgonCheckMood, + FRAME_wait8, NULL, 0, 0, 0, NULL, 0, gorgonCheckMood, +}; +animmove_t gorgon_move_delay = {8, gorgon_frames_delay, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + Gorgon roar- make noise, alert others +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_roar [] = +{ + FRAME_speak1, NULL, 0, 0, 0, NULL, 0, gorgonRoar, + FRAME_speak2, NULL, 0, 0, 0, NULL, 0, gorgon_roar_sound, + FRAME_speak3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak7, NULL, 0, 0, 0, NULL, 0, gorgon_roar_sound, + FRAME_speak8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak13, NULL, 0, 0, 0, NULL, 0, gorgon_roar_sound, + FRAME_speak14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak17, NULL, 0, 0, 0, NULL, 0, gorgon_roar_sound, + FRAME_speak18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak19, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t gorgon_move_roar = {19, gorgon_frames_roar, gorgonCheckMood}; + +/*---------------------------------------------------------------------- + Gorgon roar2- make noise in response to main roar +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_roar2 [] = +{ + FRAME_speak1, NULL, 0, 0, 0, NULL, 0, gorgon_roar_sound, + FRAME_speak2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak4, NULL, 0, 0, 0, NULL, 0, gorgon_roar_sound, + FRAME_speak5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak8, NULL, 0, 0, 0, NULL, 0, gorgon_roar_sound, + FRAME_speak9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak10, NULL, 0, 0, 0, NULL, 0, gorgon_roar_sound, + FRAME_speak11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak15, NULL, 0, 0, 0, NULL, 0, gorgon_roar_sound, + FRAME_speak16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_speak19, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t gorgon_move_roar2 = {19, gorgon_frames_roar2, gorgonCheckMood}; + +//===================================================== + +//SWIMMING + +//===================================================== + +/*---------------------------------------------------------------------- + Gorgon Swimming +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_to_swim [] = +{ //FIXME: add wake and bubbles and sploosh swim sounds + FRAME_swim1, NULL, 0, 0, 0, NULL, 0, gorgonCheckInWater, + FRAME_swim2, NULL, 0, 0, 0, NULL, 0, gorgonCheckInWater, + FRAME_swim3, NULL, 0, 0, 0, NULL, 0, gorgonCheckInWater, + FRAME_swim4, NULL, 0, 0, 0, NULL, 0, gorgonCheckInWater, + FRAME_swim5, NULL, 0, 0, 0, NULL, 0, gorgonCheckInWater, +}; +animmove_t gorgon_move_to_swim = {5, gorgon_frames_to_swim, gorgonGoSwim}; + +animframe_t gorgon_frames_swim [] = +{ //FIXME: add wake and bubbles and sploosh swim sounds + FRAME_swim6, NULL, 0, 0, 0, gorgon_ai_swim, 31, fish_under_water_wake, + FRAME_swim7, NULL, 0, 0, 0, gorgon_ai_swim, 32, NULL, + FRAME_swim8, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swim9, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swim10, NULL, 0, 0, 0, gorgon_ai_swim, 30, NULL, + FRAME_swim11, NULL, 0, 0, 0, gorgon_ai_swim, 30, NULL, + FRAME_swim12, NULL, 0, 0, 0, gorgon_ai_swim, 31, NULL, + FRAME_swim13, NULL, 0, 0, 0, gorgon_ai_swim, 32, NULL, + FRAME_swim14, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swim15, NULL, 0, 0, 0, gorgon_ai_swim, 30, NULL, + FRAME_swim16, NULL, 0, 0, 0, gorgon_ai_swim, 31, NULL, + FRAME_swim17, NULL, 0, 0, 0, gorgon_ai_swim, 32, NULL, + FRAME_swim18, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, +}; +animmove_t gorgon_move_swim = {13, gorgon_frames_swim, NULL}; + +animframe_t gorgon_frames_swim_bite_a [] = +{ //FIXME: add wake and bubbles and sploosh swim sounds + FRAME_swimata1, NULL, 0, 0, 0, gorgon_ai_swim, 31, fish_under_water_wake, + FRAME_swimata2, NULL, 0, 0, 0, gorgon_ai_swim, 32, NULL, + FRAME_swimata3, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swimata4, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swimata5, NULL, 0, 0, 0, gorgon_ai_swim, 30, NULL, + FRAME_swimata6, NULL, 0, 0, 0, gorgon_ai_swim, 30, NULL, + FRAME_swimata7, NULL, 0, 0, 0, gorgon_ai_swim, 31, NULL, + FRAME_swimata8, NULL, 0, 0, 0, gorgon_ai_swim, 32, NULL, + FRAME_swimata9, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swimata10,NULL, 0, 0, 0, gorgon_ai_swim, 30, NULL, + FRAME_swimata11,NULL, 0, 0, 0, gorgon_ai_swim, 31, NULL, + FRAME_swimata12,NULL, 0, 0, 0, gorgon_ai_swim, 32, gorgonbite, + FRAME_swimata13,NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swimata14,NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, +}; +animmove_t gorgon_move_swim_bite_a = {14, gorgon_frames_swim_bite_a, NULL}; + +animframe_t gorgon_frames_swim_bite_b [] = +{ //FIXME: add wake and bubbles and sploosh swim sounds + FRAME_swimatb1, NULL, 0, 0, 0, gorgon_ai_swim, 31, fish_under_water_wake, + FRAME_swimatb2, NULL, 0, 0, 0, gorgon_ai_swim, 32, NULL, + FRAME_swimatb3, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swimatb4, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swimatb5, NULL, 0, 0, 0, gorgon_ai_swim, 30, NULL, + FRAME_swimatb6, NULL, 0, 0, 0, gorgon_ai_swim, 30, gorgonbite, + FRAME_swimatb7, NULL, 0, 0, 0, gorgon_ai_swim, 31, NULL, + FRAME_swimatb8, NULL, 0, 0, 0, gorgon_ai_swim, 32, NULL, + FRAME_swimatb9, NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swimatb10,NULL, 0, 0, 0, gorgon_ai_swim, 30, NULL, + FRAME_swimatb11,NULL, 0, 0, 0, gorgon_ai_swim, 31, NULL, + FRAME_swimatb12,NULL, 0, 0, 0, gorgon_ai_swim, 32, gorgonbite, + FRAME_swimatb13,NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, + FRAME_swimatb14,NULL, 0, 0, 0, gorgon_ai_swim, 34, NULL, +}; +animmove_t gorgon_move_swim_bite_b = {14, gorgon_frames_swim_bite_b, NULL}; + +animframe_t gorgon_frames_outwater [] = +{ //FIXME: add wake and bubbles and sploosh swim sounds + FRAME_swimata1, NULL, 0, 0, 0, gorgon_ai_swim, -1, NULL, + FRAME_swimata3, NULL, 0, 0, 0, gorgon_ai_swim, -1, NULL, + FRAME_swimata6, NULL, 0, 0, 0, gorgon_ai_swim, -1, NULL, + FRAME_swimata8, NULL, 0, 0, 0, gorgon_ai_swim, -1, NULL, + FRAME_swimata10,NULL, 0, 0, 0, gorgon_ai_swim, -1, NULL, + FRAME_swimata12,NULL, 0, 0, 0, gorgon_ai_swim, -1, gorgon_growl, + FRAME_swimata14,NULL, 0, 0, 0, gorgon_ai_swim, -1, gorgonJumpOutWater, + FRAME_jumpb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb6, NULL, 0, 0, 0, NULL, 0, gorgonFixPitch, + FRAME_jumpb7, NULL, 0, 0, 0, NULL, 0, gorgonFixPitch, + FRAME_jumpb8, NULL, 0, 0, 0, gorgonForward, 100, gorgonFixPitch, + FRAME_jumpb9, NULL, 0, 0, 0, gorgonForward, 100, gorgonFixPitch, + FRAME_jumpb10, NULL, 0, 0, 0, gorgonForward, 100, gorgonFixPitch, + FRAME_jumpb11, NULL, 0, 0, 0, gorgonForward, 100, gorgonFixPitch, + FRAME_jumpb12, NULL, 0, 0, 0, gorgonForward, 100, gorgonFixPitch, + FRAME_jumpb13, NULL, 0, 0, 0, gorgonForward, 100, gorgonFixPitch, + FRAME_jumpb14, NULL, 0, 0, 0, gorgonForward, 100, gorgonFixPitch, + FRAME_jumpb15, NULL, 0, 0, 0, gorgonForward, 100, gorgonZeroPitch, + FRAME_jumpb16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jumpb17, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t gorgon_move_outwater = {20, gorgon_frames_outwater, gorgonCheckMood}; + +//============================================================================= + +//EATING ANIMS + +//FIXME: add sounds too... + +//============================================================================= + +/*---------------------------------------------------------------------- + eating trand to down +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_eat_down [] = +{ + FRAME_eatinga1, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga2, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga3, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga4, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL, +}; +animmove_t gorgon_move_eat_down = {4, gorgon_frames_eat_down, NULL}; + +/*---------------------------------------------------------------------- + eating trans to up +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_eat_up [] = +{ + FRAME_eatinga4, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga3, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga2, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga1, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL, +}; +animmove_t gorgon_move_eat_up = {4, gorgon_frames_eat_up, NULL}; + +/*---------------------------------------------------------------------- + eat cycle +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_eat_loop [] = +{ + FRAME_eatinga5, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga6, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga7, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga8, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga9, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga10, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL, +}; +animmove_t gorgon_move_eat_loop = {6, gorgon_frames_eat_loop, NULL}; + +/*---------------------------------------------------------------------- + eating - tear +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_eat_tear [] = +{ + FRAME_eatingb1, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb2, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb3, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb4, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb5, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb6, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb7, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb8, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb9, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb10, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb11, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb12, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb13, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb14, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb15, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb16, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb17, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb18, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb19, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb20, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatingb21, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL, +}; +animmove_t gorgon_move_eat_tear = {21, gorgon_frames_eat_tear, NULL}; + + +/*---------------------------------------------------------------------- + eat- up & down +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_eat_pullback [] = +{ + FRAME_eatinga5, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga4, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga3, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga4, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_eatinga5, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL, +}; +animmove_t gorgon_move_eat_pullback = {5, gorgon_frames_eat_pullback, NULL}; + +/*---------------------------------------------------------------------- + look around +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_look_around [] = +{//fixme: modify view_ofs so they actually look behind them + FRAME_idleb1, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb2, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb3, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb4, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb5, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb6, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb7, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb8, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb9, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb10, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb11, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb12, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb13, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb14, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb15, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb16, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb17, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb18, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb19, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb20, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_idleb21, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL, +}; +animmove_t gorgon_move_look_around = {21, gorgon_frames_look_around, NULL}; + +/*---------------------------------------------------------------------- + looking left from eat +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_eat_left [] = +{ + FRAME_loklft1, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft2, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft3, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft4, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft5, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft6, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft7, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft8, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft9, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft10, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft11, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft12, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft13, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft14, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft15, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft16, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft17, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft18, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft19, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft20, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft21, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft22, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft21, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft20, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft19, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft18, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft17, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft16, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft15, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft14, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft13, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft12, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft11, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft10, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft9, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft8, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft7, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft6, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft5, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft4, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft3, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft2, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_loklft1, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL +}; +animmove_t gorgon_move_eat_left = {43, gorgon_frames_eat_left, NULL}; + +/*---------------------------------------------------------------------- + looking right from eat +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_eat_right [] = +{ + FRAME_lokrt1, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt2, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt3, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt4, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt5, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt6, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt7, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt8, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt9, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt10, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt11, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt12, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt13, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt14, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt15, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt16, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt17, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt18, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt19, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt20, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt19, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt18, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt17, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt16, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt15, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt14, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt13, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt12, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt11, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt10, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt9, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt8, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt7, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt6, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt5, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt4, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt3, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt2, NULL, 0, 0, 0, gorgon_ai_eat, 0, NULL, + FRAME_lokrt1, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL, +}; +animmove_t gorgon_move_eat_right = {39, gorgon_frames_eat_right, NULL}; + +/*---------------------------------------------------------------------- + snap at something to right +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_eat_snap [] = +{ + FRAME_snap1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_snap2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_snap3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_snap4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_snap5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_snap6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_snap7, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL, +}; +animmove_t gorgon_move_eat_snap = {7, gorgon_frames_eat_snap, NULL}; + +/*---------------------------------------------------------------------- + react tp something to left +-----------------------------------------------------------------------*/ +animframe_t gorgon_frames_eat_react [] = +{ + FRAME_react1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_react2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_react3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_react4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_react5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_react6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_react7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_react8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_react9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_react10, NULL, 0, 0, 0, gorgon_ai_eat, -1, NULL, +}; +animmove_t gorgon_move_eat_react = {10, gorgon_frames_eat_react, NULL}; diff --git a/Toolkit/Programming/GameCode/game/m_gorgon_anim.h b/Toolkit/Programming/GameCode/game/m_gorgon_anim.h new file mode 100644 index 0000000..2dc2ad4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_gorgon_anim.h @@ -0,0 +1,422 @@ +// R:\Art\models/monsters\gorgon + +// This file generated by qdata - Do NOT Modify + +#define FRAME_atka1 0 +#define FRAME_atka2 1 +#define FRAME_atka3 2 +#define FRAME_atka4 3 +#define FRAME_atkb1 4 +#define FRAME_atkb2 5 +#define FRAME_atkb3 6 +#define FRAME_atkb4 7 +#define FRAME_atkc1 8 +#define FRAME_atkc2 9 +#define FRAME_atkc3 10 +#define FRAME_atkc4 11 +#define FRAME_atkd1 12 +#define FRAME_atkd2 13 +#define FRAME_atkd3 14 +#define FRAME_atkd4 15 +#define FRAME_atke1 16 +#define FRAME_atke2 17 +#define FRAME_atke3 18 +#define FRAME_atke4 19 +#define FRAME_deatha1 20 +#define FRAME_deatha10 21 +#define FRAME_deatha11 22 +#define FRAME_deatha12 23 +#define FRAME_deatha13 24 +#define FRAME_deatha14 25 +#define FRAME_deatha15 26 +#define FRAME_deatha16 27 +#define FRAME_deatha17 28 +#define FRAME_deatha18 29 +#define FRAME_deatha19 30 +#define FRAME_deatha2 31 +#define FRAME_deatha3 32 +#define FRAME_deatha4 33 +#define FRAME_deatha5 34 +#define FRAME_deatha6 35 +#define FRAME_deatha7 36 +#define FRAME_deatha8 37 +#define FRAME_deatha9 38 +#define FRAME_death1 39 +#define FRAME_death2 40 +#define FRAME_death3 41 +#define FRAME_death4 42 +#define FRAME_death5 43 +#define FRAME_death6 44 +#define FRAME_death7 45 +#define FRAME_death8 46 +#define FRAME_death9 47 +#define FRAME_death10 48 +#define FRAME_death11 49 +#define FRAME_death12 50 +#define FRAME_death13 51 +#define FRAME_death14 52 +#define FRAME_death15 53 +#define FRAME_death16 54 +#define FRAME_death17 55 +#define FRAME_death18 56 +#define FRAME_death19 57 +#define FRAME_eatinga1 58 +#define FRAME_eatinga2 59 +#define FRAME_eatinga3 60 +#define FRAME_eatinga4 61 +#define FRAME_eatinga5 62 +#define FRAME_eatinga6 63 +#define FRAME_eatinga7 64 +#define FRAME_eatinga8 65 +#define FRAME_eatinga9 66 +#define FRAME_eatinga10 67 +#define FRAME_eatingb1 68 +#define FRAME_eatingb2 69 +#define FRAME_eatingb3 70 +#define FRAME_eatingb4 71 +#define FRAME_eatingb5 72 +#define FRAME_eatingb6 73 +#define FRAME_eatingb7 74 +#define FRAME_eatingb8 75 +#define FRAME_eatingb9 76 +#define FRAME_eatingb10 77 +#define FRAME_eatingb11 78 +#define FRAME_eatingb12 79 +#define FRAME_eatingb13 80 +#define FRAME_eatingb14 81 +#define FRAME_eatingb15 82 +#define FRAME_eatingb16 83 +#define FRAME_eatingb17 84 +#define FRAME_eatingb18 85 +#define FRAME_eatingb19 86 +#define FRAME_eatingb20 87 +#define FRAME_eatingb21 88 +#define FRAME_hit1 89 +#define FRAME_hit2 90 +#define FRAME_hit3 91 +#define FRAME_hit4 92 +#define FRAME_hit5 93 +#define FRAME_hit6 94 +#define FRAME_hit7 95 +#define FRAME_hit8 96 +#define FRAME_hit9 97 +#define FRAME_hit10 98 +#define FRAME_hit11 99 +#define FRAME_hit12 100 +#define FRAME_hop1 101 +#define FRAME_hop2 102 +#define FRAME_hop3 103 +#define FRAME_hop4 104 +#define FRAME_hop5 105 +#define FRAME_hop6 106 +#define FRAME_hop7 107 +#define FRAME_hop8 108 +#define FRAME_hop9 109 +#define FRAME_hop10 110 +#define FRAME_idleb1 111 +#define FRAME_idleb2 112 +#define FRAME_idleb3 113 +#define FRAME_idleb4 114 +#define FRAME_idleb5 115 +#define FRAME_idleb6 116 +#define FRAME_idleb7 117 +#define FRAME_idleb8 118 +#define FRAME_idleb9 119 +#define FRAME_idleb10 120 +#define FRAME_idleb11 121 +#define FRAME_idleb12 122 +#define FRAME_idleb13 123 +#define FRAME_idleb14 124 +#define FRAME_idleb15 125 +#define FRAME_idleb16 126 +#define FRAME_idleb17 127 +#define FRAME_idleb18 128 +#define FRAME_idleb19 129 +#define FRAME_idleb20 130 +#define FRAME_idleb21 131 +#define FRAME_jumpa1 132 +#define FRAME_jumpa2 133 +#define FRAME_jumpa3 134 +#define FRAME_jumpa4 135 +#define FRAME_jumpa5 136 +#define FRAME_jumpa6 137 +#define FRAME_jumpa7 138 +#define FRAME_jumpa8 139 +#define FRAME_jumpa9 140 +#define FRAME_jumpa10 141 +#define FRAME_jumpa11 142 +#define FRAME_jumpa12 143 +#define FRAME_jumpa13 144 +#define FRAME_jumpa14 145 +#define FRAME_jumpa15 146 +#define FRAME_jumpa16 147 +#define FRAME_jumpa17 148 +#define FRAME_jumpb1 149 +#define FRAME_jumpb2 150 +#define FRAME_jumpb3 151 +#define FRAME_jumpb4 152 +#define FRAME_jumpb5 153 +#define FRAME_jumpb6 154 +#define FRAME_jumpb7 155 +#define FRAME_jumpb8 156 +#define FRAME_jumpb9 157 +#define FRAME_jumpb10 158 +#define FRAME_jumpb11 159 +#define FRAME_jumpb12 160 +#define FRAME_jumpb13 161 +#define FRAME_jumpb14 162 +#define FRAME_jumpb15 163 +#define FRAME_jumpb16 164 +#define FRAME_jumpb17 165 +#define FRAME_jumpb18 166 +#define FRAME_jumpb19 167 +#define FRAME_loklft1 168 +#define FRAME_loklft2 169 +#define FRAME_loklft3 170 +#define FRAME_loklft4 171 +#define FRAME_loklft5 172 +#define FRAME_loklft6 173 +#define FRAME_loklft7 174 +#define FRAME_loklft8 175 +#define FRAME_loklft9 176 +#define FRAME_loklft10 177 +#define FRAME_loklft11 178 +#define FRAME_loklft12 179 +#define FRAME_loklft13 180 +#define FRAME_loklft14 181 +#define FRAME_loklft15 182 +#define FRAME_loklft16 183 +#define FRAME_loklft17 184 +#define FRAME_loklft18 185 +#define FRAME_loklft19 186 +#define FRAME_loklft20 187 +#define FRAME_loklft21 188 +#define FRAME_loklft22 189 +#define FRAME_lokrt1 190 +#define FRAME_lokrt2 191 +#define FRAME_lokrt3 192 +#define FRAME_lokrt4 193 +#define FRAME_lokrt5 194 +#define FRAME_lokrt6 195 +#define FRAME_lokrt7 196 +#define FRAME_lokrt8 197 +#define FRAME_lokrt9 198 +#define FRAME_lokrt10 199 +#define FRAME_lokrt11 200 +#define FRAME_lokrt12 201 +#define FRAME_lokrt13 202 +#define FRAME_lokrt14 203 +#define FRAME_lokrt15 204 +#define FRAME_lokrt16 205 +#define FRAME_lokrt17 206 +#define FRAME_lokrt18 207 +#define FRAME_lokrt19 208 +#define FRAME_lokrt20 209 +#define FRAME_oldbase3 210 +#define FRAME_painb1 211 +#define FRAME_painb2 212 +#define FRAME_painb3 213 +#define FRAME_painb4 214 +#define FRAME_painb5 215 +#define FRAME_painc1 216 +#define FRAME_painc2 217 +#define FRAME_painc3 218 +#define FRAME_painc4 219 +#define FRAME_painc5 220 +#define FRAME_pain1 221 +#define FRAME_pain2 222 +#define FRAME_pain3 223 +#define FRAME_pain4 224 +#define FRAME_pain5 225 +#define FRAME_pain6 226 +#define FRAME_pain7 227 +#define FRAME_pain8 228 +#define FRAME_pain9 229 +#define FRAME_react1 230 +#define FRAME_react2 231 +#define FRAME_react3 232 +#define FRAME_react4 233 +#define FRAME_react5 234 +#define FRAME_react6 235 +#define FRAME_react7 236 +#define FRAME_react8 237 +#define FRAME_react9 238 +#define FRAME_react10 239 +#define FRAME_rollover1 240 +#define FRAME_rollover2 241 +#define FRAME_rollover3 242 +#define FRAME_rollover4 243 +#define FRAME_rollover5 244 +#define FRAME_runatk1 245 +#define FRAME_runatk2 246 +#define FRAME_runatk3 247 +#define FRAME_runatk4 248 +#define FRAME_runatk5 249 +#define FRAME_runatk6 250 +#define FRAME_runatk7 251 +#define FRAME_runatk8 252 +#define FRAME_run1 253 +#define FRAME_run2 254 +#define FRAME_run3 255 +#define FRAME_run4 256 +#define FRAME_run5 257 +#define FRAME_run6 258 +#define FRAME_run7 259 +#define FRAME_run8 260 +#define FRAME_slide1 261 +#define FRAME_slide2 262 +#define FRAME_slide3 263 +#define FRAME_slide4 264 +#define FRAME_slide5 265 +#define FRAME_slide6 266 +#define FRAME_slide7 267 +#define FRAME_slide8 268 +#define FRAME_slide9 269 +#define FRAME_slide10 270 +#define FRAME_slide11 271 +#define FRAME_slide12 272 +#define FRAME_slide13 273 +#define FRAME_slide14 274 +#define FRAME_slide15 275 +#define FRAME_slide16 276 +#define FRAME_slide17 277 +#define FRAME_slide18 278 +#define FRAME_slide19 279 +#define FRAME_slide20 280 +#define FRAME_slide21 281 +#define FRAME_slide22 282 +#define FRAME_slide23 283 +#define FRAME_slide24 284 +#define FRAME_slide25 285 +#define FRAME_slide26 286 +#define FRAME_slide27 287 +#define FRAME_slide28 288 +#define FRAME_slide29 289 +#define FRAME_slide30 290 +#define FRAME_slide31 291 +#define FRAME_snap1 292 +#define FRAME_snap2 293 +#define FRAME_snap3 294 +#define FRAME_snap4 295 +#define FRAME_snap5 296 +#define FRAME_snap6 297 +#define FRAME_snap7 298 +#define FRAME_speak1 299 +#define FRAME_speak2 300 +#define FRAME_speak3 301 +#define FRAME_speak4 302 +#define FRAME_speak5 303 +#define FRAME_speak6 304 +#define FRAME_speak7 305 +#define FRAME_speak8 306 +#define FRAME_speak9 307 +#define FRAME_speak10 308 +#define FRAME_speak11 309 +#define FRAME_speak12 310 +#define FRAME_speak13 311 +#define FRAME_speak14 312 +#define FRAME_speak15 313 +#define FRAME_speak16 314 +#define FRAME_speak17 315 +#define FRAME_speak18 316 +#define FRAME_speak19 317 +#define FRAME_swim1 318 +#define FRAME_swim2 319 +#define FRAME_swim3 320 +#define FRAME_swim4 321 +#define FRAME_swim5 322 +#define FRAME_swim6 323 +#define FRAME_swim7 324 +#define FRAME_swim8 325 +#define FRAME_swim9 326 +#define FRAME_swim10 327 +#define FRAME_swim11 328 +#define FRAME_swim12 329 +#define FRAME_swim13 330 +#define FRAME_swim14 331 +#define FRAME_swim15 332 +#define FRAME_swim16 333 +#define FRAME_swim17 334 +#define FRAME_swim18 335 +#define FRAME_swim19 336 +#define FRAME_swimata1 337 +#define FRAME_swimata2 338 +#define FRAME_swimata3 339 +#define FRAME_swimata4 340 +#define FRAME_swimata5 341 +#define FRAME_swimata6 342 +#define FRAME_swimata7 343 +#define FRAME_swimata8 344 +#define FRAME_swimata9 345 +#define FRAME_swimata10 346 +#define FRAME_swimata11 347 +#define FRAME_swimata12 348 +#define FRAME_swimata13 349 +#define FRAME_swimata14 350 +#define FRAME_swimatb1 351 +#define FRAME_swimatb2 352 +#define FRAME_swimatb3 353 +#define FRAME_swimatb4 354 +#define FRAME_swimatb5 355 +#define FRAME_swimatb6 356 +#define FRAME_swimatb7 357 +#define FRAME_swimatb8 358 +#define FRAME_swimatb9 359 +#define FRAME_swimatb10 360 +#define FRAME_swimatb11 361 +#define FRAME_swimatb12 362 +#define FRAME_swimatb13 363 +#define FRAME_swimatb14 364 +#define FRAME_twitch 365 +#define FRAME_twitch_1 366 +#define FRAME_twitch_2 367 +#define FRAME_wait1 368 +#define FRAME_wait2 369 +#define FRAME_wait3 370 +#define FRAME_wait4 371 +#define FRAME_wait5 372 +#define FRAME_wait6 373 +#define FRAME_wait7 374 +#define FRAME_wait8 375 +#define FRAME_walk1 376 +#define FRAME_walk2 377 +#define FRAME_walk3 378 +#define FRAME_walk4 379 +#define FRAME_walk5 380 +#define FRAME_walk6 381 +#define FRAME_walk7 382 +#define FRAME_walk8 383 +#define FRAME_walk9 384 +#define FRAME_walk10 385 +#define FRAME_walk11 386 +#define FRAME_walk12 387 +#define FRAME_wlklft1 388 +#define FRAME_wlklft2 389 +#define FRAME_wlklft3 390 +#define FRAME_wlklft4 391 +#define FRAME_wlklft5 392 +#define FRAME_wlklft6 393 +#define FRAME_wlklft7 394 +#define FRAME_wlklft8 395 +#define FRAME_wlklft9 396 +#define FRAME_wlklft10 397 +#define FRAME_wlklft11 398 +#define FRAME_wlklft12 399 +#define FRAME_wlkrt1 400 +#define FRAME_wlkrt2 401 +#define FRAME_wlkrt3 402 +#define FRAME_wlkrt4 403 +#define FRAME_wlkrt5 404 +#define FRAME_wlkrt6 405 +#define FRAME_wlkrt7 406 +#define FRAME_wlkrt8 407 +#define FRAME_wlkrt9 408 +#define FRAME_wlkrt10 409 +#define FRAME_wlkrt11 410 +#define FRAME_wlkrt12 411 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 1 + +#define MESH_BROKEN_GUY 0 diff --git a/Toolkit/Programming/GameCode/game/m_harpy.c b/Toolkit/Programming/GameCode/game/m_harpy.c new file mode 100644 index 0000000..18b8509 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_harpy.c @@ -0,0 +1,1722 @@ +/*------------------------------------------------------------------- +m_harpy.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + HOVER1 :hovering in midair + FLY1 :flying forwards + FLYBACK :flying backwards + +-------------------------------------------------------------------*/ + +#include "g_local.h" +#include "m_harpy.h" +#include "m_harpy_anim.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "fx.h" +#include "g_HitLocation.h" +#include "g_misc.h" +#include "m_stats.h" +#include "p_anim_branch2.h" +#include "p_anims2.h" + +#define HARPY_CHECK_DIST 128 +#define HARPY_COLLISION_DIST 148 +#define HARPY_MIN_SSWOOP_DIST 128 +#define HARPY_MIN_HOVER_DIST 128 +#define HARPY_MAX_HOVER_DIST 512 +#define HARPY_MIN_SWOOP_DIST 108 + +#define HARPY_DRIFT_AMOUNT_X 128 +#define HARPY_DRIFT_AMOUNT_Y 128 +#define HARPY_DRIFT_AMOUNT_Z 64 + +#define HARPY_SWOOP_INCR 2 +#define HARPY_SWOOP_SPEED_MAX 512 + +#define HARPY_PROJECTILE_RADIUS 1024 + +void harpy_blocked (edict_t *self, struct trace_s *trace); +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); + +/*----------------------------------------------------------------- + harpy base info +-----------------------------------------------------------------*/ + +int BPN_for_hitloc [hl_harpy_max] = { + 0, + BPN_BACKSPIKES,//hl_backspikes + BPN_HEAD|BPN_HORNS|BPN_HORN|BPN_NECKSPIKES,//hl_head + BPN_STINGER,//hl_stinger + BPN_LWING,//hl_lwing + BPN_LHAND,//hl_lefthand + BPN_RWING,//hl_rwing + BPN_RHAND,//hl_righthand + BPN_LUARM|BPN_LLARM|BPN_LHAND,//hl_leftupperleg + BPN_LLARM|BPN_LHAND,//hl_leftlowerleg + BPN_RUARM|BPN_RLARM|BPN_RHAND,//hl_rightupperleg + BPN_RLARM|BPN_RHAND//hl_rightlowerleg +}; + +int MESH_for_hitloc [hl_harpy_max] = +{ + 0, + MESH_BACKSPIKES,//hl_backspikes + MESH_HEAD,//hl_head + MESH_STINGER,//hl_stinger + MESH_LWING,//hl_lwing + MESH_LHAND,//hl_lefthand + MESH_RWING,//hl_rwing + MESH_RHAND,//hl_righthand + MESH_LUARM,//hl_leftupperleg + MESH_LLARM,//hl_leftlowerleg + MESH_RUARM,//hl_rightupperleg + MESH_RLARM//hl_rightlowerleg +}; + +static animmove_t *animations[NUM_ANIMS] = +{ + &harpy_move_die1, + &harpy_move_fly1, + &harpy_move_flyback1, + &harpy_move_hover1, + &harpy_move_hoverscream, + &harpy_move_dive_go, + &harpy_move_dive_loop, + &harpy_move_dive_end, + &harpy_move_pain1, + &harpy_move_glide, + &harpy_move_dive_trans, + &harpy_move_dive_hit_loop, + &harpy_move_tumble, + &harpy_move_pirch1_idle, + &harpy_move_pirch2_idle, + &harpy_move_pirch3_idle, + &harpy_move_pirch4_idle, + &harpy_move_pirch5_idle, + &harpy_move_pirch6_idle, + &harpy_move_pirch7_idle, + &harpy_move_pirch8_idle, + &harpy_move_pirch9_idle, + &harpy_move_takeoff, + &harpy_move_circle, + &harpy_move_circle_flap +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + + +/*=============================================================== + + Harpy Helper Functions + +===============================================================*/ + +void harpy_throw_wings(edict_t *self) +{ + int throw_nodes = 0; + vec3_t gore_spot; + + if (!(self->s.fmnodeinfo[MESH_RWING].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_for_hitloc[hl_rwing]; + } + + if (!(self->s.fmnodeinfo[MESH_LWING].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_for_hitloc[hl_lwing]; + } + + VectorCopy(vec3_origin, gore_spot); + gore_spot[2]+=10; + + ThrowBodyPart(self, &gore_spot, throw_nodes, 50, FRAME_partfly1); +} + +int head_die(edict_t *self, edict_t *inflictor, edict_t *attacker,int damage,vec3_t point) +{ + BecomeDebris(self); + return true; +} + +void harpy_head_think (edict_t *self) +{ + vec3_t down; + + if(!self->owner || self->owner->health <= 0) + { + self->movetype = PHYSICSTYPE_STEP; + self->elasticity = 0.8; + self->gravity = 1.0; + self->solid = SOLID_BBOX; + self->takedamage = DAMAGE_YES; + self->clipmask = MASK_MONSTERSOLID; + self->nextthink = -1; + self->svflags |= SVF_DEADMONSTER; + self->health = 25; + self->die = head_die; + AngleVectors(self->s.angles, down, NULL, NULL); + VectorScale(down, 100, self->velocity); + VectorSet(self->mins, -4, -4, -4); + VectorSet(self->maxs, 4, 4, 4); + gi.linkentity(self); + return; + } + + VectorCopy(self->owner->s.angles, self->s.angles); + VectorCopy(self->owner->s.origin, self->s.origin); + + AngleVectors(self->s.angles, NULL, NULL, down); + Vec3ScaleAssign(-1, down); + + VectorMA(self->s.origin, self->count, down, self->s.origin); + + self->nextthink = level.time + 0.1; +} + +void harpy_take_head(edict_t *self, edict_t *victim, int BodyPart, int frame, int flags) +{ + edict_t *head; + vec3_t forward, down; + + head = G_Spawn(); + + head->s.effects |= EF_CAMERA_NO_CLIP; + head->svflags |= SVF_ALWAYS_SEND; + head->solid = SOLID_NOT; + head->movetype = PHYSICSTYPE_NOCLIP; + head->gravity = 0; + head->clipmask = 0; + head->materialtype = victim->materialtype; + + head->owner = self; + head->activator = victim; + + VectorCopy(self->s.angles, head->s.angles); + VectorCopy(self->s.origin, head->s.origin); + + AngleVectors(head->s.angles, forward, NULL, down); + Vec3ScaleAssign(-1, down); + + head->count = 8; + VectorMA(head->s.origin, head->count, down, head->s.origin); + + head->s.origin[2] += 100; + + gi.CreateEffect(&head->s,//owner + FX_BODYPART,//type + flags,//can't mess with this, sends only 1st byte and effects message + head->s.origin,//spot, + "ssbbb",//int int float byte + (short)(frame),//only 1 frame, sorry no anim + (short)(BodyPart),//bitwise - node(s) to leave on + 0,//speed + victim->s.modelindex,//my modelindex + victim->s.number);//my number + + head->think = harpy_head_think; + head->nextthink = level.time + 0.1; + + gi.linkentity(head); + + give_head_to_harpy = NULL; + take_head_from = NULL; + + VectorScale(forward, 200, self->velocity); + self->velocity[2] = 20; + //fix angles? + self->enemy = NULL; + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + //go into a circle? +} + +void player_decap (edict_t *self, edict_t *other); +void harpy_blocked (edict_t *self, struct trace_s *trace) +{ + vec3_t vf, dir; + float dot; + int damage; + + if(!self->enemy && self->spawnflags & MSF_SPECIAL1) + { + SetAnim(self, ANIM_CIRCLING_FLAP); + return; + } + + if (self->health <= 0) + return; + + if (!trace->ent) + return; + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorCopy(self->velocity, dir); + VectorNormalize(dir); + dot = DotProduct(dir, vf); + if (trace->ent->takedamage && (self->curAnimID == ANIM_DIVE_GO || self->curAnimID == ANIM_DIVE_LOOP || self->curAnimID == ANIM_DIVE_END || self->curAnimID == ANIM_HIT_LOOP)) + { + if(trace->ent->client || classStatics[trace->ent->classID].msgReceivers[MSG_DISMEMBER]) + { + if(trace->ent->health < HARPY_DMG_MAX && trace->ent->s.origin[2] < self->s.origin[2]) + {//also make this skill dependant + give_head_to_harpy = self; + take_head_from = trace->ent; + if(trace->ent->client) + { + trace->ent->health = 1; + player_decap(trace->ent, self); + } + else + QPostMessage(trace->ent, MSG_DISMEMBER, PRI_DIRECTIVE, "ii", 9999999, hl_Head|hl_MeleeHit); + return; + } + } + + damage = irand(HARPY_DMG_MIN, HARPY_DMG_MAX); + T_Damage (trace->ent, self, self, dir, trace->ent->s.origin, trace->plane.normal, damage, damage*2, 0,MOD_DIED); + if(trace->ent->health>0) + { + if(trace->ent->client) + { + if(!irand(0, 5)) + { + if(trace->ent->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + KnockDownPlayer(&trace->ent->client->playerinfo); + } + } + } + SetAnim(self, ANIM_FLYBACK1); + return; + } + else if(self->damage_debounce_time < level.time || dot>0) + {//only back up from a block once every 2 seconds + self->damage_debounce_time = level.time + 2; + SetAnim(self, ANIM_FLYBACK1); + return; + } + SetAnim(self, ANIM_FLY1); +} + +//Various sound functions +void harpy_flap_noise(edict_t *self) +{ + gi.sound(self,CHAN_BODY,sounds[SND_FLAP],1,ATTN_NORM,0); +} + +void harpy_flap_fast_noise(edict_t *self) +{ + gi.sound(self,CHAN_BODY,sounds[SND_FLAP_FAST],1,ATTN_NORM,0); +} + +void harpy_death_noise(edict_t *self) +{ + gi.sound(self,CHAN_BODY,sounds[SND_DEATH],1,ATTN_NORM,0); +} + +void harpy_pain1_noise(edict_t *self) +{ + gi.sound(self,CHAN_BODY,sounds[SND_PAIN1],1,ATTN_NORM,0); +} + +void harpy_pain2_noise(edict_t *self) +{ + gi.sound(self,CHAN_BODY,sounds[SND_PAIN2],1,ATTN_NORM,0); +} + +void harpy_attack_noise(edict_t *self) +{ + gi.sound(self,CHAN_BODY,sounds[SND_ATTACK],1,ATTN_NORM,0); +} + +void harpy_dive_noise(edict_t *self) +{ + gi.sound(self, CHAN_BODY, sounds[SND_DIVE], 1, ATTN_NORM, 0); +} + +int harpy_check_move(edict_t *self, float dist) +{ + trace_t trace; + vec3_t vec, vf; + + VectorCopy(self->s.origin, vec); + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(vec, dist, vf, vec); + + gi.trace(self->s.origin, self->mins, self->maxs, vec, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1 || trace.allsolid || trace.startsolid) + { + if (trace.ent == self->enemy) + return true; + + return false; + } + + return true; +} + +/*----------------------------------------------- + harpy_ai_circle +-----------------------------------------------*/ + +#define HARPY_CIRCLE_AMOUNT 4 +#define HARPY_CIRCLE_SPEED 64 + +void harpy_ai_circle (edict_t *self, float fd, float rd, float ud) +{ + vec3_t vf; + + self->s.angles[ROLL] += flrand(-1.25, 1); + + if(self->s.angles[ROLL] < -45) + self->s.angles[ROLL] = -45; + + if(self->s.angles[ROLL] > 0) + self->s.angles[ROLL] = 0; + + self->s.angles[YAW] = anglemod(self->s.angles[YAW] - (HARPY_CIRCLE_AMOUNT + (fd - 32)/4)); + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(self->velocity, HARPY_CIRCLE_SPEED + fd, vf, self->velocity); + Vec3ScaleAssign(0.5, self->velocity); + + if(!irand(0, 150)) + gi.sound(self, CHAN_VOICE, sounds[SND_SCREAM], 1, ATTN_NORM, 0); +} + +//replaces ai_walk and ai_run for harpy +void harpy_ai_glide (edict_t *self, float fd, float rd, float ud) +{ + vec3_t vec, vf, vr, nvec; + float yaw_delta, roll, dot, rdot; + + if (!self->enemy) + return; + + //Find our ideal yaw to the player and correct to it + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + VectorCopy(vec, nvec); + VectorNormalize(nvec); + + AngleVectors(self->s.angles, vf, vr, NULL); + + dot = DotProduct(vf, nvec); + rdot = DotProduct(vr, nvec); + + self->ideal_yaw = vectoyaw(vec); + + M_ChangeYaw(self); + + yaw_delta = self->ideal_yaw - self->s.angles[YAW]; + + //If enough, roll the creature to simulate gliding + if (Q_fabs(yaw_delta) > self->yaw_speed) + { + if (dot < 0) + { + roll = Q_fabs(yaw_delta / 4); + } + else + { + roll = yaw_delta / 4; + } + + //Going right? + if (roll > 0) + { + self->s.angles[ROLL] += roll; + if (self->s.angles[ROLL] > 65) + self->s.angles[ROLL] = 65; + } + else + { + self->s.angles[ROLL] += roll; + if (self->s.angles[ROLL] < -65) + self->s.angles[ROLL] = -65; + } + } + else + { + self->s.angles[ROLL] *= 0.75; + } +} + +void harpy_ai_fly (edict_t *self, float fd, float rd, float ud) +{ + vec3_t vec, vf, vr, vu; + + if (!self->enemy) + return; + + //Add "friction" to the movement to allow graceful flowing motion, not jittering + self->velocity[0] *= 0.8; + self->velocity[1] *= 0.8; + self->velocity[2] *= 0.8; + + //Find our ideal yaw to the player and correct to it + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + + M_ChangeYaw(self); + + if (!harpy_check_move(self, fd/10)) + { + SetAnim(self, ANIM_HOVER1); + return; + } + + //Add in the movements relative to the creature's facing + AngleVectors(self->s.angles, vf, vr, vu); + + VectorMA(self->velocity, fd, vf, self->velocity); + VectorMA(self->velocity, rd, vr, self->velocity); + VectorMA(self->velocity, ud, vu, self->velocity); + + if (self->groundentity) + self->velocity[2] += 32; +} + +//replaces ai_stand for harpy +void harpy_ai_hover(edict_t *self, float dist) +{ + vec3_t vec; + + if (!self->enemy) + { + if (!FindTarget(self)) + return; + } + + //Add "friction" to the movement to allow graceful flowing motion, not jittering + self->velocity[0] *= 0.8; + self->velocity[1] *= 0.8; + self->velocity[2] *= 0.8; + + //Make sure we're not tilted after a turn + self->s.angles[ROLL] *= 0.25; + + //Find our ideal yaw to the player and correc to it + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + + M_ChangeYaw(self); + + harpy_ai_glide(self,0,0,0); +} + +//receiver for MSG_FLYBACK +void harpy_flyback(edict_t *self) +{ + SetAnim(self, ANIM_FLYBACK1); + return; +} + + +void harpy_ai_pirch(edict_t *self) +{ + monsterinfo_t *monsterinfo = &self->monsterinfo; + vec3_t vec, vf, vr; + float dot, rdot, len; + + if (!M_ValidTarget(self, self->enemy)) + return; + + if(!visible(self, self->enemy)) + return; + + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + len = VectorNormalize(vec); + + if (len < 150) + { + SetAnim(self, ANIM_TAKEOFF); + return; + } + + if (irand(0,100) < 10 && self->monsterinfo.attack_finished < level.time) + { + self->monsterinfo.attack_finished = level.time + 5; + + if (irand(0,1)) + gi.sound (self, CHAN_WEAPON, sounds[SND_IDLE1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_IDLE2], 1, ATTN_NORM, 0); + } + + AngleVectors(self->s.angles, vf, vr, NULL); + + dot = DotProduct(vec, vf); + + if (dot < 0) + { + SetAnim(self, ANIM_TAKEOFF); + return; + } + + rdot = DotProduct(vec, vr); + + //Left + if (rdot < 0) + { + if (rdot < -0.8) + { + SetAnim(self, ANIM_PIRCH9); + } + else if (rdot < -0.6) + { + SetAnim(self, ANIM_PIRCH8); + } + else if (rdot < -0.4) + { + SetAnim(self, ANIM_PIRCH7); + } + else if (rdot < -0.2) + { + SetAnim(self, ANIM_PIRCH6); + } + else + { + SetAnim(self, ANIM_PIRCH5); + } + } + else + { + if (rdot > 0.8) + { + SetAnim(self, ANIM_PIRCH1); + } + else if (rdot > 0.6) + { + SetAnim(self, ANIM_PIRCH2); + } + else if (rdot > 0.4) + { + SetAnim(self, ANIM_PIRCH3); + } + else if (rdot > 0.2) + { + SetAnim(self, ANIM_PIRCH4); + } + else + { + SetAnim(self, ANIM_PIRCH5); + } + } +} + +void move_harpy_tumble(edict_t *self) +{ + trace_t trace; + vec3_t endpos; + + self->movetype = PHYSICSTYPE_STEP; + self->gravity = 1; + + VectorSet(self->mins, -16, -16, 0); + VectorSet(self->maxs, 16, 16, 16); + + /* + if (!self->avelocity[PITCH] && !self->avelocity[YAW] && !self->avelocity[ROLL]) + { + self->avelocity[PITCH] = flrand(128.0F, 256.0F); + self->avelocity[YAW] = flrand(64.0F, 512.0F); + self->avelocity[ROLL] = flrand(64.0F, 512.0F); + } + */ + + VectorCopy(self->s.origin, endpos); + endpos[2] -= 32; + + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&trace); + + if ( (self->groundentity != NULL) || (trace.fraction != 1) || (trace.startsolid) || (trace.allsolid) || (self->monsterinfo.jump_time < level.time) ) + { + gi.CreateEffect(&self->s, FX_DUST_PUFF, CEF_OWNERS_ORIGIN, self->s.origin, NULL); + + VectorCopy(self->s.angles, self->movedir); + harpy_death_noise(self); + + SetAnim(self, ANIM_DIE); + } +} + +void harpy_fix_angles(edict_t *self) +{ + float pitch_delta, roll_delta; + + pitch_delta = self->movedir[PITCH]; + roll_delta = self->movedir[ROLL]; + + if (pitch_delta > 0) + { + self->s.angles[PITCH] -= pitch_delta / 2; + + if (self->s.angles[PITCH] < 2) + { + self->s.angles[PITCH] = 0; + } + } + else + { + self->s.angles[PITCH] += pitch_delta / 2; + + if (self->s.angles[PITCH] > 2) + { + self->s.angles[PITCH] = 0; + } + } + + //Roll + if (roll_delta > 0) + { + self->s.angles[ROLL] -= roll_delta / 2; + + if (self->s.angles[ROLL] < 2) + { + self->s.angles[ROLL] = 0; + } + } + else + { + self->s.angles[ROLL] += roll_delta / 15; + + if (self->s.angles[ROLL] > 2) + { + self->s.angles[ROLL] = 0; + } + } +} + +/*=============================================================== + + Harpy Message Functions + +===============================================================*/ + +//receiver for MSG_DEATH +void harpy_dead_pain(edict_t *self, G_Message_t *msg) +{ + if(self->health <= -40) //gib death + { + //harpy_throw_wings(self); + BecomeDebris(self); + self->think = NULL; + self->nextthink = 0; + gi.linkentity (self); + return; + } + else if(msg) + MG_parse_dismember_msg(self, msg); + +} + +void harpy_die(edict_t *self, G_Message_t *msg) +{ + if(self->monsterinfo.aiflags&AI_DONT_THINK) + { + SetAnim(self, ANIM_DIE); + return; + } + + self->movetype = PHYSICSTYPE_STEP; + self->gravity = 1; + self->elasticity = 1.1; + + VectorSet(self->mins, -16, -16, 0); + VectorSet(self->maxs, 16, 16, 16); + + if(self->health <= -40) //gib death + { + //harpy_throw_wings(self); + gi.sound(self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + + BecomeDebris(self); + gi.linkentity (self); + return; + } + + self->msgHandler = DeadMsgHandler; + + if(irand(0, 1)) + self->svflags &= ~SVF_TAKE_NO_IMPACT_DMG; + + SetAnim(self, ANIM_DIE); + return; +} + +void harpy_dismember(edict_t *self, int damage, int HitLocation) +{ + int throw_nodes, MeshLoc; + vec3_t gore_spot; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation>hl_WingedPoints) + return; + + if (HitLocation==hl_backspikes) + HitLocation = irand(hl_lwing, hl_rwing); + + switch (HitLocation) + { + case hl_head: + + if (self->s.fmnodeinfo[MESH_HEAD].flags & FMNI_NO_DRAW) + dismember_ok = false; + + if (irand(0,10) > 2) + dismember_ok = false; + + break; + + case hl_rightlowerleg: + case hl_rightupperleg: + + if (self->s.fmnodeinfo[MESH_RUARM].flags & FMNI_NO_DRAW) + dismember_ok = false; + + if (irand(0,10) > 4) + dismember_ok = false; + + break; + + case hl_leftlowerleg: + case hl_leftupperleg: + + if (self->s.fmnodeinfo[MESH_LUARM].flags & FMNI_NO_DRAW) + dismember_ok = false; + + if (irand(0,10) > 4) + dismember_ok = false; + + break; + + case hl_rwing: + + if (self->s.fmnodeinfo[MESH_RWING].flags & FMNI_NO_DRAW) + dismember_ok = false; + + if (irand(0,10) > 6) + dismember_ok = false; + + break; + + case hl_lwing: + + if (self->s.fmnodeinfo[MESH_LWING].flags & FMNI_NO_DRAW) + dismember_ok = false; + + if (irand(0,10) > 6) + dismember_ok = false; + + break; + + default : + + dismember_ok = false; + + break; + } + + if (dismember_ok) + { + VectorCopy(vec3_origin, gore_spot); + gore_spot[2]+=10; + + throw_nodes = BPN_for_hitloc[HitLocation]; + + MeshLoc = MESH_for_hitloc[HitLocation]; + + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly1); + + switch(MeshLoc) + { + case hl_head : + + self->s.fmnodeinfo[MESH_HEAD].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH_HORN].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH_HORNS].flags |= FMNI_NO_DRAW; + break; + + case hl_leftlowerleg : + case hl_leftupperleg : + + self->s.fmnodeinfo[MESH_LUARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH_LLARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH_LHAND].flags |= FMNI_NO_DRAW; + break; + + case hl_rightlowerleg : + case hl_rightupperleg : + + self->s.fmnodeinfo[MESH_RUARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH_RLARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH_RHAND].flags |= FMNI_NO_DRAW; + break; + + default : + + self->s.fmnodeinfo[MeshLoc].flags |= FMNI_NO_DRAW; + break; + } + + if (HitLocation == hl_rwing || HitLocation == hl_lwing || HitLocation == hl_head) + { + self->monsterinfo.jump_time = level.time + 2; + + if (self->health > 0) + { + self->health = -1; + harpy_death_noise(self); + SetAnim(self, ANIM_TUMBLE); + self->msgHandler = DeadMsgHandler; + } + } + } + else + { + if (irand(0,10) < 1) + { + MeshLoc = MESH_for_hitloc[HitLocation]; + + if (!(self->s.fmnodeinfo[MeshLoc].flags & FMNI_USE_SKIN)) + { + self->s.fmnodeinfo[MeshLoc].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MeshLoc].skin = self->s.skinnum+1; + } + } + } +} + +//receiver for MSG_PAIN +void harpy_pain(edict_t *self, G_Message_t *msg) +{ + int temp, damage; + qboolean force_pain; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_pain, &damage, &temp); + + if (self->curAnimID >= ANIM_PIRCH1 && self->curAnimID <= ANIM_PIRCH9) + { + SetAnim(self, ANIM_TAKEOFF); + return; + } + if (force_pain||((irand(0,10) < 2) && (self->pain_debounce_time < level.time))) + { + if (irand(0,1)) + harpy_pain1_noise(self); + else + harpy_pain2_noise(self); + + self->pain_debounce_time = level.time + 2; + SetAnim(self, ANIM_PAIN1); + } +} + +//receiver for MSG_STAND, MSG_HOVER +void harpy_hover(edict_t *self, G_Message_t *msg) +{ + //NOTENOTE: We use the animation IDs to make sure we don't reject a stand message after leaving these animations + //if (self->curAnimID >= ANIM_PIRCH1 && self->curAnimID <= ANIM_PIRCH9 && self->curAnimID != ANIM_CIRCLING) + // return; + + if ( (self->spawnflags & MSF_PERCHING) || (self->spawnflags & MSF_SPECIAL1) ) + return; + + if(irand(1, 10) > 3) + { + SetAnim(self, ANIM_HOVER1); + } + else + { + gi.sound(self, CHAN_BODY, sounds[SND_SCREAM], 1, ATTN_NORM, 0); + SetAnim(self, ANIM_HOVERSCREAM); + } +} + +void harpy_stand(edict_t *self, G_Message_t *msg) +{ + //NOTENOTE: We use the animation IDs to make sure we don't reject a stand message after leaving these animations + //if (self->curAnimID >= ANIM_PIRCH1 && self->curAnimID <= ANIM_PIRCH9 && self->curAnimID != ANIM_CIRCLING) + // return; + + if ( (self->spawnflags & MSF_PERCHING) || (self->spawnflags & MSF_SPECIAL1) ) + return; + + if(irand(1, 10) > 3) + { + SetAnim(self, ANIM_HOVER1); + } + else + { + gi.sound(self, CHAN_BODY, sounds[SND_SCREAM], 1, ATTN_NORM, 0); + SetAnim(self, ANIM_HOVERSCREAM); + } +} + +void harpy_fly(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_FLY1); +} + +void harpy_evade(edict_t *self, G_Message_t *msg) +{ + if (self->curAnimID > ANIM_PIRCH1 && self->curAnimID < ANIM_PIRCH9) + { + self->mins[2] -= 4; + SetAnim(self, ANIM_TAKEOFF); + } +} + +void harpy_perch(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_PIRCH5); +} + +void harpy_hit(edict_t *self) +{ + trace_t trace; + edict_t *victim; + vec3_t vf;//, hitPos, mins, maxs; + float movedist, damage; + + AngleVectors(self->s.angles, vf, NULL, NULL); + movedist = VectorLength(self->velocity); + + victim = M_CheckMeleeHit( self, movedist, &trace); + + if (victim) + { + if (victim == self) + { + SetAnim(self, ANIM_FLYBACK1); + } + else + { + damage = irand(HARPY_DMG_MIN, HARPY_DMG_MAX); + T_Damage (victim, self, self, vf, self->enemy->s.origin, trace.plane.normal, damage, damage*2, 0,MOD_DIED); + } + } +} + +void harpy_pause (edict_t *self) +{ + if (M_ValidTarget(self, self->enemy)) + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + else if(self->curAnimID == ANIM_CIRCLING) + { + if(!irand(0, 6)) + SetAnim(self, ANIM_CIRCLING_FLAP); + } + else if(self->curAnimID == ANIM_CIRCLING_FLAP && irand(0, 1)) + SetAnim(self, ANIM_CIRCLING); +} + + +//end of anim func for death anim +void harpy_dead(edict_t *self) +{ + VectorSet(self->mins, -16, -16, 0); + VectorSet(self->maxs, 16, 16, 16); + + M_EndDeath(self); +} + +qboolean harpy_check_directions(edict_t *self, vec3_t goal, vec3_t vf, vec3_t vr, vec3_t vu, float checkdist, vec3_t ret) +{ + trace_t trace; + vec3_t goalpos; + + //Don't always check one direction first (looks mechanical) + if (irand(0,1)) + VectorScale(vr, -1, vr); + + VectorMA(self->s.origin, checkdist, vr, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + //We've found somewhere to go + if (trace.ent == self->enemy) + { + VectorCopy(vr, ret); + return true; + } + else //Check the other directions + { + VectorScale(vr, -1, vr); + VectorMA(goalpos, checkdist, vr, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.ent == self->enemy) + { + VectorCopy(vr, ret); + return true; + } + } + + //Check up and down + VectorCopy(self->s.origin, goalpos); + + //Don't always check one direction first (looks mechanical) + if (irand(0,1)) + VectorScale(vu, -1, vu); + + VectorMA(goalpos, checkdist, vu, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + //We've found somewhere to go + if (trace.ent == self->enemy) + { + VectorCopy(vu, ret); + return true; + } + else //Check the other directions + { + VectorScale(vu, -1, vu); + VectorMA(goalpos, checkdist, vu, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.ent == self->enemy) + { + VectorCopy(vu, ret); + return true; + } + } + + //Check forward and back + VectorCopy(self->s.origin, goalpos); + + //Don't always check one direction first (looks mechanical) + if (irand(0,1)) + VectorScale(vf, -1, vf); + + VectorMA(goalpos, checkdist, vf, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + //We've found somewhere to go + if (trace.ent == self->enemy) + { + VectorCopy(vf, ret); + return true; + } + else //Check the other directions + { + VectorScale(vf, -1, vf); + VectorMA(goalpos, checkdist, vf, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.ent == self->enemy) + { + VectorCopy(vf, ret); + return true; + } + } + + return false; +} + +qboolean harpy_check_swoop(edict_t *self, vec3_t goal) +{ + trace_t trace; + vec3_t checkpos; + float zd; + + //Find the difference in the target's height and the creature's height + zd = Q_fabs(self->enemy->s.origin[2] - self->s.origin[2]); + + if (zd < HARPY_MIN_SSWOOP_DIST) + return false; + + zd -= zd/4; + + VectorCopy(self->s.origin, checkpos); + checkpos[2] -= zd; + + //Trace down about that far and about one forth the distance to the target + gi.trace(self->s.origin, self->mins, self->maxs, checkpos, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1 || trace.startsolid || trace.allsolid) + { + //gi.dprintf("harpy_check_swoop: failed down check\n"); + return false; + } + + //Trace straight to the target + + gi.trace(checkpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.ent != self->enemy) + { + //gi.dprintf("harpy_check_swoop: failed out check\n"); + return false; + } + + //There's a clear path + return true; +} + +void move_harpy_dive(edict_t *self) +{ + vec3_t vec, vf, enemy_pos; + float dist, zd, hd, forward; + + VectorSet(enemy_pos, self->enemy->s.origin[0], self->enemy->s.origin[1], self->enemy->s.origin[2] + flrand(self->maxs[2], self->enemy->maxs[2])); + //Find out the Z and Horizontal deltas to target + zd = Q_fabs(self->s.origin[2] - enemy_pos[2]); + + AngleVectors(self->s.angles, vf, NULL, NULL); + + VectorCopy(self->s.origin, vec); + vec[2] = enemy_pos[2]; + + VectorSubtract(enemy_pos, vec, vec); + hd = VectorLength(vec); + + if ((self->groundentity != NULL) || (!harpy_check_move(self, 64))) + { + if (self->groundentity == self->enemy) + SetAnim(self, ANIM_DIVE_END); + + SetAnim(self, ANIM_FLYBACK1); + return; + } + + dist = Q_fabs(self->s.origin[2] - enemy_pos[2]); + + forward = (256 - (dist*0.85)); + + if (forward > 256) + forward = 256; + else if (forward < 0) + forward = 0; + + if (dist > HARPY_MIN_SWOOP_DIST) + { + VectorMA(vf, forward, vf, self->velocity); + self->velocity[2] = -dist*2.25; + if (self->velocity[2] < -300) + self->velocity[2] = -300; + } + else + { + SetAnim(self, ANIM_DIVE_TRANS); + return; + } + + harpy_ai_glide(self, 0, 0, 0); +} + +void move_harpy_dive_end(edict_t *self) +{ + vec3_t vec, vf, vr, vu, nvec, enemy_pos; + float dist, hd, fd, dot; + + VectorSet(enemy_pos, self->enemy->s.origin[0], self->enemy->s.origin[1], self->enemy->s.origin[2] + flrand(self->maxs[2], self->enemy->maxs[2])); + + VectorCopy(self->s.origin, vec); + vec[2] = enemy_pos[2]; + + VectorSubtract(enemy_pos, vec, vec); + hd = VectorLength(vec); + self->ideal_yaw = vectoyaw(vec); + + M_ChangeYaw(self); + + AngleVectors(self->s.angles, vf, vr, vu); + + self->velocity[2] *= 0.75; + + self->monsterinfo.jump_time *= HARPY_SWOOP_INCR; + + fd = self->monsterinfo.jump_time; + + if (fd > HARPY_SWOOP_SPEED_MAX) + fd = HARPY_SWOOP_SPEED_MAX; + + if ((self->groundentity != NULL) || (!harpy_check_move(self, 128))) + { + if (self->groundentity == self->enemy) + SetAnim(self, ANIM_DIVE_END); + + SetAnim(self, ANIM_FLYBACK1); + return; + } + + VectorSubtract(enemy_pos, self->s.origin, vec); + VectorCopy(vec, nvec); + VectorNormalize(nvec); + + AngleVectors(self->s.angles, vf, vr, NULL); + + dot = DotProduct(vf, nvec); + + if (dot < -0.5) + { + SetAnim(self, ANIM_FLYBACK1); + return; + } + + VectorMA(self->velocity, fd, vf, self->velocity); + + //Are we about to hit the target? + VectorSubtract(enemy_pos, self->s.origin, vec); + dist = VectorLength(vec); + + if (dist < HARPY_COLLISION_DIST) + { + SetAnim(self, ANIM_DIVE_END); + return; + } + + harpy_ai_glide(self, 0, 0, 0); +} + +void harpy_dive_loop(edict_t *self) +{ + SetAnim(self, ANIM_DIVE_LOOP); +} + +void harpy_hit_loop(edict_t *self) +{ + SetAnim(self, ANIM_HIT_LOOP); +} + +void harpy_check_dodge(edict_t *self) +{ + qboolean dodge = false; + trace_t trace; + edict_t *ent = NULL; + vec3_t vec, vr, projvec, dodgedir, goalpos; + float dodgedot; + + if (!self->enemy) + return; + + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + VectorNormalize(vec); + + while ((ent = findradius(ent, self->s.origin, HARPY_PROJECTILE_RADIUS)) != NULL) + { + //We're only interested in his projectiles + if (ent->owner != self->enemy) + continue; + + //VectorCopy(ent->velocity, projvec); + VectorNormalize2(ent->velocity, projvec); + + dodgedot = DotProduct(projvec, vec); + + //gi.dprintf("Found projectile with dot %f\n", dodgedot); + + if (dodgedot < -0.85 && irand(0,1)) + { + //gi.dprintf("Dodge it!\n"); + + dodge = true; + AngleVectors(self->s.angles, NULL, vr, NULL); + + if (irand(0,1)) + VectorScale(vr, -1, vr); + + VectorMA(self->s.origin, 100, vr, goalpos); + + gi.trace(self->s.origin, self->mins, self->maxs, goalpos, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1 || trace.startsolid || trace.allsolid) + VectorScale(vr, -1, dodgedir); + } + } + + if (dodge) + { + //If he is, dodge! + if (self->monsterinfo.misc_debounce_time < level.time) + { + VectorMA(self->velocity, irand(300, 500), dodgedir, self->velocity); + self->monsterinfo.misc_debounce_time = level.time + irand(2,4); + } + } + + harpy_ai_glide(self, 0, 0, 0); +} + +void move_harpy_hover(edict_t *self) +{ + qboolean canmove = false, dodge = false; + trace_t trace; + edict_t *ent = NULL; + vec3_t goal, dodgedir, mins, maxs, vf, vr, vu, vec, projvec, goalpos; + float dist, zd, dodgedot; + + //gi.dprintf("move_harpy_hover: entered function\n"); + + if (!self->enemy) + { + if (!FindTarget(self)) + { + //gi.dprintf("move_harpy_hover: Enemy lost\n"); + return; + } + } + + //First check to see that the player is at least 128 units away in (discounting z height) + VectorCopy(self->enemy->s.origin, goal); + goal[2] = self->s.origin[2]; + + VectorSubtract(goal, self->s.origin, goal); + dist = VectorLength(goal); + + //Face target + self->ideal_yaw = vectoyaw(goal); + M_ChangeYaw(self); + + //If he is... + if (dist > HARPY_MIN_HOVER_DIST && dist < HARPY_MAX_HOVER_DIST) + { + //gi.dprintf("move_harpy_hover: valid player distance\n"); + + //Make sure we've got line of sight + VectorSet(mins, -1, -1, -1); + VectorSet(maxs, 1, 1, 1); + + gi.trace(self->s.origin, mins, maxs, self->enemy->s.origin, self, MASK_SHOT|MASK_WATER,&trace); + + //If not, try looking from a bit to the side in all six directions + if (trace.ent != self->enemy) + { + //gi.dprintf("move_harpy_hover: lost line of sight to player\n"); + + //Setup the directions + AngleVectors(self->s.angles, vf, vr, vu); + + canmove = harpy_check_directions(self, self->enemy->s.origin, vf, vr, vu, HARPY_CHECK_DIST, goal); + + //If we can see him from one of these, go there + if (canmove) + { + //gi.dprintf("move_harpy_hover: new position found, moving...\n"); + VectorMA(self->velocity, flrand(300.0F, 400.0F), goal, self->velocity); + return; + } + + //gi.dprintf("move_harpy_hover: no new direction found, bumping about\n"); + + //Otherwise just flap around and wait, perhaps lower yourself a bit if high up + self->velocity[0] = flrand(-HARPY_DRIFT_AMOUNT_X, HARPY_DRIFT_AMOUNT_X); + self->velocity[1] = flrand(-HARPY_DRIFT_AMOUNT_Y, HARPY_DRIFT_AMOUNT_Y); + self->velocity[2] = flrand(-HARPY_DRIFT_AMOUNT_Z, HARPY_DRIFT_AMOUNT_Z); + + return; + } + else + { + //Check to make sure the player isn't shooting anything + + //This won't change over the calculations + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + VectorNormalize(vec); + + while ((ent = findradius(ent, self->s.origin, HARPY_PROJECTILE_RADIUS)) != NULL) + { + //We're only interested in his projectiles + if (ent->owner != self->enemy) + continue; + + VectorCopy(ent->velocity, projvec); + VectorNormalize(projvec); + + dodgedot = DotProduct(projvec, vec); + + //gi.dprintf("Found projectile with dot %f\n", dodgedot); + + if (dodgedot < -0.6) + { + //gi.dprintf("Dodge it!\n"); + + dodge = true; + AngleVectors(self->s.angles, NULL, vr, NULL); + + if (irand(0,1)) + VectorScale(vr, -1, vr); + + VectorMA(self->s.origin, 100, vr, goalpos); + + gi.trace(self->s.origin, self->mins, self->maxs, goalpos, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1 || trace.startsolid || trace.allsolid) + VectorScale(vr, -1, vr); + + VectorCopy(vr, dodgedir); + } + } + + if (dodge) + { + //If he is, dodge! + VectorMA(self->velocity, irand(300, 500), dodgedir, self->velocity); + return; + } + + //If nothing is happening, check to swoop + canmove = harpy_check_swoop(self, self->enemy->s.origin); + + //If you can--nail um + if (canmove) + { + //gi.dprintf("move_harpy_hover: valid swoop\n"); + self->monsterinfo.jump_time = 2; + SetAnim(self, ANIM_DIVE_GO); + + return; + } + + //If not, check to see if there's somewhere that you can get to that will allow it + //FIXME: Too many checks.. just try something simple + + //If all else fails, then just pick a random direction to nudge yourself to + else + { + //gi.dprintf("move_harpy_hover: swoop worthless\n"); + + //Find the difference in the target's height and the creature's height + zd = Q_fabs(self->enemy->s.origin[2] - self->s.origin[2]); + + //We can't swoop because we're too low, so fly upwards if possible + if (zd < HARPY_MIN_SSWOOP_DIST) + { + if (!harpy_check_move(self, -64)) + { + SetAnim(self, ANIM_FLY1); + return; + } + else + { + //gi.dprintf("Moveback ok\n"); + SetAnim(self, ANIM_FLYBACK1); + return; + } + } + else + { + //Otherwise just flap around and wait, perhaps lower yourself a bit if high up + self->velocity[0] = flrand(-HARPY_DRIFT_AMOUNT_X, HARPY_DRIFT_AMOUNT_X); + self->velocity[1] = flrand(-HARPY_DRIFT_AMOUNT_Y, HARPY_DRIFT_AMOUNT_Y); + self->velocity[2] = flrand(-HARPY_DRIFT_AMOUNT_Z, HARPY_DRIFT_AMOUNT_Z); + + AngleVectors(self->s.angles, vec, NULL, NULL); + VectorMA(self->velocity, irand(200,300), vec, self->velocity); + } + + return; + } + + } + + //If he's too far away trace a line (expanded) to see if you can move at him + } + else if (dist < HARPY_MIN_HOVER_DIST) + { + //gi.dprintf("move_harpy_hover: backing away\n"); + if (!harpy_check_move(self, -64)) + { + SetAnim(self, ANIM_FLY1); + } + else + { + SetAnim(self, ANIM_FLYBACK1); + } + } + else + { + //gi.dprintf("move_harpy_hover: covering ground\n"); + if (!harpy_check_move(self, 64)) + { + SetAnim(self, ANIM_FLYBACK1); + } + else + { + SetAnim(self, ANIM_FLY1); + } + } + + return; +} + +//New physics call that modifies the harpy's velocity and angles based on aerodynamics +void harpy_flight_model(edict_t *self) +{ +} + +void move_harpy_fly(edict_t *self) +{ + edict_t *dummy; + dummy = self; + + return; +} + +void move_harpy_die(edict_t *self) +{ + //fall to the floor + return; +} + +void harpy_hover_anim(edict_t *self) +{ + SetAnim(self, ANIM_HOVER1); +} + +/*=============================================================== + + Harpy Spawn Functions + +===============================================================*/ +void harpy_dead_pain(edict_t *self, G_Message_t *msg); + +void HarpyStaticsInit() +{ + classStatics[CID_HARPY].msgReceivers[MSG_DEATH] = harpy_die; + classStatics[CID_HARPY].msgReceivers[MSG_FLY] = harpy_hover; + classStatics[CID_HARPY].msgReceivers[MSG_STAND] = harpy_stand; + classStatics[CID_HARPY].msgReceivers[MSG_RUN] = harpy_hover; + classStatics[CID_HARPY].msgReceivers[MSG_PAIN] = harpy_pain; + classStatics[CID_HARPY].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_HARPY].msgReceivers[MSG_WATCH] = harpy_perch; + classStatics[CID_HARPY].msgReceivers[MSG_DEATH_PAIN] = harpy_dead_pain; + classStatics[CID_HARPY].msgReceivers[MSG_EVADE] = harpy_evade; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/harpy/tris.fm"); + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + sounds[SND_GIB]=gi.soundindex("misc/fleshbreak.wav"); + sounds[SND_FLAP]=gi.soundindex("monsters/harpy/flap.wav"); + sounds[SND_SCREAM]=gi.soundindex("monsters/harpy/scream.wav"); + sounds[SND_FLAP_FAST]=gi.soundindex("monsters/harpy/flap_quick.wav"); + sounds[SND_DIVE]=gi.soundindex("monsters/harpy/dive.wav"); + sounds[SND_DEATH]=gi.soundindex("monsters/harpy/death.wav"); + sounds[SND_PAIN1]=gi.soundindex("monsters/harpy/pain1.wav"); + sounds[SND_PAIN2]=gi.soundindex("monsters/harpy/pain2.wav"); + sounds[SND_ATTACK]=gi.soundindex("monsters/harpy/attack.wav"); + + sounds[SND_IDLE1]=gi.soundindex("monsters/harpy/pain1.wav"); + sounds[SND_IDLE2]=gi.soundindex("monsters/harpy/pain2.wav"); + + classStatics[CID_HARPY].resInfo = &resInfo; +} + +/*QUAKED monster_harpy(1 .5 0) (-16 -16 -12) (16 16 12) AMBUSH ASLEEP PERCHING CIRCLING + +The harpy + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +PERCHING - Will watch player until get too close or get behind the harpy + +CIRCLING - harpy circles around in the air + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +*/ +void SP_monster_harpy(edict_t *self) +{ + if (!flymonster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_HARPY; + self->monsterinfo.dismember = harpy_dismember; + + if (!self->health) + self->health = HARPY_HEALTH; + + self->mass = HARPY_MASS; + self->yaw_speed = 14; + + self->movetype = PHYSICSTYPE_FLY; + self->gravity = 0; + self->flags |= FL_FLY; + self->solid = SOLID_BBOX; + self->clipmask = MASK_MONSTERSOLID; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + self->svflags |= SVF_TAKE_NO_IMPACT_DMG; + self->svflags |= SVF_DO_NO_IMPACT_DMG; + + self->materialtype = MAT_FLESH; + + self->s.modelindex = classStatics[CID_HARPY].resInfo->modelIndex; + self->s.skinnum = 0; + + self->isBlocked = harpy_blocked; + self->bounced = harpy_blocked; + + if (!self->s.scale) + { + self->monsterinfo.scale = self->s.scale = flrand(1.25, 1.75); + } + + self->monsterinfo.otherenemyname = "monster_rat"; + + self->monsterinfo.aiflags |= AI_NO_ALERT;//pay no attention to alert ents + + if (self->spawnflags & MSF_PERCHING) + { + + self->s.origin[2] += 4; + SetAnim(self, ANIM_PIRCH5); + } + else if (self->spawnflags & MSF_SPECIAL1) + { + SetAnim(self, ANIM_CIRCLING); + } + else + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } + + if(irand(0,1)) + self->s.fmnodeinfo[MESH_HORNS].flags |= FMNI_NO_DRAW; + + if(irand(0,1)) + self->s.fmnodeinfo[MESH_HORN].flags |= FMNI_NO_DRAW; + + if(irand(0,1)) + self->s.fmnodeinfo[MESH_BACKSPIKES].flags |= FMNI_NO_DRAW; + + if(irand(0,4)) + self->s.fmnodeinfo[MESH_NECKSPIKES].flags |= FMNI_NO_DRAW; + + if(irand(0,2)) + self->s.fmnodeinfo[MESH_TAILSPIKES].flags |= FMNI_NO_DRAW; + + gi.linkentity(self); +} diff --git a/Toolkit/Programming/GameCode/game/m_harpy.h b/Toolkit/Programming/GameCode/game/m_harpy.h new file mode 100644 index 0000000..b360091 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_harpy.h @@ -0,0 +1,161 @@ +typedef enum AnimID_e +{ + ANIM_DIE, + ANIM_FLY1, + ANIM_FLYBACK1, + ANIM_HOVER1, + ANIM_HOVERSCREAM, + ANIM_DIVE_GO, + ANIM_DIVE_LOOP, + ANIM_DIVE_END, + ANIM_PAIN1, + ANIM_GLIDE1, + ANIM_DIVE_TRANS, + ANIM_HIT_LOOP, + ANIM_TUMBLE, + ANIM_PIRCH1, + ANIM_PIRCH2, + ANIM_PIRCH3, + ANIM_PIRCH4, + ANIM_PIRCH5, + ANIM_PIRCH6, + ANIM_PIRCH7, + ANIM_PIRCH8, + ANIM_PIRCH9, + ANIM_TAKEOFF, + ANIM_CIRCLING, + ANIM_CIRCLING_FLAP, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_FLAP, + SND_SCREAM, + SND_FLAP_FAST, + SND_DIVE, + SND_DEATH, + SND_PAIN1, + SND_PAIN2, + SND_ATTACK, + SND_GIB, + SND_IDLE1, + SND_IDLE2, + NUM_SOUNDS +} SoundID_t; + +void move_harpy_tumble(edict_t *self); + +void harpy_flap_noise(edict_t *self); +void harpy_flap_fast_noise(edict_t *self); +void harpy_dive_noise(edict_t *self); +void harpy_death_noise(edict_t *self); +void harpy_pain1_noise(edict_t *self); +void harpy_pain2_noise(edict_t *self); +void harpy_attack_noise(edict_t *self); + +extern animmove_t harpy_move_die1; +extern animmove_t harpy_move_fly1; +extern animmove_t harpy_move_flyback1; +extern animmove_t harpy_move_hover1; +extern animmove_t harpy_move_hoverscream; +extern animmove_t harpy_move_dive_go; +extern animmove_t harpy_move_dive_loop; +extern animmove_t harpy_move_dive_end; +extern animmove_t harpy_move_pain1; +extern animmove_t harpy_move_glide; +extern animmove_t harpy_move_dive_trans; +extern animmove_t harpy_move_dive_hit_loop; +extern animmove_t harpy_move_tumble; +extern animmove_t harpy_move_takeoff; +extern animmove_t harpy_move_circle; +extern animmove_t harpy_move_circle_flap; +//Pirches +extern animmove_t harpy_move_pirch1_idle; +extern animmove_t harpy_move_pirch2_idle; +extern animmove_t harpy_move_pirch3_idle; +extern animmove_t harpy_move_pirch4_idle; +extern animmove_t harpy_move_pirch5_idle; +extern animmove_t harpy_move_pirch6_idle; +extern animmove_t harpy_move_pirch7_idle; +extern animmove_t harpy_move_pirch8_idle; +extern animmove_t harpy_move_pirch9_idle; + +void harpy_dismember(edict_t *self, int damage, int HitLocation0); + +qboolean SV_StepDirection (edict_t *ent, float yaw, float dist); +qboolean SV_FlyDirection (edict_t *ent, vec3_t *attitude, float dist); +qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink); +qboolean ai_checkattack (edict_t *self, float dist); +void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist); + +void harpy_ai_fly (edict_t *self, float fd, float rd, float ud); +void harpy_ai_glide (edict_t *self, float fd, float rd, float ud); +void harpy_ai_circle (edict_t *self, float fd, float rd, float ud); +void harpy_ai_pirch (edict_t *self); +void harpy_ai_hover (edict_t *self, float dist); + +void harpy_flight_model (edict_t *self); + +void harpy_dive_loop(edict_t *self); +void harpy_hit_loop(edict_t *self); +void harpy_check_dodge(edict_t *self); + +void harpy_dead (edict_t *self); +void harpy_hit (edict_t *self); +void harpy_pause(edict_t *self); +void harpy_die(edict_t *self, G_Message_t *msg); +void harpy_fly(edict_t *self, G_Message_t *msg); +void harpy_fly_attack(edict_t *self, G_Message_t *msg); +void harpy_flyback(edict_t *self); +void harpy_hover(edict_t *self, G_Message_t *msg); +void harpy_stand(edict_t *self, G_Message_t *msg); +void harpy_hoverscream(edict_t *self, G_Message_t *msg); +void harpy_dive(edict_t *self, G_Message_t *msg); +void harpy_pain(edict_t *self, G_Message_t *msg); +void harpy_perch(edict_t *self, G_Message_t *msg); + +void SP_monster_harpy(edict_t* self); +void harpy_init(void); +void harpy_pain_init(edict_t *self); + +void harpy_fix_angles(edict_t *self); + +void move_harpy_die(edict_t *self); +void move_harpy_hover(edict_t *self); +void move_harpy_fly(edict_t *self); +void move_harpy_dive(edict_t *self); +void move_harpy_dive_end(edict_t *self); + +void harpy_hover_anim(edict_t *self); + +#define hl_backspikes 1 +#define hl_head 2 +#define hl_stinger 3 +#define hl_lwing 4 +#define hl_lefthand 5 +#define hl_rwing 6 +#define hl_righthand 7 +#define hl_leftupperleg 8 +#define hl_leftlowerleg 9 +#define hl_rightupperleg 10 +#define hl_rightlowerleg 11 +#define hl_harpy_max 12 + +#define BPN_PAIN 0 +#define BPN_HEAD 1 +#define BPN_HORNS 2 +#define BPN_HORN 4 +#define BPN_BACKSPIKES 8 +#define BPN_NECKSPIKES 16 +#define BPN_LUARM 32 +#define BPN_LLARM 64 +#define BPN_LHAND 128 +#define BPN_RUARM 256 +#define BPN_RLARM 512 +#define BPN_RHAND 1024 +#define BPN_TAILSPIKES 2048 +#define BPN_RWING 4096 +#define BPN_LWING 8192 +#define BPN_STINGER 16384 + diff --git a/Toolkit/Programming/GameCode/game/m_harpy_anim.c b/Toolkit/Programming/GameCode/game/m_harpy_anim.c new file mode 100644 index 0000000..9c33b16 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_harpy_anim.c @@ -0,0 +1,419 @@ +#include "m_harpy_anim.h" +#include "g_local.h" +#include "m_harpy.h" + + +/*---------------------------------------------------- +harpy dying 1 +----------------------------------------------------*/ +animframe_t harpy_frames_die1[] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death2, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death3, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death4, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death5, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death6, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death7, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death8, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death9, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death10, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death11, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death12, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death13, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death14, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles, + FRAME_death15, NULL, 0, 0, 0, NULL, 0, harpy_fix_angles +}; +animmove_t harpy_move_die1 = {15,harpy_frames_die1, harpy_dead}; + +/*---------------------------------------------------- +harpy flying 1 +----------------------------------------------------*/ +animframe_t harpy_frames_fly1[] = +{ + FRAME_fly1, harpy_ai_fly, 64, 0, 0, NULL, 15, harpy_flap_noise, + FRAME_fly2, harpy_ai_fly, 64, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly3, harpy_ai_fly, 72, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly4, harpy_ai_fly, 128, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly5, harpy_ai_fly, 114, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly6, harpy_ai_fly, 108, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly7, harpy_ai_fly, 84, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly8, harpy_ai_fly, 72, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly9, harpy_ai_fly, 64, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly10, harpy_ai_fly, 52, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly11, harpy_ai_fly, 48, 0, 0, NULL, 15, move_harpy_fly, + FRAME_fly12, harpy_ai_fly, 52, 0, 0, NULL, 15, move_harpy_fly +}; +animmove_t harpy_move_fly1 = {12, harpy_frames_fly1, harpy_pause}; + +/*------------------------------------------------------ +harpy flying backwards 1 +------------------------------------------------------*/ +animframe_t harpy_frames_flyback1[] = +{ + FRAME_flyback1, harpy_ai_fly, -32, 0, 16, NULL, 0, harpy_flap_fast_noise, + FRAME_flyback2, harpy_ai_fly, -64, 0, 64, NULL, 0, move_harpy_fly, + FRAME_flyback3, harpy_ai_fly, -52, 0, 54, NULL, 0, move_harpy_fly, + FRAME_flyback4, harpy_ai_fly, -48, 0, 48, NULL, 0, move_harpy_fly, + FRAME_flyback5, harpy_ai_fly, -42, 0, 32, NULL, 0, move_harpy_fly, + FRAME_flyback6, harpy_ai_fly, -36, 0, 24, NULL, 0, move_harpy_fly +}; +animmove_t harpy_move_flyback1 = { 6, harpy_frames_flyback1, harpy_pause}; + + +/*------------------------------------------------------- +harpy hovering +-------------------------------------------------------*/ +animframe_t harpy_frames_hover1[] = +{ + FRAME_hover1, NULL, 0, 0, 0, harpy_ai_hover, 2, harpy_flap_noise, + FRAME_hover2, NULL, 0, 0, 0, harpy_ai_hover, 1, NULL, + FRAME_hover3, NULL, 0, 0, 0, harpy_ai_hover, -1, NULL, + FRAME_hover4, NULL, 0, 0, 0, harpy_ai_hover, -2, NULL, + FRAME_hover5, NULL, 0, 0, 0, harpy_ai_hover, -2, harpy_check_dodge, + FRAME_hover6, NULL, 0, 0, 0, harpy_ai_hover, -1, NULL, + FRAME_hover7, NULL, 0, 0, 0, harpy_ai_hover, 1, NULL, + FRAME_hover8, NULL, 0, 0, 0, harpy_ai_hover, 2, NULL +}; +animmove_t harpy_move_hover1 = {8, harpy_frames_hover1, move_harpy_hover}; + +animframe_t harpy_frames_tumble[] = +{ + FRAME_hover1, NULL, 0, 0, 0, NULL, 0, move_harpy_tumble, + FRAME_hover2, NULL, 0, 0, 0, NULL, 0, move_harpy_tumble, + FRAME_hover3, NULL, 0, 0, 0, NULL, 0, move_harpy_tumble, + FRAME_hover4, NULL, 0, 0, 0, NULL, 0, move_harpy_tumble, + FRAME_hover5, NULL, 0, 0, 0, NULL, 0, move_harpy_tumble, + FRAME_hover6, NULL, 0, 0, 0, NULL, 0, move_harpy_tumble, + FRAME_hover7, NULL, 0, 0, 0, NULL, 0, move_harpy_tumble, + FRAME_hover8, NULL, 0, 0, 0, NULL, 0, move_harpy_tumble +}; +animmove_t harpy_move_tumble = {8, harpy_frames_tumble, NULL}; + +/*------------------------------------------------------- +harpy hovering and screaming +-------------------------------------------------------*/ +animframe_t harpy_frames_hoverscream[] = +{ + FRAME_hoverscream1, NULL, 0, 0, 0, harpy_ai_hover, 2, harpy_flap_noise, + FRAME_hoverscream2, NULL, 0, 0, 0, harpy_ai_hover, 1, NULL, + FRAME_hoverscream3, NULL, 0, 0, 0, harpy_ai_hover, -1, NULL, + FRAME_hoverscream4, NULL, 0, 0, 0, harpy_ai_hover, -2, NULL, + FRAME_hoverscream5, NULL, 0, 0, 0, harpy_ai_hover, -2, NULL, + FRAME_hoverscream6, NULL, 0, 0, 0, harpy_ai_hover, -1, NULL, + FRAME_hoverscream7, NULL, 0, 0, 0, harpy_ai_hover, 1, NULL, + FRAME_hoverscream8, NULL, 0, 0, 0, harpy_ai_hover, 2, NULL, + FRAME_hoverscream9, NULL, 0, 0, 0, harpy_ai_hover, 2, NULL, + FRAME_hoverscream10,NULL, 0, 0, 0, harpy_ai_hover, 1, NULL, + FRAME_hoverscream11,NULL, 0, 0, 0, harpy_ai_hover, -1, NULL, + FRAME_hoverscream12,NULL, 0, 0, 0, harpy_ai_hover, -2, NULL, + FRAME_hoverscream13,NULL, 0, 0, 0, harpy_ai_hover, -2, NULL, + FRAME_hoverscream14,NULL, 0, 0, 0, harpy_ai_hover, -1, NULL, + FRAME_hoverscream15,NULL, 0, 0, 0, harpy_ai_hover, 1, NULL, + FRAME_hoverscream16,NULL, 0, 0, 0, harpy_ai_hover, 2, NULL +}; +animmove_t harpy_move_hoverscream = {16, harpy_frames_hoverscream, move_harpy_hover}; + + +/*------------------------------------------------------- +harpy diving and attacking +-------------------------------------------------------*/ +animframe_t harpy_frames_dive_go[] = +{ + FRAME_dive01, NULL, 0, 0, 0, NULL, 0, harpy_dive_noise, + FRAME_dive02, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive03, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive04, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive05, NULL, 0, 0, 0, NULL, 0, move_harpy_dive, + FRAME_dive06, NULL, 0, 0, 0, NULL, 0, move_harpy_dive, +}; +animmove_t harpy_move_dive_go = {6, harpy_frames_dive_go, harpy_dive_loop}; + +animframe_t harpy_frames_dive_loop[] = +{ + FRAME_dive07, NULL, 0, 0, 0, NULL, 0, move_harpy_dive, + FRAME_dive08, NULL, 0, 0, 0, NULL, 0, move_harpy_dive, + FRAME_dive09, NULL, 0, 0, 0, NULL, 0, move_harpy_dive, + FRAME_dive10, NULL, 0, 0, 0, NULL, 0, move_harpy_dive, + FRAME_dive11, NULL, 0, 0, 0, NULL, 0, move_harpy_dive, + FRAME_dive12, NULL, 0, 0, 0, NULL, 0, move_harpy_dive, +}; +animmove_t harpy_move_dive_loop = {6, harpy_frames_dive_loop, NULL}; + +animframe_t harpy_frames_dive_trans[] = +{ + FRAME_dive13, NULL, 0, 0, 0, NULL, 0, move_harpy_dive_end, + FRAME_dive14, NULL, 0, 0, 0, NULL, 0, move_harpy_dive_end, + FRAME_dive15, NULL, 0, 0, 0, NULL, 0, move_harpy_dive_end, + FRAME_dive16, NULL, 0, 0, 0, NULL, 0, move_harpy_dive_end, + FRAME_dive17, NULL, 0, 0, 0, NULL, 0, move_harpy_dive_end, +}; +animmove_t harpy_move_dive_trans = {5, harpy_frames_dive_trans, harpy_hit_loop}; + +animframe_t harpy_frames_dive_hit_loop[] = +{ + FRAME_dive18, NULL, 0, 0, 0, NULL, 0, move_harpy_dive_end, +}; +animmove_t harpy_move_dive_hit_loop = {1, harpy_frames_dive_hit_loop, NULL}; + +animframe_t harpy_frames_dive_end[] = +{ + FRAME_dive19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive22, NULL, 0, 0, 0, NULL, 0, harpy_hit, + FRAME_dive23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive30, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t harpy_move_dive_end = {11, harpy_frames_dive_end, harpy_flyback}; + +/*------------------------------------------------------- +harpy attacking up close +-------------------------------------------------------*/ +animframe_t harpy_frames_closeattack[] = +{ + FRAME_dive17, NULL, 0, 0, 0, NULL, 6, harpy_hit, +// FRAME_dive18, NULL, 0, 0, 0, NULL, 6, NULL, + FRAME_dive19, NULL, 0, 0, 0, NULL, 6, NULL, +// FRAME_dive20, NULL, 0, 0, 0, NULL, 6, NULL, + FRAME_dive21, NULL, 0, 0, 0, NULL, 6, NULL, +// FRAME_dive22, NULL, 0, 0, 0, NULL, 6, NULL, + FRAME_dive23, NULL, 0, 0, 0, NULL, 6, NULL, +// FRAME_dive24, NULL, 0, 0, 0, NULL, 6, NULL, + FRAME_dive25, NULL, 0, 0, 0, NULL, 6, NULL, +// FRAME_dive26, NULL, 0, 0, 0, NULL, 6, NULL, + FRAME_dive27, NULL, 0, 0, 0, NULL, 6, NULL, +// FRAME_dive28, NULL, 0, 0, 0, NULL, 6, NULL +}; +animmove_t harpy_closeattack = {6, harpy_frames_closeattack, harpy_pause}; + + +/*------------------------------------------------------- +harpy pain +-------------------------------------------------------*/ +animframe_t harpy_frames_pain1 [] = +{ + FRAME_pain1, NULL, 0, 0, 0, NULL, 2, move_harpy_hover, + FRAME_pain2, NULL, 0, 0, 0, NULL, 1, move_harpy_hover, + FRAME_pain3, NULL, 0, 0, 0, NULL, -1, move_harpy_hover, + FRAME_pain4, NULL, 0, 0, 0, NULL, -2, move_harpy_hover, + FRAME_pain5, NULL, 0, 0, 0, NULL, -2, move_harpy_hover, + FRAME_pain6, NULL, 0, 0, 0, NULL, -1, move_harpy_hover, + FRAME_pain7, NULL, 0, 0, 0, NULL, 1, move_harpy_hover, + FRAME_pain8, NULL, 0, 0, 0, NULL, 2, move_harpy_hover +}; +animmove_t harpy_move_pain1 = { 8, harpy_frames_pain1, harpy_pause}; + +animframe_t harpy_frames_glide [] = +{ + FRAME_glide1, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide2, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide3, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide4, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide5, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide6, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide7, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide8, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide9, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide10, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide11, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, + FRAME_glide12, harpy_ai_glide, 64, 0, 0, NULL, 0, NULL, +}; +animmove_t harpy_move_glide = { 12, harpy_frames_glide, NULL}; + +//pirch 1 +animframe_t harpy_frames_pirch1_idle [] = +{ + FRAME_pirch1, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch2, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch3, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch4, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch5, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch6, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch7, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch8, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch9, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch10, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, +}; +animmove_t harpy_move_pirch1_idle = { 10, harpy_frames_pirch1_idle, NULL}; + +//pirch 2 +animframe_t harpy_frames_pirch2_idle [] = +{ + FRAME_pirch11, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch12, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch13, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch14, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch15, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch16, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch17, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch18, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch19, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch20, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, +}; +animmove_t harpy_move_pirch2_idle = { 10, harpy_frames_pirch2_idle, NULL}; + +//pirch 3 +animframe_t harpy_frames_pirch3_idle [] = +{ + FRAME_pirch21, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch22, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch23, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch24, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch25, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch26, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch27, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch28, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch29, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch30, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, +}; +animmove_t harpy_move_pirch3_idle = { 10, harpy_frames_pirch3_idle, NULL}; + +//pirch 4 +animframe_t harpy_frames_pirch4_idle [] = +{ + FRAME_pirch31, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch32, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch33, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch34, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch35, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch36, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch37, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch38, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch39, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch40, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, +}; +animmove_t harpy_move_pirch4_idle = { 10, harpy_frames_pirch4_idle, NULL}; + +//pirch 5 +animframe_t harpy_frames_pirch5_idle [] = +{ + FRAME_pirch41, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch42, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch43, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch44, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch45, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch46, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch47, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch48, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch49, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch50, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, +}; +animmove_t harpy_move_pirch5_idle = { 10, harpy_frames_pirch5_idle, NULL}; + +//pirch 6 +animframe_t harpy_frames_pirch6_idle [] = +{ + FRAME_pirch51, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch52, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch53, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch54, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch55, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch56, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch57, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch58, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch59, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch60, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, +}; +animmove_t harpy_move_pirch6_idle = { 10, harpy_frames_pirch6_idle, NULL}; + +//pirch 7 +animframe_t harpy_frames_pirch7_idle [] = +{ + FRAME_pirch61, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch62, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch63, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch64, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch65, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch66, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch67, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch68, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch69, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch70, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, +}; +animmove_t harpy_move_pirch7_idle = { 10, harpy_frames_pirch7_idle, NULL}; + +//pirch 8 +animframe_t harpy_frames_pirch8_idle [] = +{ + FRAME_pirch71, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch72, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch73, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch74, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch75, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch76, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch77, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch78, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch79, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch80, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, +}; +animmove_t harpy_move_pirch8_idle = { 10, harpy_frames_pirch8_idle, NULL}; + +//pirch 9 +animframe_t harpy_frames_pirch9_idle [] = +{ + FRAME_pirch81, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch82, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch83, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch84, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch85, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch86, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch87, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch88, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch89, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, + FRAME_pirch90, NULL, 0, 0, 0, NULL, 0, harpy_ai_pirch, +}; +animmove_t harpy_move_pirch9_idle = { 10, harpy_frames_pirch9_idle, NULL}; + +animframe_t harpy_frames_takeoff [] = +{ + FRAME_takeoff1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_takeoff3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_takeoff5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_takeoff7, harpy_ai_fly, -32, 0, 16, NULL, 0, harpy_flap_fast_noise, + FRAME_takeoff9, harpy_ai_fly, -48, 0, 32, NULL, 0, NULL, + FRAME_takeoff11, harpy_ai_fly, -32, 0, 32, NULL, 0, NULL, + FRAME_takeoff13, harpy_ai_fly, -64, 0, 32, NULL, 0, NULL, + FRAME_takeoff15, harpy_ai_fly, -32, 0, 32, NULL, 0, NULL, +}; +animmove_t harpy_move_takeoff = { 8, harpy_frames_takeoff, harpy_pause}; + +animframe_t harpy_frames_circle [] = +{ + FRAME_glide1, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide2, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide3, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide4, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide5, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide6, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide7, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide8, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide9, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide10, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide11, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, + FRAME_glide12, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, +}; +animmove_t harpy_move_circle = { 12, harpy_frames_circle, harpy_pause}; + +animframe_t harpy_frames_circle_flap [] = +{ + FRAME_fly1, harpy_ai_circle, 32, 0, 0, NULL, 0, harpy_flap_noise, + FRAME_fly2, harpy_ai_circle, 48, 0, 0, NULL, 0, NULL, + FRAME_fly3, harpy_ai_circle, 64, 0, 0, NULL, 0, NULL, + FRAME_fly4, harpy_ai_circle, 64, 0, 0, NULL, 0, NULL, + FRAME_fly5, harpy_ai_circle, 56, 0, 0, NULL, 0, NULL, + FRAME_fly6, harpy_ai_circle, 56, 0, 0, NULL, 0, NULL, + FRAME_fly7, harpy_ai_circle, 50, 0, 0, NULL, 0, NULL, + FRAME_fly8, harpy_ai_circle, 50, 0, 0, NULL, 0, NULL, + FRAME_fly9, harpy_ai_circle, 44, 0, 0, NULL, 0, NULL, + FRAME_fly10, harpy_ai_circle, 40, 0, 0, NULL, 0, NULL, + FRAME_fly11, harpy_ai_circle, 36, 0, 0, NULL, 0, NULL, + FRAME_fly12, harpy_ai_circle, 32, 0, 0, NULL, 0, NULL, +}; +animmove_t harpy_move_circle_flap = { 12, harpy_frames_circle_flap, harpy_pause}; diff --git a/Toolkit/Programming/GameCode/game/m_harpy_anim.h b/Toolkit/Programming/GameCode/game/m_harpy_anim.h new file mode 100644 index 0000000..fae94b3 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_harpy_anim.h @@ -0,0 +1,238 @@ +// R:\Art\models/monsters\harpy\work + +// This file generated by qdata - Do NOT Modify + +#define FRAME_death1 0 +#define FRAME_death2 1 +#define FRAME_death3 2 +#define FRAME_death4 3 +#define FRAME_death5 4 +#define FRAME_death6 5 +#define FRAME_death7 6 +#define FRAME_death8 7 +#define FRAME_death9 8 +#define FRAME_death10 9 +#define FRAME_death11 10 +#define FRAME_death12 11 +#define FRAME_death13 12 +#define FRAME_death14 13 +#define FRAME_death15 14 +#define FRAME_dive01 15 +#define FRAME_dive02 16 +#define FRAME_dive03 17 +#define FRAME_dive04 18 +#define FRAME_dive05 19 +#define FRAME_dive06 20 +#define FRAME_dive07 21 +#define FRAME_dive08 22 +#define FRAME_dive09 23 +#define FRAME_dive10 24 +#define FRAME_dive11 25 +#define FRAME_dive12 26 +#define FRAME_dive13 27 +#define FRAME_dive14 28 +#define FRAME_dive15 29 +#define FRAME_dive16 30 +#define FRAME_dive17 31 +#define FRAME_dive18 32 +#define FRAME_dive19 33 +#define FRAME_dive20 34 +#define FRAME_dive21 35 +#define FRAME_dive22 36 +#define FRAME_dive23 37 +#define FRAME_dive24 38 +#define FRAME_dive25 39 +#define FRAME_dive26 40 +#define FRAME_dive27 41 +#define FRAME_dive28 42 +#define FRAME_dive29 43 +#define FRAME_dive30 44 +#define FRAME_flyback1 45 +#define FRAME_flyback2 46 +#define FRAME_flyback3 47 +#define FRAME_flyback4 48 +#define FRAME_flyback5 49 +#define FRAME_flyback6 50 +#define FRAME_fly1 51 +#define FRAME_fly2 52 +#define FRAME_fly3 53 +#define FRAME_fly4 54 +#define FRAME_fly5 55 +#define FRAME_fly6 56 +#define FRAME_fly7 57 +#define FRAME_fly8 58 +#define FRAME_fly9 59 +#define FRAME_fly10 60 +#define FRAME_fly11 61 +#define FRAME_fly12 62 +#define FRAME_glide1 63 +#define FRAME_glide2 64 +#define FRAME_glide3 65 +#define FRAME_glide4 66 +#define FRAME_glide5 67 +#define FRAME_glide6 68 +#define FRAME_glide7 69 +#define FRAME_glide8 70 +#define FRAME_glide9 71 +#define FRAME_glide10 72 +#define FRAME_glide11 73 +#define FRAME_glide12 74 +#define FRAME_hoverscream1 75 +#define FRAME_hoverscream2 76 +#define FRAME_hoverscream3 77 +#define FRAME_hoverscream4 78 +#define FRAME_hoverscream5 79 +#define FRAME_hoverscream6 80 +#define FRAME_hoverscream7 81 +#define FRAME_hoverscream8 82 +#define FRAME_hoverscream9 83 +#define FRAME_hoverscream10 84 +#define FRAME_hoverscream11 85 +#define FRAME_hoverscream12 86 +#define FRAME_hoverscream13 87 +#define FRAME_hoverscream14 88 +#define FRAME_hoverscream15 89 +#define FRAME_hoverscream16 90 +#define FRAME_hover1 91 +#define FRAME_hover2 92 +#define FRAME_hover3 93 +#define FRAME_hover4 94 +#define FRAME_hover5 95 +#define FRAME_hover6 96 +#define FRAME_hover7 97 +#define FRAME_hover8 98 +#define FRAME_pain1 99 +#define FRAME_pain2 100 +#define FRAME_pain3 101 +#define FRAME_pain4 102 +#define FRAME_pain5 103 +#define FRAME_pain6 104 +#define FRAME_pain7 105 +#define FRAME_pain8 106 +#define FRAME_partfly1 107 +#define FRAME_pirch1 108 +#define FRAME_pirch2 109 +#define FRAME_pirch3 110 +#define FRAME_pirch4 111 +#define FRAME_pirch5 112 +#define FRAME_pirch6 113 +#define FRAME_pirch7 114 +#define FRAME_pirch8 115 +#define FRAME_pirch9 116 +#define FRAME_pirch10 117 +#define FRAME_pirch11 118 +#define FRAME_pirch12 119 +#define FRAME_pirch13 120 +#define FRAME_pirch14 121 +#define FRAME_pirch15 122 +#define FRAME_pirch16 123 +#define FRAME_pirch17 124 +#define FRAME_pirch18 125 +#define FRAME_pirch19 126 +#define FRAME_pirch20 127 +#define FRAME_pirch21 128 +#define FRAME_pirch22 129 +#define FRAME_pirch23 130 +#define FRAME_pirch24 131 +#define FRAME_pirch25 132 +#define FRAME_pirch26 133 +#define FRAME_pirch27 134 +#define FRAME_pirch28 135 +#define FRAME_pirch29 136 +#define FRAME_pirch30 137 +#define FRAME_pirch31 138 +#define FRAME_pirch32 139 +#define FRAME_pirch33 140 +#define FRAME_pirch34 141 +#define FRAME_pirch35 142 +#define FRAME_pirch36 143 +#define FRAME_pirch37 144 +#define FRAME_pirch38 145 +#define FRAME_pirch39 146 +#define FRAME_pirch40 147 +#define FRAME_pirch41 148 +#define FRAME_pirch42 149 +#define FRAME_pirch43 150 +#define FRAME_pirch44 151 +#define FRAME_pirch45 152 +#define FRAME_pirch46 153 +#define FRAME_pirch47 154 +#define FRAME_pirch48 155 +#define FRAME_pirch49 156 +#define FRAME_pirch50 157 +#define FRAME_pirch51 158 +#define FRAME_pirch52 159 +#define FRAME_pirch53 160 +#define FRAME_pirch54 161 +#define FRAME_pirch55 162 +#define FRAME_pirch56 163 +#define FRAME_pirch57 164 +#define FRAME_pirch58 165 +#define FRAME_pirch59 166 +#define FRAME_pirch60 167 +#define FRAME_pirch61 168 +#define FRAME_pirch62 169 +#define FRAME_pirch63 170 +#define FRAME_pirch64 171 +#define FRAME_pirch65 172 +#define FRAME_pirch66 173 +#define FRAME_pirch67 174 +#define FRAME_pirch68 175 +#define FRAME_pirch69 176 +#define FRAME_pirch70 177 +#define FRAME_pirch71 178 +#define FRAME_pirch72 179 +#define FRAME_pirch73 180 +#define FRAME_pirch74 181 +#define FRAME_pirch75 182 +#define FRAME_pirch76 183 +#define FRAME_pirch77 184 +#define FRAME_pirch78 185 +#define FRAME_pirch79 186 +#define FRAME_pirch80 187 +#define FRAME_pirch81 188 +#define FRAME_pirch82 189 +#define FRAME_pirch83 190 +#define FRAME_pirch84 191 +#define FRAME_pirch85 192 +#define FRAME_pirch86 193 +#define FRAME_pirch87 194 +#define FRAME_pirch88 195 +#define FRAME_pirch89 196 +#define FRAME_pirch90 197 +#define FRAME_takeoff1 198 +#define FRAME_takeoff2 199 +#define FRAME_takeoff3 200 +#define FRAME_takeoff4 201 +#define FRAME_takeoff5 202 +#define FRAME_takeoff6 203 +#define FRAME_takeoff7 204 +#define FRAME_takeoff8 205 +#define FRAME_takeoff9 206 +#define FRAME_takeoff10 207 +#define FRAME_takeoff11 208 +#define FRAME_takeoff12 209 +#define FRAME_takeoff13 210 +#define FRAME_takeoff14 211 +#define FRAME_takeoff15 212 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_POLY 0 +#define MESH_HEAD 1 +#define MESH_HORNS 2 +#define MESH_HORN 3 +#define MESH_BACKSPIKES 4 +#define MESH_NECKSPIKES 5 +#define MESH_LUARM 6 +#define MESH_LLARM 7 +#define MESH_LHAND 8 +#define MESH_RUARM 9 +#define MESH_RLARM 10 +#define MESH_RHAND 11 +#define MESH_TAILSPIKES 12 +#define MESH_RWING 13 +#define MESH_LWING 14 +#define MESH_STINGER 15 diff --git a/Toolkit/Programming/GameCode/game/m_imp.c b/Toolkit/Programming/GameCode/game/m_imp.c new file mode 100644 index 0000000..9343953 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_imp.c @@ -0,0 +1,1454 @@ +/*------------------------------------------------------------------- +m_imp.c + +Heretic II +Copyright 1998 Raven Software + + AI: + + HOVER1 :hovering in midair + FLY1 :flying forwards + FLYBACK :flying backwards + +-------------------------------------------------------------------*/ + +#include "g_local.h" +#include "m_imp.h" +#include "m_imp_anim.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "fx.h" +#include "g_HitLocation.h" +#include "g_misc.h" +#include "m_stats.h" +#include "p_anim_branch2.h" +#include "g_playstats.h" + +#define IMP_CHECK_DIST 128 +#define IMP_COLLISION_DIST 148 +#define IMP_MIN_SSWOOP_DIST 128 +#define IMP_MIN_HOVER_DIST 128 +#define IMP_MAX_HOVER_DIST 512 +#define IMP_MIN_SWOOP_DIST 108 + +#define IMP_DRIFT_AMOUNT_X 128 +#define IMP_DRIFT_AMOUNT_Y 128 +#define IMP_DRIFT_AMOUNT_Z 64 + +#define IMP_SWOOP_INCR 2 +#define IMP_SWOOP_SPEED_MAX 512 + +#define IMP_PROJECTILE_RADIUS 1024 + +void imp_blocked (edict_t *self, struct trace_s *trace); +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); + +/*----------------------------------------------------------------- + imp base info +-----------------------------------------------------------------*/ + +static animmove_t *animations[NUM_ANIMS] = +{ + &imp_move_die1, + &imp_move_fly1, + &imp_move_flyback, + &imp_move_hover1, + &imp_move_fireball, + &imp_move_dive_go, + &imp_move_dive_loop, + &imp_move_dive_end, + &imp_move_dive_out, + &imp_move_pain1, + &imp_move_tumble, + &imp_move_perch, + &imp_move_takeoff, + &imp_move_dup, + &imp_move_ddown, +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + + +/*=============================================================== + + Imp Helper Functions + +===============================================================*/ + +void imp_blocked (edict_t *self, struct trace_s *trace) +{ + vec3_t vf; + int damage; + + if (self->health <= 0) + return; + + if (!trace->ent) + return; + + if(self->curAnimID == ANIM_DIVE_GO || self->curAnimID == ANIM_DIVE_LOOP || self->curAnimID == ANIM_DIVE_END) + { + if(!stricmp(trace->ent->classname, "player")) + { + if(!irand(0,4)) + KnockDownPlayer(&trace->ent->client->playerinfo); + } + damage = irand(IMP_DMG_MIN, IMP_DMG_MAX); + T_Damage (trace->ent, self, self, vf, trace->ent->s.origin, trace->plane.normal, damage, damage*2, 0,MOD_DIED); + gi.sound(self, CHAN_BODY, sounds[SND_HIT], 1, ATTN_NORM, 0); + if(self->curAnimID != ANIM_DIVE_END) + SetAnim(self, ANIM_DIVE_END); + } +} + +//Various sound functions +void imp_flap_noise(edict_t *self) +{ + gi.sound(self,CHAN_ITEM,sounds[SND_FLAP],1,ATTN_NORM,0); +} + +void imp_death_noise(edict_t *self) +{ + gi.sound(self,CHAN_VOICE,sounds[SND_DEATH],1,ATTN_NORM,0); +} + +void imp_dive_noise(edict_t *self) +{ + gi.sound(self,CHAN_VOICE,sounds[SND_DIVE],1,ATTN_NORM,0); +} + +int imp_check_move(edict_t *self, float dist) +{ + trace_t trace; + vec3_t vec, vf; + + VectorCopy(self->s.origin, vec); + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(vec, dist, vf, vec); + + gi.trace(self->s.origin, self->mins, self->maxs, vec, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1) + { + if (trace.ent == self->enemy) + return true; + + return false; + } + + return true; +} + +//replaces ai_walk and ai_run for imp +void imp_ai_glide (edict_t *self, float fd, float rd, float ud) +{ + vec3_t vec, vf, vr, nvec; + float yaw_delta, roll, dot, rdot; + + if (!self->enemy) + return; + + //Find our ideal yaw to the player and correct to it + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + VectorCopy(vec, nvec); + VectorNormalize(nvec); + + AngleVectors(self->s.angles, vf, vr, NULL); + + dot = DotProduct(vf, nvec); + rdot = DotProduct(vr, nvec); + + self->ideal_yaw = vectoyaw(vec); + + M_ChangeYaw(self); + + yaw_delta = self->ideal_yaw - self->s.angles[YAW]; + + //If enough, roll the creature to simulate gliding + if (Q_fabs(yaw_delta) > self->yaw_speed) + { + if (dot < 0) + { + roll = Q_fabs(yaw_delta / 4); + } + else + { + roll = yaw_delta / 4; + } + + //Going right? + if (roll > 0) + { + self->s.angles[ROLL] += roll; + if (self->s.angles[ROLL] > 65) + self->s.angles[ROLL] = 65; + } + else + { + self->s.angles[ROLL] += roll; + if (self->s.angles[ROLL] < -65) + self->s.angles[ROLL] = -65; + } + } + else + { + self->s.angles[ROLL] *= 0.75; + } +} + +void imp_ai_fly (edict_t *self, float fd, float rd, float ud) +{ + vec3_t vec, vf, vr, vu; + + if (!self->enemy) + return; + + //Add "friction" to the movement to allow graceful flowing motion, not jittering + self->velocity[0] *= 0.8; + self->velocity[1] *= 0.8; + self->velocity[2] *= 0.8; + + //Find our ideal yaw to the player and correct to it + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + + M_ChangeYaw(self); + + if (!imp_check_move(self, fd/10)) + { + SetAnim(self, ANIM_HOVER1); + return; + } + + if(self->spawnflags&MSF_FIXED) + return; + + //Add in the movements relative to the creature's facing + AngleVectors(self->s.angles, vf, vr, vu); + + VectorMA(self->velocity, fd, vf, self->velocity); + VectorMA(self->velocity, rd, vr, self->velocity); + VectorMA(self->velocity, ud, vu, self->velocity); + + if (self->groundentity) + self->velocity[2] += 32; +} + +//replaces ai_stand for imp +void imp_ai_hover(edict_t *self, float dist) +{ + vec3_t vec; + + if (!self->enemy) + { + if (!FindTarget(self)) + return; + } + + //Add "friction" to the movement to allow graceful flowing motion, not jittering + self->velocity[0] *= 0.8; + self->velocity[1] *= 0.8; + self->velocity[2] *= 0.8; + + //Make sure we're not tilted after a turn + self->s.angles[ROLL] *= 0.25; + + //Find our ideal yaw to the player and correc to it + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + + M_ChangeYaw(self); + + imp_ai_glide(self,0,0,0); +} + +//receiver for MSG_FLYBACK +void imp_flyback(edict_t *self) +{ + SetAnim(self, ANIM_FLYBACK1); + return; +} + + +void imp_ai_pirch(edict_t *self) +{ + monsterinfo_t *monsterinfo = &self->monsterinfo; + vec3_t vec, vf, vr; + float dot, len; + + if (!M_ValidTarget(self, self->enemy)) + return; + + if(!visible(self, self->enemy)) + return; + + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + len = VectorNormalize(vec); + + if (len < 150) + { + SetAnim(self, ANIM_TAKEOFF); + return; + } + +/* + if (irand(0,100) < 10 && self->monsterinfo.attack_finished < level.time) + { + self->monsterinfo.attack_finished = level.time + 5; + + if (irand(0,1)) + gi.sound (self, CHAN_VOICE, sounds[SND_IDLE1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_VOICE, sounds[SND_IDLE2], 1, ATTN_NORM, 0); + } +*/ + AngleVectors(self->s.angles, vf, vr, NULL); + + dot = DotProduct(vec, vf); + + if (dot < 0) + { + SetAnim(self, ANIM_TAKEOFF); + return; + } +} + +void move_imp_tumble(edict_t *self) +{ + self->movetype = PHYSICSTYPE_STEP; + self->gravity = 1; + + VectorSet(self->mins, -16, -16, 0); + VectorSet(self->maxs, 16, 16, 16); + + if (!self->avelocity[PITCH] && !self->avelocity[YAW] && !self->avelocity[ROLL]) + { + self->avelocity[PITCH] = flrand(128.0F, 256.0F); + self->avelocity[YAW] = flrand(64.0F, 512.0F); + self->avelocity[ROLL] = flrand(64.0F, 512.0F); + } + + if (self->groundentity != NULL || self->monsterinfo.jump_time < level.time) + { + gi.CreateEffect(&self->s, FX_DUST_PUFF, CEF_OWNERS_ORIGIN, self->s.origin, NULL); + + VectorCopy(self->s.angles, self->movedir); + imp_death_noise(self); + + SetAnim(self, ANIM_DIE); + } +} + +void imp_fix_angles(edict_t *self) +{ + float pitch_delta, roll_delta; + + pitch_delta = self->movedir[PITCH]; + roll_delta = self->movedir[ROLL]; + + if (pitch_delta > 0) + { + self->s.angles[PITCH] -= pitch_delta / 2; + + if (self->s.angles[PITCH] < 2) + { + self->s.angles[PITCH] = 0; + } + } + else + { + self->s.angles[PITCH] += pitch_delta / 2; + + if (self->s.angles[PITCH] > 2) + { + self->s.angles[PITCH] = 0; + } + } + + //Roll + if (roll_delta > 0) + { + self->s.angles[ROLL] -= roll_delta / 2; + + if (self->s.angles[ROLL] < 2) + { + self->s.angles[ROLL] = 0; + } + } + else + { + self->s.angles[ROLL] += roll_delta / 15; + + if (self->s.angles[ROLL] > 2) + { + self->s.angles[ROLL] = 0; + } + } +} + +/*=============================================================== + + Imp Message Functions + +===============================================================*/ + +void imp_death_pain (edict_t *self, G_Message_t *msg) +{ + if(self->health <= -40) //gib death + { + BecomeDebris(self); + return; + } +} + +//receiver for MSG_DEATH +void imp_die(edict_t *self, G_Message_t *msg) +{ + if(self->monsterinfo.aiflags&AI_DONT_THINK) + { + SetAnim(self, ANIM_DIE); + return; + } + + self->movetype = PHYSICSTYPE_STEP; + self->gravity = 1; + self->elasticity = 1.1; + + VectorSet(self->mins, -16, -16, 0); + VectorSet(self->maxs, 16, 16, 16); + + if(self->health <= -40) //gib death + { + BecomeDebris(self); + self->think = NULL; + self->nextthink = 0; + gi.linkentity (self); + return; + } + + self->msgHandler = DeadMsgHandler; + + SetAnim(self, ANIM_DIE); + return; +} + + +//receiver for MSG_PAIN +void imp_pain(edict_t *self, G_Message_t *msg) +{ + int temp, damage; + qboolean force_pain; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_pain, &damage, &temp); + + if (self->curAnimID == ANIM_PERCH) + { + SetAnim(self, ANIM_TAKEOFF); + return; + } + if (force_pain||((irand(0,10) < 2) && (self->pain_debounce_time < level.time))) + { +/* if (irand(0,1)) + imp_pain1_noise(self); + else + imp_pain2_noise(self);*/ + + self->pain_debounce_time = level.time + 2; + if(self->curAnimID == ANIM_DIVE_GO || self->curAnimID == ANIM_DIVE_LOOP) + SetAnim(self, ANIM_DIVE_END); + else + SetAnim(self, ANIM_PAIN1); + } +} + +//receiver for MSG_STAND, MSG_HOVER +//FIXME -- is MSG_HOVER redundant? +void imp_hover(edict_t *self, G_Message_t *msg) +{ + if (self->curAnimID == ANIM_PERCH) + return; + + SetAnim(self, ANIM_HOVER1); +} + +void imp_stand(edict_t *self, G_Message_t *msg) +{ + if (self->spawnflags & MSF_PERCHING) + return; + + SetAnim(self, ANIM_HOVER1); +} + +void imp_fly(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_FLY1); +} + +void imp_perch(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_PERCH); +} + +void imp_hit(edict_t *self, float stop_swoop) +{ + trace_t trace; + edict_t *victim; + vec3_t vf;//, hitPos, mins, maxs; + float movedist, damage; + + AngleVectors(self->s.angles, vf, NULL, NULL); + movedist = VectorLength(self->velocity); + + victim = M_CheckMeleeHit( self, movedist, &trace); + + if (victim) + { + if (victim == self && stop_swoop) + { + SetAnim(self, ANIM_DIVE_OUT); + } + else + { + damage = irand(IMP_DMG_MIN, IMP_DMG_MAX); + gi.sound(self, CHAN_BODY, sounds[SND_HIT], 1, ATTN_NORM, 0); + T_Damage (victim, self, self, vf, self->enemy->s.origin, trace.plane.normal, damage, damage*2, 0,MOD_DIED); + SetAnim(self, ANIM_DIVE_END); + } + } +} + +void imp_pause (edict_t *self) +{ + if (M_ValidTarget(self, self->enemy)) + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); +} + + +//end of anim func for death anim +void imp_dead(edict_t *self) +{ + VectorSet(self->mins, -16, -16, 0); + VectorSet(self->maxs, 16, 16, 16); + + M_EndDeath(self); +} + +qboolean imp_check_directions(edict_t *self, vec3_t goal, vec3_t vf, vec3_t vr, vec3_t vu, float checkdist, vec3_t ret) +{ + trace_t trace; + vec3_t goalpos; + + //Check right and left first + VectorCopy(self->s.origin, goalpos); + + //Don't always check one direction first (looks mechanical) + if (irand(0,1)) + VectorScale(vr, -1, vr); + + VectorMA(goalpos, checkdist, vr, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + //We've found somewhere to go + if (trace.ent == self->enemy) + { + VectorCopy(vr, ret); + return true; + } + else //Check the other directions + { + VectorScale(vr, -1, vr); + VectorMA(goalpos, checkdist, vr, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.ent == self->enemy) + { + VectorCopy(vr, ret); + return true; + } + } + + //Check up and down + VectorCopy(self->s.origin, goalpos); + + //Don't always check one direction first (looks mechanical) + if (irand(0,1)) + VectorScale(vu, -1, vu); + + VectorMA(goalpos, checkdist, vu, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + //We've found somewhere to go + if (trace.ent == self->enemy) + { + VectorCopy(vu, ret); + return true; + } + else //Check the other directions + { + VectorScale(vu, -1, vu); + VectorMA(goalpos, checkdist, vu, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.ent == self->enemy) + { + VectorCopy(vu, ret); + return true; + } + } + + //Check forward and back + VectorCopy(self->s.origin, goalpos); + + //Don't always check one direction first (looks mechanical) + if (irand(0,1)) + VectorScale(vf, -1, vf); + + VectorMA(goalpos, checkdist, vf, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + //We've found somewhere to go + if (trace.ent == self->enemy) + { + VectorCopy(vf, ret); + return true; + } + else //Check the other directions + { + VectorScale(vf, -1, vf); + VectorMA(goalpos, checkdist, vf, goalpos); + + gi.trace(goalpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.ent == self->enemy) + { + VectorCopy(vf, ret); + return true; + } + } + + return false; +} + +qboolean imp_check_swoop(edict_t *self, vec3_t goal) +{ + trace_t trace; + vec3_t checkpos; + float zd; + + //Find the difference in the target's height and the creature's height + zd = Q_fabs(self->enemy->s.origin[2] - self->s.origin[2]); + + if (zd < IMP_MIN_SSWOOP_DIST) + return false; + + zd -= zd/4; + + VectorCopy(self->s.origin, checkpos); + checkpos[2] -= zd; + + //Trace down about that far and about one forth the distance to the target + gi.trace(self->s.origin, self->mins, self->maxs, checkpos, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1) + { + //gi.dprintf("imp_check_swoop: failed down check\n"); + return false; + } + + //Trace straight to the target + + gi.trace(checkpos, self->mins, self->maxs, goal, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.ent != self->enemy) + { + //gi.dprintf("imp_check_swoop: failed out check\n"); + return false; + } + + //There's a clear path + return true; +} + +void move_imp_dive(edict_t *self) +{ + vec3_t vec, vf; + float dist, zd, hd, forward; + + //Find out the Z and Horizontal deltas to target + zd = Q_fabs(self->s.origin[2] - self->enemy->s.origin[2]); + + AngleVectors(self->s.angles, vf, NULL, NULL); + + VectorCopy(self->s.origin, vec); + vec[2] = self->enemy->s.origin[2]; + + VectorSubtract(self->enemy->s.origin, vec, vec); + hd = VectorLength(vec); + + if ((self->groundentity != NULL) || (!imp_check_move(self, 64))) + { + if (self->groundentity == self->enemy) + imp_hit(self, true); + return; + } + + dist = Q_fabs(self->s.origin[2] - self->enemy->s.origin[2]); + + forward = (256 - (dist*0.85)); + + if (forward > 256) + forward = 256; + else if (forward < 0) + forward = 0; + +// if (dist > IMP_MIN_SWOOP_DIST) +// { + VectorMA(vf, forward, vf, self->velocity); + self->velocity[2] = -dist*2.25; + if (self->velocity[2] < -300) + self->velocity[2] = -300; +// } +/* else + { + SetAnim(self, ANIM_DIVE_TRANS); + return; + }*/ + + imp_ai_glide(self, 0, 0, 0); +} + +void move_imp_dive_end(edict_t *self) +{ + vec3_t vec, vf, vr, vu, nvec; + float hd, fd, dot; + + VectorCopy(self->s.origin, vec); + vec[2] = self->enemy->s.origin[2]; + + VectorSubtract(self->enemy->s.origin, vec, vec); + hd = VectorLength(vec); + self->ideal_yaw = vectoyaw(vec); + + M_ChangeYaw(self); + + AngleVectors(self->s.angles, vf, vr, vu); + + self->velocity[2] *= 0.75; + + self->monsterinfo.jump_time *= IMP_SWOOP_INCR; + + fd = self->monsterinfo.jump_time; + + if (fd > IMP_SWOOP_SPEED_MAX) + fd = IMP_SWOOP_SPEED_MAX; + + if ((self->groundentity != NULL) || (!imp_check_move(self, 128))) + { + if (self->groundentity == self->enemy) + SetAnim(self, ANIM_DIVE_END); + + SetAnim(self, ANIM_FLYBACK1); + return; + } + + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + VectorCopy(vec, nvec); + VectorNormalize(nvec); + + AngleVectors(self->s.angles, vf, vr, NULL); + + dot = DotProduct(vf, nvec); + + if (dot < -0.5) + { + SetAnim(self, ANIM_FLYBACK1); + return; + } + + VectorMA(self->velocity, fd, vf, self->velocity); + + //Are we about to hit the target? +/* VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + dist = VectorLength(vec); + + if (dist < IMP_COLLISION_DIST) + { + SetAnim(self, ANIM_DIVE_END); + return; + } */ + + imp_ai_glide(self, 0, 0, 0); +} + +void imp_dive_loop(edict_t *self) +{ + SetAnim(self, ANIM_DIVE_LOOP); +} + +void imp_check_dodge(edict_t *self) +{ + qboolean dodge = false; + trace_t trace; + edict_t *ent = NULL; + vec3_t vec, vr, projvec, ddir, goalpos, vu; + float dodgedot; + qboolean vert = false; + + if (!self->enemy) + return; + + if(self->spawnflags&MSF_FIXED) + return; + + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + VectorNormalize(vec); + + while ((ent = findradius(ent, self->s.origin, IMP_PROJECTILE_RADIUS)) != NULL) + { + //We're only interested in his projectiles + if (ent->owner != self->enemy) + continue; + + VectorCopy(ent->velocity, projvec); + VectorNormalize(projvec); + + dodgedot = DotProduct(projvec, vec); + + //gi.dprintf("Found projectile with dot %f\n", dodgedot); + + if (dodgedot < -0.85 && irand(0,1)) + { + //gi.dprintf("Dodge it!\n"); + + dodge = true; + AngleVectors(self->s.angles, NULL, vr, vu); + + VectorCopy(self->s.origin, goalpos); + + if (irand(0,1)) + { + if (irand(0,1)) + VectorScale(vr, -1, ddir); + else + VectorScale(vr, 1, ddir); + } + else + { + vert = true; + if (irand(0,1)) + VectorScale(vu, -1, ddir); + else + VectorScale(vu, 1, ddir); + } + + VectorMA(goalpos, 100, ddir, goalpos); + + gi.trace(self->s.origin, self->mins, self->maxs, goalpos, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1)//bad dir, try other + VectorScale(ddir, -1, ddir); + + if(vert) + {//ok, better check this new opposite dir + gi.trace(self->s.origin, self->mins, self->maxs, goalpos, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1) + {//uh-oh, let's go for a side dir + if (irand(0,1)) + VectorScale(vr, 1, ddir); + else + VectorScale(vr, -1, ddir); + } + + gi.trace(self->s.origin, self->mins, self->maxs, goalpos, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1)//what the hell, just go the other way + VectorScale(ddir, -1, ddir); + + } + } + } + + if (dodge) + { + //If he is, dodge! + if (self->monsterinfo.misc_debounce_time < level.time) + { + if(self->curAnimID!=ANIM_FIREBALL) + { + if(ddir[2] > 0.1) + SetAnim(self, ANIM_DUP); + else if(ddir[2] < -0.1) + SetAnim(self, ANIM_DDOWN); + } + VectorMA(self->velocity, irand(300, 500), ddir, self->velocity); + self->monsterinfo.misc_debounce_time = level.time + irand(2,4); + } + } + + imp_ai_glide(self, 0, 0, 0); +} + +void move_imp_hover(edict_t *self) +{ + qboolean canmove = false, dodge = false; + trace_t trace; + edict_t *ent = NULL; + vec3_t goal, dodgedir, mins, maxs, vf, vr, vu, vec, projvec, goalpos; + float dist, zd, dodgedot, enemy_dist; + + + if (!self->enemy) + { + if (!FindTarget(self)) + { + return; + } + } + + //First check to see that the player is at least 128 units away in (discounting z height) + VectorCopy(self->enemy->s.origin, goal); + goal[2] = self->s.origin[2]; + + VectorSubtract(goal, self->s.origin, goal); + dist = VectorLength(goal); + + //Face target + self->ideal_yaw = vectoyaw(goal); + M_ChangeYaw(self); + + //If he is... + if (dist > IMP_MIN_HOVER_DIST && dist < IMP_MAX_HOVER_DIST) + { + + //Make sure we've got line of sight + VectorSet(mins, -1, -1, -1); + VectorSet(maxs, 1, 1, 1); + + gi.trace(self->s.origin, mins, maxs, self->enemy->s.origin, self, MASK_SHOT|MASK_WATER,&trace); + + //If not, try looking from a bit to the side in all six directions + if (trace.ent != self->enemy) + { + + //Setup the directions + AngleVectors(self->s.angles, vf, vr, vu); + + canmove = imp_check_directions(self, self->enemy->s.origin, vf, vr, vu, IMP_CHECK_DIST, goal); + + //If we can see him from one of these, go there + if (canmove) + { + VectorMA(self->velocity, flrand(300.0F, 400.0F), goal, self->velocity); + return; + } + + + //Otherwise just flap around and wait, perhaps lower yourself a bit if high up + self->velocity[0] = flrand(-IMP_DRIFT_AMOUNT_X, IMP_DRIFT_AMOUNT_X); + self->velocity[1] = flrand(-IMP_DRIFT_AMOUNT_Y, IMP_DRIFT_AMOUNT_Y); + self->velocity[2] = flrand(-IMP_DRIFT_AMOUNT_Z, IMP_DRIFT_AMOUNT_Z); + + return; + } + else + { + //Check to make sure the player isn't shooting anything + + //This won't change over the calculations + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + enemy_dist = VectorNormalize(vec); + + while ((ent = findradius(ent, self->s.origin, IMP_PROJECTILE_RADIUS)) != NULL) + { + //We're only interested in his projectiles + if (ent->owner != self->enemy) + continue; + + VectorCopy(ent->velocity, projvec); + VectorNormalize(projvec); + + dodgedot = DotProduct(projvec, vec); + + //gi.dprintf("Found projectile with dot %f\n", dodgedot); + + if (dodgedot < -0.6) + { + //gi.dprintf("Dodge it!\n"); + + dodge = true; + AngleVectors(self->s.angles, NULL, vr, NULL); + + if (irand(0,1)) + VectorScale(vr, -1, vr); + + VectorMA(self->s.origin, 100, vr, goalpos); + + gi.trace(self->s.origin, self->mins, self->maxs, goalpos, self, MASK_SHOT|MASK_WATER,&trace); + + if (trace.fraction < 1) + VectorScale(vr, -1, vr); + + VectorCopy(vr, dodgedir); + } + } + + if (dodge) + { + //If he is, dodge! + VectorMA(self->velocity, irand(300, 500), dodgedir, self->velocity); + return; + } + + //see if he's too close + if(enemy_dist < Q_fabs(self->melee_range)) + SetAnim(self, ANIM_FLYBACK1); + else if(enemy_dist < self->missile_range) + {//see if we can and want to attack him + if(enemy_dist > self->min_missile_range) + { + if(flrand(0, 100) > self->bypass_missile_chance) + { + SetAnim(self, ANIM_FIREBALL); + return; + } + } + } + + //If nothing is happening, check to swoop + canmove = imp_check_swoop(self, self->enemy->s.origin); + + //If you can--nail um + if (canmove) + { + self->monsterinfo.jump_time = 2; + SetAnim(self, ANIM_DIVE_GO); + + return; + } + + //If not, check to see if there's somewhere that you can get to that will allow it + //FIXME: Too many checks.. just try something simple + + //If all else fails, then just pick a random direction to nudge yourself to + else + { + + //Find the difference in the target's height and the creature's height + zd = Q_fabs(self->enemy->s.origin[2] - self->s.origin[2]); + + //We can't swoop because we're too low, so fly upwards if possible + if (zd < IMP_MIN_SSWOOP_DIST) + { + if (!imp_check_move(self, -64)) + { + SetAnim(self, ANIM_FLY1); + return; + } + else + { + //gi.dprintf("Moveback ok\n"); + SetAnim(self, ANIM_FLYBACK1); + return; + } + } + else + { + //Otherwise just flap around and wait, perhaps lower yourself a bit if high up + self->velocity[0] = flrand(-IMP_DRIFT_AMOUNT_X, IMP_DRIFT_AMOUNT_X); + self->velocity[1] = flrand(-IMP_DRIFT_AMOUNT_Y, IMP_DRIFT_AMOUNT_Y); + self->velocity[2] = flrand(-IMP_DRIFT_AMOUNT_Z, IMP_DRIFT_AMOUNT_Z); + + AngleVectors(self->s.angles, vec, NULL, NULL); + VectorMA(self->velocity, irand(200,300), vec, self->velocity); + } + + return; + } + + } + + //If he's too far away trace a line (expanded) to see if you can move at him + } + else if (dist < IMP_MIN_HOVER_DIST) + { + if (!imp_check_move(self, -64)) + { + SetAnim(self, ANIM_FLY1); + } + else + { + SetAnim(self, ANIM_FLYBACK1); + } + } + else + { + if (!imp_check_move(self, 64)) + { + SetAnim(self, ANIM_FLYBACK1); + } + else + { + SetAnim(self, ANIM_FLY1); + } + } + + return; +} + +//New physics call that modifies the imp's velocity and angles based on aerodynamics +void imp_flight_model(edict_t *self) +{ +} + +void move_imp_fly(edict_t *self) +{ + edict_t *dummy; + dummy = self; + + if(!irand(0,3)) + imp_check_dodge(self); + + return; +} + +void move_imp_die(edict_t *self) +{ + //fall to the floor + return; +} + +void imp_hover_anim(edict_t *self) +{ + SetAnim(self, ANIM_HOVER1); +} + +//=============================== + +//IMP FIREBALL + +//=============================== + + +void FireFizzle (edict_t *self) +{ + vec3_t dir; + gi.sound (self, CHAN_BODY, sounds[SND_FIZZLE], 1, ATTN_NORM, 0); + VectorSet(dir, flrand(0, 1),flrand(0, 1), flrand(0.5, 1)); + VectorNormalize(dir); + gi.CreateEffect(&self->s, + FX_ENVSMOKE, + CEF_BROADCAST,self->s.origin, + "bdbbb",irand(1,3),dir,irand(1,2),irand(3, 4),irand(1,2)); + G_SetToFree(self); +} + +void fireball_blocked( edict_t *self, trace_t *trace ); +void create_imp_proj(edict_t *self,edict_t *proj) +{ + proj->svflags |= SVF_ALWAYS_SEND; + proj->movetype = PHYSICSTYPE_FLY; + proj->gravity = 0; + proj->solid = SOLID_BBOX; + proj->classname = "imp fireball"; + proj->s.scale = 1.0; + proj->clipmask = (MASK_SHOT|CONTENTS_WATER); + proj->s.effects=EF_MARCUS_FLAG1; + proj->enemy = self->enemy; + + proj->isBlocked = fireball_blocked; + proj->isBlocking = fireball_blocked; + proj->bounced = fireball_blocked; + + VectorSet(proj->mins, -1.0, -1.0, -1.0); + VectorSet(proj->maxs, 1.0, 1.0, 1.0); + VectorCopy(self->s.origin, proj->s.origin); +} + +void fireball_blocked( edict_t *self, trace_t *trace ) +{ + edict_t *proj; + + if(trace->surface) + { + if(trace->surface->flags & SURF_SKY) + { + SkyFly(self); + return; + } + } + + if(trace->contents&CONTENTS_WATER || trace->contents&CONTENTS_SLIME) + { + FireFizzle(self); + return; + } + + if(trace->ent) + { + if(trace->ent->reflect_debounce_time && EntReflecting(trace->ent, true, true)) + { + proj = G_Spawn(); + + create_imp_proj(self,proj); + proj->owner = self->owner; + proj->ideal_yaw = self->ideal_yaw; + proj->classID = self->classID; + + Create_rand_relect_vect(self->velocity, proj->velocity); + Vec3ScaleAssign(proj->ideal_yaw,proj->velocity); + vectoangles(proj->velocity, proj->s.angles); + + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + FX_IMP_FIRE, + proj->velocity); + + proj->reflect_debounce_time = self->reflect_debounce_time -1; + gi.linkentity(proj); + + G_SetToFree(self); + + return; + } + } + + if (trace->ent->takedamage ) + { + vec3_t hitDir; + float damage = flrand(2,5); + + if(self->dmg) + damage += self->dmg; + VectorCopy( self->velocity, hitDir ); + VectorNormalize( hitDir ); + + T_Damage(trace->ent, self, self->owner, hitDir, self->s.origin, trace->plane.normal, damage, 0, DAMAGE_SPELL | DAMAGE_NO_KNOCKBACK,MOD_DIED); + } + + gi.sound(self, CHAN_BODY, sounds[SND_FBHIT], 1, ATTN_NORM, 0); + + gi.CreateEffect(&self->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + self->s.origin, + "bv", + FX_IMP_FBEXPL, + vec3_origin); + + G_SetToFree(self); +} + +void imp_fireball (edict_t *self) +{ + edict_t *proj; + vec3_t vf, vr, check_lead; + + // Spawn the projectile + + proj = G_Spawn(); + + create_imp_proj(self,proj); + proj->reflect_debounce_time = MAX_REFLECT; + + proj->owner = self; + + proj->dmg = irand(10, 20); + + AngleVectors(self->s.angles, vf, vr, NULL); + + if(self->classID == CID_IMP) + { + VectorMA(self->s.origin, -4*self->monsterinfo.scale, vf, proj->s.origin); + VectorMA(proj->s.origin, 16*self->monsterinfo.scale, vr, proj->s.origin); + proj->s.origin[2] += 32*self->monsterinfo.scale; + gi.sound(proj,CHAN_BODY,sounds[SND_ATTACK],1,ATTN_NORM,0); + } + else + { + VectorCopy(self->s.origin, proj->s.origin); + VectorMA(proj->s.origin, 16, vf, proj->s.origin); + proj->s.origin[2] += 12; + gi.sound(proj, CHAN_BODY, gi.soundindex("monsters/imp/fireball.wav"), 1, ATTN_NORM, 0); + } + + extrapolateFiredir (self, proj->s.origin, 666, self->enemy, 0.3, check_lead); + if(Vec3IsZero(check_lead)) + { + VectorScale(vf, 666, proj->velocity); + } + else + { + VectorScale(check_lead, 666, proj->velocity); + } + + VectorCopy(proj->velocity, proj->movedir); + VectorNormalize(proj->movedir); + vectoangles(proj->movedir, proj->s.angles); + + gi.CreateEffect(&proj->s, + FX_M_EFFECTS,//just so I don't have to make a new FX_ id + CEF_OWNERS_ORIGIN, + NULL, + "bv", + FX_IMP_FIRE, + proj->velocity); + + gi.linkentity(proj); +} + +/*=============================================================== + + Imp Spawn Functions + +===============================================================*/ + +void ImpStaticsInit() +{ + classStatics[CID_IMP].msgReceivers[MSG_DEATH] = imp_die; + classStatics[CID_IMP].msgReceivers[MSG_FLY] = imp_hover; + classStatics[CID_IMP].msgReceivers[MSG_STAND] = imp_stand; + classStatics[CID_IMP].msgReceivers[MSG_RUN] = imp_hover; + classStatics[CID_IMP].msgReceivers[MSG_PAIN] = imp_pain; + classStatics[CID_IMP].msgReceivers[MSG_WATCH] = imp_perch; + classStatics[CID_IMP].msgReceivers[MSG_DEATH_PAIN] = imp_death_pain; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/imp/tris.fm"); + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + sounds[SND_GIB]=gi.soundindex("misc/fleshbreak.wav"); + sounds[SND_FLAP]=gi.soundindex("monsters/imp/fly.wav"); + sounds[SND_SCREAM]=gi.soundindex("monsters/imp/up.wav"); + sounds[SND_DIVE]=gi.soundindex("monsters/imp/swoop.wav"); + sounds[SND_DEATH]=gi.soundindex("monsters/imp/die.wav"); + sounds[SND_HIT]=gi.soundindex("monsters/imp/swoophit.wav"); + sounds[SND_ATTACK]=gi.soundindex("monsters/imp/fireball.wav"); + sounds[SND_FIZZLE]=gi.soundindex("monsters/imp/fout.wav"); + sounds[SND_FBHIT]=gi.soundindex("monsters/imp/fbfire.wav"); + + classStatics[CID_IMP].resInfo = &resInfo; +} + +/*QUAKED monster_imp(1 .5 0) (-16 -16 0) (16 16 32) AMBUSH ASLEEP Perching 8 16 32 64 FIXED + +Our old pal, the fire imp! + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +PERCHING - Will watch player until get too close or get behind the imp + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 14 +melee_range = -64 +missile_range = 1024 +min_missile_range = 32 +bypass_missile_chance = 20 +jump_chance = 0 (flying, no jump) +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +void SP_monster_imp(edict_t *self) +{ + if (!flymonster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_IMP; + + if (!self->health) + self->health = IMP_HEALTH; + + self->mass = IMP_MASS; + self->yaw_speed = 14; + + self->movetype = PHYSICSTYPE_FLY; + self->gravity = 0; + self->flags |= FL_FLY; + self->solid = SOLID_BBOX; + self->clipmask = MASK_MONSTERSOLID; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + self->svflags |= SVF_TAKE_NO_IMPACT_DMG; + + self->materialtype = MAT_FLESH; + + self->s.modelindex = classStatics[CID_IMP].resInfo->modelIndex; + self->s.skinnum = 0; + + self->isBlocked = imp_blocked; + + if (!self->s.scale) + self->monsterinfo.scale = self->s.scale = flrand(0.7, 1.2); + + self->monsterinfo.otherenemyname = "monster_rat"; + + if (self->spawnflags & MSF_PERCHING) + { + SetAnim(self, ANIM_PERCH); + } + else + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } + + if(!self->melee_range) + self->melee_range = AttackRangesForClass[self->classID * 4 + 0]; + + if(!self->missile_range) + self->missile_range = AttackRangesForClass[self->classID * 4 + 1]; + + if(!self->min_missile_range) + self->min_missile_range = AttackRangesForClass[self->classID * 4 + 2]; + + if(!self->bypass_missile_chance) + self->bypass_missile_chance = AttackRangesForClass[self->classID * 4 + 3]; + + if(!self->jump_chance) + self->jump_chance = JumpChanceForClass[self->classID]; + + if(!self->wakeup_distance) + self->wakeup_distance = MAX_SIGHT_PLAYER_DIST; +} diff --git a/Toolkit/Programming/GameCode/game/m_imp.h b/Toolkit/Programming/GameCode/game/m_imp.h new file mode 100644 index 0000000..8e53087 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_imp.h @@ -0,0 +1,113 @@ +typedef enum AnimID_e +{ + ANIM_DIE, + ANIM_FLY1, + ANIM_FLYBACK1, + ANIM_HOVER1, + ANIM_FIREBALL, + ANIM_DIVE_GO, + ANIM_DIVE_LOOP, + ANIM_DIVE_END, + ANIM_DIVE_OUT, + ANIM_PAIN1, + ANIM_TUMBLE, + ANIM_PERCH, + ANIM_TAKEOFF, + ANIM_DUP, + ANIM_DDOWN, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_GIB, + SND_FLAP, + SND_SCREAM, + SND_DIVE, + SND_DEATH, +// SND_PAIN1, +// SND_PAIN2, + SND_HIT, + SND_ATTACK, + SND_FIZZLE, + SND_FBHIT, +// SND_IDLE1, +// SND_IDLE2, + NUM_SOUNDS +} SoundID_t; + +void move_imp_tumble(edict_t *self); + +void imp_flap_noise(edict_t *self); +void imp_flap_fast_noise(edict_t *self); +void imp_dive_noise(edict_t *self); +void imp_death_noise(edict_t *self); +void imp_pain1_noise(edict_t *self); +void imp_pain2_noise(edict_t *self); +void imp_attack_noise(edict_t *self); + +extern animmove_t imp_move_die1; +extern animmove_t imp_move_fly1; +extern animmove_t imp_move_flyback; +extern animmove_t imp_move_hover1; +extern animmove_t imp_move_fireball; +extern animmove_t imp_move_dive_go; +extern animmove_t imp_move_dive_loop; +extern animmove_t imp_move_dive_end; +extern animmove_t imp_move_dive_out; +extern animmove_t imp_move_pain1; +extern animmove_t imp_move_tumble; +extern animmove_t imp_move_takeoff; +//Pirches +extern animmove_t imp_move_perch; +extern animmove_t imp_move_dup; +extern animmove_t imp_move_ddown; + + +qboolean SV_StepDirection (edict_t *ent, float yaw, float dist); +qboolean SV_FlyDirection (edict_t *ent, vec3_t *attitude, float dist); +qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink); +qboolean ai_checkattack (edict_t *self, float dist); +void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist); +void extrapolateFiredir (edict_t *self,vec3_t p1,float pspeed,edict_t *targ,float accept,vec3_t vec2);; + +void imp_ai_fly (edict_t *self, float fd, float rd, float ud); +void imp_ai_pirch (edict_t *self); +void imp_ai_hover (edict_t *self, float dist); + +void imp_flight_model (edict_t *self); + +void imp_dive_loop(edict_t *self); +void imp_hit_loop(edict_t *self); +void imp_check_dodge(edict_t *self); + +void imp_dead (edict_t *self); +void imp_hit (edict_t *self, float stop_swoop); +void imp_pause(edict_t *self); +void imp_die(edict_t *self, G_Message_t *msg); +void imp_fly(edict_t *self, G_Message_t *msg); +void imp_fly_attack(edict_t *self, G_Message_t *msg); +void imp_flyback(edict_t *self); +void imp_hover(edict_t *self, G_Message_t *msg); +void imp_stand(edict_t *self, G_Message_t *msg); +void imp_hoverscream(edict_t *self, G_Message_t *msg); +void imp_dive(edict_t *self, G_Message_t *msg); +void imp_pain(edict_t *self, G_Message_t *msg); +void imp_perch(edict_t *self, G_Message_t *msg); + +void SP_monster_imp(edict_t* self); +void imp_init(void); +void imp_pain_init(edict_t *self); + +void imp_fix_angles(edict_t *self); + +void move_imp_die(edict_t *self); +void move_imp_hover(edict_t *self); +void move_imp_fly(edict_t *self); +void move_imp_dive(edict_t *self); +void move_imp_dive_end(edict_t *self); + +void imp_hover_anim(edict_t *self); +void imp_fireball (edict_t *self); +void imp_death_pain (edict_t *self, G_Message_t *msg); + diff --git a/Toolkit/Programming/GameCode/game/m_imp_anim.c b/Toolkit/Programming/GameCode/game/m_imp_anim.c new file mode 100644 index 0000000..4fac354 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_imp_anim.c @@ -0,0 +1,378 @@ +#include "m_imp_anim.h" +#include "g_local.h" +#include "m_imp.h" +#include "random.h" + + +/*---------------------------------------------------- +imp dying 1 +----------------------------------------------------*/ +animframe_t imp_frames_die1[] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death2, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death3, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death4, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death5, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death6, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death7, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death8, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death9, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death10, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death11, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death12, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death13, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, + FRAME_death14, NULL, 0, 0, 0, NULL, 0, imp_fix_angles, +}; +animmove_t imp_move_die1 = {14,imp_frames_die1, imp_dead}; + +/*---------------------------------------------------- +imp flying 1 +----------------------------------------------------*/ +animframe_t imp_frames_fly1[] = +{ + FRAME_impfly1, imp_ai_fly, 32, 0, 0, NULL, 15, imp_flap_noise, + FRAME_impfly2, imp_ai_fly, 32, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly3, imp_ai_fly, 32, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly4, imp_ai_fly, 36, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly5, imp_ai_fly, 36, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly6, imp_ai_fly, 64, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly7, imp_ai_fly, 64, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly8, imp_ai_fly, 57, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly9, imp_ai_fly, 54, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly9, imp_ai_fly, 54, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly11, imp_ai_fly, 42, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly11, imp_ai_fly, 42, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly13, imp_ai_fly, 36, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly14, imp_ai_fly, 32, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly14, imp_ai_fly, 32, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly16, imp_ai_fly, 26, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly16, imp_ai_fly, 26, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly18, imp_ai_fly, 24, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly18, imp_ai_fly, 24, 0, 0, NULL, 15, move_imp_fly, + FRAME_impfly20, imp_ai_fly, 26, 0, 0, NULL, 15, move_imp_fly +}; +animmove_t imp_move_fly1 = {20, imp_frames_fly1, imp_pause}; + +/*------------------------------------------------------ +imp flying backwards 1 +------------------------------------------------------*/ +animframe_t imp_frames_flyback[] = +{ + FRAME_impfly1, imp_ai_fly, -16, 0, 8, NULL, 0, imp_flap_noise, + FRAME_impfly2, imp_ai_fly, -32, 0, 32, NULL, 0, move_imp_fly, + FRAME_impfly3, imp_ai_fly, -26, 0, 27, NULL, 0, move_imp_fly, + FRAME_impfly4, imp_ai_fly, -24, 0, 24, NULL, 0, move_imp_fly, + FRAME_impfly5, imp_ai_fly, -21, 0, 16, NULL, 0, move_imp_fly, + FRAME_impfly6, imp_ai_fly, -18, 0, 24, NULL, 0, move_imp_fly, + FRAME_impfly7, imp_ai_fly, -16, 0, 8, NULL, 0, imp_flap_noise, + FRAME_impfly8, imp_ai_fly, -32, 0, 32, NULL, 0, move_imp_fly, + FRAME_impfly9, imp_ai_fly, -26, 0, 27, NULL, 0, move_imp_fly, + FRAME_impfly10, imp_ai_fly, -24, 0, 24, NULL, 0, move_imp_fly, + FRAME_impfly11, imp_ai_fly, -21, 0, 16, NULL, 0, move_imp_fly, + FRAME_impfly12, imp_ai_fly, -18, 0, 24, NULL, 0, move_imp_fly, + FRAME_impfly13, imp_ai_fly, -16, 0, 8, NULL, 0, imp_flap_noise, + FRAME_impfly14, imp_ai_fly, -32, 0, 32, NULL, 0, move_imp_fly, + FRAME_impfly15, imp_ai_fly, -26, 0, 27, NULL, 0, move_imp_fly, + FRAME_impfly16, imp_ai_fly, -24, 0, 24, NULL, 0, move_imp_fly, + FRAME_impfly17, imp_ai_fly, -21, 0, 16, NULL, 0, move_imp_fly, + FRAME_impfly18, imp_ai_fly, -18, 0, 24, NULL, 0, move_imp_fly, + FRAME_impfly19, imp_ai_fly, -26, 0, 27, NULL, 0, move_imp_fly, + FRAME_impfly20, imp_ai_fly, -24, 0, 24, NULL, 0, move_imp_fly, +}; +animmove_t imp_move_flyback = { 20, imp_frames_flyback, imp_pause}; + + +/*------------------------------------------------------ +imp hit from swoop +------------------------------------------------------*/ +animframe_t imp_frames_dive_end[] = +{ + FRAME_swpend1, imp_ai_fly, -32, 0, 16, NULL, 0, imp_flap_noise, + FRAME_swpend2, imp_ai_fly, -64, 0, 64, NULL, 0, move_imp_fly, + FRAME_swpend3, imp_ai_fly, -52, 0, 54, NULL, 0, move_imp_fly, + FRAME_swpend4, imp_ai_fly, -48, 0, 48, NULL, 0, move_imp_fly, + FRAME_swpend5, imp_ai_fly, -42, 0, 32, NULL, 0, move_imp_fly, + FRAME_swpend6, imp_ai_fly, -36, 0, 24, NULL, 0, move_imp_fly, + FRAME_swpend7, imp_ai_fly, -32, 0, 16, NULL, 0, imp_flap_noise, + FRAME_swpend8, imp_ai_fly, -64, 0, 64, NULL, 0, move_imp_fly, + FRAME_swpend9, imp_ai_fly, -52, 0, 54, NULL, 0, move_imp_fly, + FRAME_swpend10, imp_ai_fly, -48, 0, 48, NULL, 0, move_imp_fly, + FRAME_swpend11, imp_ai_fly, -42, 0, 32, NULL, 0, move_imp_fly, + FRAME_swpend12, imp_ai_fly, -36, 0, 24, NULL, 0, move_imp_fly, + FRAME_swpend13, imp_ai_fly, -32, 0, 16, NULL, 0, imp_flap_noise, + FRAME_swpend14, imp_ai_fly, -64, 0, 64, NULL, 0, move_imp_fly, + FRAME_swpend15, imp_ai_fly, -52, 0, 54, NULL, 0, move_imp_fly, +}; +animmove_t imp_move_dive_end = { 15, imp_frames_dive_end, imp_flyback}; + +/*------------------------------------------------------ +imp hit from swoop +------------------------------------------------------*/ +animframe_t imp_frames_dive_out[] = +{ + FRAME_swpout1, imp_ai_fly, -32, 0, 16, NULL, 0, imp_flap_noise, + FRAME_swpout2, imp_ai_fly, -64, 0, 64, NULL, 0, move_imp_fly, + FRAME_swpout3, imp_ai_fly, -52, 0, 54, NULL, 0, move_imp_fly, + FRAME_swpout4, imp_ai_fly, -48, 0, 48, NULL, 0, move_imp_fly, + FRAME_swpout5, imp_ai_fly, -42, 0, 32, NULL, 0, move_imp_fly, + FRAME_swpout6, imp_ai_fly, -36, 0, 24, NULL, 0, move_imp_fly, + FRAME_swpout7, imp_ai_fly, -32, 0, 16, NULL, 0, imp_flap_noise, + FRAME_swpout8, imp_ai_fly, -64, 0, 64, NULL, 0, move_imp_fly, + FRAME_swpout9, imp_ai_fly, -52, 0, 54, NULL, 0, move_imp_fly, + FRAME_swpout10, imp_ai_fly, -48, 0, 48, NULL, 0, move_imp_fly, + FRAME_swpout11, imp_ai_fly, -42, 0, 32, NULL, 0, move_imp_fly, + FRAME_swpout12, imp_ai_fly, -36, 0, 24, NULL, 0, move_imp_fly, + FRAME_swpout13, imp_ai_fly, -32, 0, 16, NULL, 0, imp_flap_noise, + FRAME_swpout14, imp_ai_fly, -64, 0, 64, NULL, 0, move_imp_fly, + FRAME_swpout15, imp_ai_fly, -52, 0, 54, NULL, 0, move_imp_fly, +}; +animmove_t imp_move_dive_out = { 15, imp_frames_dive_out, imp_flyback}; + +/*------------------------------------------------------- +imp hovering +-------------------------------------------------------*/ +animframe_t imp_frames_hover1[] = +{ + FRAME_impfly1, NULL, 0, 0, 0, imp_ai_hover, 2, imp_flap_noise, + FRAME_impfly2, NULL, 0, 0, 0, imp_ai_hover, 2, imp_check_dodge, + FRAME_impfly3, NULL, 0, 0, 0, imp_ai_hover, 1, NULL, + FRAME_impfly4, NULL, 0, 0, 0, imp_ai_hover, 1, NULL, + FRAME_impfly5, NULL, 0, 0, 0, imp_ai_hover, -1, imp_check_dodge, + FRAME_impfly6, NULL, 0, 0, 0, imp_ai_hover, -1, NULL, + FRAME_impfly7, NULL, 0, 0, 0, imp_ai_hover, -1, NULL, + FRAME_impfly8, NULL, 0, 0, 0, imp_ai_hover, -2, imp_check_dodge, + FRAME_impfly9, NULL, 0, 0, 0, imp_ai_hover, -2, NULL, + FRAME_impfly10, NULL, 0, 0, 0, imp_ai_hover, -2, NULL, + FRAME_impfly11, NULL, 0, 0, 0, imp_ai_hover, -2, imp_check_dodge, + FRAME_impfly12, NULL, 0, 0, 0, imp_ai_hover, -1, NULL, + FRAME_impfly13, NULL, 0, 0, 0, imp_ai_hover, -1, NULL, + FRAME_impfly14, NULL, 0, 0, 0, imp_ai_hover, -1, imp_check_dodge, + FRAME_impfly15, NULL, 0, 0, 0, imp_ai_hover, 1, NULL, + FRAME_impfly16, NULL, 0, 0, 0, imp_ai_hover, 1, NULL, + FRAME_impfly17, NULL, 0, 0, 0, imp_ai_hover, 2, imp_check_dodge, + FRAME_impfly18, NULL, 0, 0, 0, imp_ai_hover, 2, NULL, + FRAME_impfly19, NULL, 0, 0, 0, imp_ai_hover, 2, NULL, + FRAME_impfly20, NULL, 0, 0, 0, imp_ai_hover, 2, imp_check_dodge, +}; +animmove_t imp_move_hover1 = {20, imp_frames_hover1, move_imp_hover}; + +animframe_t imp_frames_tumble[] = +{ + FRAME_impfly1, NULL, 0, 0, 0, imp_ai_hover, 2, move_imp_tumble, + FRAME_impfly2, NULL, 0, 0, 0, imp_ai_hover, 2, move_imp_tumble, + FRAME_impfly3, NULL, 0, 0, 0, imp_ai_hover, 1, move_imp_tumble, + FRAME_impfly4, NULL, 0, 0, 0, imp_ai_hover, 1, move_imp_tumble, + FRAME_impfly5, NULL, 0, 0, 0, imp_ai_hover, -1, move_imp_tumble, + FRAME_impfly6, NULL, 0, 0, 0, imp_ai_hover, -1, move_imp_tumble, + FRAME_impfly7, NULL, 0, 0, 0, imp_ai_hover, -1, move_imp_tumble, + FRAME_impfly8, NULL, 0, 0, 0, imp_ai_hover, -1, move_imp_tumble, + FRAME_impfly9, NULL, 0, 0, 0, imp_ai_hover, -2, move_imp_tumble, + FRAME_impfly10, NULL, 0, 0, 0, imp_ai_hover, -2, move_imp_tumble, + FRAME_impfly11, NULL, 0, 0, 0, imp_ai_hover, -2, move_imp_tumble, + FRAME_impfly12, NULL, 0, 0, 0, imp_ai_hover, -2, move_imp_tumble, + FRAME_impfly13, NULL, 0, 0, 0, imp_ai_hover, -1, move_imp_tumble, + FRAME_impfly14, NULL, 0, 0, 0, imp_ai_hover, -1, move_imp_tumble, + FRAME_impfly15, NULL, 0, 0, 0, imp_ai_hover, -1, move_imp_tumble, + FRAME_impfly16, NULL, 0, 0, 0, imp_ai_hover, -1, move_imp_tumble, + FRAME_impfly17, NULL, 0, 0, 0, imp_ai_hover, 1, move_imp_tumble, + FRAME_impfly18, NULL, 0, 0, 0, imp_ai_hover, 1, move_imp_tumble, + FRAME_impfly19, NULL, 0, 0, 0, imp_ai_hover, 2, move_imp_tumble, + FRAME_impfly20, NULL, 0, 0, 0, imp_ai_hover, 2, move_imp_tumble, +}; +animmove_t imp_move_tumble = {20, imp_frames_tumble, NULL}; + +/*------------------------------------------------------- +imp firing fireball +-------------------------------------------------------*/ +animframe_t imp_frames_fireball[] = +{ + FRAME_impfir1, NULL, 0, 0, 0, imp_ai_hover, 2, imp_flap_noise, + FRAME_impfir2, NULL, 0, 0, 0, imp_ai_hover, 1, NULL, + FRAME_impfir3, NULL, 0, 0, 0, imp_ai_hover, -1, NULL, + FRAME_impfir4, NULL, 0, 0, 0, imp_ai_hover, -2, imp_check_dodge, + FRAME_impfir5, NULL, 0, 0, 0, imp_ai_hover, -2, NULL, + FRAME_impfir6, NULL, 0, 0, 0, imp_ai_hover, -1, NULL, + FRAME_impfir7, NULL, 0, 0, 0, imp_ai_hover, 1, imp_check_dodge, + FRAME_impfir8, NULL, 0, 0, 0, imp_ai_hover, 2, NULL, + FRAME_impfir9, NULL, 0, 0, 0, imp_ai_hover, 2, NULL, + FRAME_impfir10, NULL, 0, 0, 0, imp_ai_hover, 1, NULL, + FRAME_impfir11, NULL, 0, 0, 0, imp_ai_hover, -1, imp_check_dodge, + FRAME_impfir12, NULL, 0, 0, 0, imp_ai_hover, -2, NULL, + FRAME_impfir13, NULL, 0, 0, 0, imp_ai_hover, -2, NULL, + FRAME_impfir14, NULL, 0, 0, 0, imp_ai_hover, -1, NULL, + FRAME_impfir15, NULL, 0, 0, 0, imp_ai_hover, 1, NULL, + FRAME_impfir16, NULL, 0, 0, 0, imp_ai_hover, 2, imp_fireball, + FRAME_impfir15, NULL, 0, 0, 0, imp_ai_hover, -2, NULL, + FRAME_impfir16, NULL, 0, 0, 0, imp_ai_hover, -1, NULL, + FRAME_impfir17, NULL, 0, 0, 0, imp_ai_hover, 1, NULL, + FRAME_impfir18, NULL, 0, 0, 0, imp_ai_hover, 2, NULL, + FRAME_impfir19, NULL, 0, 0, 0, imp_ai_hover, 2, imp_check_dodge, + FRAME_impfir20, NULL, 0, 0, 0, imp_ai_hover, 1, NULL, + FRAME_impfir21, NULL, 0, 0, 0, imp_ai_hover, -1, NULL +}; +animmove_t imp_move_fireball = {21, imp_frames_fireball, move_imp_hover}; + + +/*------------------------------------------------------- +imp diving and attacking +-------------------------------------------------------*/ +animframe_t imp_frames_dive_go[] = +{ + FRAME_swoop1, NULL, 0, 0, 0, NULL, 0, imp_dive_noise, + FRAME_swoop2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop5, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop6, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop7, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop8, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop9, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop10, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop11, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop12, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop13, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop14, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop15, NULL, 0, 0, 0, NULL, 0, move_imp_dive, + FRAME_swoop16, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swoop17, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swoop18, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swoop19, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swoop20, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, +}; +animmove_t imp_move_dive_go = {6, imp_frames_dive_go, imp_dive_loop}; + +animframe_t imp_frames_dive_loop[] = +{ + FRAME_swpcyc1, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc2, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc3, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc4, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc1, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc2, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc3, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc4, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc1, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc2, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc3, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc4, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc1, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc2, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc3, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc4, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc1, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc2, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc3, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc4, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc1, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc2, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc3, NULL, 0, 0, 0, imp_hit, 0, move_imp_dive, + FRAME_swpcyc4, NULL, 0, 0, 0, imp_hit, true, move_imp_dive, +}; +animmove_t imp_move_dive_loop = {24, imp_frames_dive_loop, NULL}; + +/*------------------------------------------------------- +imp pain +-------------------------------------------------------*/ +animframe_t imp_frames_pain1 [] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 2, move_imp_hover, + FRAME_death2, NULL, 0, 0, 0, NULL, 1, move_imp_hover, + FRAME_death3, NULL, 0, 0, 0, NULL, -1, move_imp_hover, + FRAME_death2, NULL, 0, 0, 0, NULL, -2, move_imp_hover, + FRAME_death1, NULL, 0, 0, 0, NULL, -2, move_imp_hover, +}; +animmove_t imp_move_pain1 = { 5, imp_frames_pain1, imp_pause}; + +//perch +animframe_t imp_frames_perch[] = +{ + FRAME_impwat1 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat2 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat3 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat4 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat5 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat6 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat7 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat8 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat9 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat10 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat11 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat12 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat13 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat14 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat15 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat16 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat17 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat18 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat19 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat20 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat21 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat22 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat23 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, + FRAME_impwat24 , NULL, 0, 0, 0, NULL, 0, imp_ai_pirch, +}; +animmove_t imp_move_perch = { 24, imp_frames_perch, NULL}; + +animframe_t imp_frames_takeoff [] = +{ + FRAME_impup1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_impup2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_impup3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_impup4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_impup5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_impup6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_impup7, imp_ai_fly, 16, 0, 16, NULL, 0, imp_flap_noise, + FRAME_impup8, imp_ai_fly, 18, 0, 16, NULL, 0, NULL, + FRAME_impup9, imp_ai_fly, 24, 0, 32, NULL, 0, NULL, + FRAME_impup10, imp_ai_fly, 36, 0, 64, NULL, 0, NULL, + FRAME_impup11, imp_ai_fly, 24, 0, 32, NULL, 0, NULL, + FRAME_impup12, imp_ai_fly, 18, 0, 16, NULL, 0, NULL, + FRAME_impup13, imp_ai_fly, 16, 0, 32, NULL, 0, NULL, + FRAME_impup14, imp_ai_fly, 12, 0, 64, NULL, 0, NULL, + FRAME_impup15, imp_ai_fly, 8, 0, 32, NULL, 0, NULL, + FRAME_impup16, imp_ai_fly, 6, 0, 32, NULL, 0, NULL, + FRAME_impup17, imp_ai_fly, 4, 0, 16, NULL, 0, imp_flap_noise, + FRAME_impup18, imp_ai_fly, 2, 0, 16, NULL, 0, NULL, + FRAME_impup19, imp_ai_fly, -2, 0, 32, NULL, 0, NULL, + FRAME_impup20, imp_ai_fly, -4, 0, 64, NULL, 0, NULL, + FRAME_impup21, imp_ai_fly, -6, 0, 32, NULL, 0, NULL, + FRAME_impup22, imp_ai_fly, -8, 0, 16, NULL, 0, NULL, + FRAME_impup23, imp_ai_fly, -16, 0, 32, NULL, 0, NULL, +}; +animmove_t imp_move_takeoff = { 23, imp_frames_takeoff, imp_pause}; + +animframe_t imp_frames_dup[] = +{ + FRAME_swpend6, imp_ai_fly, -36, 0, 24, NULL, 0, move_imp_fly, + FRAME_swpend7, imp_ai_fly, -32, 0, 16, NULL, 0, imp_flap_noise, + FRAME_swpend8, imp_ai_fly, -64, 0, 64, NULL, 0, move_imp_fly, + FRAME_swpend9, imp_ai_fly, -52, 0, 54, NULL, 0, move_imp_fly, + FRAME_swpend10, imp_ai_fly, -48, 0, 48, NULL, 0, move_imp_fly, + FRAME_swpend11, imp_ai_fly, -42, 0, 32, NULL, 0, move_imp_fly, + FRAME_swpend12, imp_ai_fly, -36, 0, 24, NULL, 0, move_imp_fly, + FRAME_swpend13, imp_ai_fly, -32, 0, 16, NULL, 0, imp_flap_noise, + FRAME_swpend14, imp_ai_fly, -64, 0, 64, NULL, 0, move_imp_fly, + FRAME_swpend15, imp_ai_fly, -52, 0, 54, NULL, 0, move_imp_fly, +}; +animmove_t imp_move_dup = { 10, imp_frames_dup, imp_pause}; + +animframe_t imp_frames_ddown[] = +{ + FRAME_swoop1, NULL, 0, 0, 0, NULL, 0, imp_dive_noise, + FRAME_swoop2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swoop20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swpout1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swpout4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swpout6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swpout9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swpout12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swpout15, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t imp_move_ddown = {15, imp_frames_ddown , imp_pause}; diff --git a/Toolkit/Programming/GameCode/game/m_imp_anim.h b/Toolkit/Programming/GameCode/game/m_imp_anim.h new file mode 100644 index 0000000..19d987a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_imp_anim.h @@ -0,0 +1,166 @@ +// R:\Art\models/monsters\imp\final + +// This file generated by qdata - Do NOT Modify + +#define FRAME_death1 0 +#define FRAME_death2 1 +#define FRAME_death3 2 +#define FRAME_death4 3 +#define FRAME_death5 4 +#define FRAME_death6 5 +#define FRAME_death7 6 +#define FRAME_death8 7 +#define FRAME_death9 8 +#define FRAME_death10 9 +#define FRAME_death11 10 +#define FRAME_death12 11 +#define FRAME_death13 12 +#define FRAME_death14 13 +#define FRAME_impfir1 14 +#define FRAME_impfir2 15 +#define FRAME_impfir3 16 +#define FRAME_impfir4 17 +#define FRAME_impfir5 18 +#define FRAME_impfir6 19 +#define FRAME_impfir7 20 +#define FRAME_impfir8 21 +#define FRAME_impfir9 22 +#define FRAME_impfir10 23 +#define FRAME_impfir11 24 +#define FRAME_impfir12 25 +#define FRAME_impfir13 26 +#define FRAME_impfir14 27 +#define FRAME_impfir15 28 +#define FRAME_impfir16 29 +#define FRAME_impfir17 30 +#define FRAME_impfir18 31 +#define FRAME_impfir19 32 +#define FRAME_impfir20 33 +#define FRAME_impfir21 34 +#define FRAME_impfly1 35 +#define FRAME_impfly2 36 +#define FRAME_impfly3 37 +#define FRAME_impfly4 38 +#define FRAME_impfly5 39 +#define FRAME_impfly6 40 +#define FRAME_impfly7 41 +#define FRAME_impfly8 42 +#define FRAME_impfly9 43 +#define FRAME_impfly10 44 +#define FRAME_impfly11 45 +#define FRAME_impfly12 46 +#define FRAME_impfly13 47 +#define FRAME_impfly14 48 +#define FRAME_impfly15 49 +#define FRAME_impfly16 50 +#define FRAME_impfly17 51 +#define FRAME_impfly18 52 +#define FRAME_impfly19 53 +#define FRAME_impfly20 54 +#define FRAME_impup1 55 +#define FRAME_impup2 56 +#define FRAME_impup3 57 +#define FRAME_impup4 58 +#define FRAME_impup5 59 +#define FRAME_impup6 60 +#define FRAME_impup7 61 +#define FRAME_impup8 62 +#define FRAME_impup9 63 +#define FRAME_impup10 64 +#define FRAME_impup11 65 +#define FRAME_impup12 66 +#define FRAME_impup13 67 +#define FRAME_impup14 68 +#define FRAME_impup15 69 +#define FRAME_impup16 70 +#define FRAME_impup17 71 +#define FRAME_impup18 72 +#define FRAME_impup19 73 +#define FRAME_impup20 74 +#define FRAME_impup21 75 +#define FRAME_impup22 76 +#define FRAME_impup23 77 +#define FRAME_impwat1 78 +#define FRAME_impwat2 79 +#define FRAME_impwat3 80 +#define FRAME_impwat4 81 +#define FRAME_impwat5 82 +#define FRAME_impwat6 83 +#define FRAME_impwat7 84 +#define FRAME_impwat8 85 +#define FRAME_impwat9 86 +#define FRAME_impwat10 87 +#define FRAME_impwat11 88 +#define FRAME_impwat12 89 +#define FRAME_impwat13 90 +#define FRAME_impwat14 91 +#define FRAME_impwat15 92 +#define FRAME_impwat16 93 +#define FRAME_impwat17 94 +#define FRAME_impwat18 95 +#define FRAME_impwat19 96 +#define FRAME_impwat20 97 +#define FRAME_impwat21 98 +#define FRAME_impwat22 99 +#define FRAME_impwat23 100 +#define FRAME_impwat24 101 +#define FRAME_swoop1 102 +#define FRAME_swoop2 103 +#define FRAME_swoop3 104 +#define FRAME_swoop4 105 +#define FRAME_swoop5 106 +#define FRAME_swoop6 107 +#define FRAME_swoop7 108 +#define FRAME_swoop8 109 +#define FRAME_swoop9 110 +#define FRAME_swoop10 111 +#define FRAME_swoop11 112 +#define FRAME_swoop12 113 +#define FRAME_swoop13 114 +#define FRAME_swoop14 115 +#define FRAME_swoop15 116 +#define FRAME_swoop16 117 +#define FRAME_swoop17 118 +#define FRAME_swoop18 119 +#define FRAME_swoop19 120 +#define FRAME_swoop20 121 +#define FRAME_swpcyc1 122 +#define FRAME_swpcyc2 123 +#define FRAME_swpcyc3 124 +#define FRAME_swpcyc4 125 +#define FRAME_swpend1 126 +#define FRAME_swpend2 127 +#define FRAME_swpend3 128 +#define FRAME_swpend4 129 +#define FRAME_swpend5 130 +#define FRAME_swpend6 131 +#define FRAME_swpend7 132 +#define FRAME_swpend8 133 +#define FRAME_swpend9 134 +#define FRAME_swpend10 135 +#define FRAME_swpend11 136 +#define FRAME_swpend12 137 +#define FRAME_swpend13 138 +#define FRAME_swpend14 139 +#define FRAME_swpend15 140 +#define FRAME_swpout1 141 +#define FRAME_swpout2 142 +#define FRAME_swpout3 143 +#define FRAME_swpout4 144 +#define FRAME_swpout5 145 +#define FRAME_swpout6 146 +#define FRAME_swpout7 147 +#define FRAME_swpout8 148 +#define FRAME_swpout9 149 +#define FRAME_swpout10 150 +#define FRAME_swpout11 151 +#define FRAME_swpout12 152 +#define FRAME_swpout13 153 +#define FRAME_swpout14 154 +#define FRAME_swpout15 155 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 1 + +#define MESH_DEFAULT 0 diff --git a/Toolkit/Programming/GameCode/game/m_morcalavin.c b/Toolkit/Programming/GameCode/game/m_morcalavin.c new file mode 100644 index 0000000..36dc37a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_morcalavin.c @@ -0,0 +1,2070 @@ +//============================================================================== +// +// m_morcalavin.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "m_morcalavin.h" +#include "m_morcalavin_anim.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "fx.h" +#include "g_HitLocation.h" +#include "p_main2.h" +#include "g_misc.h" +#include "m_stats.h" +#include "g_playstats.h" + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + +void create_morcalavin_proj(edict_t *self,edict_t *proj); +void BecomeDebris(edict_t *self); + +enum { + HPMISSILE1, + HPMISSILE2, + HPMISSILE3, + HPMISSILE4, + HPMISSILE5, + HPMISSILE1_EXPLODE, + HPMISSILE2_EXPLODE, + HPMISSILE3_EXPLODE, + HPMISSILE4_EXPLODE, + HPMISSILE5_EXPLODE, + HPMISSILE1_LIGHT, + HPMISSILE2_LIGHT, + HPMISSILE3_LIGHT, + HPMISSILE4_LIGHT, + HPMISSILE5_LIGHT, + HPTELEPORT_START, + HPTELEPORT_END, + HPLIGHTNING_BOLT, +}; + +static animmove_t *animations[NUM_ANIMS] = +{ + &morcalavin_move_float, + &morcalavin_move_hurtidle, + &morcalavin_move_attack1, + &morcalavin_move_attack2, + &morcalavin_move_attack2b, + &morcalavin_move_attack3, + &morcalavin_move_def1, + &morcalavin_move_def2, + &morcalavin_move_walk, + &morcalavin_move_fly, + &morcalavin_move_getup, + &morcalavin_move_retort, + &morcalavin_move_fall, + &morcalavin_move_glide, + &morcalavin_move_ground_attack, + &morcalavin_move_tracking_attack1, + &morcalavin_move_attack4, +}; + +void morcalavin_end_retort(edict_t *self) +{ + SetAnim(self, ANIM_WALK); +} + +void morcalavin_check_lightning2(edict_t *self) +{ + vec3_t vel, org, org2; + float dist; + + if (!self->owner->enemy) + { + self->nextthink = level.time + 0.1; + return; + } + + VectorSubtract(self->s.origin, self->owner->enemy->s.origin, vel); + dist = VectorNormalize(vel); + + if (dist < 72) + { + T_Damage(self->owner->enemy, self, self->owner, vel, vec3_origin, vec3_origin, 2, 0, DAMAGE_SPELL, MOD_SHIELD); + + VectorNormalize2(self->velocity, vel); + + VectorMA(self->s.origin, 600*FRAMETIME, vel, org); + + VectorCopy(self->owner->enemy->s.origin, org2); + org2[2] += irand(-16, 32); + + gi.CreateEffect(NULL, FX_LIGHTNING, 0, + org, "vbb", org2, (byte) irand(2,4), (byte) 0); + } + + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + morcalavin_big_shot +-----------------------------------------------*/ + +void morcalavin_big_shot( edict_t *self ) +{ + edict_t *proj; + vec3_t vf, vr; + + proj = G_Spawn(); + + proj->solid = SOLID_BBOX; + + VectorSet(proj->mins, -4, -4, -4); + VectorSet(proj->maxs, 4, 4, 4); + + proj->movetype = PHYSICSTYPE_FLY; + proj->gravity = 0; + proj->clipmask = MASK_SHOT; + + proj->think = morcalavin_check_lightning2; + proj->nextthink = level.time + 0.1; + + proj->isBlocked = proj->isBlocking = proj->bounced = morcalavin_proj3_blocked; + + proj->owner = self; + + self->target_ent = proj; + + AngleVectors(self->s.angles, vf, vr, NULL); + VectorMA(self->s.origin, 24, vf, proj->s.origin); + VectorMA(proj->s.origin, 12, vr, proj->s.origin); + proj->s.origin[2] += 32; + + VectorSubtract(self->enemy->s.origin, proj->s.origin, vf); + VectorNormalize(vf); + VectorScale(vf, 600, proj->velocity); + + proj->s.effects = EF_MARCUS_FLAG1 | EF_CAMERA_NO_CLIP; + + gi.linkentity(proj); + + //Create the effect + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + proj->s.origin, + "bv", + FX_MORK_MISSILE, + proj->s.origin); + + gi.sound (self, CHAN_AUTO, sounds[SND_PPCHARGE], 1, ATTN_NORM, 0); +} + +/*----------------------------------------------- + morcalavin_proj_track +-----------------------------------------------*/ + +void morcalavin_proj_track( edict_t *self ) +{ + vec3_t olddir, newdir, huntdir; + float oldvelmult , newveldiv, speed_mod; + + //No enemy, stop tracking + if (!self->enemy) + { + self->think = NULL; + return; + } + + //Enemy is dead, stop tracking + if (self->enemy->health <= 0) + { + self->think = NULL; + return; + } + + //Timeout? + if (self->monsterinfo.attack_finished < level.time) + { + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + HPMISSILE1_EXPLODE); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; + + return; + } + + VectorCopy(self->velocity, olddir); + VectorNormalize(olddir); + + VectorSubtract(self->enemy->s.origin, self->s.origin, huntdir); + VectorNormalize(huntdir); + + if (self->delay + 0.05 < 4.0) + self->delay += 0.05; + + if (self->ideal_yaw + 10 < 1000) + self->ideal_yaw += 10; + + oldvelmult = self->delay; + newveldiv = 1/(oldvelmult + 1); + + VectorScale(olddir, oldvelmult, olddir); + VectorAdd(olddir, huntdir, newdir); + VectorScale(newdir, newveldiv, newdir); + + speed_mod = DotProduct( olddir , newdir ); + + if (speed_mod < 0.05) + speed_mod = 0.05; + + newveldiv *= self->ideal_yaw * speed_mod; + + VectorScale(olddir, oldvelmult, olddir); + VectorAdd(olddir, huntdir, newdir); + VectorScale(newdir, newveldiv, newdir); + + VectorCopy(newdir, self->velocity); + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + morcalavin_tracking_projectile +-----------------------------------------------*/ + +void morcalavin_tracking_projectile ( edict_t *self, float pitch, float yaw, float roll) +{ + edict_t *proj; + vec3_t vf, vr, vu, ang; + + proj = G_Spawn(); + + proj->monsterinfo.attack_finished = level.time + 10; + proj->owner = self; + + proj->svflags |= SVF_ALWAYS_SEND; + proj->movetype = PHYSICSTYPE_FLY; + proj->gravity = 0; + proj->solid = SOLID_BBOX; + proj->classname = "Morcalavin_Tracking_Missile"; + proj->dmg = 1.0; + proj->s.scale = 1.0; + proj->clipmask = MASK_SHOT; + proj->nextthink = level.time + 0.1; + + proj->delay = 1.0; + proj->bounced = morcalavin_proj1_blocked; + proj->isBlocking = morcalavin_proj1_blocked; + proj->isBlocked = morcalavin_proj1_blocked; + + proj->s.effects=EF_MARCUS_FLAG1|EF_CAMERA_NO_CLIP; + proj->enemy = self->enemy; + + VectorSet(proj->mins, -2.0, -2.0, -2.0); + VectorSet(proj->maxs, 2.0, 2.0, 2.0); + VectorCopy(self->s.origin, proj->s.origin); + + //Determine the starting velocity of the ball + VectorCopy(self->s.angles, ang); + ang[PITCH] += pitch; + ang[YAW] += yaw; + ang[ROLL] += roll; + + AngleVectors(ang, vf, vr, vu); + VectorMA(self->s.origin, 24, vf, proj->s.origin); + VectorMA(proj->s.origin, -16, vr, proj->s.origin); + VectorMA(proj->s.origin, 52, vu, proj->s.origin); + + VectorScale(vu, 16, proj->velocity); + proj->ideal_yaw = 300; + + proj->think = morcalavin_proj_track; + + if (skill->value < 1) + proj->nextthink = level.time + 2; + else + proj->nextthink = level.time + flrand(1.5, 3.0); + + gi.sound (self, CHAN_AUTO, sounds[SND_HOMING], 1, ATTN_NORM, 0); + + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + FX_MORK_TRACKING_MISSILE, + proj->velocity); +} + +/*----------------------------------------------- + morcalavin_proj2_blocked +-----------------------------------------------*/ + +void morcalavin_proj2_blocked( edict_t *self, trace_t *trace ) +{ + edict_t *proj; + vec3_t hitDir; + byte exp; + + if (trace->ent == self->owner) + return; + + //Reflection stuff + if(EntReflecting(trace->ent, true, true)) + { + proj = G_Spawn(); + + create_morcalavin_proj(self,proj); + proj->owner = self->owner; + proj->ideal_yaw = self->ideal_yaw; + + Create_rand_relect_vect(self->velocity, proj->velocity); + Vec3ScaleAssign(proj->ideal_yaw,proj->velocity); + vectoangles(proj->velocity, proj->s.angles); + + exp = HPMISSILE1_EXPLODE; + + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + (unsigned char) exp); + + gi.linkentity(proj); + + G_SetToFree(self); + + return; + } + + if ( trace->ent->takedamage ) + { + VectorCopy( self->velocity, hitDir ); + VectorNormalize( hitDir ); + + T_Damage( trace->ent, self, self->owner, hitDir, self->s.origin, trace->plane.normal, 40, 0, DAMAGE_SPELL | DAMAGE_NO_KNOCKBACK,MOD_DIED ); + } + + gi.CreateEffect(NULL, + FX_M_EFFECTS, + 0, + self->s.origin, + "bv", + FX_MORK_MISSILE_HIT, + trace->plane.normal); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + morcalavin_proj3_blocked +-----------------------------------------------*/ + +void morcalavin_proj3_blocked( edict_t *self, trace_t *trace ) +{ + edict_t *proj; + vec3_t hitDir; + byte exp; + + if (trace->ent == self->owner) + return; + + //Reflection stuff + if(EntReflecting(trace->ent, true, true)) + { + proj = G_Spawn(); + + create_morcalavin_proj(self,proj); + proj->owner = self->owner; + proj->ideal_yaw = self->ideal_yaw; + + Create_rand_relect_vect(self->velocity, proj->velocity); + Vec3ScaleAssign(proj->ideal_yaw,proj->velocity); + vectoangles(proj->velocity, proj->s.angles); + + exp = HPMISSILE1_EXPLODE; + + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + (unsigned char) exp); + + gi.linkentity(proj); + + G_SetToFree(self); + + return; + } + + if ( trace->ent->takedamage ) + { + VectorCopy( self->velocity, hitDir ); + VectorNormalize( hitDir ); + + T_Damage( trace->ent, self, self->owner, hitDir, self->s.origin, trace->plane.normal, irand(3,5), 0, DAMAGE_SPELL | DAMAGE_NO_KNOCKBACK,MOD_DIED ); + } + + gi.CreateEffect(NULL, + FX_M_EFFECTS, + 0, + self->s.origin, + "bv", + FX_MORK_MISSILE_HIT, + trace->plane.normal); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; +} + +void morcalavin_check_lightning(edict_t *self) +{ + vec3_t vel, org, org2; + float dist; + + if (!self->owner->enemy) + { + self->nextthink = level.time + 0.1; + return; + } + + VectorSubtract(self->s.origin, self->owner->enemy->s.origin, vel); + dist = VectorNormalize(vel); + + if (dist < 150) + { + T_Damage(self->owner->enemy, self, self->owner, vel, vec3_origin, vec3_origin, irand(2,4), 0, DAMAGE_SPELL, MOD_SHIELD); + + VectorNormalize2(self->velocity, vel); + + VectorMA(self->s.origin, 400*FRAMETIME, vel, org); + + VectorCopy(self->owner->enemy->s.origin, org2); + org2[2] += irand(-16, 32); + + gi.CreateEffect(NULL, FX_LIGHTNING, 0, + org, "vbb", org2, (byte) irand(2,4), (byte) 0); + + if (skill->value < 1) + { + VectorScale(vel, 1.0, vel); + VectorNormalize(self->velocity); + VectorAdd(self->velocity, vel, self->velocity); + VectorScale(self->velocity, 400, self->velocity); + } + + } + + self->nextthink = level.time + 0.1; +} + +void morcalavin_missile_update(edict_t *self) +{ + vec3_t vf, vr, endpos; + + AngleVectors(self->owner->s.angles, vf, vr, NULL); + + switch( self->owner->s.frame ) + { + case FRAME_atakc3: + VectorMA(self->owner->s.origin, 16, vf, self->s.origin); + VectorMA(self->s.origin, 10, vr, self->s.origin); + self->s.origin[2] += 24; + break; + + case FRAME_atakc4: + VectorMA(self->owner->s.origin, 16, vf, self->s.origin); + VectorMA(self->s.origin, 12, vr, self->s.origin); + self->s.origin[2] += 26; + break; + + case FRAME_atakc5: + VectorMA(self->owner->s.origin, 16, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 28; + break; + + case FRAME_atakc6: + VectorMA(self->owner->s.origin, 15, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 32; + break; + + case FRAME_atakc7: + VectorMA(self->owner->s.origin, 15, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 36; + break; + + case FRAME_atakc8: + VectorMA(self->owner->s.origin, 14, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 37; + break; + + case FRAME_atakc9: + VectorMA(self->owner->s.origin, 14, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 38; + break; + + case FRAME_atakc10: + VectorMA(self->owner->s.origin, 14, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 39; + break; + + case FRAME_atakc11: + VectorMA(self->owner->s.origin, 14, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 40; + break; + + case FRAME_atakc12: + VectorMA(self->owner->s.origin, 14, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 41; + break; + + case FRAME_atakc13: + VectorMA(self->owner->s.origin, 14, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 42; + break; + + case FRAME_atakc14: + VectorMA(self->owner->s.origin, 14, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 42; + break; + + case FRAME_atakc15: + VectorMA(self->owner->s.origin, 16, vf, self->s.origin); + VectorMA(self->s.origin, 14, vr, self->s.origin); + self->s.origin[2] += 42; + + VectorSet(endpos, self->owner->enemy->s.origin[0], self->owner->enemy->s.origin[1], self->owner->enemy->s.origin[2] + self->owner->enemy->viewheight); + VectorSubtract(endpos, self->s.origin, vf); + VectorNormalize(vf); + VectorScale(vf, 400, self->velocity); + + self->think = morcalavin_check_lightning; + self->nextthink = level.time + 0.1; + return; + break; + } + + gi.linkentity(self); + + self->nextthink = level.time + 0.1; +} + +void morcalavin_start_missile(edict_t *self) +{ + edict_t *proj; + vec3_t vf, vr; + + proj = G_Spawn(); + + proj->solid = SOLID_BBOX; + + VectorSet(proj->mins, -4, -4, -4); + VectorSet(proj->maxs, 4, 4, 4); + + proj->movetype = PHYSICSTYPE_FLY; + proj->gravity = 0; + proj->clipmask = MASK_SHOT; + + proj->think = morcalavin_missile_update; + proj->nextthink = level.time + 0.1; + + proj->isBlocked = proj->isBlocking = proj->bounced = morcalavin_proj2_blocked; + + proj->owner = self; + + self->target_ent = proj; + + AngleVectors(self->s.angles, vf, vr, NULL); + VectorMA(self->s.origin, 16, vf, proj->s.origin); + VectorMA(proj->s.origin, 10, vr, proj->s.origin); + proj->s.origin[2] += 24; + + proj->s.effects = EF_MARCUS_FLAG1 | EF_CAMERA_NO_CLIP; + + gi.linkentity(proj); + + //Create the effect + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + proj->s.origin, + "bv", + FX_MORK_MISSILE, + proj->s.origin); + + gi.sound (self, CHAN_AUTO, sounds[SND_PPCHARGE], 1, ATTN_NORM, 0); +} + +void morcalavin_release_missile(edict_t *self) +{ + gi.sound (self, CHAN_AUTO, sounds[SND_PPFIRE], 1, ATTN_NORM, 0); +} + +/*----------------------------------------------- + morcalavin_proj1_blocked +-----------------------------------------------*/ + +void morcalavin_proj1_blocked( edict_t *self, trace_t *trace ) +{ + edict_t *proj; + vec3_t hitDir; + int damage; + byte exp; + + if (trace->ent == self->owner) + return; + + if (!stricmp(trace->ent->classname, "Morcalavin_Missile")) + return; + + //Reflection stuff + if(EntReflecting(trace->ent, true, true)) + { + proj = G_Spawn(); + + create_morcalavin_proj(self,proj); + proj->owner = self->owner; + proj->ideal_yaw = self->ideal_yaw; + + Create_rand_relect_vect(self->velocity, proj->velocity); + Vec3ScaleAssign(proj->ideal_yaw,proj->velocity); + vectoangles(proj->velocity, proj->s.angles); + + exp = HPMISSILE1_EXPLODE; + + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + (unsigned char) exp); + + gi.linkentity(proj); + + G_SetToFree(self); + + return; + } + + //Do the rest of the stuff + exp = HPMISSILE1_EXPLODE; + damage = irand(4, 8); + + if ( trace->ent->takedamage ) + { + VectorCopy( self->velocity, hitDir ); + VectorNormalize( hitDir ); + + T_Damage( trace->ent, self, self->owner, hitDir, self->s.origin, trace->plane.normal, damage, 0, DAMAGE_SPELL | DAMAGE_NO_KNOCKBACK,MOD_DIED ); + } + + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + (unsigned char) exp); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + create_morcalavin_proj +-----------------------------------------------*/ + +// create the guts of morcalavin's projectile +void create_morcalavin_proj(edict_t *self,edict_t *proj) +{ + proj->svflags |= SVF_ALWAYS_SEND; + proj->movetype = PHYSICSTYPE_FLY; + proj->gravity = 0; + proj->solid = SOLID_BBOX; + proj->classname = "Morcalavin_Missile"; + proj->dmg = 1.0; + proj->s.scale = 1.0; + proj->clipmask = MASK_SHOT; + proj->nextthink = level.time + 0.1; + + proj->isBlocked = proj->isBlocking = proj->bounced = morcalavin_proj1_blocked; + + proj->s.effects=EF_MARCUS_FLAG1|EF_CAMERA_NO_CLIP; + proj->enemy = self->enemy; + + VectorSet(proj->mins, -2.0, -2.0, -2.0); + VectorSet(proj->maxs, 2.0, 2.0, 2.0); + VectorCopy(self->s.origin, proj->s.origin); +} + +/*----------------------------------------------- + morcalavin_taunt_shot +-----------------------------------------------*/ + +void morcalavin_taunt_shot(edict_t *self) +{ + //Bang + edict_t *proj; + vec3_t vf, vr, predPos; + vec3_t ang, vel, startOfs, angles; + + if (!self->enemy) + return; + + //Only predict once for all the missiles + M_PredictTargetPosition ( self->enemy, self->enemy->velocity, 5, predPos ); + + AngleVectors(self->s.angles, vf, vr, NULL); + + VectorMA(self->s.origin, -8, vf, startOfs); + VectorMA(startOfs, -16, vr, startOfs); + startOfs[2] += 8; + + VectorSubtract(predPos, startOfs, vf); + VectorNormalize(vf); + + vectoangles( vf, angles ); + + // Spawn the projectile + proj = G_Spawn(); + + create_morcalavin_proj(self,proj); + proj->owner = self; + + VectorCopy(startOfs, proj->s.origin); + VectorCopy(angles, ang); + + ang[PITCH] = flrand( -4, 4 ) + -ang[PITCH]; + ang[YAW] += flrand( -4, 4 ); + + AngleVectors( ang, vel, NULL, NULL ); + + VectorScale(vel, irand(700,800) + (skill->value * 100), proj->velocity); + + vectoangles(proj->velocity, proj->s.angles); + + gi.sound (self, CHAN_AUTO, sounds[SND_HOMING], 1, ATTN_NORM, 0); + + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + FX_MORK_TRACKING_MISSILE, + proj->s.origin); + + gi.linkentity(proj); +} + +void morcalavin_phase_out (edict_t *self) +{ + int interval = 40; + + if(self->s.color.a > interval) + { + self->s.color.a -= irand(interval/2, interval); + self->pre_think = morcalavin_phase_out; + self->next_pre_think = level.time + 0.05; + } + else + { + self->s.color.a = 0; + self->pre_think = NULL; + self->next_pre_think = -1; + } +} + +void morcalavin_phase_in (edict_t *self) +{ + int interval = 12; + + if(self->s.color.a < 255 - interval) + { + self->s.color.a += irand(interval/2, interval); + self->pre_think = morcalavin_phase_in; + self->next_pre_think = level.time + 0.05; + } + else + { + self->svflags &= ~SVF_NO_AUTOTARGET; + self->s.color.c = 0xffffffff; + + if(self->health <= 0 || self->monsterinfo.lefty >= 6) + { + self->pre_think = NULL; + self->next_pre_think = -1; + } + else + morcalavin_init_phase_out(self); + } +} + +void morcalavin_init_phase_out (edict_t *self) +{ + //Become tangible once more + self->solid = SOLID_NOT; + self->pre_think = morcalavin_phase_out; + self->next_pre_think = level.time + FRAMETIME; + self->svflags |= SVF_NO_AUTOTARGET; +} + +void morcalavin_init_phase_in (edict_t *self) +{ + self->pre_think = morcalavin_phase_in; + self->next_pre_think = level.time + FRAMETIME; +} + +/* + + morcalavin Shield Functions + +*/ + +void mork_laugh (edict_t *self) +{ + gi.sound(self, CHAN_VOICE, sounds[SND_LAUGH], 1, ATTN_NONE, 0); + self->post_think = NULL; + self->next_post_think = -1; +} + +void mork_check_killed_enemy(edict_t *attacker) +{ + if(attacker->enemy && attacker->enemy->health<=0) + { + attacker->post_think = mork_laugh; + attacker->next_post_think = level.time + flrand(1.3, 2.3); + } +} + +void projectile_veer(edict_t *self, float amount) +{ +//useful code for making projectiles wander randomly to a specified degree + vec3_t veerdir; + float speed; + + speed = VectorLength(self->velocity); + VectorSet(veerdir, + flrand(-amount, amount), + flrand(-amount, amount), + flrand(-amount, amount)); + VectorAdd(veerdir, self->velocity, self->velocity); + VectorNormalize(self->velocity); + Vec3ScaleAssign(speed, self->velocity); + + //check to see if this is needed + // self.angles=vectoangles(self.velocity); +} + +void projectile_homethink (edict_t *self) +{ + vec3_t olddir, newdir, huntdir; + float oldvelmult , newveldiv, speed_mod; + float turnspeed; + + if(self->delay) + turnspeed = self->delay; + else + turnspeed = 1.3; + + VectorCopy(self->velocity, olddir); + VectorNormalize(olddir); + + VectorSubtract(self->enemy->s.origin, self->s.origin, huntdir); + VectorNormalize(huntdir); + + oldvelmult = turnspeed; + newveldiv = 1/(oldvelmult + 1); + + VectorScale(olddir, oldvelmult, olddir); + VectorAdd(olddir, huntdir, newdir); + VectorScale(newdir, newveldiv, newdir); + + speed_mod = DotProduct( olddir , newdir ); + + if (speed_mod < 0.05) + speed_mod = 0.05; + + newveldiv *= self->ideal_yaw * speed_mod; + + VectorScale(olddir, oldvelmult, olddir); + VectorAdd(olddir, huntdir, newdir); + VectorScale(newdir, newveldiv, newdir); + + VectorCopy(newdir, self->velocity); + + if(self->random) + projectile_veer(self, self->random); +} + +/* + + morcalavin Projectile Functions + +*/ + +/*----------------------------------------------- + morcalavin_proj1_think +-----------------------------------------------*/ + +void morcalavin_proj1_think( edict_t *self ) +{ + if(clear_visible(self, self->enemy)) + projectile_homethink(self); + + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + morcalavin_proj1_blocked +-----------------------------------------------*/ + +void beam_blocked( edict_t *self, trace_t *trace ) +{ +// edict_t *proj; + + /* + if(EntReflecting(trace->ent, true, true) && self->reflect_debounce_time) + { + proj = G_Spawn(); + + create_morcalavin_proj(self,proj); + proj->isBlocked = beam_blocked; + proj->classname = "M_ref_HMissile"; + proj->owner = self->owner; + proj->ideal_yaw = self->ideal_yaw; + proj->classID = self->classID; + + Create_rand_relect_vect(self->velocity, proj->velocity); + Vec3ScaleAssign(proj->ideal_yaw,proj->velocity); + vectoangles(proj->velocity, proj->s.angles); + + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + proj->classID, + proj->velocity); + + proj->reflect_debounce_time = self->reflect_debounce_time -1; + gi.linkentity(proj); + + G_SetToFree(self); + + return; + }*/ + + if (trace->ent->takedamage ) + { + vec3_t hitDir; + float damage = flrand(MORK_DMG_PROJ1_MIN, MORK_DMG_PROJ1_MAX); + + if(self->dmg) + damage += self->dmg; + VectorCopy( self->velocity, hitDir ); + VectorNormalize( hitDir ); + + T_Damage(trace->ent, self, self->owner, hitDir, self->s.origin, trace->plane.normal, damage, 0, DAMAGE_SPELL | DAMAGE_NO_KNOCKBACK,MOD_DIED); + } + + gi.sound(self, CHAN_WEAPON, gi.soundindex("monsters/seraph/guard/spellhit.wav"), 1, ATTN_NORM, 0); + + gi.CreateEffect(&self->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + self->s.origin, + "bv", + FX_M_MISC_EXPLODE, + vec3_origin); + + G_SetToFree(self); +} + +void beam_think (edict_t *self) +{ + self->think = NULL; + self->nextthink = -1; +} + +void morcalavin_beam( edict_t *self) +{ + edict_t *proj; + vec3_t Forward, vf, vr, endpos; + + // Spawn the projectile + + proj = G_Spawn(); + + create_morcalavin_proj(self,proj); + + proj->reflect_debounce_time = MAX_REFLECT; + proj->classname = "M_Beam"; + + proj->isBlocked = beam_blocked; + + proj->owner = self; + + AngleVectors(self->s.angles, vf, vr, NULL); + VectorMA(proj->s.origin, 48, vf, proj->s.origin); + VectorMA(proj->s.origin, -20, vr, proj->s.origin); + proj->s.origin[2] += 16; + + VectorSet(endpos, self->enemy->s.origin[0], self->enemy->s.origin[1], self->enemy->s.origin[2] + self->enemy->viewheight); + VectorSubtract(endpos, proj->s.origin, Forward); + VectorNormalize(Forward); + + VectorScale(Forward, 1250, proj->velocity); + + vectoangles(proj->velocity, proj->s.angles); + + proj->dmg = flrand(MORK_DMG_BEAM_MIN, MORK_DMG_BEAM_MAX); + + proj->think=beam_think; + proj->nextthink = level.time + 1; + + gi.sound(self, CHAN_WEAPON, gi.soundindex("monsters/seraph/guard/spell.wav"), 1, ATTN_NORM, 0); + + //TODO: Spawn a muzzle flash + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_M_BEAM, + proj->s.angles); + + + gi.linkentity(proj); +} + + +void morcalavin_beam2( edict_t *self) +{ + edict_t *proj; + vec3_t Forward, vf, vr; + + // Spawn the projectile + + proj = G_Spawn(); + + create_morcalavin_proj(self,proj); + + proj->reflect_debounce_time = MAX_REFLECT; + proj->classname = "M_Beam"; + + proj->isBlocked = beam_blocked; + + proj->owner = self; + + AngleVectors(self->s.angles, vf, vr, NULL); + VectorMA(proj->s.origin, 48, vf, proj->s.origin); + VectorMA(proj->s.origin, -20, vr, proj->s.origin); + proj->s.origin[2] += 16; + + VectorSubtract(self->enemy->s.origin, proj->s.origin, Forward); + VectorNormalize(Forward); + + VectorScale(Forward, 1250, proj->velocity); + + vectoangles(proj->velocity, proj->s.angles); + + proj->dmg = flrand(MORK_DMG_BEAM_MIN, MORK_DMG_BEAM_MAX); + + proj->think=beam_think; + proj->nextthink = level.time + 1; + + gi.sound(self, CHAN_WEAPON, gi.soundindex("monsters/seraph/guard/spell.wav"), 1, ATTN_NORM, 0); + + //TODO: Spawn a muzzle flash + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_M_BEAM, + proj->s.angles); + + + gi.linkentity(proj); +} + +/*----------------------------------------------- + morcalavin_ground_attack +-----------------------------------------------*/ + +void morcalavin_ground_attack( edict_t *self ) +{ + gi.CreateEffect(NULL, + FX_M_EFFECTS, + 0, + self->s.origin, + "bv", + FX_GROUND_ATTACK, + self->enemy->s.origin); +} + +/*----------------------------------------------- + morcalavin_quake_pause +-----------------------------------------------*/ + +void morcalavin_quake_pause( edict_t *self ) +{ + if (self->monsterinfo.flee_finished) + { + self->monsterinfo.flee_finished = false; + SetAnim(self, ANIM_GROUND_ATTACK); + } +} + +/*----------------------------------------------- + morcalavin_quake +-----------------------------------------------*/ +void morcalavin_quake(edict_t *self, float pitch_ofs, float yaw_ofs, float roll_ofs) +{ + H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); + + vec3_t org, vf, vr; + + //Create the effect + AngleVectors(self->s.angles, vf, vr, NULL); + + VectorMA(self->s.origin, 44, vf, org); + VectorMA(org, -14, vr, org); + org[2] += self->mins[2]; + + gi.CreateEffect( NULL, + FX_M_EFFECTS, + 0, + self->s.origin, + "bv", + FX_QUAKE_RING, + org); + + //Check to see if the player is on the ground, and if he is, then knock him down + if (self->enemy && self->enemy->groundentity && self->enemy->client) + { + //Knock the player down + KnockDownPlayer(&self->enemy->client->playerinfo); + + //Denote we've done so to follow it with an attack + self->monsterinfo.flee_finished = true; + } +} + +/* + + Morcalavin Helper Functions + +*/ + + +/*----------------------------------------------- + morcalavin_move +-----------------------------------------------*/ + +void morcalavin_move( edict_t *self, float vf, float vr, float vu ) +{ +} + +void morcalavin_rush_sound (edict_t *self) +{ + vec3_t forward; + gi.sound(self, CHAN_BODY, sounds[SND_RUSH], 1, ATTN_NORM, 0); + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorScale(forward, 250, self->velocity); + self->velocity[2] = 150; +} + +/*----------------------------------------------- + morcalavin_pause +-----------------------------------------------*/ + +void morcalavin_pause( edict_t *self ) +{ + if (self->monsterinfo.lefty < 6 && self->health > 0) + { + SetAnim(self, ANIM_FLOAT); + return; + } + + self->takedamage = DAMAGE_YES; + self->mood_think(self); + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + if(self->ai_mood_flags & AI_MOOD_FLAG_MISSILE) + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_PURSUE: + case AI_MOOD_NAVIGATE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_DELAY: + case AI_MOOD_STAND: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_WANDER: + SetAnim(self, ANIM_WALK); + break; + + default : +#ifdef _DEVEL + gi.dprintf("mork: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } +} + +/*----------------------------------------------- + morcalavin_idle +-----------------------------------------------*/ + +void morcalavin_idle(edict_t *self) +{ +} + +/* + + morcalavin Message Functions + +*/ + +/*----------------------------------------------- + morcalavin_death +-----------------------------------------------*/ + +void morcalavin_death( edict_t *self, G_Message_t *msg ) +{ + self->monsterinfo.stepState++; +} + +void morcalavin_retort( edict_t *self) +{ + self->msgHandler = DefaultMsgHandler; + SetAnim(self, ANIM_RETORT); +} + +void morcalavin_getup( edict_t *self) +{ + if (self->monsterinfo.lefty==7) + { + if (self->monsterinfo.attack_finished > 0 && self->monsterinfo.attack_finished < level.time) + { + self->monsterinfo.attack_finished = -1; + gi.sound(self, CHAN_VOICE, sounds[SND_REVIVE], 1, ATTN_NORM, 0); + SetAnim(self, ANIM_GETUP); + } + } +} + +void morcalavin_hurtidle( edict_t *self) +{ + SetAnim(self, ANIM_HURTIDLE); +} + +/*----------------------------------------------- + morcalavin_evade +-----------------------------------------------*/ + + +void morcalavin_evade( edict_t *self, G_Message_t *msg ) +{ + //FIXME: Make him do something smart here... +} + +/*----------------------------------------------- + morcalavin_stand +-----------------------------------------------*/ + +void morcalavin_stand(edict_t *self, G_Message_t *msg) +{ + if (self->health <= 0) + return; + + //SetAnim(self, ANIM_ATTACK1); + SetAnim(self, ANIM_FLOAT); +} + +/*----------------------------------------------- + morcalavin_run +-----------------------------------------------*/ + +void mork_ai_hover (edict_t *self, float dist) +{ + vec3_t bottom; + trace_t trace; + float desired_vel; + + if (self->health <= 0) + return; + + if(self->enemy) + ai_charge(self, 0); + else + ai_stand(self, 0); + + if(dist) + { + VectorCopy(self->s.origin, bottom); + bottom[2] -= dist; + gi.trace(self->s.origin, self->mins, self->maxs, bottom, self, MASK_SOLID, &trace); + + if(trace.fraction<1.0) + { + desired_vel = (1 - trace.fraction) * dist; + + if(self->velocity[2] < desired_vel) + self->velocity[2] = desired_vel; + + return; + } + } +} + +void mork_ai_run (edict_t *self, float dist) +{ + vec3_t forward; + + if (self->health <= 0) + return; + + if(self->curAnimID!=ANIM_FLY) + { + ai_run(self, dist); + if(!self->groundentity) + { + if(self->curAnimID == ANIM_WALK) + { + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorScale(forward, 250, self->velocity); + self->velocity[2] = 150; + } + SetAnim(self, ANIM_GLIDE); + } + else + SetAnim(self, ANIM_WALK); + } + else + { + /* + gi.CreateEffect(&self->s, + FX_M_EFFECTS, + 0, + vec3_origin, + "bv", + FX_M_MOBLUR, + self->s.angles); + */ + + ai_charge(self, dist); + } +} + +void morcalavin_run(edict_t *self, G_Message_t *msg) +{//if can't move, go into a float for a bit + + if (self->health <= 0) + return; + + if(!self->enemy) + { + SetAnim(self, ANIM_FLOAT); + return; + } + + if(self->enemy->health<=0) + { + mork_check_killed_enemy(self->enemy); + SetAnim(self, ANIM_FLOAT); + return; + } + + if (self->monsterinfo.lefty == 0) + { + morcalavin_init_phase_out(self); + SetAnim(self, ANIM_FLOAT); + gi.sound(self, CHAN_VOICE, sounds[SND_REVIVE], 1, ATTN_NORM, 0); + self->solid = SOLID_NOT; + self->monsterinfo.sound_start = level.time + 2.5; + self->monsterinfo.lefty++; + + return; + } + + if(!self->groundentity) + SetAnim(self, ANIM_GLIDE); + else + SetAnim(self, ANIM_WALK); +} + +void morcalavin_rush(edict_t *self, G_Message_t *msg) +{ +// self->gravity = 0.0f; + SetAnim(self, ANIM_FLY); +} + +enum +{ + MORK_ATTACK_FADE, + MORK_ATTACK_TRACKING, + MORK_ATTACK_SPHERE, + MORK_ATTACK_BEAM, + MORK_ATTACK_5SPHERE +}; morcalavin_attackID_t; + +void morcalavin_missile( edict_t *self, G_Message_t *msg) +{ + int chance = irand(0, 100); + + if (chance < 5 && self->wait != MORK_ATTACK_FADE) + { + morcalavin_attack_fade_out(self); + self->wait = MORK_ATTACK_FADE; + } + else if (chance < 25 && self->wait != MORK_ATTACK_TRACKING) + { + SetAnim(self, ANIM_TRACKING1); + self->wait = MORK_ATTACK_TRACKING; + } + else if (chance < 50 && self->wait != MORK_ATTACK_SPHERE) + { + SetAnim(self, ANIM_ATTACK2B); + self->wait = MORK_ATTACK_SPHERE; + } + else if (chance < 75 && self->wait != MORK_ATTACK_BEAM) + { + SetAnim(self, ANIM_ATTACK3); + self->wait = MORK_ATTACK_BEAM; + } + else if (self->monsterinfo.stepState > 1 && self->wait != MORK_ATTACK_5SPHERE) + { + SetAnim(self, ANIM_ATTACK4); + self->wait = MORK_ATTACK_5SPHERE; + } +} + +void morcalavin_melee( edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_ATTACK1); +} + +/* + + morcalavin Spawn Functions + +*/ + +void morcalavinStaticsInit() +{ + classStatics[CID_MORK].msgReceivers[MSG_STAND] = morcalavin_stand; + classStatics[CID_MORK].msgReceivers[MSG_MELEE] = morcalavin_melee; + classStatics[CID_MORK].msgReceivers[MSG_MISSILE] = morcalavin_missile; + classStatics[CID_MORK].msgReceivers[MSG_RUN] = morcalavin_run; + classStatics[CID_MORK].msgReceivers[MSG_EVADE] = morcalavin_evade; + classStatics[CID_MORK].msgReceivers[MSG_DEATH] = morcalavin_death; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/morcalavin/tris.fm"); + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + +//quake attack + sounds[SND_QUAKE]=gi.soundindex("monsters/mork/quake.wav"); +//straightt-fire beam + sounds[SND_BEAM]=gi.soundindex("monsters/mork/beam.wav"); + sounds[SND_BEAMHIT]=gi.soundindex("monsters/mork/beamhit.wav"); +//homing balls + sounds[SND_HOMING]=gi.soundindex("monsters/mork/homing.wav"); + sounds[SND_HOMEHIT]=gi.soundindex("monsters/mork/homehit.wav"); +//power Puff + sounds[SND_PPCHARGE]=gi.soundindex("monsters/mork/ppcharge.wav"); + sounds[SND_PPFIRE]=gi.soundindex("monsters/mork/ppfire.wav"); + sounds[SND_PPEXPLODE]=gi.soundindex("monsters/mork/ppexplode.wav"); +//Lightning from eyes + sounds[SND_LIGHTNING]=gi.soundindex("monsters/mork/lightning.wav"); + sounds[SND_LGHTNGHIT]=gi.soundindex("monsters/mork/lghtnghit.wav"); +//Shove + sounds[SND_FORCEWALL]=gi.soundindex("monsters/mork/forcewall.wav"); +//Shield + sounds[SND_MAKESHIELD]=gi.soundindex("monsters/mork/makeshield.wav"); + sounds[SND_SHIELDHIT]=gi.soundindex("monsters/mork/shieldhit.wav"); + sounds[SND_SHIELDPULSE]=gi.soundindex("monsters/mork/shieldpulse.wav"); + sounds[SND_SHIELDGONE]=gi.soundindex("monsters/mork/shieldgone.wav"); + sounds[SND_SHIELDBREAK]=gi.soundindex("monsters/mork/shieldbreak.wav"); +//Fly forward + sounds[SND_RUSH]=gi.soundindex("monsters/mork/rush.wav"); +//hurt and get up + sounds[SND_FALL]=gi.soundindex("monsters/mork/fall.wav"); + sounds[SND_REVIVE]=gi.soundindex("monsters/mork/revive.wav"); +//strafing beams attack + sounds[SND_STRAFEON]=gi.soundindex("monsters/mork/strafeon.wav"); + sounds[SND_STRFSWNG]=gi.soundindex("monsters/mork/strfswng.wav"); + sounds[SND_STRAFEOFF]=gi.soundindex("monsters/mork/strafeoff.wav"); +//hurt/kill player laugh + sounds[SND_LAUGH]=gi.soundindex("monsters/mork/laugh.wav"); + +//Taunts + sounds[TAUNT_LAUGH1] =gi.soundindex("monsters/mork/laugh1.wav"); + sounds[TAUNT_LAUGH2] =gi.soundindex("monsters/mork/laugh2.wav"); + sounds[TAUNT_LAUGH3] =gi.soundindex("monsters/mork/laugh3.wav"); + sounds[TAUNT_LAUGH4] =gi.soundindex("monsters/mork/laugh4.wav"); + + sounds[TAUNT_BELLY1] =gi.soundindex("monsters/mork/belly.wav"); + sounds[TAUNT_BELLY2] =gi.soundindex("monsters/mork/belly2.wav"); + sounds[TAUNT_BELLY3] =gi.soundindex("monsters/mork/digest.wav"); + + classStatics[CID_MORK].resInfo = &resInfo; +} + +void morcalavin_attack_fade_out(edict_t *self) +{ + gi.sound(self, CHAN_VOICE, sounds[SND_REVIVE], 1, ATTN_NORM, 0); + self->monsterinfo.sound_start = level.time + 2.0; + morcalavin_init_phase_out(self); + SetAnim(self, ANIM_FLOAT); + self->monsterinfo.lefty = 8; +} + +void morcalavin_fade_out(edict_t *self) +{ + gi.sound(self, CHAN_VOICE, sounds[SND_REVIVE], 1, ATTN_NORM, 0); + self->monsterinfo.sound_start = level.time + 2.0; + morcalavin_init_phase_out(self); + SetAnim(self, ANIM_FLOAT); +} + +qboolean morcalavin_choose_teleport_destination(edict_t *self) +{ + vec3_t teleport_angles, forward, endpos, startpos; + trace_t trace; + int num_tries, i; + edict_t *noblockent; + float tracedist; + + //Instead of chance, do around self if evade, around other if ambush + if(!self->enemy) + { + //Phase in and become tangible again + morcalavin_init_phase_in(self); + self->takedamage = DAMAGE_YES; + self->monsterinfo.lefty = 10; + return false; + } + + num_tries = 10; + + for(i = 0; i < num_tries; i++) + { + VectorSet(teleport_angles, 0, anglemod(flrand(0, 360)), 0); + AngleVectors(teleport_angles, forward, NULL, NULL); + VectorCopy(self->enemy->s.origin, startpos); + startpos[2]+=self->enemy->mins[2]; + startpos[2]-=self->mins[2]; + tracedist = irand(self->min_missile_range, self->missile_range); + VectorMA(startpos, -tracedist, forward, endpos); + noblockent = self->enemy; + + gi.trace(startpos, self->mins, self->maxs, endpos, noblockent, MASK_MONSTERSOLID, &trace); + + if(trace.fraction*tracedist < 100)//min origin lerp dist + continue; + + if(trace.allsolid || trace.startsolid) + continue; + + if(vhlen(trace.endpos, self->enemy->s.origin)>=128) + { + VectorCopy(trace.endpos, startpos); + VectorCopy(trace.endpos, endpos); + endpos[2] -=64; + gi.trace(startpos, self->mins, self->maxs, endpos, noblockent, MASK_MONSTERSOLID,&trace); + if(trace.fraction<1.0 && !trace.allsolid && !trace.startsolid)//the last two should be false if trace.fraction is < 1.0 but doesn't hurt to check + { + VectorCopy(trace.endpos, self->s.origin); + gi.linkentity(self); + return true; + } + } + } + return false; +} + +//Teleport in and attack the player quickly, before fading out again +void morcalavin_teleport_attack(edict_t *self) +{ + int chance; + + //Find a valid point away from the player + morcalavin_choose_teleport_destination(self); + + //Start the animation for the attack + if (self->monsterinfo.lefty == 8) + SetAnim(self, ANIM_ATTACK4); + else + SetAnim(self, ANIM_ATTACK2); + + //Play the teleport in sound fx + gi.sound(self, CHAN_AUTO, sounds[SND_MAKESHIELD], 1, ATTN_NORM, 0); + + //Start phasing back in + morcalavin_init_phase_in(self); + + //Become tangible once more + self->solid = SOLID_BBOX; + + if (self->monsterinfo.stepState) + { + chance = irand(0,6); + switch (chance) + { + case 0: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH2], 1, ATTN_NONE, 0); + break; + + case 1: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH3], 1, ATTN_NONE, 0); + break; + + case 2: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH4], 1, ATTN_NONE, 0); + break; + + default: + break; + } + } +} + +void morcalavin_postthink(edict_t *self) +{ + int chance; + + if (!self->monsterinfo.lefty) + MG_CheckEvade(self); + + if (self->enemy && self->monsterinfo.stepState) + { + if (self->dmg < self->max_health) + { + M_ShowLifeMeter( self, self->dmg, self->dmg); + self->dmg+=50; + } + else + { + M_ShowLifeMeter( self, self->health, self->max_health); + mork_check_killed_enemy(self->enemy); + } + } + + //Check for a teleport razzing + if (self->monsterinfo.jump_time > 0 && self->monsterinfo.jump_time < level.time) + { + if (self->monsterinfo.stepState) + { + morcalavin_init_phase_in(self); + self->monsterinfo.jump_time = -1; + self->monsterinfo.sound_start = -1; + morcalavin_teleport_attack(self); + return; + } + else + { + morcalavin_teleport_attack(self); + self->monsterinfo.jump_time = -1; + return; + } + } + + //Check for a pending taunt + if (self->monsterinfo.sound_start > 0 && self->monsterinfo.sound_start < level.time) + { + switch (self->monsterinfo.lefty) + { + case 1: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH1], 1, ATTN_NONE, 0); + self->monsterinfo.sound_start = -1; + self->monsterinfo.jump_time = level.time + 1.0; + self->monsterinfo.lefty++; + break; + + case 2: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_BELLY1], 1, ATTN_NONE, 0); + self->monsterinfo.sound_start = -1; + self->monsterinfo.jump_time = level.time + 8.0; + self->monsterinfo.lefty++; + break; + + case 3: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_BELLY2], 1, ATTN_NONE, 0); + self->monsterinfo.sound_start = -1; + self->monsterinfo.jump_time = level.time + 5.0; + self->monsterinfo.lefty++; + break; + + case 4: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_BELLY3], 1, ATTN_NONE, 0); + self->monsterinfo.sound_start = -1; + self->monsterinfo.jump_time = level.time + 7.0; + self->monsterinfo.lefty++; + break; + + case 5: + chance = irand(0,6); + switch (chance) + { + case 0: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH2], 1, ATTN_NONE, 0); + break; + + case 1: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH3], 1, ATTN_NONE, 0); + break; + + case 2: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH4], 1, ATTN_NONE, 0); + break; + + default: + break; + } + + self->monsterinfo.sound_start = -1; + self->monsterinfo.jump_time = level.time + 1.0; + break; + + case 6: + self->monsterinfo.jump_time = -1; + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH1], 1, ATTN_NONE, 0); + + if (!self->targetEnt) + { +#ifdef _DEVEL + if (level.time < 5.0) // Otherwise it will print forever after Morcalavin is dead. + gi.dprintf("GDE Fault: YOU NEED TO PUT A BARRIER IN THIS ROOM FOR THE GAME TO WORK!!!n"); +#endif + return; + } + + self->svflags &= ~SVF_NO_AUTOTARGET; + + if (self->delay) + { + self->monsterinfo.sound_start = self->monsterinfo.attack_finished = level.time + ( self->delay ); + self->monsterinfo.sound_start += 1.5; + self->targetEnt->monsterinfo.attack_finished = self->monsterinfo.attack_finished; + self->delay *= 2; + } + else + { + self->monsterinfo.sound_start = level.time + 3.5; + self->monsterinfo.attack_finished = level.time + 2.0; + self->delay = 2; + } + + self->monsterinfo.lefty++; + break; + + case 7: + self->monsterinfo.sound_start = -1; + gi.sound(self, CHAN_AUTO, sounds[SND_LAUGH], 1, ATTN_NONE, 0); + self->monsterinfo.jump_time = -1; + break; + + case 8: + /* + chance = irand(0,2); + switch (chance) + { + case 0: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH2], 1, ATTN_NONE, 0); + break; + + case 1: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH3], 1, ATTN_NONE, 0); + break; + + case 2: + gi.sound(self, CHAN_AUTO, sounds[TAUNT_LAUGH4], 1, ATTN_NONE, 0); + break; + + default: + break; + }*/ + + self->monsterinfo.sound_start = -1; + self->monsterinfo.jump_time = level.time + 1.0; + break; + } + } + + self->next_post_think = level.time + 0.05; +} + +int morcalavin_resist_death (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ + vec3_t vf, vr, temp; + + self->msgHandler = DeadMsgHandler; + + gi.sound(self, CHAN_VOICE, sounds[SND_FALL], 1, ATTN_NORM, 0); + SetAnim(self, ANIM_FALL); + + self->s.color.a = 0xFFFFFFFF; + self->pre_think = NULL; + self->next_pre_think = -1; + + self->takedamage = DAMAGE_NO; + self->dmg = 1; + self->health = self->max_health = MonsterHealth(MORK_HEALTH); + self->monsterinfo.sound_start = level.time + 2.5; + self->solid = SOLID_BBOX; + + self->monsterinfo.stepState++; + self->monsterinfo.lefty = 6; + + //Check to release a charging weapon + if (self->target_ent) + { + AngleVectors(self->s.angles, vf, vr, NULL); + VectorMA(self->s.origin, 10, vf, self->target_ent->s.origin); + VectorMA(self->target_ent->s.origin, 14, vr, self->target_ent->s.origin); + self->target_ent->s.origin[2] += 42; + + VectorScale(vf, 400, self->target_ent->velocity); + + self->target_ent->think = morcalavin_check_lightning; + self->target_ent->nextthink = level.time + 0.1; + } + + //TODO: Create an effect around him + VectorClear(temp); + temp[0] = self->delay; + + /* + gi.CreateEffect( &self->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + self->s.origin, + "bv", + FX_MORK_RECHARGE, + temp); + */ + + //TODO: Create a barrier around him so the player cannot get close to him + + return false; +} + +/*QUAKED monster_morcalavin(1 .5 0) (-24 -24 -50) (24 24 40) + +Morky + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +*/ +void SP_monster_morcalavin (edict_t *self) +{ + if (!walkmonster_start(self)) // Failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_MORK; + + self->classname = "monster_morcalavin"; + + if (!self->health) + self->health = MORK_HEALTH1; + + //Apply to the end result (whether designer set or not) + self->max_health = self->health = MonsterHealth(self->health); + + self->mass = MORK_MASS; + self->yaw_speed = 24; + + self->movetype = PHYSICSTYPE_STEP; + self->solid=SOLID_BBOX; + + //This is the number of times he's died (used to calculate window of opportunity for the player) + self->delay = 0.0; + + self->s.origin[2] += 50; + VectorSet(self->mins, -24, -24, -48); + VectorSet(self->maxs, 24, 24, 40); + + self->viewheight = 36; + + self->materialtype = MAT_FLESH; + + self->s.modelindex = classStatics[CID_MORK].resInfo->modelIndex; + self->s.skinnum=0; + + self->monsterinfo.otherenemyname = "player"; + + self->post_think = morcalavin_postthink; + self->next_post_think = level.time + 0.1; + + if (self->monsterinfo.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + MG_InitMoods( self ); + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + + self->s.color.c = 0xFFFFFFFF; + + self->s.renderfx |= RF_GLOW; + + self->monsterinfo.stepState = 0; + self->svflags |= SVF_BOSS | SVF_FLOAT; + self->count = self->s.modelindex; // For Cinematic purposes + self->gravity = MORK_GRAV; + + self->die = morcalavin_resist_death; + + gi.linkentity(self); +} + +/*QUAKED obj_morcalavin_barrier (1 .5 0) ? ? + +The magical barrier that prevents the player from entering the tome area and defeating +Morcalavin + +*/ + +void morcalavin_barrier_think(edict_t *self) +{ + edict_t *owner = NULL; + + //If we haven't found an owner yet, find one + if (!self->owner) + { + owner = G_Find(NULL, FOFS(classname), "monster_morcalavin"); + + if (!owner) + { +// gi.dprintf("Unable to bind barrier to Morcalavin!\n"); + } + else + { + self->owner = owner; + owner->targetEnt = self; + } + } + + if (self->monsterinfo.attack_finished > level.time) + { + self->count = false; + self->svflags |= SVF_NOCLIENT; + } + else + { + self->count = true; + self->svflags &= ~SVF_NOCLIENT; + } + + self->nextthink = level.time + 0.1; +} + +void morcalavin_barrier_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + vec3_t vel; + + if (!strcmp(other->classname, "player")) + { + if (self->count) + { + VectorSubtract(self->s.origin, other->s.origin, vel); + VectorNormalize(vel); + VectorScale(vel, -1, vel); + VectorScale(vel, 512, other->velocity); + other->velocity[2] = 128; + other->client->playerinfo.flags |= PLAYER_FLAG_USE_ENT_POS; + + //NOTENOTE: We should always have an owner.. but this is for safety + if (self->owner) + T_Damage(other, self, self->owner, vel, other->s.origin, vel, irand(5, 10), 250, DAMAGE_AVOID_ARMOR, MOD_DIED); + else + T_Damage(other, self, self, vel, other->s.origin, vel, irand(5, 10), 250, DAMAGE_AVOID_ARMOR, MOD_DIED); + + if (self->delay < level.time) + { + self->delay = level.time + 0.5; + + gi.CreateEffect( NULL, + FX_WEAPON_STAFF_STRIKE, + 0, + other->s.origin, + "db", + vel, + 2); + } + } + } +} + +void morcalavin_barrier_use (edict_t *self, edict_t *other, edict_t *activator) +{ + //Become visible again + self->svflags &= ~SVF_NOCLIENT; + + //Never do this again + self->use = NULL; + + //Start blocking + self->think = morcalavin_barrier_think; + self->nextthink = level.time + 0.1; +} + +void SP_obj_morcalavin_barrier (edict_t *self) +{ + gi.setmodel(self, self->model); + + self->solid = SOLID_TRIGGER; + self->movetype = PHYSICSTYPE_NONE; + + self->touch = morcalavin_barrier_touch; + self->use = morcalavin_barrier_use; + + self->s.color.c = 0xFFFFFFFF; + self->count = 1; + self->health = true; + + gi.linkentity(self); + + //Be invisible until used + self->svflags |= SVF_NOCLIENT; +} + diff --git a/Toolkit/Programming/GameCode/game/m_morcalavin.h b/Toolkit/Programming/GameCode/game/m_morcalavin.h new file mode 100644 index 0000000..eab6569 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_morcalavin.h @@ -0,0 +1,133 @@ +#include "g_local.h" + +typedef enum AnimID_e +{ + ANIM_FLOAT, + ANIM_HURTIDLE, + ANIM_ATTACK1, + ANIM_ATTACK2, + ANIM_ATTACK2B, + ANIM_ATTACK3, + ANIM_DEF1, + ANIM_DEF2, + ANIM_WALK, + ANIM_FLY, + ANIM_GETUP, + ANIM_RETORT, + ANIM_FALL, + ANIM_GLIDE, + ANIM_GROUND_ATTACK, + ANIM_TRACKING1, + ANIM_ATTACK4, + + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ +//quake attack + SND_QUAKE, +//straightt-fire beam + SND_BEAM, + SND_BEAMHIT, +//homing balls + SND_HOMING, + SND_HOMEHIT, +//power Puff + SND_PPCHARGE, + SND_PPFIRE, + SND_PPEXPLODE, +//Lightning from eyes + SND_LIGHTNING, + SND_LGHTNGHIT, +//Shove + SND_FORCEWALL, +//Shield + SND_MAKESHIELD, + SND_SHIELDHIT, + SND_SHIELDPULSE, + SND_SHIELDGONE, + SND_SHIELDBREAK, +//Fly forward + SND_RUSH, +//hurt and get up + SND_FALL, + SND_REVIVE, +//strafing beams attack + SND_STRAFEON, + SND_STRFSWNG, + SND_STRAFEOFF, +//hurt/kill player laugh + SND_LAUGH, + +//Taunt sounds + TAUNT_LAUGH1, + TAUNT_LAUGH2, + TAUNT_LAUGH3, + TAUNT_LAUGH4, + + TAUNT_BELLY1, + TAUNT_BELLY2, + TAUNT_BELLY3, + + NUM_SOUNDS +} SoundID_t; + +extern animmove_t morcalavin_move_float, + morcalavin_move_hurtidle, + morcalavin_move_attack1, + morcalavin_move_attack2, + morcalavin_move_attack2b, + morcalavin_move_attack3, + morcalavin_move_def1, + morcalavin_move_def2, + morcalavin_move_walk, + morcalavin_move_fly, + morcalavin_move_getup, + morcalavin_move_retort, + morcalavin_move_fall, + morcalavin_move_glide, + morcalavin_move_ground_attack, + morcalavin_move_tracking_attack1, + morcalavin_move_attack4; + +//void morcalavin_fire1( edict_t *self, float pitch_ofs, float yaw_ofs, float roll_ofs ); +//void morcalavin_strike( edict_t *self, float damage ); +void morcalavin_idle( edict_t *self ); +void morcalavin_move( edict_t *self, float vf, float vr, float vu ); +void morcalavin_pause( edict_t *self ); +void morcalavin_retort( edict_t *self); +void morcalavin_getup( edict_t *self); +void morcalavin_hurtidle( edict_t *self); +//void morcalavin_shove (edict_t *self, float mindist, float maxdist, float throwproj); +//void morcalavin_summon_shield (edict_t *self); +//void morcalavin_lightning (edict_t *self); +//void morcalavin_powerpuff(edict_t *self); +//void morcalavin_startpuff (edict_t *self); +void morcalavin_quake( edict_t *self, float pitch_ofs, float yaw_ofs, float roll_ofs ); +//void morcalavin_galaxy (edict_t *self); +void morcalavin_beam( edict_t *self); +void morcalavin_beam2( edict_t *self); +void morcalavin_rush_sound (edict_t *self); +void mork_ai_run (edict_t *self, float dist); +void mork_ai_hover (edict_t *self, float dist); + +void morcalavin_ground_attack( edict_t *self ); +void morcalavin_quake_pause( edict_t *self ); +void morcalavin_init_phase_out (edict_t *self); +void MG_CheckEvade (edict_t *self); +void morcalavin_fade_out(edict_t *self); +void morcalavin_taunt_shot(edict_t *self); + +void morcalavin_start_missile(edict_t *self); +void morcalavin_release_missile(edict_t *self); +void morcalavin_proj1_blocked( edict_t *self, trace_t *trace ); +void morcalavin_tracking_projectile ( edict_t *self, float pitch, float yaw, float roll); +void morcalavin_big_shot( edict_t *self ); +void morcalavin_check_lightning(edict_t *self); +void morcalavin_proj2_blocked( edict_t *self, trace_t *trace ); +void morcalavin_attack_fade_out(edict_t *self); +void morcalavin_end_retort(edict_t *self); +void morcalavin_proj3_blocked( edict_t *self, trace_t *trace ); + +#define MORK_GRAV 0.3 \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/m_morcalavin_anim.c b/Toolkit/Programming/GameCode/game/m_morcalavin_anim.c new file mode 100644 index 0000000..604914f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_morcalavin_anim.c @@ -0,0 +1,421 @@ +#include "g_local.h" +#include "m_morcalavin.h" +#include "m_morcalavin_anim.h" + +animframe_t morcalavin_frames_float[] = +{ + FRAME_fltidl1, NULL, 0, 0, 0, mork_ai_hover, 60, NULL, + FRAME_fltidl2, NULL, 0, 0, 0, mork_ai_hover, 59, NULL, + FRAME_fltidl3, NULL, 0, 0, 0, mork_ai_hover, 58, NULL, + FRAME_fltidl4, NULL, 0, 0, 0, mork_ai_hover, 57, NULL, + FRAME_fltidl5, NULL, 0, 0, 0, mork_ai_hover, 56, NULL, + FRAME_fltidl6, NULL, 0, 0, 0, mork_ai_hover, 55, NULL, + FRAME_fltidl7, NULL, 0, 0, 0, mork_ai_hover, 54, NULL, + FRAME_fltidl8, NULL, 0, 0, 0, mork_ai_hover, 53, NULL, + FRAME_fltidl9, NULL, 0, 0, 0, mork_ai_hover, 52, NULL, + FRAME_fltidl10, NULL, 0, 0, 0, mork_ai_hover, 53, NULL, + FRAME_fltidl11, NULL, 0, 0, 0, mork_ai_hover, 54, NULL, + FRAME_fltidl12, NULL, 0, 0, 0, mork_ai_hover, 55, NULL, + FRAME_fltidl13, NULL, 0, 0, 0, mork_ai_hover, 56, NULL, + FRAME_fltidl14, NULL, 0, 0, 0, mork_ai_hover, 57, NULL, + FRAME_fltidl15, NULL, 0, 0, 0, mork_ai_hover, 58, NULL, +// FRAME_fltidl16, NULL, 0, 0, 0, mork_ai_hover, 59, NULL, +}; +animmove_t morcalavin_move_float = {15,morcalavin_frames_float, morcalavin_idle}; + +animframe_t morcalavin_frames_hurtidle[] = +{ + FRAME_hrtidl1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hrtidl17, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t morcalavin_move_hurtidle = {17,morcalavin_frames_hurtidle, morcalavin_getup}; + +animframe_t morcalavin_frames_attack1[] = +{ + FRAME_ataka1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka9, morcalavin_quake, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_ataka13, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t morcalavin_move_attack1 = {13, morcalavin_frames_attack1, morcalavin_quake_pause}; + +//Attack 2 + +animframe_t morcalavin_frames_attack2[] = +{ + FRAME_atakb1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb1, NULL, 0, 0, 0, ai_charge, 0, NULL, +// Go + FRAME_atakb1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb8, NULL, 0, 0, 0, ai_charge, 0, morcalavin_taunt_shot, //Release + FRAME_atakb9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb17, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t morcalavin_move_attack2 = {22,morcalavin_frames_attack2, morcalavin_fade_out}; + +animframe_t morcalavin_frames_attack2b[] = +{ + FRAME_atakb1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb8, NULL, 0, 0, 0, ai_charge, 0, morcalavin_beam, + FRAME_atakb9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb17, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t morcalavin_move_attack2b = {17,morcalavin_frames_attack2b, morcalavin_pause}; +//Attack 3 + +animframe_t morcalavin_frames_attack3[] = +{ + FRAME_atakc1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc3, NULL, 0, 0, 0, ai_charge, 0, morcalavin_start_missile, + FRAME_atakc4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc15, NULL, 0, 0, 0, ai_charge, 0, morcalavin_release_missile, + FRAME_atakc16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc17, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc18, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc19, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc20, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakc21, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t morcalavin_move_attack3 = {21,morcalavin_frames_attack3, morcalavin_pause}; + + + +animframe_t morcalavin_frames_def1[] = +{ + FRAME_defnsa1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa6, NULL, 0, 100, true, ai_charge, 0, NULL, + FRAME_defnsa7, NULL, 100, 200, 0, ai_charge, 0, NULL, + FRAME_defnsa8, NULL, 200, 300, 0, ai_charge, 0, NULL, + FRAME_defnsa9, NULL, 300, 400, 0, ai_charge, 0, NULL, + FRAME_defnsa10, NULL, 400, 500, 0, ai_charge, 0, NULL, + FRAME_defnsa11, NULL, 500, 600, 0, ai_charge, 0, NULL, + FRAME_defnsa12, NULL, 600, 700, 0, ai_charge, 0, NULL, + FRAME_defnsa13, NULL, 700, 800, 0, ai_charge, 0, NULL, + FRAME_defnsa14, NULL, 800, 900, 0, ai_charge, 0, NULL, + FRAME_defnsa15, NULL, 900, 1000, 0, ai_charge, 0, NULL, + FRAME_defnsa15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa17, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa18, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa19, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa20, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa21, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t morcalavin_move_def1 = {21,morcalavin_frames_def1, morcalavin_pause}; + +animframe_t morcalavin_frames_def2[] = +{ + FRAME_defnsb1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb5, NULL, 0, 0, 0, ai_charge, 0, NULL,//morcalavin_summon_shield, + FRAME_defnsb6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb17, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t morcalavin_move_def2 = {17,morcalavin_frames_def2, morcalavin_pause}; + +animframe_t morcalavin_frames_walk[] = +{ + FRAME_walk1, NULL, 0, 0, 0, mork_ai_run, 6, NULL, + FRAME_walk2, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_walk3, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_walk4, NULL, 0, 0, 0, mork_ai_run, 8, morcalavin_pause, + FRAME_walk5, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_walk6, NULL, 0, 0, 0, mork_ai_run, 6, NULL, + FRAME_walk7, NULL, 0, 0, 0, mork_ai_run, 6, NULL, + FRAME_walk8, NULL, 0, 0, 0, mork_ai_run, 4, morcalavin_pause, + FRAME_walk9, NULL, 0, 0, 0, mork_ai_run, 6, NULL, + FRAME_walk10, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_walk11, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_walk12, NULL, 0, 0, 0, mork_ai_run, 8, NULL, +}; +animmove_t morcalavin_move_walk = {12,morcalavin_frames_walk, morcalavin_pause}; + +animframe_t morcalavin_frames_fly[] = +{ + FRAME_fltmve1, NULL, 0, 0, 0, mork_ai_run, 16, morcalavin_rush_sound, + FRAME_fltmve2, NULL, 0, 0, 0, mork_ai_run, 24, NULL, + FRAME_fltmve3, NULL, 0, 0, 0, mork_ai_run, 24, NULL, + FRAME_fltmve4, NULL, 0, 0, 0, mork_ai_run, 24, NULL, + FRAME_fltmve5, NULL, 0, 0, 0, mork_ai_run, 24, NULL, + FRAME_fltmve6, NULL, 0, 0, 0, mork_ai_run, 16, NULL, + FRAME_fltmve7, NULL, 0, 0, 0, mork_ai_run, 16, NULL, + FRAME_fltmve8, NULL, 0, 0, 0, mork_ai_run, 12, NULL, + FRAME_fltmve9, NULL, 0, 0, 0, mork_ai_run, 16, NULL, + FRAME_fltmve10, NULL, 0, 0, 0, mork_ai_run, 24, NULL, + FRAME_fltmve11, NULL, 0, 0, 0, mork_ai_run, 24, NULL, + FRAME_fltmve12, NULL, 0, 0, 0, mork_ai_run, 24, NULL, + FRAME_fltmve13, NULL, 0, 0, 0, mork_ai_run, 24, NULL, + FRAME_fltmve14, NULL, 0, 0, 0, mork_ai_run, 16, NULL, + FRAME_fltmve15, NULL, 0, 0, 0, mork_ai_run, 16, NULL, +}; +animmove_t morcalavin_move_fly = {15,morcalavin_frames_fly, morcalavin_pause}; + +animframe_t morcalavin_frames_getup[] = +{ + FRAME_getupa1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_getupa2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_getupa3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_getupa4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_getupa5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_getupa6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_getupa7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_getupa8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_getupa9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_getupa10, NULL, 0, 0, 0, mork_ai_hover, 15, NULL, + FRAME_getupa11, NULL, 0, 0, 0, mork_ai_hover, 30, NULL, + FRAME_getupa12, NULL, 0, 0, 0, mork_ai_hover, 60, NULL, + FRAME_getupa13, NULL, 0, 0, 0, mork_ai_hover, 90, NULL, + FRAME_getupa14, NULL, 0, 0, 0, mork_ai_hover, 120, NULL, +}; +animmove_t morcalavin_move_getup = {14,morcalavin_frames_getup, morcalavin_retort}; + +animframe_t morcalavin_frames_retort[] = +{ + FRAME_getupb1, NULL, 0, 0, 0, mork_ai_hover, 120, NULL, + FRAME_getupb2, NULL, 0, 0, 0, mork_ai_hover, 120, NULL, + FRAME_getupb3, NULL, 0, 0, 0, mork_ai_hover, 120, NULL, + FRAME_getupb4, NULL, 0, 0, 0, mork_ai_hover, 120, NULL, + FRAME_getupb5, NULL, 0, 0, 0, mork_ai_hover, 115, NULL, + FRAME_getupb6, NULL, 0, 0, 0, mork_ai_hover, 110, NULL, + FRAME_getupb7, NULL, 0, 0, 0, mork_ai_hover, 105, NULL, + FRAME_getupb8, NULL, 0, 0, 0, mork_ai_hover, 100, NULL, + FRAME_getupb9, NULL, 0, 0, 0, mork_ai_hover, 80, NULL, + FRAME_getupb10, NULL, 0, 0, 0, mork_ai_hover, 60, NULL, + FRAME_getupb11, NULL, 0, 0, 0, mork_ai_hover, 40, NULL, + FRAME_getupb12, NULL, 0, 0, 0, mork_ai_hover, 20, NULL, + FRAME_getupb13, NULL, 0, 0, 0, mork_ai_hover, 15, NULL, + FRAME_getupb14, NULL, 0, 0, 0, mork_ai_hover, 10, NULL, + FRAME_getupb15, NULL, 0, 0, 0, mork_ai_hover, 5, NULL, + FRAME_getupb16, NULL, 0, 0, 0, mork_ai_hover, 2, NULL, + FRAME_getupb17, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupb18, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc1, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc2, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc3, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc4, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc5, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc6, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc7, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc8, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc9, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc10, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc11, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc12, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc13, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc14, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc15, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, + FRAME_getupc16, NULL, 0, 0, 0, mork_ai_hover, 0, NULL, +}; +animmove_t morcalavin_move_retort = {34, morcalavin_frames_retort, morcalavin_end_retort}; + +animframe_t morcalavin_frames_fall[] = +{ + FRAME_knkdwn1, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn2, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn3, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn4, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn5, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn6, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn7, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn8, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn9, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn10, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn11, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn12, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn13, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn14, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn15, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn16, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn17, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn18, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn19, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn20, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_knkdwn21, NULL, 0, 0, 0, ai_move, -8, NULL, +}; +animmove_t morcalavin_move_fall = {21,morcalavin_frames_fall, morcalavin_hurtidle}; + +animframe_t morcalavin_frames_glide[] = +{ + FRAME_fltmve1, NULL, 0, 0, 0, mork_ai_run, 6, NULL, + FRAME_fltmve2, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_fltmve3, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_fltmve4, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_fltmve5, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_fltmve6, NULL, 0, 0, 0, mork_ai_run, 6, NULL, + FRAME_fltmve7, NULL, 0, 0, 0, mork_ai_run, 6, NULL, + FRAME_fltmve8, NULL, 0, 0, 0, mork_ai_run, 4, NULL, + FRAME_fltmve9, NULL, 0, 0, 0, mork_ai_run, 6, NULL, + FRAME_fltmve10, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_fltmve11, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_fltmve12, NULL, 0, 0, 0, mork_ai_run, 8, NULL, + FRAME_fltmve13, NULL, 0, 0, 0, mork_ai_run, 6, NULL, + FRAME_fltmve14, NULL, 0, 0, 0, mork_ai_run, 4, NULL, + FRAME_fltmve15, NULL, 0, 0, 0, mork_ai_run, 8, NULL, +}; +animmove_t morcalavin_move_glide = {15,morcalavin_frames_glide, morcalavin_pause}; + +animframe_t morcalavin_frames_tracking_attack1[] = +{ + FRAME_defnsb1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb4, morcalavin_tracking_projectile, 0, 0, -60, ai_charge, 0, NULL, + FRAME_defnsb5, morcalavin_tracking_projectile, 0, 0, -30, ai_charge, 0, NULL, + FRAME_defnsb6, morcalavin_tracking_projectile, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb7, morcalavin_tracking_projectile, 0, 0, 30, ai_charge, 0, NULL, + FRAME_defnsb8, morcalavin_tracking_projectile, 0, 0, 60, ai_charge, 0, NULL, + FRAME_defnsb9, morcalavin_tracking_projectile, 0, 0, 90, ai_charge, 0, NULL, + FRAME_defnsb10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsb17, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t morcalavin_move_tracking_attack1 = {17, morcalavin_frames_tracking_attack1, morcalavin_pause}; + +animframe_t morcalavin_frames_ground_attack[] = +{ + FRAME_atakb1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb8, NULL, 0, 0, 0, ai_charge, 0, morcalavin_beam2, + FRAME_atakb9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atakb17, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t morcalavin_move_ground_attack = {17,morcalavin_frames_ground_attack, morcalavin_pause}; + +animframe_t morcalavin_frames_attack4[] = +{ + FRAME_defnsa1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa9, NULL, 0, 0, 0, ai_charge, 0, morcalavin_big_shot, + FRAME_defnsa10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa9, NULL, 0, 0, 0, ai_charge, 0, morcalavin_big_shot, + FRAME_defnsa10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa9, NULL, 0, 0, 0, ai_charge, 0, morcalavin_big_shot, + FRAME_defnsa10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa9, NULL, 0, 0, 0, ai_charge, 0, morcalavin_big_shot, + FRAME_defnsa10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa9, NULL, 0, 0, 0, ai_charge, 0, morcalavin_big_shot, + FRAME_defnsa10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa17, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa18, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa19, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa20, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_defnsa21, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t morcalavin_move_attack4 = {37,morcalavin_frames_attack4, morcalavin_pause}; diff --git a/Toolkit/Programming/GameCode/game/m_morcalavin_anim.h b/Toolkit/Programming/GameCode/game/m_morcalavin_anim.h new file mode 100644 index 0000000..0026b59 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_morcalavin_anim.h @@ -0,0 +1,240 @@ +// R:\Art\models/monsters\morcalavin\work + +// This file generated by qdata - Do NOT Modify + +#define FRAME_ataka1 0 +#define FRAME_ataka2 1 +#define FRAME_ataka3 2 +#define FRAME_ataka4 3 +#define FRAME_ataka5 4 +#define FRAME_ataka6 5 +#define FRAME_ataka7 6 +#define FRAME_ataka8 7 +#define FRAME_ataka9 8 +#define FRAME_ataka10 9 +#define FRAME_ataka11 10 +#define FRAME_ataka12 11 +#define FRAME_ataka13 12 +#define FRAME_atakb1 13 +#define FRAME_atakb2 14 +#define FRAME_atakb3 15 +#define FRAME_atakb4 16 +#define FRAME_atakb5 17 +#define FRAME_atakb6 18 +#define FRAME_atakb7 19 +#define FRAME_atakb8 20 +#define FRAME_atakb9 21 +#define FRAME_atakb10 22 +#define FRAME_atakb11 23 +#define FRAME_atakb12 24 +#define FRAME_atakb13 25 +#define FRAME_atakb14 26 +#define FRAME_atakb15 27 +#define FRAME_atakb16 28 +#define FRAME_atakb17 29 +#define FRAME_atakc1 30 +#define FRAME_atakc2 31 +#define FRAME_atakc3 32 +#define FRAME_atakc4 33 +#define FRAME_atakc5 34 +#define FRAME_atakc6 35 +#define FRAME_atakc7 36 +#define FRAME_atakc8 37 +#define FRAME_atakc9 38 +#define FRAME_atakc10 39 +#define FRAME_atakc11 40 +#define FRAME_atakc12 41 +#define FRAME_atakc13 42 +#define FRAME_atakc14 43 +#define FRAME_atakc15 44 +#define FRAME_atakc16 45 +#define FRAME_atakc17 46 +#define FRAME_atakc18 47 +#define FRAME_atakc19 48 +#define FRAME_atakc20 49 +#define FRAME_atakc21 50 +#define FRAME_defnsa1 51 +#define FRAME_defnsa2 52 +#define FRAME_defnsa3 53 +#define FRAME_defnsa4 54 +#define FRAME_defnsa5 55 +#define FRAME_defnsa6 56 +#define FRAME_defnsa7 57 +#define FRAME_defnsa8 58 +#define FRAME_defnsa9 59 +#define FRAME_defnsa10 60 +#define FRAME_defnsa11 61 +#define FRAME_defnsa12 62 +#define FRAME_defnsa13 63 +#define FRAME_defnsa14 64 +#define FRAME_defnsa15 65 +#define FRAME_defnsa16 66 +#define FRAME_defnsa17 67 +#define FRAME_defnsa18 68 +#define FRAME_defnsa19 69 +#define FRAME_defnsa20 70 +#define FRAME_defnsa21 71 +#define FRAME_defnsb1 72 +#define FRAME_defnsb2 73 +#define FRAME_defnsb3 74 +#define FRAME_defnsb4 75 +#define FRAME_defnsb5 76 +#define FRAME_defnsb6 77 +#define FRAME_defnsb7 78 +#define FRAME_defnsb8 79 +#define FRAME_defnsb9 80 +#define FRAME_defnsb10 81 +#define FRAME_defnsb11 82 +#define FRAME_defnsb12 83 +#define FRAME_defnsb13 84 +#define FRAME_defnsb14 85 +#define FRAME_defnsb15 86 +#define FRAME_defnsb16 87 +#define FRAME_defnsb17 88 +#define FRAME_fltidl1 89 +#define FRAME_fltidl2 90 +#define FRAME_fltidl3 91 +#define FRAME_fltidl4 92 +#define FRAME_fltidl5 93 +#define FRAME_fltidl6 94 +#define FRAME_fltidl7 95 +#define FRAME_fltidl8 96 +#define FRAME_fltidl9 97 +#define FRAME_fltidl10 98 +#define FRAME_fltidl11 99 +#define FRAME_fltidl12 100 +#define FRAME_fltidl13 101 +#define FRAME_fltidl14 102 +#define FRAME_fltidl15 103 +#define FRAME_fltidl16 104 +#define FRAME_fltmve1 105 +#define FRAME_fltmve2 106 +#define FRAME_fltmve3 107 +#define FRAME_fltmve4 108 +#define FRAME_fltmve5 109 +#define FRAME_fltmve6 110 +#define FRAME_fltmve7 111 +#define FRAME_fltmve8 112 +#define FRAME_fltmve9 113 +#define FRAME_fltmve10 114 +#define FRAME_fltmve11 115 +#define FRAME_fltmve12 116 +#define FRAME_fltmve13 117 +#define FRAME_fltmve14 118 +#define FRAME_fltmve15 119 +#define FRAME_getupa1 120 +#define FRAME_getupa2 121 +#define FRAME_getupa3 122 +#define FRAME_getupa4 123 +#define FRAME_getupa5 124 +#define FRAME_getupa6 125 +#define FRAME_getupa7 126 +#define FRAME_getupa8 127 +#define FRAME_getupa9 128 +#define FRAME_getupa10 129 +#define FRAME_getupa11 130 +#define FRAME_getupa12 131 +#define FRAME_getupa13 132 +#define FRAME_getupa14 133 +#define FRAME_getupb1 134 +#define FRAME_getupb2 135 +#define FRAME_getupb3 136 +#define FRAME_getupb4 137 +#define FRAME_getupb5 138 +#define FRAME_getupb6 139 +#define FRAME_getupb7 140 +#define FRAME_getupb8 141 +#define FRAME_getupb9 142 +#define FRAME_getupb10 143 +#define FRAME_getupb11 144 +#define FRAME_getupb12 145 +#define FRAME_getupb13 146 +#define FRAME_getupb14 147 +#define FRAME_getupb15 148 +#define FRAME_getupb16 149 +#define FRAME_getupb17 150 +#define FRAME_getupb18 151 +#define FRAME_getupc1 152 +#define FRAME_getupc2 153 +#define FRAME_getupc3 154 +#define FRAME_getupc4 155 +#define FRAME_getupc5 156 +#define FRAME_getupc6 157 +#define FRAME_getupc7 158 +#define FRAME_getupc8 159 +#define FRAME_getupc9 160 +#define FRAME_getupc10 161 +#define FRAME_getupc11 162 +#define FRAME_getupc12 163 +#define FRAME_getupc13 164 +#define FRAME_getupc14 165 +#define FRAME_getupc15 166 +#define FRAME_getupc16 167 +#define FRAME_hrtidl1 168 +#define FRAME_hrtidl2 169 +#define FRAME_hrtidl3 170 +#define FRAME_hrtidl4 171 +#define FRAME_hrtidl5 172 +#define FRAME_hrtidl6 173 +#define FRAME_hrtidl7 174 +#define FRAME_hrtidl8 175 +#define FRAME_hrtidl9 176 +#define FRAME_hrtidl10 177 +#define FRAME_hrtidl11 178 +#define FRAME_hrtidl12 179 +#define FRAME_hrtidl13 180 +#define FRAME_hrtidl14 181 +#define FRAME_hrtidl15 182 +#define FRAME_hrtidl16 183 +#define FRAME_hrtidl17 184 +#define FRAME_knkdwn1 185 +#define FRAME_knkdwn2 186 +#define FRAME_knkdwn3 187 +#define FRAME_knkdwn4 188 +#define FRAME_knkdwn5 189 +#define FRAME_knkdwn6 190 +#define FRAME_knkdwn7 191 +#define FRAME_knkdwn8 192 +#define FRAME_knkdwn9 193 +#define FRAME_knkdwn10 194 +#define FRAME_knkdwn11 195 +#define FRAME_knkdwn12 196 +#define FRAME_knkdwn13 197 +#define FRAME_knkdwn14 198 +#define FRAME_knkdwn15 199 +#define FRAME_knkdwn16 200 +#define FRAME_knkdwn17 201 +#define FRAME_knkdwn18 202 +#define FRAME_knkdwn19 203 +#define FRAME_knkdwn20 204 +#define FRAME_knkdwn21 205 +#define FRAME_walk1 206 +#define FRAME_walk2 207 +#define FRAME_walk3 208 +#define FRAME_walk4 209 +#define FRAME_walk5 210 +#define FRAME_walk6 211 +#define FRAME_walk7 212 +#define FRAME_walk8 213 +#define FRAME_walk9 214 +#define FRAME_walk10 215 +#define FRAME_walk11 216 +#define FRAME_walk12 217 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 13 + +#define MESH_NULL1 0 +#define MESH__TORSO 1 +#define MESH__CAPE 2 +#define MESH__DRESS 3 +#define MESH__LUPARM 4 +#define MESH__RSHOULDER 5 +#define MESH__L4ARM 6 +#define MESH__HEAD 7 +#define MESH__RUPARM 8 +#define MESH__LHAND 9 +#define MESH__RHAND 10 +#define MESH__LSHOULDER 11 +#define MESH__R4ARM 12 diff --git a/Toolkit/Programming/GameCode/game/m_mother.c b/Toolkit/Programming/GameCode/game/m_mother.c new file mode 100644 index 0000000..8a781f4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_mother.c @@ -0,0 +1,168 @@ +//============================================================================== +// +// m_mother.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// +// AI : +// +// STAND1 : Looking straight ahead +// +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "m_mother.h" +#include "m_mother_anim.h" +#include "g_misc.h" +#include "angles.h" +#include "c_ai.h" +#include "m_stats.h" + + +/*---------------------------------------------------------------------- +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + &mother_move_pain, + &mother_move_stand, +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + + +void mother_growl(edict_t *self) +{ + int chance; + + chance = irand(0,2); + + if (chance == 1) + gi.sound(self, CHAN_BODY, sounds[SND_GROWL1], 1, ATTN_NORM, 0); + else if (chance == 2) + gi.sound(self, CHAN_BODY, sounds[SND_GROWL2], 1, ATTN_NORM, 0); +} + +void mother_pain(edict_t *self, G_Message_t *msg) +{ + int temp, damage; + qboolean force_pain; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_pain, &damage, &temp); + + if (self->pain_debounce_time < level.time) + { + self->pain_debounce_time = level.time + 1; + SetAnim(self, ANIM_PAIN); + } + + gi.sound(self, CHAN_BODY, sounds[SND_PAIN], 1, ATTN_NORM, 0); +} + + + +/*------------------------------------------------------------------------- +-------------------------------------------------------------------------*/ +void mother_stand(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_STAND); + + return; +} + +void mother_pause (edict_t *self) +{ + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + + +void mother_gib(edict_t *self, G_Message_t *msg) +{ + gi.sound(self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + self->think = BecomeDebris; + self->nextthink = level.time + 0.1; +} + +/*------------------------------------------------------------------------- + MotherStaticsInit +-------------------------------------------------------------------------*/ +void MotherStaticsInit() +{ + + classStatics[CID_MOTHER].msgReceivers[MSG_STAND] = mother_stand; + classStatics[CID_MOTHER].msgReceivers[MSG_PAIN] = mother_pain; + classStatics[CID_MOTHER].msgReceivers[MSG_DEATH] = mother_gib; + + sounds[SND_GROWL1]=gi.soundindex("monsters/insect/growlf1.wav"); + sounds[SND_GROWL2] = gi.soundindex ("monsters/insect/growlf2.wav"); + sounds[SND_PAIN] = gi.soundindex("monsters/insect/painf.wav"); + sounds[SND_GIB] = gi.soundindex("monsters/insect/gib.wav"); + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + resInfo.modelIndex = gi.modelindex("models/monsters/mother/tris.fm"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_MOTHER].resInfo = &resInfo; +} + +/*QUAKED monster_tcheckrik_mothers (1 .5 0) (-40 -40 -75) (40 40 75) +Momma egg layer + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) +*/ +void SP_monster_tcheckrik_mothers (edict_t *self) +{ + + self->classID = CID_MOTHER; + + if (!monster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->think = walkmonster_start_go; + + if (!self->health) + { + self->health = PLAGUEELF_HEALTH; + } + + self->mass = 2000; + self->yaw_speed = 20; + + self->movetype = PHYSICSTYPE_STATIC; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + VectorSet (self->mins, -40, -40, -75); + VectorSet (self->maxs, 40, 40, 75); + self->viewheight = self->maxs[2]*0.8; + + self->s.modelindex = classStatics[CID_MOTHER].resInfo->modelIndex; + + if (!self->s.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + self->materialtype = MAT_INSECT; + + self->svflags |= SVF_WAIT_NOTSOLID; + +} + diff --git a/Toolkit/Programming/GameCode/game/m_mother.h b/Toolkit/Programming/GameCode/game/m_mother.h new file mode 100644 index 0000000..b72d48e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_mother.h @@ -0,0 +1,22 @@ +typedef enum AnimID_e +{ + ANIM_PAIN, + ANIM_STAND, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_GROWL1, + SND_GROWL2, + SND_PAIN, + SND_GIB, + + NUM_SOUNDS +} SoundID_t; + +extern animmove_t mother_move_pain; +extern animmove_t mother_move_stand; + +void mother_pause (edict_t *self); + diff --git a/Toolkit/Programming/GameCode/game/m_mother_anim.c b/Toolkit/Programming/GameCode/game/m_mother_anim.c new file mode 100644 index 0000000..558a0e4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_mother_anim.c @@ -0,0 +1,108 @@ +//============================================================================== +// +// m_plagueElf_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_mother_anim.h" +#include "m_mother.h" + +#include "g_monster.h" +#include "c_ai.h" + +void mother_growl(edict_t *self); + +/*---------------------------------------------------------------------- +-----------------------------------------------------------------------*/ +animframe_t mother_frames_pain [] = +{ + FRAME_pain001, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain003, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain005, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain007, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain009, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain011, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain013, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain015, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain017, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain019, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t mother_move_pain = {10, mother_frames_pain, mother_pause}; + +/*---------------------------------------------------------------------- +-----------------------------------------------------------------------*/ +animframe_t mother_frames_stand [] = +{ + FRAME_poly000, NULL, 0, 0, 0, NULL, 0, mother_growl, + FRAME_poly001, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly002, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly003, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly004, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly005, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly006, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly007, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly008, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly009, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly010, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly011, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly012, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly013, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly014, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly015, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly016, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly017, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly018, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly019, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly020, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly021, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly022, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly023, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly024, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly025, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly026, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly027, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly028, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly029, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly030, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly031, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly032, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly033, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly034, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly035, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly036, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly037, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly038, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly039, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly040, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly041, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly042, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly043, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly044, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly045, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly046, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly047, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly048, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly049, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly050, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly051, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly052, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly053, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly054, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly055, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly056, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly057, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly058, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly059, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poly060, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t mother_move_stand = {61, mother_frames_stand, mother_pause}; diff --git a/Toolkit/Programming/GameCode/game/m_mother_anim.h b/Toolkit/Programming/GameCode/game/m_mother_anim.h new file mode 100644 index 0000000..c481d38 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_mother_anim.h @@ -0,0 +1,92 @@ +// R:\Art\models/monsters\mother + +// This file generated by qdata - Do NOT Modify + +#define FRAME_poly000 0 +#define FRAME_poly001 1 +#define FRAME_poly002 2 +#define FRAME_poly003 3 +#define FRAME_poly004 4 +#define FRAME_poly005 5 +#define FRAME_poly006 6 +#define FRAME_poly007 7 +#define FRAME_poly008 8 +#define FRAME_poly009 9 +#define FRAME_poly010 10 +#define FRAME_poly011 11 +#define FRAME_poly012 12 +#define FRAME_poly013 13 +#define FRAME_poly014 14 +#define FRAME_poly015 15 +#define FRAME_poly016 16 +#define FRAME_poly017 17 +#define FRAME_poly018 18 +#define FRAME_poly019 19 +#define FRAME_poly020 20 +#define FRAME_poly021 21 +#define FRAME_poly022 22 +#define FRAME_poly023 23 +#define FRAME_poly024 24 +#define FRAME_poly025 25 +#define FRAME_poly026 26 +#define FRAME_poly027 27 +#define FRAME_poly028 28 +#define FRAME_poly029 29 +#define FRAME_poly030 30 +#define FRAME_poly031 31 +#define FRAME_poly032 32 +#define FRAME_poly033 33 +#define FRAME_poly034 34 +#define FRAME_poly035 35 +#define FRAME_poly036 36 +#define FRAME_poly037 37 +#define FRAME_poly038 38 +#define FRAME_poly039 39 +#define FRAME_poly040 40 +#define FRAME_poly041 41 +#define FRAME_poly042 42 +#define FRAME_poly043 43 +#define FRAME_poly044 44 +#define FRAME_poly045 45 +#define FRAME_poly046 46 +#define FRAME_poly047 47 +#define FRAME_poly048 48 +#define FRAME_poly049 49 +#define FRAME_poly050 50 +#define FRAME_poly051 51 +#define FRAME_poly052 52 +#define FRAME_poly053 53 +#define FRAME_poly054 54 +#define FRAME_poly055 55 +#define FRAME_poly056 56 +#define FRAME_poly057 57 +#define FRAME_poly058 58 +#define FRAME_poly059 59 +#define FRAME_poly060 60 +#define FRAME_pain000 61 +#define FRAME_pain001 62 +#define FRAME_pain002 63 +#define FRAME_pain003 64 +#define FRAME_pain004 65 +#define FRAME_pain005 66 +#define FRAME_pain006 67 +#define FRAME_pain007 68 +#define FRAME_pain008 69 +#define FRAME_pain009 70 +#define FRAME_pain010 71 +#define FRAME_pain011 72 +#define FRAME_pain012 73 +#define FRAME_pain013 74 +#define FRAME_pain014 75 +#define FRAME_pain015 76 +#define FRAME_pain016 77 +#define FRAME_pain017 78 +#define FRAME_pain018 79 +#define FRAME_pain019 80 +#define FRAME_pain020 81 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 1 + +#define MESH_DEFAULT 0 diff --git a/Toolkit/Programming/GameCode/game/m_move.c b/Toolkit/Programming/GameCode/game/m_move.c new file mode 100644 index 0000000..cf03119 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_move.c @@ -0,0 +1,668 @@ +// m_move.c -- monster movement + +#include "g_local.h" +#include "random.h" +#include "vector.h" + +#define STEPSIZE 18 + +/* +============= +M_CheckBottom + +Returns false if any part of the bottom of the entity is off an edge that +is not a staircase. + +============= +*/ +int c_yes, c_no; + +qboolean M_CheckBottom (edict_t *ent) +{ + vec3_t mins, maxs, start, stop; + trace_t trace; + int x, y; + float mid, bottom; + + VectorAdd (ent->s.origin, ent->mins, mins); + VectorAdd (ent->s.origin, ent->maxs, maxs); + +// if all of the points under the corners are solid world, don't bother +// with the tougher checks +// the corners must be within 16 of the midpoint + start[2] = mins[2] - 1; + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + if (gi.pointcontents (start) != CONTENTS_SOLID) + goto realcheck; + } + + c_yes++; + return true; // we got out easy + +realcheck: + c_no++; +// +// check it for real... +// + start[2] = mins[2]; + +// the midpoint must be within 16 of the bottom + start[0] = stop[0] = (mins[0] + maxs[0])*0.5; + start[1] = stop[1] = (mins[1] + maxs[1])*0.5; + stop[2] = start[2] - 2*STEPSIZE; + gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID,&trace); + + if (trace.fraction == 1.0) + return false; + mid = bottom = trace.endpos[2]; + +// the corners must be within 16 of the midpoint + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = stop[0] = x ? maxs[0] : mins[0]; + start[1] = stop[1] = y ? maxs[1] : mins[1]; + + gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID,&trace); + + if (trace.fraction != 1.0 && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) + return false; + } + + c_yes++; + return true; +} + +/* +============= +M_CheckTop + +Returns false if any part of the top of the entity touching something solid + +============= +*/ +int c_yes, c_no; + +qboolean M_CheckTop (edict_t *ent) +{ + vec3_t mins, maxs, start; + int x, y; + + VectorAdd (ent->s.origin, ent->mins, mins); + VectorAdd (ent->s.origin, ent->maxs, maxs); + +// if any of the points over the corners are solid world, don't bother +// with the tougher checks +// the corners must be within 16 of the midpoint + start[2] = maxs[2] + 1; + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + if (gi.pointcontents (start) == CONTENTS_SOLID) + return false; + } + return true; +} + +/* +============= +SV_movestep + +Called by monster program code. +The move will be adjusted for slopes and stairs, but if the move isn't +possible, no move is done, false is returned, and +pr_global_struct->trace_normal is set to the normal of the blocking wall +============= +*/ +//FIXME since we need to test end position contents here, can we avoid doing +//it again later in catagorize position? +qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) +{ + float dz; + vec3_t oldorg, neworg, end; + trace_t trace; + int i; + float stepsize; + vec3_t test; + int contents; + +// try the move + VectorCopy (ent->s.origin, oldorg); + VectorAdd (ent->s.origin, move, neworg); + + if(ent->monsterinfo.scale) + {//scale here, not before! + VectorScale(move, ent->monsterinfo.scale, move); + } + + // flying monsters don't step up + if ( ent->flags & (FL_SWIM | FL_FLY) ) + { + // try one move with vertical motion, then one without + for (i=0 ; i<2 ; i++) + { + VectorAdd (ent->s.origin, move, neworg); + if (i == 0 && ent->enemy) + { + if (!ent->goalentity) + ent->goalentity = ent->enemy; + dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; + if (ent->goalentity->client) + { + if (dz > 40) + neworg[2] -= 8; + if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) + if (dz < 30) + neworg[2] += 8; + } + else + { + if (dz > 8) + neworg[2] -= 8; + else if (dz > 0) + neworg[2] -= dz; + else if (dz < -8) + neworg[2] += 8; + else + neworg[2] += dz; + } + } + gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID,&trace); + + // fly monsters don't enter water voluntarily + if (ent->flags & FL_FLY) + { + if (!ent->waterlevel) + { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent->mins[2] + 1; + contents = gi.pointcontents(test); + if (contents & MASK_WATER) + { + QPostMessage(ent, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return false; + } + } + } + + // swim monsters don't exit water voluntarily + if (ent->flags & FL_SWIM) + { + if (ent->waterlevel < 2) + { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent->mins[2] + 1; + contents = gi.pointcontents(test); + if (!(contents & MASK_WATER)) + { + QPostMessage(ent, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return false; + } + } + } + + if (trace.fraction == 1) + { + VectorCopy (trace.endpos, ent->s.origin); + if (relink) + { + gi.linkentity (ent); + G_TouchTriggers (ent); + } + return true; + } + + if (!ent->enemy) + break; + } + + return false; + } + +// push down from a step height above the wished position + if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) + stepsize = STEPSIZE; + else + stepsize = 1; + + neworg[2] += stepsize; + VectorCopy (neworg, end); + end[2] -= stepsize*2; + + gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID,&trace); + + if (trace.allsolid) + { + QPostMessage(ent, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return false; + } + + if (trace.startsolid) + { + neworg[2] -= stepsize; + gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID,&trace); + if (trace.allsolid || trace.startsolid) + { + QPostMessage(ent, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return false; + } + } + + + // don't go in to water unless only 40% hieght deep + if (ent->waterlevel == 0) + { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent->mins[2];// + 1; + test[2] += (ent->maxs[2] - ent->mins[2]) * 0.4; + contents = gi.pointcontents(test); + + if (contents & MASK_WATER) + return false; + } + + if (trace.fraction == 1) + { + // if monster had the ground pulled out, go ahead and fall + if ( ent->flags & FL_PARTIALGROUND ) + { + VectorAdd (ent->s.origin, move, ent->s.origin); + if (relink) + { + gi.linkentity (ent); + G_TouchTriggers (ent); + } +// ent->groundentity = NULL; +// SV_Printf ("fall down\n"); + return true; + } + QPostMessage(ent, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return false; // walked off an edge + } + +// check point traces down for dangling corners + VectorCopy (trace.endpos, ent->s.origin); + + if (!M_CheckBottom (ent)) + { + if ( ent->flags & FL_PARTIALGROUND ) + { // entity had floor mostly pulled out from underneath it + // and is trying to correct + if (relink) + { + gi.linkentity (ent); + G_TouchTriggers (ent); + } + return true; + } + VectorCopy (oldorg, ent->s.origin); + QPostMessage(ent, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return false; + } + + if ( ent->flags & FL_PARTIALGROUND ) + { +// SV_Printf ("back on ground\n"); + ent->flags &= ~FL_PARTIALGROUND; + } + ent->groundentity = trace.ent; + ent->groundentity_linkcount = trace.ent->linkcount; + +// the move is ok + if (relink) + { + gi.linkentity (ent); + G_TouchTriggers (ent); + } + return true; +} + + +//============================================================================ + +/* +=============== +M_ChangeYaw + +=============== +*/ +float M_ChangeYaw (edict_t *ent) +{ + float ideal; + float current; + float move; + float speed; + + current = anglemod(ent->s.angles[YAW]); + ideal = ent->ideal_yaw; + + if (current == ideal) + return false; + + move = ideal - current; + speed = ent->yaw_speed; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + ent->s.angles[YAW] = anglemod (current + move); + return move; +} + +/* +=============== +M_ChangePitch + +=============== +*/ +void M_ChangePitch (edict_t *ent) +{ + float current; + float move; + + current = anglemod(ent->s.angles[PITCH]); + + if (current == ent->ideal_pitch) + return; + + move = ent->ideal_pitch - current; + if (ent->ideal_pitch > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + //FIXME do we need a pitchspeed? + + ent->s.angles[PITCH] = anglemod (current + move); +} + + + +/* +====================== +SV_StepDirection + +Turns to the movement direction, and walks the current distance if +facing it. + +====================== +*/ +qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) +{ + vec3_t move, oldorigin; + float delta; + + ent->ideal_yaw = yaw; + M_ChangeYaw (ent); + + yaw = yaw*M_PI*2 / 360; + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + VectorCopy (ent->s.origin, oldorigin); + if (SV_movestep (ent, move, false)) + { + delta = ent->s.angles[YAW] - ent->ideal_yaw; + if (delta > 45 && delta < 315) + { // not turned far enough, so don't take the step + VectorCopy (oldorigin, ent->s.origin); + } + gi.linkentity (ent); + G_TouchTriggers (ent); + return true; + } + gi.linkentity (ent); + G_TouchTriggers (ent); + return false; +} + +/* +====================== +SV_FixCheckBottom + +====================== +*/ +void SV_FixCheckBottom (edict_t *ent) +{ +// SV_Printf ("SV_FixCheckBottom\n"); + + ent->flags |= FL_PARTIALGROUND; +} + + + +/* +================ +SV_NewChaseDir + +================ +*/ +#define DI_NODIR -1 +void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) +{ + float deltax,deltay; + float d[3]; + float tdir, olddir, turnaround; + + //FIXME: how did we get here with no enemy + if (!enemy) + return; + + olddir = anglemod( (int)(actor->ideal_yaw/45)*45 ); + turnaround = anglemod(olddir - 180); + + deltax = enemy->s.origin[0] - actor->s.origin[0]; + deltay = enemy->s.origin[1] - actor->s.origin[1]; + if (deltax>10) + d[1]= 0; + else if (deltax<-10) + d[1]= 180; + else + d[1]= DI_NODIR; + if (deltay<-10) + d[2]= 270; + else if (deltay>10) + d[2]= 90; + else + d[2]= DI_NODIR; + +// try direct route + if (d[1] != DI_NODIR && d[2] != DI_NODIR) + { + if (d[1] == 0) + tdir = d[2] == 90 ? 45 : 315; + else + tdir = d[2] == 90 ? 135 : 215; + + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + +// try other directions + if ( irand(0, 1) || abs(deltay)>abs(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + if (d[1]!=DI_NODIR && d[1]!=turnaround + && SV_StepDirection(actor, d[1], dist)) + return; + + if (d[2]!=DI_NODIR && d[2]!=turnaround + && SV_StepDirection(actor, d[2], dist)) + return; + +/* there is no direct path to the player, so pick another direction */ + + if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) + return; + + if (irand(0, 1)) /*randomly determine direction of search*/ + { + for (tdir=0 ; tdir<=315 ; tdir += 45) + if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) + return; + } + else + { + for (tdir=315 ; tdir >=0 ; tdir -= 45) + if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) + return; + } + + if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) + return; + + actor->ideal_yaw = olddir; // can't move + +// if a bridge was pulled out from underneath a monster, it may not have +// a valid standing position at all + + if (!M_CheckBottom (actor)) + SV_FixCheckBottom (actor); +} + +/* +====================== +SV_CloseEnough + +====================== +*/ +qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (goal->absmin[i] > ent->absmax[i] + dist) + return false; + if (goal->absmax[i] < ent->absmin[i] - dist) + return false; + } + return true; +} + + + +/* +====================== +M_MoveFromGoal +====================== +*/ +void M_MoveAwayFromGoal (edict_t *ent, float dist) +{ + float tdir, olddir, turnaround; + + olddir = anglemod( (int)(ent->ideal_yaw/45)*45 ); + turnaround = anglemod(olddir - 180); + + // bump around... + if (!SV_StepDirection (ent, ent->ideal_yaw, dist)) + { + for (tdir=0 ; tdir<=315 ; tdir += 45) + { + if (tdir!=turnaround && SV_StepDirection(ent, tdir, dist)) + return; + } + } +} + + + + +/* +====================== +M_MoveToGoal +====================== +*/ +void M_MoveToGoal (edict_t *ent, float dist) +{ + edict_t *goal; + + goal = ent->goalentity; + + if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) + return; + +// This was commented out because it was causing monsters to get stuck on the edges of bounding +// boxes and they'd keep running. + +// if the next step hits the enemy, return immediately +// if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) ) +// return; + + +// bump around... + if ( (irand(0, 3)==1) || !SV_StepDirection (ent, ent->ideal_yaw, dist)) + { + if (ent->inuse) + SV_NewChaseDir (ent, goal, dist); + } +} + +/* +=============== +M_movetoside - move creature to the side determined by the given yaw +=============== +*/ +void M_movetoside (edict_t *self,float yaw, float dist) +{ + M_walkmove (self, yaw, dist); +} + +/* +=============== +M_walkmove +=============== +*/ +qboolean M_walkmove (edict_t *ent, float yaw, float dist) +{ + vec3_t move; + + if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) + return false; + + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + return SV_movestep(ent, move, true); +} diff --git a/Toolkit/Programming/GameCode/game/m_mssithra.c b/Toolkit/Programming/GameCode/game/m_mssithra.c new file mode 100644 index 0000000..9272b99 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_mssithra.c @@ -0,0 +1,772 @@ +//============================================================================== +// +// m_mssithra.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "m_mssithra.h" +#include "m_mssithra_anim.h" +#include "g_misc.h" +#include "g_HitLocation.h" +#include "p_anim_branch2.h" +#include "m_stats.h" +#include "g_playstats.h" + +void extrapolateFiredir (edict_t *self,vec3_t p1,float pspeed,edict_t *targ,float accept,vec3_t vec2); +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); +void create_ssithra_arrow(edict_t *Arrow); + +#define MSSITHRA_JUMP_VELOCITY 300.0 +#define MSSITHRA_HOP_VELOCITY 128.0 +#define MSSITHRA_SF_NAMOR 8 +#define MSSITHRA_SF_SPIN 16 + +//======================================== +//INITIALIZE +//======================================== +static animmove_t *animations[NUM_ANIMS] = +{ + &mssithra_move_claw1, + &mssithra_move_death1, + &mssithra_move_idle1, + &mssithra_move_jump1, + &mssithra_move_fjump, +// &mssithra_move_pain1, + &mssithra_move_roar, + &mssithra_move_shoota1, + &mssithra_move_shootb1, + &mssithra_move_walk1, + &mssithra_move_backpedal1, + &mssithra_move_run1, + &mssithra_move_delay, + &mssithra_move_shoot1_trans, + &mssithra_move_shoot1_loop, + &mssithra_move_shoot1_detrans +}; + +static int Sounds[NUM_SOUNDS]; + +static ClassResourceInfo_t resInfo; +/* + +//======================================== +//MOVEMENT +//======================================== + +*/ + +void mssithra_stand(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_IDLE1); +} + +void mssithra_decide_stand(edict_t *self) +{ + if(mssithraCheckMood(self)) + return; + + SetAnim(self, ANIM_IDLE1); +} + +void mssithra_pain(edict_t *self, G_Message_t *msg) +{//fixme - make part fly dir the vector from hit loc to sever loc + int temp, damage; + qboolean force_pain; + + if(self->deadflag == DEAD_DEAD) //Dead but still being hit + return; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_pain, &damage, &temp); + + if(!force_pain) + { + if(irand(0,10)<5||!self->groundentity) + return; + + if(self->pain_debounce_time > level.time) + return; + } + + if(self->curAnimID == ANIM_CLAW1) + return; + + self->pain_debounce_time = level.time + 2; + + if(irand(0,10)<5) + gi.sound (self, CHAN_VOICE, Sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_VOICE, Sounds[SND_PAIN2], 1, ATTN_NORM, 0); + + if (self->flags&FL_INWATER) + self->flags |= FL_SWIM; + else + self->flags &= ~FL_SWIM; + + if(irand(0,10)<1) + SetAnim(self, ANIM_ROAR1);//make him tougher? more aggressive? +} + +void mssithra_pain_react (edict_t *self) +{ + if(!self->enemy) + { + mssithra_decide_stand(self); + return; + } + + if(self->enemy->health<=0||self->enemy == self||!self->enemy->takedamage) + { + self->enemy=NULL; + mssithra_decide_stand(self); + return; + } +} + +//=========================================== +//DEATHS +//=========================================== + +void mssithra_death(edict_t *self, G_Message_t *msg) +{ + self->svflags |= SVF_DEADMONSTER; + self->msgHandler=DyingMsgHandler; + + if(self->deadflag == DEAD_DEAD) + return; + + self->deadflag = DEAD_DEAD; + + gi.sound (self, CHAN_VOICE, Sounds[SND_DIE], 1, ATTN_NORM, 0); + if (self->flags&FL_INWATER) + self->flags |= FL_SWIM; + else + self->flags &= ~FL_SWIM; + + SetAnim(self, ANIM_DEATH1); + + //Remove the life bar once dead + M_ShowLifeMeter( self, 0, 0); + self->post_think = NULL; + self->next_post_think = -1; +} + +void mssithra_dead(edict_t *self) +{//maybe allow dead bodies to be chopped? Make BBOX small? + self->msgHandler = DeadMsgHandler; + self->deadState = DEAD_DEAD; + + self->think = NULL; + self->nextthink = 0; + self->flags |= FL_DONTANIMATE; + + gi.linkentity(self); +} + +void mssithraKillSelf (edict_t *self) +{ + vec3_t gore_spot; + + self->svflags &= ~SVF_DEADMONSTER; // now treat as a different content type + self->msgHandler = DefaultMsgHandler; + self->deadflag = false; + VectorCopy(self->s.origin,gore_spot); + gore_spot[2]+=12; + self->health = 1; + T_Damage (self, self, self, vec3_origin, gore_spot, vec3_origin, 10, 0,0,MOD_DIED); + self->health = -69; +} + +//=========================================== +//SOUNDS +//=========================================== + +void mssithraSound(edict_t *self, float soundnum, float channel, float attenuation) +{ + return; + if(!channel) + channel = CHAN_AUTO; + + if(!attenuation) + attenuation = ATTN_NORM; + else if(attenuation == -1) + attenuation = ATTN_NONE; + + gi.sound(self, (int)channel, Sounds[(int)(soundnum)], 1, (int)attenuation, 0); +} + +//=========================================== +//ATTACKS +//=========================================== + +void mssithra_melee(edict_t *self, G_Message_t *msg) +{ + vec3_t v; + float len, melee_range, min_seperation, jump_range; + + if(M_ValidTarget(self, self->enemy)) + { + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + melee_range = 64; + jump_range = 128; + min_seperation = self->maxs[0] + self->enemy->maxs[0]; + + if (len < min_seperation + melee_range) // A hit + { + SetAnim(self, ANIM_CLAW1); + } + } + else + QPostMessage(self, MSG_STAND,PRI_DIRECTIVE, NULL); +} + +void mssithra_missile(edict_t *self, G_Message_t *msg) +{//NEWSTUFF: jump closer to claw, loop shooting anims + vec3_t v; + float len, min_seperation, jump_range; + + if(M_ValidTarget(self, self->enemy)) + { + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + jump_range = 128; + min_seperation = self->maxs[0] + self->enemy->maxs[0]; + + if (irand(0,(skill->value+1)*2)) + { + SetAnim(self, ANIM_SHOOT_TRANS); + } + else + { + SetAnim(self, ANIM_IDLE1); + } + } + else + QPostMessage(self, MSG_STAND,PRI_DIRECTIVE, NULL); +} + +void mssithraSwipe (edict_t *self) +{ + vec3_t v, off, dir, org, ang; + float len; + + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + + if (len < (self->maxs[0] + self->enemy->maxs[0] + 45) ) // A hit + { + if (infront(self, self->enemy)) + { + gi.sound (self, CHAN_WEAPON, Sounds[SND_SWIPEHIT], 1, ATTN_NORM, 0); + VectorSet(off, 35.0, 0.0, 32.0); + VectorGetOffsetOrigin(off, self->s.origin, self->s.angles[YAW], org); + VectorCopy(self->s.angles, ang); + ang[YAW] += DEGREE_90; + AngleVectors(ang, dir, NULL, NULL); + T_Damage (self->enemy, self, self, dir, org, vec3_origin, + MSSITHRA_DMG_SWIPE, 0, DAMAGE_DISMEMBER,MOD_DIED); + + if(self->enemy->health>0)//else don't gib? + { + if(!irand(0,5)) + { + if(!stricmp(self->enemy->classname, "player")) + KnockDownPlayer(&self->enemy->client->playerinfo); + } + } + return; + } + } + gi.sound (self, CHAN_WEAPON, Sounds[SND_SWIPE], 1, ATTN_NORM, 0); +} + +void mssithra_missile_explode(edict_t *self) +{ + int damage = irand(8, 16); + + //TODO: Spawn an explosion effect + gi.CreateEffect( NULL, + FX_M_EFFECTS, + 0, + self->s.origin, + "bv", + FX_MSSITHRA_EXPLODE, + self->movedir); + + T_DamageRadius(self, self->owner, self->owner, 128, damage, damage/2, DAMAGE_ATTACKER_IMMUNE, MOD_DIED); + + G_FreeEdict(self); +} + +void mssithraAlphaArrowTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + edict_t *Arrow; + + // are we reflecting ? + if (self->reflect_debounce_time) + { + if(EntReflecting(other, true, true)) + { + Arrow = G_Spawn(); + + create_ssithra_arrow(Arrow); + VectorCopy(self->s.origin, Arrow->s.origin); + Arrow->owner = self->owner; + + Arrow->nextthink=self->nextthink; + Arrow->think=G_FreeEdict; + + Create_rand_relect_vect(self->velocity, Arrow->velocity); + + vectoangles(Arrow->velocity, Arrow->s.angles); + Arrow->s.angles[YAW]+=90; + + Vec3ScaleAssign(MSSITHRA_ARROW_SPEED/2,Arrow->velocity); + + Arrow->reflect_debounce_time = self->reflect_debounce_time - 1; + + G_LinkMissile(Arrow); + //gi.CreateEffect(&Arrow->s, FX_WEAPON_REDRAINMISSILE, CEF_OWNERS_ORIGIN|CEF_FLAG8|CEF_FLAG7, NULL, "t", Arrow->velocity); + + G_SetToFree(self); + + return; + } + } + + if(other->takedamage) + { + if (plane->normal) + VectorCopy(plane->normal, self->movedir); + + self->dmg = irand(MSSITHRA_DMG_MIN*2, MSSITHRA_DMG_MAX*2); + mssithra_missile_explode(self); + } + else + { + gi.sound(self, CHAN_WEAPON, Sounds[SND_INWALL], 0.5, ATTN_NORM, 0); + + self->s.effects |= EF_ALTCLIENTFX; + + VectorClear(self->velocity); + + if (plane->normal) + VectorCopy(plane->normal, self->movedir); + + self->dmg = irand(MSSITHRA_DMG_MIN, MSSITHRA_DMG_MAX); + self->think = mssithra_missile_explode; + self->nextthink = level.time + flrand(0.5, 1.5); + } +} + +// create the guts of the ssithra arrow +void create_ssithra_arrow(edict_t *Arrow) +{ + Arrow->s.modelindex = gi.modelindex("models/objects/exarrow/tris.fm"); + Arrow->movetype = MOVETYPE_FLYMISSILE; + Arrow->solid = SOLID_BBOX; + Arrow->classname = "mssithra_Arrow"; + + Arrow->touch = mssithraAlphaArrowTouch; + + Arrow->clipmask = MASK_SHOT; + + Arrow->s.effects |= EF_ALWAYS_ADD_EFFECTS | EF_CAMERA_NO_CLIP; + Arrow->svflags |= SVF_ALWAYS_SEND; + + VectorSet(Arrow->mins,-1.0,-1.0,-1.0); + VectorSet(Arrow->maxs,1.0,1.0,1.0); + Arrow->s.scale = 1.5; +} + +void mssithraArrow(edict_t *self) +{//fixme; adjust for up/down + vec3_t Forward, targ_pos; + vec3_t Right, fire_spot, fire_dir;// , up; + edict_t *Arrow; + float spread; + int num_shots = 3; + + if (!self->enemy) + return; + + if(self->enemy->health<=0) + { + self->enemy=NULL; + mssithra_decide_stand(self); + return; + } + + if(self->monsterinfo.attack_finished>level.time) + return; + + gi.sound(self,CHAN_WEAPON,Sounds[SND_ARROW],1,ATTN_NORM,0); + self->monsterinfo.attack_finished = level.time + 0.4; + + VectorCopy(self->s.origin,fire_spot); + fire_spot[2]+=self->maxs[2]*0.5; + AngleVectors(self->s.angles,Forward,Right,NULL); + VectorMA(fire_spot,72,Forward,fire_spot); + VectorMA(fire_spot,16,Right,fire_spot); + fire_spot[2] += 24; + + VectorRandomCopy(self->enemy->s.origin, targ_pos, 16); + VectorSubtract(targ_pos, fire_spot, Forward); + VectorNormalize2(Forward, fire_dir); + + while(num_shots) + { + Arrow = G_Spawn(); + + create_ssithra_arrow(Arrow); + Arrow->reflect_debounce_time = MAX_REFLECT; + + VectorCopy(fire_spot,Arrow->s.origin); + VectorCopy(self->movedir,Arrow->movedir); + + //Increase the spread for lower levels + switch((int)skill->value) + { + case 0: + spread = 0.35; + break; + + case 1: + spread = 0.2; + break; + + case 2: + default: + spread = 0.1; + break; + } + + AngleVectors(self->s.angles,NULL,Right,NULL); + switch (num_shots) + { + case 3: + VectorScale(Right, spread,Right); + break; + + case 1: + VectorScale(Right,-spread,Right); + break; + + case 2: + default: + VectorClear(Right); + break; + } + + VectorAdd(fire_dir, Right, Arrow->movedir); + VectorNormalize(Arrow->movedir); + VectorScale(Arrow->movedir,MSSITHRA_ARROW_SPEED,Arrow->velocity); + + vectoangles(Arrow->velocity, Arrow->s.angles); + Arrow->s.angles[YAW] += 90; + + Arrow->owner=self; + Arrow->enemy=self->enemy; + + gi.CreateEffect(&Arrow->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN | CEF_FLAG6, + NULL, + "bv", + FX_MSSITHRA_ARROW, + Arrow->velocity); + + G_LinkMissile(Arrow); + + Arrow->nextthink=level.time+5; + Arrow->think=G_FreeEdict;//mssithraArrowThink; + + num_shots--; + } +} + +void mssithraCheckLoop (edict_t *self, float frame) +{//see if should fire again + vec3_t v; + float len, melee_range, min_seperation, jump_range; + + if(!self->enemy) + return; + + ai_charge2(self, 0); + + if(!visible(self, self->enemy)) + return; + + if(!infront(self, self->enemy)) + return; + + if(irand(0,10)<5) + return; + + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + melee_range = 64; + jump_range = 128; + min_seperation = self->maxs[0] + self->enemy->maxs[0]; + + if (infront(self, self->enemy)) + {//don't loop if enemy close enough + if (len < min_seperation + melee_range) + return; + else if (len < min_seperation + jump_range && irand(0,10)<3) + return; + } + + self->monsterinfo.currframeindex = (int)frame; +} + +/*------------------------------------------------------------------------- + mssithra_pause +-------------------------------------------------------------------------*/ +qboolean mssithraCheckMood (edict_t *self) +{ + if(self->monsterinfo.aiflags&AI_OVERRIDE_GUIDE) + return false; + + self->mood_think(self); + + if (self->ai_mood == AI_MOOD_NORMAL) + return false; + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + if(self->ai_mood_flags & AI_MOOD_FLAG_MISSILE) + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + return true; + break; + case AI_MOOD_PURSUE: + case AI_MOOD_NAVIGATE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + return true; + break; + case AI_MOOD_WALK: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + return true; + break; + + case AI_MOOD_STAND: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + return true; + break; + } + + return false; +} + +void mssithra_postthink(edict_t *self) +{ + //Only display a lifemeter if we have an enemy + if (self->enemy) + { + if (self->dmg < self->max_health) + { + M_ShowLifeMeter( self, self->dmg, self->dmg); + self->dmg+=50; + } + else + { + M_ShowLifeMeter( self, self->health, self->max_health); + } + } + + self->next_post_think = level.time + 0.05; +} + +void mmssithraRandomGrowlSound (edict_t *self) +{ + if(!irand(0,2)) + gi.sound(self, CHAN_VOICE, Sounds[SND_GROWL1], 1, ATTN_NORM, 0); + else if(!irand(0,1)) + gi.sound(self, CHAN_VOICE, Sounds[SND_GROWL2], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, Sounds[SND_GROWL3], 1, ATTN_NORM, 0); +} + +void mssithra_ShotLoop(edict_t *self) +{ + SetAnim(self, ANIM_SHOOT_LOOP); +} + +void mssithraCheckShotLoop(edict_t *self) +{ + //TODO: Check to keep shooting or to stop shooting + if (irand(0,(skill->value+1)*2)) + { + //Just keep playing the animation + return; + } + else + { + SetAnim(self, ANIM_SHOOT_DETRANS); + } +} + +void MssithraStaticsInit() +{ + classStatics[CID_MSSITHRA].msgReceivers[MSG_STAND] = mssithra_stand; + classStatics[CID_MSSITHRA].msgReceivers[MSG_MISSILE] = mssithra_missile; + classStatics[CID_MSSITHRA].msgReceivers[MSG_MELEE] = mssithra_melee; + classStatics[CID_MSSITHRA].msgReceivers[MSG_DEATH] = mssithra_death; + classStatics[CID_MSSITHRA].msgReceivers[MSG_PAIN] = mssithra_pain; + classStatics[CID_MSSITHRA].msgReceivers[MSG_RUN] = mssithra_missile; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/mutantsithra/tris.fm"); + + Sounds[SND_PAIN1]=gi.soundindex("monsters/mssithra/pain1.wav"); + Sounds[SND_PAIN2]=gi.soundindex("monsters/mssithra/pain2.wav"); + Sounds[SND_DIE]=gi.soundindex("monsters/mssithra/death1.wav"); + Sounds[SND_SWIPE] = gi.soundindex ("monsters/mssithra/swipe.wav"); + Sounds[SND_SWIPEHIT]=gi.soundindex("monsters/mssithra/swipehit.wav"); + Sounds[SND_ARROW]=gi.soundindex("weapons/RedRainPowerFire.wav"); + Sounds[SND_AEXPLODE]=gi.soundindex("weapons/FlyingFistImpact.wav"); + Sounds[SND_GROWL1]=gi.soundindex("monsters/mssithra/growl1.wav"); + Sounds[SND_GROWL2] = gi.soundindex ("monsters/mssithra/growl2.wav"); + Sounds[SND_GROWL3] = gi.soundindex ("monsters/mssithra/growl3.wav"); + Sounds[SND_ROAR]=gi.soundindex("monsters/mssithra/roar.wav"); + Sounds[SND_INWALL]=gi.soundindex("weapons/staffhitwall.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = Sounds; + + classStatics[CID_MSSITHRA].resInfo = &resInfo; +} + +/*QUAKED monster_mssithra (1 .5 0) (-36 -36 0) (36 36 96) AMBUSH ASLEEP 4 8 16 32 64 FIXED WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +The mssithra + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING - Use WANDER instead + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 16 +melee_range = 100 +missile_range = 400 +min_missile_range = 100 +bypass_missile_chance = 25 +jump_chance = 25 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +void SP_monster_mssithra (edict_t *self) +{ + // Generic Monster Initialization + if (!walkmonster_start (self)) // failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_MSSITHRA; + self->materialtype = MAT_FLESH; + self->flags |= FL_IMMUNE_SLIME; + if(self->flags&FL_INWATER|| + gi.pointcontents(self->s.origin)&CONTENTS_WATER|| + self->waterlevel >= 3) + self->flags|=FL_SWIM; + + if(self->health<=0) + self->health = MSSITHRA_HEALTH; + + //Apply to the end result (whether designer set or not) + self->max_health = self->health = MonsterHealth(self->health); + + self->mass = MSSITHRA_MASS; + self->yaw_speed = 20; + self->viewheight = 88; + self->monsterinfo.aiflags |= AI_BRUTAL|AI_AGRESSIVE; + + self->movetype=PHYSICSTYPE_STEP;//MOVETYPE_STEP + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + self->s.modelindex = classStatics[CID_MSSITHRA].resInfo->modelIndex; + + self->s.skinnum = 0; + + if (!self->monsterinfo.scale) + { + self->s.scale = self->monsterinfo.scale = (MODEL_SCALE + 0.25); + } + + self->monsterinfo.otherenemyname = "obj_barrel"; + + //set up my mood function + MG_InitMoods(self); + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + + self->post_think = mssithra_postthink; + self->next_post_think = level.time + 0.1; + + //Turn the goofy bolts off! + self->s.fmnodeinfo[MESH__BOLTS].flags |= FMNI_NO_DRAW; + + self->dmg = 0; + self->svflags|=SVF_BOSS; +} diff --git a/Toolkit/Programming/GameCode/game/m_mssithra.h b/Toolkit/Programming/GameCode/game/m_mssithra.h new file mode 100644 index 0000000..810e4a7 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_mssithra.h @@ -0,0 +1,74 @@ +//m_plagueSsithra.h + + +typedef enum AnimID_e +{ + ANIM_CLAW1, + ANIM_DEATH1, + ANIM_IDLE1, + ANIM_JUMP1, + ANIM_FJUMP, +// ANIM_PAIN1, + ANIM_ROAR1, + ANIM_SHOOTA1, + ANIM_SHOOTB1, + ANIM_WALK1, + ANIM_BACKPEDAL, + ANIM_RUN, + ANIM_DELAY, + + ANIM_SHOOT_TRANS, + ANIM_SHOOT_LOOP, + ANIM_SHOOT_DETRANS, + + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PAIN1, + SND_PAIN2, + SND_DIE, + SND_SWIPE, + SND_SWIPEHIT, + SND_ARROW, + SND_AEXPLODE, + SND_GROWL1, + SND_GROWL2, + SND_GROWL3, + SND_ROAR, + SND_INWALL, + + NUM_SOUNDS +} SoundID_t; + + +extern animmove_t mssithra_move_idle1; +extern animmove_t mssithra_move_walk1; +extern animmove_t mssithra_move_backpedal1; +extern animmove_t mssithra_move_death1; +extern animmove_t mssithra_move_claw1; +extern animmove_t mssithra_move_jump1; +extern animmove_t mssithra_move_fjump; +extern animmove_t mssithra_move_shoota1; +extern animmove_t mssithra_move_shootb1; +extern animmove_t mssithra_move_roar; +extern animmove_t mssithra_move_run1; +extern animmove_t mssithra_move_delay; + +extern animmove_t mssithra_move_shoot1_trans; +extern animmove_t mssithra_move_shoot1_loop; +extern animmove_t mssithra_move_shoot1_detrans; + +void mssithraSwipe(edict_t *self); +void mssithraArrow(edict_t *self); +void ai_charge2 (edict_t *self, float dist); +qboolean mssithraCheckMood (edict_t *self); +void mssithraArrow(edict_t *self); +void mssithraSwipe(edict_t *self); +void mmssithraRandomGrowlSound (edict_t *self); +void mssithra_dead(edict_t *self); + +void mssithraCheckShotLoop(edict_t *self); +void mssithra_ShotLoop(edict_t *self); + diff --git a/Toolkit/Programming/GameCode/game/m_mssithra_anim.c b/Toolkit/Programming/GameCode/game/m_mssithra_anim.c new file mode 100644 index 0000000..15215d4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_mssithra_anim.c @@ -0,0 +1,396 @@ +//============================================================================== +// +// m_plagueSsitra_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#include "m_mssithra_anim.h" +#include "m_mssithra.h" + +/*---------------------------------------------------------------------- + mssithra Idle - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_idle1 [] = +{ + FRAME_idle1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle20, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle21, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t mssithra_move_idle1 = {21, mssithra_frames_idle1, mssithraCheckMood}; + +/*---------------------------------------------------------------------- + mssithra Walk - walking along +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_walk1 [] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk2, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_walk, 9, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_walk, 9, NULL, + FRAME_walk7, NULL, 0, 0, 0, ai_walk, 9, NULL, + FRAME_walk8, NULL, 0, 0, 0, ai_walk, 10, NULL, + FRAME_walk9, NULL, 0, 0, 0, ai_walk, 10, NULL, + FRAME_walk10, NULL, 0, 0, 0, ai_walk, 10, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_walk, 10, NULL, + FRAME_walk12, NULL, 0, 0, 0, ai_walk, 10, NULL, + FRAME_walk13, NULL, 0, 0, 0, ai_walk, 9, NULL, + FRAME_walk14, NULL, 0, 0, 0, ai_walk, 9, NULL, + FRAME_walk15, NULL, 0, 0, 0, ai_walk, 9, NULL, + FRAME_walk16, NULL, 0, 0, 0, ai_walk, 8, NULL, +}; +animmove_t mssithra_move_walk1 = {16, mssithra_frames_walk1, NULL};//mssithraCheckMood}; + +/*---------------------------------------------------------------------- + mssithra Walk - walking along +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_run1 [] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk2, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_walk7, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_walk8, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_walk9, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_walk10, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_walk12, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_walk13, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_walk14, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_walk15, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_walk16, NULL, 0, 0, 0, ai_run, 9, NULL, +}; +animmove_t mssithra_move_run1 = {16, mssithra_frames_run1, NULL};//mssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + mssithra backpedal - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_backpedal1 [] = +{ + FRAME_walk16, NULL, 0, 0, 0, ai_charge2, -8, NULL, + FRAME_walk15, NULL, 0, 0, 0, ai_charge2, -8, NULL, + FRAME_walk14, NULL, 0, 0, 0, ai_charge2, -8, NULL,//mssithraArrow, + FRAME_walk13, NULL, 0, 0, 0, ai_charge2, -8, NULL, + FRAME_walk12, NULL, 0, 0, 0, ai_charge2, -9, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_charge2, -9, NULL, + FRAME_walk10, NULL, 0, 0, 0, ai_charge2, -9, NULL,//mssithraArrow, + FRAME_walk9, NULL, 0, 0, 0, ai_charge2, -9, NULL, + FRAME_walk8, NULL, 0, 0, 0, ai_charge2, -10, NULL, + FRAME_walk7, NULL, 0, 0, 0, ai_charge2, -10, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_charge2, -10, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_charge2, -10, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_charge2, -9, NULL,//mssithraArrow, + FRAME_walk3, NULL, 0, 0, 0, ai_charge2, -9, NULL, + FRAME_walk2, NULL, 0, 0, 0, ai_charge2, -9, NULL, + FRAME_walk1, NULL, 0, 0, 0, ai_charge2, -9, NULL, +}; +animmove_t mssithra_move_backpedal1 = {16, mssithra_frames_backpedal1, NULL};//mssithra_decide_backpedal}; + + +/*---------------------------------------------------------------------- + mssithra death_b - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_death1 [] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death32, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death33, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death34, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death35, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death36, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death37, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death38, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death39, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death40, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death41, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death42, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death43, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death44, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death45, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t mssithra_move_death1 = {45, mssithra_frames_death1, mssithra_dead}; + + +/*---------------------------------------------------------------------- + mssithra melee - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_claw1 [] = +{ + FRAME_claw1, NULL, 0, 0, 0, ai_charge2, 20, NULL, + FRAME_claw2, NULL, 0, 0, 0, ai_charge2, 10, mmssithraRandomGrowlSound, + FRAME_claw3, NULL, 0, 0, 0, ai_charge2, 8, NULL, + FRAME_claw4, NULL, 0, 0, 0, ai_charge2, 6, NULL, + FRAME_claw5, NULL, 0, 0, 0, ai_charge2, 4, mssithraSwipe, + FRAME_claw6, NULL, 0, 0, 0, ai_charge2, 3, NULL, + FRAME_claw7, NULL, 0, 0, 0, ai_charge2, 3, NULL, + FRAME_claw8, NULL, 0, 0, 0, ai_charge2, 4, mssithraSwipe, + FRAME_claw9, NULL, 0, 0, 0, ai_charge2, 3, NULL, + FRAME_claw10, NULL, 0, 0, 0, ai_charge2, 3, NULL, +}; +animmove_t mssithra_move_claw1 = {7, mssithra_frames_claw1, mssithraCheckMood};//mssithra_decide_gallop}; + + +/*---------------------------------------------------------------------- + mssithra jump +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_jump1 [] = +{ + FRAME_jump1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t mssithra_move_jump1 = {14, mssithra_frames_jump1, mssithraCheckMood};//mssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + mssithra forced jump +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_fjump [] = +{ + FRAME_jump1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, NULL, 0, NULL,//mmssithraRandomGrowlSound, + FRAME_jump10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t mssithra_move_fjump = {14, mssithra_frames_fjump, mssithraCheckMood};//mssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + mssithra pain_a - looking around and standing +-----------------------------------------------------------------------*/ +/* +animframe_t mssithra_frames_pain1 [] = +{ + FRAME_pain1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain5, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t mssithra_move_pain1 = {5, mssithra_frames_pain1, mssithra_pain_react}; +*/ + +/*---------------------------------------------------------------------- + mssithra shoot +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_shoota1 [] = +{ + FRAME_shoota1, NULL, 0, 0, 0, ai_charge2, 0, NULL,//0 + FRAME_shoota2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota4, NULL, 0, 0, 0, ai_charge2, 0, mmssithraRandomGrowlSound, + FRAME_shoota5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota7, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota8, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota9, NULL, 0, 0, 0, ai_charge2, 0, mssithraArrow,//8: arrow here + FRAME_shoota10, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota11, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota12, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota13, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota14, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota15, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota16, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota17, NULL, 0, 0, 0, ai_charge2, 0, NULL,//check here to loop back to 8 + FRAME_shoota18, NULL, 0, 0, 0, ai_charge2, 0, mssithraArrow, + FRAME_shoota19, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota20, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota21, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoota22, NULL, 0, 0, 0, ai_charge2, 0, mmssithraRandomGrowlSound, + FRAME_shoota23, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t mssithra_move_shoota1 = {23, mssithra_frames_shoota1, mssithraCheckMood};//mssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + mssithra shoot +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_shootb1 [] = +{ + FRAME_shootb1, NULL, 0, 0, 0, ai_charge2, 0, NULL,//0 + FRAME_shootb2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb7, NULL, 0, 0, 0, ai_charge2, 0, mmssithraRandomGrowlSound, + FRAME_shootb8, NULL, 0, 0, 0, ai_charge2, 0, mssithraArrow,//7: shoot here + FRAME_shootb9, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb10, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb11, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb12, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb13, NULL, 0, 0, 0, ai_charge2, 0, mmssithraRandomGrowlSound, + FRAME_shootb14, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb15, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb16, NULL, 0, 0, 0, ai_charge2, 0, NULL,//check here to loop back to 7 + FRAME_shootb17, NULL, 0, 0, 0, ai_charge2, 0, mssithraArrow, + FRAME_shootb18, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb19, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb20, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb21, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shootb22, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t mssithra_move_shootb1 = {22, mssithra_frames_shootb1, mssithraCheckMood};//mssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + mssithra roar +-----------------------------------------------------------------------*/ +animframe_t mssithra_frames_roar [] = +{ + FRAME_roar1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_roar24, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t mssithra_move_roar = {24, mssithra_frames_roar, mssithraCheckMood};//mssithra_decide_gallop}; + + +animframe_t mssithra_frames_delay [] = +{ + FRAME_idle1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle21, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t mssithra_move_delay = {21, mssithra_frames_delay, NULL};//mssithraCheckMood}; + +//New shooting animations +animframe_t mssithra_frames_shoot1_trans [] = +{ + FRAME_newshot1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newshot2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newshot3, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t mssithra_move_shoot1_trans = {3, mssithra_frames_shoot1_trans, mssithra_ShotLoop}; + +animframe_t mssithra_frames_shoot1_loop [] = +{ + FRAME_newshot4, NULL, 0, 0, 0, ai_charge2, 0, mssithraArrow, + FRAME_newshot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newshot6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newshot7, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newshot8, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newshot9, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t mssithra_move_shoot1_loop = {6, mssithra_frames_shoot1_loop, mssithraCheckShotLoop}; + +animframe_t mssithra_frames_shoot1_detrans [] = +{ + FRAME_newshot3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newshot2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_newshot1, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t mssithra_move_shoot1_detrans = {3, mssithra_frames_shoot1_detrans, mssithraCheckMood}; + diff --git a/Toolkit/Programming/GameCode/game/m_mssithra_anim.h b/Toolkit/Programming/GameCode/game/m_mssithra_anim.h new file mode 100644 index 0000000..81b9995 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_mssithra_anim.h @@ -0,0 +1,202 @@ +// R:\Art\models/monsters\mutantsithra + +// This file generated by qdata - Do NOT Modify + +#define FRAME_claw1 0 +#define FRAME_claw2 1 +#define FRAME_claw3 2 +#define FRAME_claw4 3 +#define FRAME_claw5 4 +#define FRAME_claw6 5 +#define FRAME_claw7 6 +#define FRAME_claw8 7 +#define FRAME_claw9 8 +#define FRAME_claw10 9 +#define FRAME_death1 10 +#define FRAME_death2 11 +#define FRAME_death3 12 +#define FRAME_death4 13 +#define FRAME_death5 14 +#define FRAME_death6 15 +#define FRAME_death7 16 +#define FRAME_death8 17 +#define FRAME_death9 18 +#define FRAME_death10 19 +#define FRAME_death11 20 +#define FRAME_death12 21 +#define FRAME_death13 22 +#define FRAME_death14 23 +#define FRAME_death15 24 +#define FRAME_death16 25 +#define FRAME_death17 26 +#define FRAME_death18 27 +#define FRAME_death19 28 +#define FRAME_death20 29 +#define FRAME_death21 30 +#define FRAME_death22 31 +#define FRAME_death23 32 +#define FRAME_death24 33 +#define FRAME_death25 34 +#define FRAME_death26 35 +#define FRAME_death27 36 +#define FRAME_death28 37 +#define FRAME_death29 38 +#define FRAME_death30 39 +#define FRAME_death31 40 +#define FRAME_death32 41 +#define FRAME_death33 42 +#define FRAME_death34 43 +#define FRAME_death35 44 +#define FRAME_death36 45 +#define FRAME_death37 46 +#define FRAME_death38 47 +#define FRAME_death39 48 +#define FRAME_death40 49 +#define FRAME_death41 50 +#define FRAME_death42 51 +#define FRAME_death43 52 +#define FRAME_death44 53 +#define FRAME_death45 54 +#define FRAME_idle1 55 +#define FRAME_idle2 56 +#define FRAME_idle3 57 +#define FRAME_idle4 58 +#define FRAME_idle5 59 +#define FRAME_idle6 60 +#define FRAME_idle7 61 +#define FRAME_idle8 62 +#define FRAME_idle9 63 +#define FRAME_idle10 64 +#define FRAME_idle11 65 +#define FRAME_idle12 66 +#define FRAME_idle13 67 +#define FRAME_idle14 68 +#define FRAME_idle15 69 +#define FRAME_idle16 70 +#define FRAME_idle17 71 +#define FRAME_idle18 72 +#define FRAME_idle19 73 +#define FRAME_idle20 74 +#define FRAME_idle21 75 +#define FRAME_jump1 76 +#define FRAME_jump2 77 +#define FRAME_jump3 78 +#define FRAME_jump4 79 +#define FRAME_jump5 80 +#define FRAME_jump6 81 +#define FRAME_jump7 82 +#define FRAME_jump8 83 +#define FRAME_jump9 84 +#define FRAME_jump10 85 +#define FRAME_jump11 86 +#define FRAME_jump12 87 +#define FRAME_jump13 88 +#define FRAME_jump14 89 +#define FRAME_roar1 90 +#define FRAME_roar2 91 +#define FRAME_roar3 92 +#define FRAME_roar4 93 +#define FRAME_roar5 94 +#define FRAME_roar6 95 +#define FRAME_roar7 96 +#define FRAME_roar8 97 +#define FRAME_roar9 98 +#define FRAME_roar10 99 +#define FRAME_roar11 100 +#define FRAME_roar12 101 +#define FRAME_roar13 102 +#define FRAME_roar14 103 +#define FRAME_roar15 104 +#define FRAME_roar16 105 +#define FRAME_roar17 106 +#define FRAME_roar18 107 +#define FRAME_roar19 108 +#define FRAME_roar20 109 +#define FRAME_roar21 110 +#define FRAME_roar22 111 +#define FRAME_roar23 112 +#define FRAME_roar24 113 +#define FRAME_shoota1 114 +#define FRAME_shoota2 115 +#define FRAME_shoota3 116 +#define FRAME_shoota4 117 +#define FRAME_shoota5 118 +#define FRAME_shoota6 119 +#define FRAME_shoota7 120 +#define FRAME_shoota8 121 +#define FRAME_shoota9 122 +#define FRAME_shoota10 123 +#define FRAME_shoota11 124 +#define FRAME_shoota12 125 +#define FRAME_shoota13 126 +#define FRAME_shoota14 127 +#define FRAME_shoota15 128 +#define FRAME_shoota16 129 +#define FRAME_shoota17 130 +#define FRAME_shoota18 131 +#define FRAME_shoota19 132 +#define FRAME_shoota20 133 +#define FRAME_shoota21 134 +#define FRAME_shoota22 135 +#define FRAME_shoota23 136 +#define FRAME_shootb1 137 +#define FRAME_shootb2 138 +#define FRAME_shootb3 139 +#define FRAME_shootb4 140 +#define FRAME_shootb5 141 +#define FRAME_shootb6 142 +#define FRAME_shootb7 143 +#define FRAME_shootb8 144 +#define FRAME_shootb9 145 +#define FRAME_shootb10 146 +#define FRAME_shootb11 147 +#define FRAME_shootb12 148 +#define FRAME_shootb13 149 +#define FRAME_shootb14 150 +#define FRAME_shootb15 151 +#define FRAME_shootb16 152 +#define FRAME_shootb17 153 +#define FRAME_shootb18 154 +#define FRAME_shootb19 155 +#define FRAME_shootb20 156 +#define FRAME_shootb21 157 +#define FRAME_shootb22 158 +#define FRAME_walk1 159 +#define FRAME_walk2 160 +#define FRAME_walk3 161 +#define FRAME_walk4 162 +#define FRAME_walk5 163 +#define FRAME_walk6 164 +#define FRAME_walk7 165 +#define FRAME_walk8 166 +#define FRAME_walk9 167 +#define FRAME_walk10 168 +#define FRAME_walk11 169 +#define FRAME_walk12 170 +#define FRAME_walk13 171 +#define FRAME_walk14 172 +#define FRAME_walk15 173 +#define FRAME_walk16 174 +#define FRAME_newshot1 175 +#define FRAME_newshot2 176 +#define FRAME_newshot3 177 +#define FRAME_newshot4 178 +#define FRAME_newshot5 179 +#define FRAME_newshot6 180 +#define FRAME_newshot7 181 +#define FRAME_newshot8 182 +#define FRAME_newshot9 183 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 9 + +#define MESH_BASEBIN 0 +#define MESH__CROSSBOW 1 +#define MESH__BOLTS 2 +#define MESH__HEAD 3 +#define MESH__BODY 4 +#define MESH__ARMRT 5 +#define MESH__LEGLFT 6 +#define MESH__LEGRT 7 +#define MESH__ARMLFT 8 diff --git a/Toolkit/Programming/GameCode/game/m_ogle.c b/Toolkit/Programming/GameCode/game/m_ogle.c new file mode 100644 index 0000000..976c83f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_ogle.c @@ -0,0 +1,1888 @@ +//============================================================================== +// +// m_ogle.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "m_ogle.h" +#include "m_ogle_anim.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "fx.h" +#include "g_HitLocation.h" +#include "g_misc.h" +#include "c_ai.h" +#include "m_stats.h" + +#define OGLE_WORKER_CHISEL 1 +#define OGLE_WORKER_HAMMER 2 +#define OGLE_WORKER_PICK 4 + +#define OF_PUSHING 1 +#define OF_PICK_UP 4 +#define OF_PICK_DOWN 8 +#define OF_CHISEL_UP 16 +#define OF_CHISEL_DOWN 32 +#define OF_HAMMER_UP 64 +#define OF_HAMMER_DOWN 128 +#define OF_SONG_LEADER 256 +#define OF_CINEMATIC 8448 + +//#define OGLE_RADIUS 1000 //FIXME: Tweak this out, activation range + + +qboolean MG_CheckClearPathToEnemy( edict_t *self ); +void MG_Pathfind(edict_t *self, qboolean check_clear_path); + +static animmove_t *animations[NUM_ANIMS] = +{ + &ogle_move_walk1, + &ogle_move_push1, + &ogle_move_push2, + &ogle_move_push3, + &ogle_move_stand1, + &ogle_move_work1, + &ogle_move_work2, + &ogle_move_work3, + &ogle_move_work4, + &ogle_move_work5, + &ogle_move_pain1, + &ogle_move_pain2, + &ogle_move_pain3, + &ogle_move_rest1_trans, + &ogle_move_rest1_wipe, + &ogle_move_rest1, + &ogle_move_rest2_wipe, + &ogle_move_rest3_wipe, + &ogle_move_rest4_trans, + &ogle_move_rest4_trans2, + &ogle_move_rest4, + &ogle_move_celebrate1, + &ogle_move_celebrate2, + &ogle_move_celebrate3_trans, + &ogle_move_celebrate3, + &ogle_move_celebrate4_trans, + &ogle_move_celebrate4, + &ogle_move_celebrate5_trans, + &ogle_move_celebrate5, + &ogle_move_charge1, + &ogle_move_charge2, + &ogle_move_charge3, + &ogle_move_charge4, + &ogle_move_charge5, + &ogle_move_attack1, + &ogle_move_attack2, + &ogle_move_attack3, + &ogle_move_death1, + &ogle_move_death2, + + &ogle_c_move_action1, + &ogle_c_move_action2, + &ogle_c_move_action3, + &ogle_c_move_action4, + &ogle_c_move_action5, + &ogle_c_move_action6, + &ogle_c_move_action7, + &ogle_c_move_action8, + &ogle_c_move_action9, + &ogle_c_move_action10, + &ogle_c_move_action11, + &ogle_c_move_action12, + &ogle_c_move_action13, + &ogle_c_move_action14, + &ogle_c_move_action15, + &ogle_c_move_attack1, + &ogle_c_move_attack2, + &ogle_c_move_attack3, + &ogle_c_move_death1, + &ogle_c_move_death2, + NULL, + &ogle_c_move_idle1, + &ogle_c_move_idle2, + &ogle_c_move_idle3, + &ogle_c_move_idle4, + &ogle_c_move_idle5, + &ogle_c_move_idle6, + &ogle_c_move_pain1, + &ogle_c_move_pain2, + &ogle_c_move_pain3, + &ogle_move_rest1, + &ogle_c_move_trans1, + &ogle_c_move_trans2, + &ogle_c_move_trans3, + &ogle_c_move_trans4, + &ogle_c_move_trans5, + &ogle_c_move_trans6, + &ogle_c_move_walk1, + &ogle_c_move_walk2, + &ogle_c_move_walk3, + &ogle_c_move_walk4, + +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + +int MG_SetFirstBuoy(edict_t *self); +qboolean MG_WanderToNextBuoy(edict_t *self); + +/*QUAKED obj_corpse_ogle (1 .5 0) (-30 -12 -2) (30 12 2) pushing pick_up pick_down chisel_up chisel_down hammer_up hammer_down +A dead ogle. +---------- KEYS ----------------- +style - skin of ogle (default 0) +0 - damage skin +1 - normal skin +------- FIELDS ------------------ +same as monster ogle +----------------------------------- +*/ +void SP_obj_corpse_ogle(edict_t *self) +{ + self->s.origin[2] += 22.0; + + VectorSet(self->mins,-30,-30,-2); + VectorSet(self->maxs,30,30,8); + + self->s.modelindex = gi.modelindex("models/monsters/ogle/tris.fm"); + + self->s.frame = FRAME_deatha14; //Ths is the reason the function can't be put in g_obj.c + + // Setting the skinnum correctly + if (!self->style) + self->s.skinnum = 1; + else + self->s.skinnum = 0; + + self->svflags |= SVF_DEADMONSTER;//doesn't block walking + + if (self->monsterinfo.ogleflags & OF_PUSHING) + { + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + else if (self->monsterinfo.ogleflags & OF_PICK_UP) + { + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + } + else if (self->monsterinfo.ogleflags & OF_PICK_DOWN) + { + SetAnim(self, ANIM_WORK5); + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + } + else if (self->monsterinfo.ogleflags & OF_CHISEL_UP) + { + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + else if (self->monsterinfo.ogleflags & OF_HAMMER_UP) + { + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + else if (self->monsterinfo.ogleflags & OF_HAMMER_DOWN) + { + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + else + { + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + + ObjectInit(self,40,80,MAT_FLESH,SOLID_BBOX); +} + +/*------------------------------------------------------------------------- + ogle_c_anims +-------------------------------------------------------------------------*/ +void ogle_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ACTION5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION5; + break; + case MSG_C_ACTION6: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION6; + break; + case MSG_C_ACTION7: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION7; + break; + case MSG_C_ACTION8: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION8; + break; + case MSG_C_ACTION9: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION9; + break; + case MSG_C_ACTION10: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION10; + break; + case MSG_C_ACTION11: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_ACTION11; + break; + case MSG_C_ACTION12: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_ACTION12; + break; + case MSG_C_ACTION13: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_ACTION13; + break; + case MSG_C_ACTION14: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_ACTION14; + break; + case MSG_C_ACTION15: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_ACTION15; + break; + case MSG_C_ATTACK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_ATTACK1; + break; + case MSG_C_ATTACK2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK2; + break; + case MSG_C_ATTACK3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK3; + break; + case MSG_C_DEATH1: + self->monsterinfo.c_anim_flag |= C_ANIM_DONE; + curr_anim = ANIM_C_DEATH1; + break; + case MSG_C_DEATH2: + self->monsterinfo.c_anim_flag |= C_ANIM_DONE; + curr_anim = ANIM_C_DEATH2; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_IDLE4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE4; + break; + case MSG_C_IDLE5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE5; + break; + case MSG_C_IDLE6: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE6; + break; + case MSG_C_PAIN1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PAIN1; + break; + case MSG_C_PAIN2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PAIN2; + break; + case MSG_C_PAIN3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PAIN3; + break; + case MSG_C_THINKAGAIN: // Think for yourself, little ogle man + self->monsterinfo.c_anim_flag = 0; + curr_anim = ANIM_C_THINKAGAIN; + self->monsterinfo.c_mode = 0; + break; + case MSG_C_TRANS1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_TRANS1; + break; + case MSG_C_TRANS2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_TRANS2; + break; + case MSG_C_TRANS3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_TRANS3; + break; + case MSG_C_TRANS4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_TRANS4; + break; + case MSG_C_TRANS5: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_TRANS5; + break; + case MSG_C_TRANS6: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_TRANS6; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + case MSG_C_WALK3: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK3; + break; + case MSG_C_WALK4: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK4; + break; + default: + break; + } + + SetAnim(self, curr_anim); +} + +void ogle_mood_think ( edict_t *self ) +{ + qboolean coward = self->monsterinfo.aiflags & AI_COWARD; + vec3_t v; + float len; + qboolean path = false; + + if (self->enemy && self->ai_mood == AI_MOOD_WANDER) + self->ai_mood = AI_MOOD_PURSUE; + + if (!self->enemy) + { + if (self->targetEnt && self->targetEnt->health > 0) + { + if (self->targetEnt->health < SERAPH_HEALTH/2 || self->targetEnt->ai_mood == AI_MOOD_FLEE) + { + if (irand(0,1)) + gi.sound (self, CHAN_BODY, sounds[SND_ENRAGE1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_BODY, sounds[SND_ENRAGE2], 1, ATTN_NORM, 0); + + self->enemy = self->targetEnt; + self->ai_mood = AI_MOOD_PURSUE; + return; + } + } + + switch (self->ai_mood) + { + case AI_MOOD_NORMAL: + if ( (irand(0,100) > 50) && (self->monsterinfo.attack_finished < level.time) ) + { + self->ai_mood = AI_MOOD_REST; + self->monsterinfo.attack_finished = level.time + 45; + } + break; + } + + self->enemy = NULL; + return; + } + + if(self->monsterinfo.aiflags & AI_COWARD) + self->ai_mood = AI_MOOD_FLEE; + + if(self->enemy) + path = MG_CheckClearPathToEnemy(self); + else + path = false; + + if ((!path && self->enemy) || self->monsterinfo.aiflags & AI_NO_MELEE || self->ai_mood == AI_MOOD_FLEE) + { + MG_Pathfind(self, false); + return; + } + else + { + self->monsterinfo.searchType = SEARCH_COMMON; + + if(self->enemy) + { + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + + if (v[2] <= 40) + v[2] = 0; + + len = VectorLength (v) - self->enemy->maxs[0]; + + // Far enough to run after + if ((len > self->melee_range) || (self->monsterinfo.aiflags & AI_FLEE)) + self->ai_mood = AI_MOOD_PURSUE; + else // Close enough to Attack + { + self->ai_mood = AI_MOOD_ATTACK; + self->ai_mood_flags |= AI_MOOD_FLAG_MELEE; + self->ai_mood_flags &= ~AI_MOOD_FLAG_MISSILE; + } + } + } +} + +/* +========================================================== + + Ogle Helper functions + +========================================================== +*/ + +//Cast off the tools which have oppressed the ogle people for centuries... or something +void ogle_cast_off_tools_of_oppression ( edict_t *self ) +{ + int throw_nodes = 0; + + if (!(self->s.fmnodeinfo[MESH__NAIL].flags & FMNI_NO_DRAW)) + {//Cast off the hammer and nail + throw_nodes |= BPN_NAIL; + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + ThrowWeapon(self, &vec3_origin, throw_nodes, 0, 0); + + throw_nodes |= BPN_HAMMER | BPN_HANDLE; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + + ThrowWeapon(self, &vec3_origin, throw_nodes, 0, 0); + } + else if (!(self->s.fmnodeinfo[MESH__PICK].flags & FMNI_NO_DRAW)) + {//Cast off the pick + throw_nodes |= BPN_PICK | BPN_HANDLE; + + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + + ThrowWeapon(self, &vec3_origin, throw_nodes, 0, 0); + } + else if (!(self->s.fmnodeinfo[MESH__HAMMER].flags & FMNI_NO_DRAW)) + {//Cast off the hammer + throw_nodes |= BPN_HAMMER | BPN_HANDLE; + + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + + ThrowWeapon(self, &vec3_origin, throw_nodes, 0, 0); + } + + self->monsterinfo.aiflags |= AI_NO_MELEE; +} + +//The ogle's been yelled at or struck by the overlord, get back to work! +void ogle_use(edict_t *self, edict_t *other, edict_t *activator) +{ + switch (self->curAnimID) + { + case ANIM_REST1: + SetAnim(self, ANIM_PAIN2); + break; + + case ANIM_REST4: + SetAnim(self, ANIM_PAIN3); + break; + + default: + SetAnim(self, ANIM_PAIN2); + break; + } + + self->ai_mood = AI_MOOD_NORMAL; +} + +//When the ogle is spawned, he checks around to figure out who his tormentor is +void ogle_init_overlord(edict_t *self) +{ + edict_t *seraph = NULL; + + while((seraph = G_Find(seraph, FOFS(targetname), self->target)) != NULL) + { + if (seraph->classID != CID_SERAPH_OVERLORD) + continue; + + //Restore what we lost from monsterstart() + self->targetEnt = seraph; + self->nextthink = level.time + 0.1; + self->think = walkmonster_start_go; + self->use = ogle_use; + return; + } + + self->use = ogle_use; + self->think = walkmonster_start_go; + self->nextthink = level.time + 0.1; +} + +//Ogle Singing Technology (tm) All Right Reserved +void ogle_sing (edict_t *self) +{ + edict_t *ogle = NULL; + + if(self->monsterinfo.awake) + return; + + switch( self->noise_index ) + { + case 0: + while((ogle = G_Find(ogle, FOFS(target), self->target)) != NULL) + { + if(!ogle->monsterinfo.awake) + gi.sound(ogle, CHAN_VOICE, sounds[SND_CHORUS1], 0.25, ATTN_NORM, 0); + } + + self->monsterinfo.jump_time = level.time + 16; + break; + + case 1: + gi.sound (self, CHAN_VOICE, sounds[SND_SOLO1], 1, ATTN_NORM, 0); + self->monsterinfo.jump_time = level.time + 4; + break; + + case 2: + while((ogle = G_Find(ogle, FOFS(target), self->target)) != NULL) + { + if(!ogle->monsterinfo.awake) + gi.sound (ogle, CHAN_VOICE, sounds[SND_CHORUS2], 0.25, ATTN_NORM, 0); + } + self->monsterinfo.jump_time = level.time + 3; + break; + + case 3: + gi.sound (self, CHAN_VOICE, sounds[SND_SOLO2], 1, ATTN_NORM, 0); + self->monsterinfo.jump_time = level.time + 4; + break; + + case 4: + while((ogle = G_Find(ogle, FOFS(target), self->target)) != NULL) + { + if(!ogle->monsterinfo.awake) + gi.sound (ogle, CHAN_VOICE, sounds[SND_CHORUS3], 0.25, ATTN_NORM, 0); + } + self->monsterinfo.jump_time = level.time + 4; + break; + } + + self->noise_index++; + + if (self->noise_index > 4) + self->noise_index = 0; +} + +//High level AI interface +void ogle_pause(edict_t *self) +{ + edict_t *ogle = NULL; + int chance = irand(0,100); + + if ( (self->monsterinfo.ogleflags & OF_SONG_LEADER) && (self->monsterinfo.jump_time < level.time) && (!self->enemy) ) + ogle_sing(self); + + if (!self->enemy) + { + //If we're in pain, get back to work! + if ( self->curAnimID == ANIM_PAIN2) + { + SetAnim(self, ANIM_WORK4); + } + else if ( self->curAnimID == ANIM_PAIN3) + { + SetAnim(self, ANIM_WORK4); + } + + //Switch up the animation speeds + if ( (self->curAnimID == ANIM_WORK1) || (self->curAnimID == ANIM_WORK2) ) + { + if (irand(1,10) < 8) + { + SetAnim(self, ANIM_WORK1); + } + else + { + SetAnim(self, ANIM_WORK2); + } + } + } + + if(self->mood_think) + self->mood_think(self); + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_FLEE: + case AI_MOOD_PURSUE: + case AI_MOOD_NAVIGATE: + if (self->enemy) + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + + break; + case AI_MOOD_WALK: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_STAND: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_DELAY: + break; + + case AI_MOOD_NORMAL: + break; + case AI_MOOD_REST: + if ( (self->curAnimID != ANIM_REST1) && (self->curAnimID != ANIM_REST1_WIPE) && + (self->curAnimID != ANIM_REST1_TRANS) && (self->curAnimID != ANIM_REST2_WIPE) && (self->curAnimID != ANIM_REST3_WIPE) ) + { + if ( (self->curAnimID == ANIM_WORK4) || (self->curAnimID == ANIM_WORK5) ) + { + if (chance < 30) + { + gi.sound (self, CHAN_BODY, sounds[SND_WIPE_BROW], 1, ATTN_IDLE, 0); + SetAnim(self, ANIM_REST2_WIPE); + self->ai_mood = AI_MOOD_NORMAL; + } + else if (chance < 60) + { + SetAnim(self, ANIM_REST1_TRANS); + } + else + { + SetAnim(self, ANIM_REST4_TRANS); + } + } + else if (self->curAnimID == ANIM_WORK1 || self->curAnimID == ANIM_WORK2) + { + gi.sound (self, CHAN_BODY, sounds[SND_WIPE_BROW], 1, ATTN_IDLE, 0); + SetAnim(self, ANIM_REST3_WIPE); + self->ai_mood = AI_MOOD_NORMAL; + } + } + break; + + default : + break; + } +} + +//The ogle is resting, choose a few different possible things to do +void ogle_rest(edict_t *self) +{ + int chance = irand(0,100); + + ogle_pause(self); + + switch(self->curAnimID) + { + case ANIM_REST4_TRANS: + SetAnim(self, ANIM_REST4); + break; + + case ANIM_REST2_WIPE: + SetAnim(self, ANIM_WORK4); + break; + + case ANIM_REST3_WIPE: + SetAnim(self, ANIM_WORK2); + break; + + case ANIM_REST1_TRANS: + SetAnim(self, ANIM_REST1); + break; + + case ANIM_REST1: + if (chance < 20) + SetAnim(self, ANIM_REST1_WIPE); + break; + + case ANIM_REST1_WIPE: + SetAnim(self, ANIM_REST1); + break; + } +} + +//Check to do damage with the ogle's weapon +void ogle_strike(edict_t *self) +{ + trace_t trace; + edict_t *victim; + vec3_t soff, eoff, mins, maxs, bloodDir, direction; + float damage = flrand(OGLE_DMG_MIN, OGLE_DMG_MAX); + + VectorSet(soff, 0, 16, 8); + VectorSet(eoff, self->melee_range, 2, 8); + + VectorSet(mins, -4, -4, -4); + VectorSet(maxs, 4, 4, 4); + + //Purposely backwards + VectorSubtract(soff, eoff, bloodDir); + VectorNormalize(bloodDir); + + victim = M_CheckMeleeLineHit(self, soff, eoff, mins, maxs, &trace, direction); + + if (victim) + { + if (victim == self) + { + //Create a puff effect + gi.CreateEffect(NULL, FX_SPARKS, CEF_FLAG6, trace.endpos, "d", bloodDir); + } + else + { + //Hurt whatever we were whacking away at + if (!(self->s.fmnodeinfo[MESH__HAMMER].flags & FMNI_NO_DRAW)) + gi.sound (self, CHAN_WEAPON, sounds[SND_HAMMER_FLESH], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_PICK_FLESH], 1, ATTN_NORM, 0); + + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, damage, damage*2, 0,MOD_DIED); + } + } + else + { + //Play swoosh sound? + } +} + +//Pick and choose from a wide assortment of happy, joyous dances +void ogle_celebrate(edict_t *self) +{ + int chance = irand(0,100); + + if (!irand(0, 10)) + { + if (chance < 33) + gi.sound (self, CHAN_VOICE, sounds[SND_CHEER1], 1, ATTN_IDLE, 0); + else if (chance < 66) + gi.sound (self, CHAN_VOICE, sounds[SND_CHEER2], 1, ATTN_IDLE, 0); + else + gi.sound (self, CHAN_VOICE, sounds[SND_CHEER3], 1, ATTN_IDLE, 0); + } + + switch (self->curAnimID) + { + case ANIM_CELEBRATE1: + if (chance < 70) + SetAnim(self, ANIM_CELEBRATE1); + else if (chance < 80) + SetAnim(self, ANIM_CELEBRATE5_TRANS); + else + SetAnim(self, ANIM_CELEBRATE2); + break; + + case ANIM_CELEBRATE2: + if (chance < 5) + SetAnim(self, ANIM_CELEBRATE4_TRANS); + else if (chance < 10) + SetAnim(self, ANIM_CELEBRATE3_TRANS); + else if (chance < 50) + SetAnim(self, ANIM_CELEBRATE1); + else if (chance < 80) + SetAnim(self, ANIM_CELEBRATE5_TRANS); + else + SetAnim(self, ANIM_CELEBRATE2); + break; + + case ANIM_CELEBRATE3_TRANS: + SetAnim(self, ANIM_CELEBRATE3); + break; + + case ANIM_CELEBRATE4_TRANS: + SetAnim(self, ANIM_CELEBRATE4); + break; + + case ANIM_CELEBRATE5_TRANS: + SetAnim(self, ANIM_CELEBRATE5); + break; + + case ANIM_CELEBRATE3: + if (chance < 50) + SetAnim(self, ANIM_CELEBRATE4); + else if (chance < 60) + SetAnim(self, ANIM_CELEBRATE2); + else + SetAnim(self, ANIM_CELEBRATE3); + break; + + case ANIM_CELEBRATE4: + if (chance < 50) + SetAnim(self, ANIM_CELEBRATE3); + else if (chance < 60) + SetAnim(self, ANIM_CELEBRATE2); + else + SetAnim(self, ANIM_CELEBRATE4); + break; + + case ANIM_CELEBRATE5: + if (chance < 90) + SetAnim(self, ANIM_CELEBRATE5); + else if (chance < 95) + SetAnim(self, ANIM_CELEBRATE1); + else + SetAnim(self, ANIM_CELEBRATE2); + break; + } +} + +//Spawn the dust and debris, based on what anim the ogle is in +void ogle_pick_dust(edict_t *self) +{ + vec3_t dustPos, vf, vr, vu; + byte type = 0; + + AngleVectors(self->s.angles, vf, vr, vu); + VectorCopy(self->s.origin, dustPos); + + switch (self->curAnimID) + { + case ANIM_WORK3: + VectorMA(dustPos, 38, vf, dustPos); + VectorMA(dustPos, 6, vr, dustPos); + VectorMA(dustPos, -4, vu, dustPos); + VectorScale(vf, -1, vf); + break; + + case ANIM_WORK5: + VectorMA(dustPos, 42, vf, dustPos); + VectorMA(dustPos, 2, vr, dustPos); + VectorMA(dustPos, -24, vu, dustPos); + VectorScale(vu, 1, vf); + type = CEF_FLAG6; + break; + + case ANIM_WORK4: + VectorMA(dustPos, 42, vf, dustPos); + VectorMA(dustPos, 4, vr, dustPos); + VectorMA(dustPos, 8, vu, dustPos); + VectorScale(vf, -1, vf); + break; + + default: + VectorMA(dustPos, 32, vf, dustPos); + VectorMA(dustPos, 4, vr, dustPos); + VectorMA(dustPos, 22, vu, dustPos); + VectorScale(vf, -1, vf); + break; + } + + //Random chance to create a spark + if (irand(0,20) < 1) + gi.CreateEffect(NULL, FX_SPARKS, CEF_FLAG6, dustPos, "d", vu); + + gi.CreateEffect(NULL, FX_OGLE_HITPUFF, type, dustPos, "v", vf); + + //Check for the chisel and hammer + if (!(self->s.fmnodeinfo[MESH__NAIL].flags & FMNI_NO_DRAW)) + { + if (irand(0,1)) + gi.sound (self, CHAN_WEAPON, sounds[SND_SPIKE1], 1, ATTN_IDLE, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_SPIKE2], 1, ATTN_IDLE, 0); + } + else if (!(self->s.fmnodeinfo[MESH__PICK].flags & FMNI_NO_DRAW)) + { + if (irand(0,1)) + gi.sound (self, CHAN_WEAPON, sounds[SND_PICK1], 1, ATTN_IDLE, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_PICK2], 1, ATTN_IDLE, 0); + } + else + { + if (irand(0,1)) + gi.sound (self, CHAN_WEAPON, sounds[SND_HAMMER1], 1, ATTN_IDLE, 0); + else + gi.sound (self, CHAN_WEAPON, sounds[SND_HAMMER2], 1, ATTN_IDLE, 0); + } +} + +/* +========================================================== + + Ogle Message functions + +========================================================== +*/ + +void ogle_pain (edict_t *self, G_Message_t *msg) +{ + edict_t *targ, *attacker; + int chance, damage, temp; + qboolean force_pain; + + chance = irand(0,100); + + ParseMsgParms(msg, "eeiii", &targ, &attacker, &force_pain, &damage, &temp); + +// if (attacker->client) +// { + self->mood_think = ogle_mood_think; + + /* + if (chance < 95) + { + self->monsterinfo.aiflags |= AI_COWARD; + self->ai_mood = AI_MOOD_FLEE; + + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + return; + } + */ + if(attacker && !infront(self, attacker)) + SetAnim(self, ANIM_PAIN3); + else if (chance < 33) + SetAnim(self, ANIM_PAIN1); + else if (chance < 66) + SetAnim(self, ANIM_PAIN2); + else + SetAnim(self, ANIM_PAIN3); +// } + + gi.sound(self, CHAN_VOICE, sounds[irand(SND_PAIN1, SND_PAIN2)], 1, ATTN_NORM, 0); +} + +void ogle_dismember(edict_t *self, int damage, int HitLocation) +{ + int throw_nodes = 0; + vec3_t gore_spot, right; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; + + VectorCopy(vec3_origin,gore_spot); + + switch(HitLocation) + { + case hl_Head: + self->s.fmnodeinfo[MESH__TORSO].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__TORSO].skin = self->s.skinnum+1; + break; + + case hl_TorsoFront: + case hl_TorsoBack: + self->s.fmnodeinfo[MESH__TORSO].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__TORSO].skin = self->s.skinnum+1; + break; + + case hl_ArmUpperLeft: + if(self->s.fmnodeinfo[MESH__LUPARM].flags & FMNI_NO_DRAW) + break; + + if (dismember_ok) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-8,right,gore_spot); + + throw_nodes |= BPN_LUPARM; + self->s.fmnodeinfo[MESH__LUPARM].flags |= FMNI_NO_DRAW; + + if (!(self->s.fmnodeinfo[MESH__L4ARM].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_L4ARM; + self->s.fmnodeinfo[MESH__L4ARM].flags |= FMNI_NO_DRAW; + } + + if (!(self->s.fmnodeinfo[MESH__NAIL].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_NAIL; + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + } + + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + else + { + self->s.fmnodeinfo[MESH__LUPARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LUPARM].skin = self->s.skinnum+1; + } + + break; + + case hl_ArmLowerLeft: + if(self->s.fmnodeinfo[MESH__L4ARM].flags & FMNI_NO_DRAW) + break; + + if (dismember_ok) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-8,right,gore_spot); + + throw_nodes |= BPN_L4ARM; + self->s.fmnodeinfo[MESH__L4ARM].flags |= FMNI_NO_DRAW; + + if (!(self->s.fmnodeinfo[MESH__NAIL].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_NAIL; + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + } + + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + else + { + self->s.fmnodeinfo[MESH__L4ARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__L4ARM].skin = self->s.skinnum+1; + } + + break; + + case hl_ArmUpperRight: + if(self->s.fmnodeinfo[MESH__RUPARM].flags & FMNI_NO_DRAW) + break; + + if (dismember_ok) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,8,right,gore_spot); + + throw_nodes |= BPN_RUPARM; + self->s.fmnodeinfo[MESH__RUPARM].flags |= FMNI_NO_DRAW; + + if (!(self->s.fmnodeinfo[MESH__R4ARM].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_R4ARM; + self->s.fmnodeinfo[MESH__R4ARM].flags |= FMNI_NO_DRAW; + } + + if (!(self->s.fmnodeinfo[MESH__HAMMER].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_HAMMER; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + } + + if (!(self->s.fmnodeinfo[MESH__HANDLE].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_HANDLE; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + } + + if (!(self->s.fmnodeinfo[MESH__PICK].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_PICK; + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + + self->monsterinfo.aiflags |= AI_NO_MELEE; + self->monsterinfo.aiflags |= AI_COWARD; + } + else + { + self->s.fmnodeinfo[MESH__RUPARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RUPARM].skin = self->s.skinnum+1; + } + + break; + + case hl_ArmLowerRight: + if(self->s.fmnodeinfo[MESH__R4ARM].flags & FMNI_NO_DRAW) + break; + + if (dismember_ok) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,8,right,gore_spot); + + throw_nodes |= BPN_R4ARM; + self->s.fmnodeinfo[MESH__R4ARM].flags |= FMNI_NO_DRAW; + + if (!(self->s.fmnodeinfo[MESH__HAMMER].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_HAMMER; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + } + + if (!(self->s.fmnodeinfo[MESH__HANDLE].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_HANDLE; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + } + + if (!(self->s.fmnodeinfo[MESH__PICK].flags & FMNI_NO_DRAW)) + { + throw_nodes |= BPN_PICK; + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + + self->monsterinfo.aiflags |= AI_NO_MELEE; + self->monsterinfo.aiflags |= AI_COWARD; + } + else + { + self->s.fmnodeinfo[MESH__R4ARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__R4ARM].skin = self->s.skinnum+1; + } + + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft: + self->s.fmnodeinfo[MESH__LLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LLEG].skin = self->s.skinnum+1; + break; + + case hl_LegUpperRight: + case hl_LegLowerRight: + self->s.fmnodeinfo[MESH__RLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RLEG].skin = self->s.skinnum+1; + break; + } +} + +void ogle_death_pain(edict_t *self, G_Message_t *msg) +{ + if(self->health <= -80) //gib death + { + BecomeDebris(self); + return; + } + else if(msg) + MG_parse_dismember_msg(self, msg); +} + +void ogle_death(edict_t *self, G_Message_t *msg) +{ + edict_t *targ, *inflictor, *attacker; + float damage; + vec3_t dVel, vf, yf; + + ParseMsgParms(msg, "eeei", &targ, &inflictor, &attacker, &damage); + + M_StartDeath(self, ANIM_DEATH1); + + ogle_cast_off_tools_of_oppression ( self ); + + if (self->health < -80) + { + return; + } + else if (self->health < -10) + { + SetAnim(self, ANIM_DEATH2); + + VectorCopy(targ->velocity, vf); + VectorNormalize(vf); + + VectorScale(vf, -1, yf); + + self->elasticity = 1.2; + self->friction = 0.8; + + VectorScale(vf, 300, dVel); + dVel[2] = irand(200,250); + + VectorCopy(dVel, self->velocity); +// self->groundentity = NULL; + } + else + { + SetAnim(self, ANIM_DEATH1); + } + + gi.sound (self, CHAN_BODY, sounds[SND_DEATH], 1, ATTN_NORM, 0); + +} + +//Get to work! +void ogle_work1(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_WORK1); +} + +qboolean ogle_findtarget (edict_t *self) +{ + edict_t *found = NULL; + + //take down weak overlords + while(found = findradius(found, self->s.origin, 1024)) + { + if(found->classID == CID_SERAPH_OVERLORD && found->health > 0 && (found->healthai_mood == AI_MOOD_FLEE)) + { + self->enemy = found; + FoundTarget(self, false); + return true; + } + } + + /*//Used to go after other stuff and break it... + found = NULL; + //ok, search for utensils of their oppression + while(found = findradius(found, self->s.origin, 512)) + { + if(found->classID == CID_OBJECT) + { + if(found->takedamage && found->health > 0) + { + if(!strcmp(found->classname, "obj_minecart1")|| + !strcmp(found->classname, "obj_minecart2")|| + !strcmp(found->classname, "obj_minecart3")|| + !strcmp(found->classname, "obj_pick")|| + !strcmp(found->classname, "obj_gascan")|| + !strcmp(found->classname, "obj_barrel_metal")|| + !strcmp(found->classname, "obj_metalchunk1")|| + !strcmp(found->classname, "obj_metalchunk2")|| + !strcmp(found->classname, "obj_metalchunk3")|| + !strcmp(found->classname, "obj_pipe1")|| + !strcmp(found->classname, "obj_pipe2")|| + !strcmp(found->classname, "obj_pushcart")|| + !strcmp(found->classname, "obj_shovel")|| + !strcmp(found->classname, "obj_wheelbarrow")|| + !strcmp(found->classname, "obj_wheelbarrowdamaged")) + { + if(irand(0, 1)) + { + if(visible(self, found)) + { + self->enemy = found; + FoundTarget(self, false); + return true; + } + } + } + } + } + }*/ + + found = NULL; + //help out other ogles + while(found = findradius(found, self->s.origin, 1024)) + { + if(found->classID == CID_OGLE && found->health > 0 && found != self) + { + if(found->enemy) + { + if(found->enemy->health > 0) + { + { + if(found->enemy->client) + found->enemy = NULL; + else + { + self->enemy = found->enemy; + FoundTarget(self, false); + return true; + } + } + } + } + } + } + + return false; +} +//Classic melee function (fear the ogles) +void ogle_melee( edict_t *self, G_Message_t *msg ) +{ + qboolean ret; + int chance = irand(0,4); + + if (!self->enemy) + return; + + if(self->enemy->client) + self->enemy = NULL; + + if (self->enemy->health <= 0) + { + ret = ogle_findtarget(self); + + if (!ret) + { + self->enemy = self->goalentity = NULL; + self->ai_mood = AI_MOOD_PURSUE; + + ogle_cast_off_tools_of_oppression( self ); + + switch( chance ) + { + case 0: SetAnim(self, ANIM_CELEBRATE1); break; + case 1: SetAnim(self, ANIM_CELEBRATE2); break; + case 2: SetAnim(self, ANIM_CELEBRATE3); break; + case 3: SetAnim(self, ANIM_CELEBRATE4); break; + case 4: SetAnim(self, ANIM_CELEBRATE5); break; + } + + return; + } + } + + SetAnim(self, ANIM_ATTACK1); +} + +//do a little dance.. make a little.. oh, sorry +void ogle_stand1(edict_t *self, G_Message_t *msg) +{ + if(self->monsterinfo.awake) + { + int change = irand(0,4); + + switch( change ) + { + case 0: SetAnim(self, ANIM_CELEBRATE1); break; + case 1: SetAnim(self, ANIM_CELEBRATE2); break; + case 2: SetAnim(self, ANIM_CELEBRATE3); break; + case 3: SetAnim(self, ANIM_CELEBRATE4); break; + case 4: SetAnim(self, ANIM_CELEBRATE5); break; + } + } +} + +//Classic run-attack function, who thought mortal combat could be so cute? +void ogle_run1(edict_t *self, G_Message_t *msg) +{ + trace_t trace; + vec3_t start, end, mins; + float len; + int change = irand(0,4); + qboolean ret; + + if(self->enemy && self->enemy->client) + self->enemy = NULL; + + if (self->enemy && self->enemy->health <= 0) + { + ret = ogle_findtarget(self); + + if (!ret) + { + self->enemy = self->goalentity = NULL; + self->ai_mood = AI_MOOD_PURSUE; + + ogle_cast_off_tools_of_oppression( self ); + + switch( change ) + { + case 0: SetAnim(self, ANIM_CELEBRATE1); break; + case 1: SetAnim(self, ANIM_CELEBRATE2); break; + case 2: SetAnim(self, ANIM_CELEBRATE3); break; + case 3: SetAnim(self, ANIM_CELEBRATE4); break; + case 4: SetAnim(self, ANIM_CELEBRATE5); break; + } + } + + return; + } + else if (self->enemy) + { + len = M_DistanceToTarget(self, self->enemy); + + if (len < 40) // close enough to swing, not necessarily hit + { + SetAnim(self, ANIM_ATTACK1); + } + else if (len < 100) // close enough to swing, not necessarily hit + { + VectorCopy(self->s.origin, start); + VectorCopy(self->enemy->s.origin, end); + start[2]+=self->viewheight; + end[2]+=self->enemy->viewheight; + + VectorCopy(self->mins, mins); + mins[2]+=self->maxs[0]/2;//because this guys's mins are 0 + + gi.trace(start, mins, self->maxs, end, self, MASK_MONSTERSOLID,&trace); + + if(trace.ent==self->enemy) + { + if (irand(0,1)) + SetAnim(self, ANIM_ATTACK2); + else + SetAnim(self, ANIM_ATTACK3); + } + else + { + switch (change) + { + case 0: SetAnim(self, ANIM_CHARGE1); break; + case 1: SetAnim(self, ANIM_CHARGE2); break; + case 2: SetAnim(self, ANIM_CHARGE3); break; + case 3: SetAnim(self, ANIM_CHARGE4); break; + case 4: SetAnim(self, ANIM_CHARGE5); break; + } + } + } + else + { + switch (self->curAnimID) + { + case ANIM_CHARGE1: + case ANIM_CHARGE2: + case ANIM_CHARGE3: + case ANIM_CHARGE4: + case ANIM_CHARGE5: + break; + + default: + switch (change) + { + case 0: SetAnim(self, ANIM_CHARGE1); break; + case 1: SetAnim(self, ANIM_CHARGE2); break; + case 2: SetAnim(self, ANIM_CHARGE3); break; + case 3: SetAnim(self, ANIM_CHARGE4); break; + case 4: SetAnim(self, ANIM_CHARGE5); break; + } + break; + } + } + + return; + } + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void ogle_check_leadsong (edict_t *self) +{ + edict_t *ogle = NULL; + + while((ogle = G_Find(ogle, FOFS(target), self->target)) != NULL) + { + if(ogle->monsterinfo.ogleflags & OF_SONG_LEADER) + return; + } + + self->monsterinfo.ogleflags |= OF_SONG_LEADER; +} + +void ogle_start_push (edict_t *self, edict_t *other, edict_t *activator) +{ + if(!irand(0, 2)) + SetAnim(self, ANIM_PUSH1); + else if(irand(0, 1)) + SetAnim(self, ANIM_PUSH2); + else + SetAnim(self, ANIM_PUSH3); +} + +qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink); +void pitch_roll_for_slope (edict_t *forwhom, vec3_t *slope); +void ogle_push (edict_t *self, float dist) +{ + edict_t *found = NULL; + float yaw; + vec3_t move, forward, endpos; + trace_t trace; + qboolean done = false; + + if(found = G_Find(found, FOFS(targetname), self->target)) + { + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->s.origin, 64, forward, endpos); + gi.trace(self->s.origin, vec3_origin, vec3_origin, endpos, self, MASK_MONSTERSOLID, &trace); + if(trace.ent && trace.ent == found) + { + yaw = self->s.angles[YAW]*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + if(SV_movestep(found, move, true)) + { + pitch_roll_for_slope(found, NULL); + M_walkmove(self, self->s.angles[YAW], dist); + return; + } + done = true; + } + } + + if(!done) + SetAnim(self, ANIM_REST4_TRANS); + else + { + gi.sound (self, CHAN_VOICE, sounds[SND_WIPE_BROW], 1, ATTN_IDLE, 0); + SetAnim(self, ANIM_REST1_WIPE); + } + self->ai_mood = AI_MOOD_REST; + self->mood_think = ogle_mood_think; +} + +/* +========================================================== + + Ogle Spawn functions + +========================================================== +*/ + +void OgleStaticsInit() +{ + classStatics[CID_OGLE].msgReceivers[MSG_STAND] = ogle_stand1; + classStatics[CID_OGLE].msgReceivers[MSG_RUN] = ogle_run1; + classStatics[CID_OGLE].msgReceivers[MSG_MELEE] = ogle_melee; + classStatics[CID_OGLE].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_OGLE].msgReceivers[MSG_DEATH] = ogle_death; + classStatics[CID_OGLE].msgReceivers[MSG_PAIN] = ogle_pain; + classStatics[CID_OGLE].msgReceivers[MSG_DEATH_PAIN] = ogle_death_pain; + + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION1] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION2] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION3] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION4] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION5] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION6] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION7] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION8] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION9] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION10] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION11] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION12] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION13] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION14] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ACTION15] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ATTACK1] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ATTACK2] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_ATTACK3] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_DEATH1] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_DEATH2] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_GIB1] = ai_c_gib; + classStatics[CID_OGLE].msgReceivers[MSG_C_IDLE1] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_IDLE2] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_IDLE3] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_IDLE4] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_IDLE5] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_IDLE6] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_PAIN1] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_PAIN2] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_PAIN3] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_THINKAGAIN] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_TRANS1] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_TRANS2] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_TRANS3] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_TRANS4] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_TRANS5] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_TRANS6] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_WALK1] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_WALK2] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_WALK3] = ogle_c_anims; + classStatics[CID_OGLE].msgReceivers[MSG_C_WALK4] = ogle_c_anims; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/ogle/tris.fm"); + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + sounds[SND_PICK1] = gi.soundindex("monsters/ogle/pick1.wav"); + sounds[SND_PICK2] = gi.soundindex("monsters/ogle/pick2.wav"); + sounds[SND_SPIKE1] = gi.soundindex("monsters/ogle/spike1.wav"); + sounds[SND_SPIKE2] = gi.soundindex("monsters/ogle/spike2.wav"); + sounds[SND_HAMMER1] = gi.soundindex("monsters/ogle/hammer1.wav"); + sounds[SND_HAMMER2] = gi.soundindex("monsters/ogle/hammer2.wav"); + sounds[SND_PICK_FLESH] = gi.soundindex("monsters/ogle/pickflesh.wav"); + sounds[SND_HAMMER_FLESH]= gi.soundindex("monsters/ogle/hammerflesh.wav"); + sounds[SND_WIPE_BROW] = gi.soundindex("monsters/ogle/wipebrow.wav"); + sounds[SND_ENRAGE1] = gi.soundindex("monsters/ogle/enrage1.wav"); + sounds[SND_ENRAGE2] = gi.soundindex("monsters/ogle/enrage2.wav"); + sounds[SND_DEATH] = gi.soundindex("monsters/ogle/death.wav"); + sounds[SND_CHEER1] = gi.soundindex("monsters/ogle/cheer1.wav"); + sounds[SND_CHEER2] = gi.soundindex("monsters/ogle/cheer2.wav"); + sounds[SND_CHEER3] = gi.soundindex("monsters/ogle/cheer3.wav"); + + sounds[SND_PAIN1] = gi.soundindex("monsters/ogle/oglemoan1.wav"); + sounds[SND_PAIN2] = gi.soundindex("monsters/ogle/oglemoan2.wav"); + + //Singing + sounds[SND_CHORUS1] = gi.soundindex("monsters/ogle/chorus1.wav"); + sounds[SND_CHORUS2] = gi.soundindex("monsters/ogle/chorus3.wav"); + sounds[SND_CHORUS3] = gi.soundindex("monsters/ogle/chorus5.wav"); + sounds[SND_SOLO1] = gi.soundindex("monsters/ogle/solo2.wav"); + sounds[SND_SOLO2] = gi.soundindex("monsters/ogle/solo4.wav"); + + classStatics[CID_OGLE].resInfo = &resInfo; +} + +/*QUAKED monster_ogle(1 .5 0) (-16 -16 -24) (16 16 16) pushing pick_up pick_down chisel_up chisel_down hammer_up hammer_down singing CINEMATIC + +The little, disgruntled Ogle + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 16 +melee_range = 48 +missile_range = 0 +min_missile_range = 0 +bypass_missile_chance = 0 +jump_chance = 10 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +void SP_monster_ogle(edict_t *self) +{ + qboolean skip_inits = false; + edict_t *found = NULL; + int chance; + + if (deathmatch->value) + { + G_FreeEdict (self); + return; + } + + self->classID = CID_OGLE; + + self->monsterinfo.ogleflags = self->spawnflags; + self->spawnflags = 0;//don't want incorrect handling due to weird ogle spawnflags! + + if (!monster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->monsterinfo.alert = NULL;//can't be woken up + self->monsterinfo.dismember = ogle_dismember; + + if (!self->health) + self->health = OGLE_HEALTH; + + //Apply to the end result (whether designer set or not) + self->health = MonsterHealth(self->health); + + self->mass = OGLE_MASS; + self->yaw_speed = 16; + + self->movetype = PHYSICSTYPE_STEP; + self->solid=SOLID_BBOX; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + self->materialtype = MAT_FLESH; + + self->s.modelindex = classStatics[CID_OGLE].resInfo->modelIndex; + self->s.skinnum=0; + + if (self->monsterinfo.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + self->monsterinfo.otherenemyname = "monster_rat"; + + MG_InitMoods(self); + + self->monsterinfo.aiflags |= AI_NO_ALERT; + + self->mood_think = ogle_mood_think; + + self->use = ogle_use; + + chance = irand(0,4); + + if (!self->monsterinfo.ogleflags) + { + switch (chance) + { + case 0: self->monsterinfo.ogleflags |= OF_PICK_UP; + break; + case 1: self->monsterinfo.ogleflags |= OF_PICK_DOWN; + break; + case 2: self->monsterinfo.ogleflags |= OF_HAMMER_UP; + break; + case 3: self->monsterinfo.ogleflags |= OF_HAMMER_DOWN; + break; + case 4: self->monsterinfo.ogleflags |= OF_CHISEL_UP; + break; + } + } + + self->monsterinfo.attack_finished = level.time + irand(10,100); + + if (self->monsterinfo.ogleflags & OF_PUSHING) + { + //if (self->monsterinfo.ogleflags & OF_CINEMATIC) + if(self->targetname && self->target) + { + if(found = G_Find(NULL, FOFS(targetname), self->target)) + pitch_roll_for_slope(found, NULL); + + skip_inits = true; + + self->mood_think = NULL; + SetAnim(self, ANIM_REST4); + self->use = ogle_start_push; + + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + else + { // We gotta do SOMETHING if there is no target, otherwise the monster will puke. +#ifdef _DEVEL + gi.dprintf("Ogle at (%s) set to push with no target.\n", + vtos(self->s.origin)); +#endif + SetAnim(self, ANIM_WORK3); + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + } + else if (self->monsterinfo.ogleflags & OF_PICK_UP) + { + if (self->monsterinfo.ogleflags & OF_CINEMATIC) + SetAnim(self, ANIM_C_IDLE1); + else + SetAnim(self, ANIM_WORK4); + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + } + else if (self->monsterinfo.ogleflags & OF_PICK_DOWN) + { + if (self->monsterinfo.ogleflags & OF_CINEMATIC) + SetAnim(self, ANIM_C_IDLE1); + else + SetAnim(self, ANIM_WORK5); + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + } + else if (self->monsterinfo.ogleflags & OF_CHISEL_UP) + { + if (self->monsterinfo.ogleflags & OF_CINEMATIC) + SetAnim(self, ANIM_C_IDLE1); + else + { + if (irand(0,1)) + SetAnim(self, ANIM_WORK1); + else + SetAnim(self, ANIM_WORK2); + } + + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + else if (self->monsterinfo.ogleflags & OF_HAMMER_UP) + { + if (self->monsterinfo.ogleflags & OF_CINEMATIC) + SetAnim(self, ANIM_C_IDLE1); + else + SetAnim(self, ANIM_WORK4); + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + else if (self->monsterinfo.ogleflags & OF_HAMMER_DOWN) + { + if (self->monsterinfo.ogleflags & OF_CINEMATIC) + SetAnim(self, ANIM_C_IDLE1); + else + SetAnim(self, ANIM_WORK5); + self->s.fmnodeinfo[MESH__NAIL].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + else + { + if (self->monsterinfo.ogleflags & OF_CINEMATIC) + SetAnim(self, ANIM_C_IDLE1); + else + SetAnim(self, ANIM_WORK3); + self->s.fmnodeinfo[MESH__PICK].flags |= FMNI_NO_DRAW; + } + + if (self->monsterinfo.ogleflags & OF_CINEMATIC) + { + self->svflags|=SVF_FLOAT; + self->monsterinfo.c_mode = 1; + } + + self->svflags |= SVF_NO_AUTOTARGET; + + if(!skip_inits) + { + //Find out who our overlord is + self->think = ogle_init_overlord; + self->nextthink = level.time + 0.1; + + if(singing_ogles->value) + { + if(!(self->monsterinfo.ogleflags & OF_SONG_LEADER)) + ogle_check_leadsong(self); + } + + if (self->monsterinfo.ogleflags & OF_SONG_LEADER) + self->noise_index = 0; + } + else + { + self->think = walkmonster_start_go; + self->nextthink = level.time + 0.1; + } +} diff --git a/Toolkit/Programming/GameCode/game/m_ogle.h b/Toolkit/Programming/GameCode/game/m_ogle.h new file mode 100644 index 0000000..1c70bbf --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_ogle.h @@ -0,0 +1,221 @@ +#include "g_local.h" + +typedef enum AnimID_e +{ + ANIM_WALK1, + ANIM_PUSH1, + ANIM_PUSH2, + ANIM_PUSH3, + ANIM_STAND1, + ANIM_WORK1, + ANIM_WORK2, + ANIM_WORK3, + ANIM_WORK4, + ANIM_WORK5, + ANIM_PAIN1, + ANIM_PAIN2, + ANIM_PAIN3, + ANIM_REST1_TRANS, + ANIM_REST1_WIPE, + ANIM_REST1, + ANIM_REST2_WIPE, + ANIM_REST3_WIPE, + ANIM_REST4_TRANS, + ANIM_REST4_TRANS2, + ANIM_REST4, + ANIM_CELEBRATE1, + ANIM_CELEBRATE2, + ANIM_CELEBRATE3_TRANS, + ANIM_CELEBRATE3, + ANIM_CELEBRATE4_TRANS, + ANIM_CELEBRATE4, + ANIM_CELEBRATE5_TRANS, + ANIM_CELEBRATE5, + ANIM_CHARGE1, + ANIM_CHARGE2, + ANIM_CHARGE3, + ANIM_CHARGE4, + ANIM_CHARGE5, + ANIM_ATTACK1, + ANIM_ATTACK2, + ANIM_ATTACK3, + ANIM_DEATH1, + ANIM_DEATH2, + + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ACTION5, + ANIM_C_ACTION6, + ANIM_C_ACTION7, + ANIM_C_ACTION8, + ANIM_C_ACTION9, + ANIM_C_ACTION10, + ANIM_C_ACTION11, + ANIM_C_ACTION12, + ANIM_C_ACTION13, + ANIM_C_ACTION14, + ANIM_C_ACTION15, + ANIM_C_ATTACK1, + ANIM_C_ATTACK2, + ANIM_C_ATTACK3, + ANIM_C_DEATH1, + ANIM_C_DEATH2, + ANIM_C_GIB1, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_IDLE4, + ANIM_C_IDLE5, + ANIM_C_IDLE6, + ANIM_C_PAIN1, + ANIM_C_PAIN2, + ANIM_C_PAIN3, + ANIM_C_THINKAGAIN, + ANIM_C_TRANS1, + ANIM_C_TRANS2, + ANIM_C_TRANS3, + ANIM_C_TRANS4, + ANIM_C_TRANS5, + ANIM_C_TRANS6, + ANIM_C_WALK1, + ANIM_C_WALK2, + ANIM_C_WALK3, + ANIM_C_WALK4, + + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PICK1, + SND_PICK2, + SND_SPIKE1, + SND_SPIKE2, + SND_HAMMER1, + SND_HAMMER2, + SND_PICK_FLESH, + SND_HAMMER_FLESH, + SND_WIPE_BROW, + SND_ENRAGE1, + SND_ENRAGE2, + SND_DEATH, + SND_CHEER1, + SND_CHEER2, + SND_CHEER3, + //SINGING + SND_CHORUS1, + SND_CHORUS2, + SND_CHORUS3, + SND_SOLO1, + SND_SOLO2, + SND_PAIN1, + SND_PAIN2, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t ogle_move_walk1, + ogle_move_push1, + ogle_move_push2, + ogle_move_push3, + ogle_move_work1, + ogle_move_work2, + ogle_move_work3, + ogle_move_work4, + ogle_move_work5, + ogle_move_pain1, + ogle_move_pain2, + ogle_move_rest1, + ogle_move_stand1, + ogle_move_rest1_wipe, + ogle_move_rest2_wipe, + ogle_move_rest3_wipe, + ogle_move_rest1_trans, + ogle_move_rest4_trans, + ogle_move_rest4_trans2, + ogle_move_rest4, + ogle_move_pain3, + ogle_move_celebrate1, + ogle_move_celebrate2, + ogle_move_celebrate3_trans, + ogle_move_celebrate3, + ogle_move_celebrate4_trans, + ogle_move_celebrate4, + ogle_move_celebrate5_trans, + ogle_move_celebrate5, + ogle_move_charge1, + ogle_move_charge2, + ogle_move_charge3, + ogle_move_charge4, + ogle_move_charge5, + ogle_move_attack1, + ogle_move_attack2, + ogle_move_attack3, + ogle_move_death1, + ogle_move_death2, + + ogle_c_move_action1, + ogle_c_move_action2, + ogle_c_move_action3, + ogle_c_move_action4, + ogle_c_move_action5, + ogle_c_move_action6, + ogle_c_move_action7, + ogle_c_move_action8, + ogle_c_move_action9, + ogle_c_move_action10, + ogle_c_move_action11, + ogle_c_move_action12, + ogle_c_move_action13, + ogle_c_move_action14, + ogle_c_move_action15, + ogle_c_move_attack1, + ogle_c_move_attack2, + ogle_c_move_attack3, + ogle_c_move_death1, + ogle_c_move_death2, + ogle_c_move_idle1, + ogle_c_move_idle2, + ogle_c_move_idle3, + ogle_c_move_idle4, + ogle_c_move_idle5, + ogle_c_move_idle6, + ogle_c_move_pain1, + ogle_c_move_pain2, + ogle_c_move_pain3, + ogle_c_move_trans1, + ogle_c_move_trans2, + ogle_c_move_trans3, + ogle_c_move_trans4, + ogle_c_move_trans5, + ogle_c_move_trans6, + ogle_c_move_walk1, + ogle_c_move_walk2, + ogle_c_move_walk3, + ogle_c_move_walk4; + + +void SP_monster_ogle(edict_t *self); + +void ogle_pick_dust(edict_t *self); +void ogle_celebrate(edict_t *self); +void ogle_strike(edict_t *self); +void ogle_pause(edict_t *self); +void ogle_rest(edict_t *self); +void ogle_push (edict_t *self, float dist); + +#define BPN_GRANDDADDY 0 +#define BPN_DADDY 1 +#define BPN_TORSO 2 +#define BPN_NAIL 4 +#define BPN_PICK 8 +#define BPN_RUPARM 16 +#define BPN_RLEG 32 +#define BPN_R4ARM 64 +#define BPN_LLEG 128 +#define BPN_LUPARM 256 +#define BPN_L4ARM 512 +#define BPN_HAMMER 1024 +#define BPN_HANDLE 2048 + diff --git a/Toolkit/Programming/GameCode/game/m_ogle_anim.c b/Toolkit/Programming/GameCode/game/m_ogle_anim.c new file mode 100644 index 0000000..28421c7 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_ogle_anim.c @@ -0,0 +1,1092 @@ +#include "m_ogle.h" +#include "g_local.h" +#include "m_ogle_anim.h" + +#include "g_monster.h" +#include "c_ai.h" + +/*---------------------------------------------------- + ogle standing - temp +----------------------------------------------------*/ +animframe_t ogle_frames_stand1[] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t ogle_move_stand1 = {1,ogle_frames_stand1, ogle_pause}; + +/*---------------------------------------------------- + ogle walking +----------------------------------------------------*/ +animframe_t ogle_frames_walk1[] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_run, 2, NULL, + FRAME_walk2, NULL, 0, 0, 0, ai_run, 2, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_run, 2, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_run, 2, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_run, 2, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_run, 2, NULL, + FRAME_walk7, NULL, 0, 0, 0, ai_run, 2, NULL, + FRAME_walk8, NULL, 0, 0, 0, ai_run, 2, NULL, +}; +animmove_t ogle_move_walk1 = {8,ogle_frames_walk1, ogle_pause}; + +/*---------------------------------------------------- + ogle pushing anims + + push1 - pushing a cart, right hand higher than left + push2 - pushing a cart, both hands equal + push3 - pushing a cart, left hand higher than right +----------------------------------------------------*/ + +animframe_t ogle_frames_push1[] = +{ + FRAME_pusha1, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pusha2, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pusha3, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pusha4, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pusha5, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pusha6, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pusha7, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pusha8, NULL, 0, 0, 0, ogle_push, 4, NULL, +}; +animmove_t ogle_move_push1 = {8,ogle_frames_push1, NULL}; + +animframe_t ogle_frames_push2[] = +{ + FRAME_pushb1, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushb2, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushb3, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushb4, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushb5, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushb6, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushb7, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushb8, NULL, 0, 0, 0, ogle_push, 4, NULL, +}; +animmove_t ogle_move_push2 = {8,ogle_frames_push2, NULL}; + +animframe_t ogle_frames_push3[] = +{ + FRAME_pushc1, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushc2, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushc3, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushc4, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushc5, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushc6, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushc7, NULL, 0, 0, 0, ogle_push, 4, NULL, + FRAME_pushc8, NULL, 0, 0, 0, ogle_push, 4, NULL, +}; +animmove_t ogle_move_push3 = {8,ogle_frames_push3, NULL}; + +/*---------------------------------------------------- + ogle working anims + + work1 - hammering with chisel quickly, straight + work2 - hammering with chisel slowly, straight + work3 - hammering with chisel, downward + work4 - picking with axe, straight + work5 - picking with axe, downward +----------------------------------------------------*/ + +animframe_t ogle_frames_work1[] = +{ + FRAME_hamupa2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupa3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupa4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupa5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupa1, NULL, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_move_work1 = {5,ogle_frames_work1, ogle_pause}; + +animframe_t ogle_frames_work2[] = +{ + FRAME_hamupb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb1, NULL, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_move_work2 = {9,ogle_frames_work2, ogle_pause}; + +animframe_t ogle_frames_work3[] = +{ + FRAME_hamdwn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn1, NULL, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_move_work3 = {9,ogle_frames_work3, ogle_pause}; + +animframe_t ogle_frames_work4[] = +{ + FRAME_pikxup2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup1, NULL, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_move_work4 = {7,ogle_frames_work4, ogle_pause}; + +animframe_t ogle_frames_work5[] = +{ + FRAME_pikxdn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn1, NULL, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_move_work5 = {7,ogle_frames_work5, ogle_pause}; + +/*---------------------------------------------------- + ogle pain anims + + pain1 - guarding head + pain2 - transition from rest1 back into work4 + pain3 - transition from rest4 back into work4 +----------------------------------------------------*/ + +animframe_t ogle_frames_pain1[] = +{ + FRAME_paina1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina4, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_pain1 = {8, ogle_frames_pain1, ogle_pause}; + +animframe_t ogle_frames_pain2[] = +{ + FRAME_rstapn1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn8, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_pain2 = {12, ogle_frames_pain2, ogle_pause}; + +animframe_t ogle_frames_pain3[] = +{ + FRAME_brkpn1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_pain3 = {6,ogle_frames_pain3, ogle_pause}; + +/*---------------------------------------------------- + ogle rest anims + + rest1_trans - transition from work4 to leaning back on pick + rest1 - leaning back on pick, breating + rest1_wipe - wipes brow from picking, returns to rest + rest2_wipe - wipes brow from picking, returns to work + rest3_wipe - wipes brow from chisel, returns to work + rest4_trans - transition from work4 to resting pick on shoulder + rest4_trans2 - transition from chisel to resting pick on shoulder + rest4 - resting pick on shoulder, breathing +----------------------------------------------------*/ + +animframe_t ogle_frames_rest1_trans[] = +{ + FRAME_rsta1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_rest1_trans = {6,ogle_frames_rest1_trans, ogle_rest}; + +animframe_t ogle_frames_rest1[] = +{ + FRAME_rstaid1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid8, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_rest1 = {8,ogle_frames_rest1, ogle_rest}; + +animframe_t ogle_frames_rest1_wipe[] = +{ + FRAME_rstawp1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp10,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp11,NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_rest1_wipe = {11,ogle_frames_rest1_wipe, ogle_rest}; + +animframe_t ogle_frames_rest2_wipe[] = +{ + FRAME_pkaxwp1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp10,NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_rest2_wipe = {10,ogle_frames_rest2_wipe, ogle_rest}; + +animframe_t ogle_frames_rest3_wipe[] = +{ + FRAME_hamwp1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp10,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp11,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp12,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp13,NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_rest3_wipe = {13,ogle_frames_rest3_wipe, ogle_rest}; + +animframe_t ogle_frames_rest4_trans[] = +{ + FRAME_brka1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brka2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brka3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brka4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brka5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brka6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brka7, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_rest4_trans = {7,ogle_frames_rest4_trans, ogle_rest}; + +animframe_t ogle_frames_rest4_trans2[] = +{ + FRAME_brkb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_rest4_trans2 = {6,ogle_frames_rest4_trans2, ogle_rest}; + +animframe_t ogle_frames_rest4[] = +{ + FRAME_brkidl1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl8, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_rest4 = {8, ogle_frames_rest4, ogle_rest}; + +/*---------------------------------------------------- + ogle celebration anims + + celebrate1 - hands in the air, back field in motion + celebrate2 - hands in the air, jumping up and down + celebrate3_trans - transition from celebrate2 + celebrate3 - the infamous Butthead manuever + celebrate4_trans - transition from celebrate2 + celebrate4 - more buttheadisms + celebrate5_trans - transition from celebrate2 + celebrate5 - butt wigglin' +----------------------------------------------------*/ + +animframe_t ogle_frames_celebrate1[] = +{ + FRAME_cela1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_cela2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_cela3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_cela4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_cela5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_cela6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_celebrate1 = {6, ogle_frames_celebrate1, ogle_celebrate}; + +animframe_t ogle_frames_celebrate2[] = +{ + FRAME_celb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celb6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celb7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celb8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celb9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celb10, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_celebrate2 = {10, ogle_frames_celebrate2, ogle_celebrate}; + +animframe_t ogle_frames_celebrate3_trans[] = +{ + FRAME_celc1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celc2, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_celebrate3_trans = {2, ogle_frames_celebrate3_trans, ogle_celebrate}; + +animframe_t ogle_frames_celebrate3[] = +{ + FRAME_celc3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celc4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celc5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celc6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celc7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celc8, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_celebrate3 = {6, ogle_frames_celebrate3, ogle_celebrate}; + +animframe_t ogle_frames_celebrate4_trans[] = +{ + FRAME_celd1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celd2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celd3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celd4, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_celebrate4_trans = {4, ogle_frames_celebrate4_trans, ogle_celebrate}; + +animframe_t ogle_frames_celebrate4[] = +{ + FRAME_celd5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celd6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celd7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celd8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celd9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_celd10, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_celebrate4 = {6, ogle_frames_celebrate4, ogle_celebrate}; + +animframe_t ogle_frames_celebrate5_trans[] = +{ + FRAME_cele1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_cele2, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_celebrate5_trans = {2, ogle_frames_celebrate5_trans, ogle_celebrate}; + +animframe_t ogle_frames_celebrate5[] = +{ + FRAME_cele5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_cele6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_cele7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_cele8, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_celebrate5 = {4, ogle_frames_celebrate5, ogle_celebrate}; + +/*---------------------------------------------------- + ogle charge anims + + charge1 - arm raised and ready for action + charge2 - both arms are down + charge3 - both arms in arm, raising them up and down + charge4 - both arms in arm, moving them in unison left and right + charge5 - both arms in arm, moving them in opposingly left and right +----------------------------------------------------*/ + +animframe_t ogle_frames_charge1[] = +{ + FRAME_charga1, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_charga2, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_charga3, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_charga4, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_charga5, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_charga6, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_charga7, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_charga8, NULL, 0, 0, 0, ai_run, 10, NULL, +}; +animmove_t ogle_move_charge1 = {8, ogle_frames_charge1, ogle_pause}; + +animframe_t ogle_frames_charge2[] = +{ + FRAME_chargb1, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_chargb2, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_chargb3, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_chargb4, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_chargb5, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_chargb6, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_chargb7, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_chargb8, NULL, 0, 0, 0, ai_run, 10, NULL, +}; +animmove_t ogle_move_charge2 = {8, ogle_frames_charge2, ogle_pause}; + +animframe_t ogle_frames_charge3[] = +{ + FRAME_chargc1, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_chargc2, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_chargc3, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_chargc4, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_chargc5, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_chargc6, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_chargc7, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_chargc8, NULL, 0, 0, 0, ai_run, 10, NULL, +}; +animmove_t ogle_move_charge3 = {8, ogle_frames_charge3, ogle_pause}; + +animframe_t ogle_frames_charge4[] = +{ + FRAME_chargd1, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_chargd2, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_chargd3, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_chargd4, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_chargd5, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_chargd6, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_chargd7, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_chargd8, NULL, 0, 0, 0, ai_run, 10, NULL, +}; +animmove_t ogle_move_charge4 = {8, ogle_frames_charge4, ogle_pause}; + +animframe_t ogle_frames_charge5[] = +{ + FRAME_charge1, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_charge2, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_charge3, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_charge4, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_charge5, NULL, 0, 0, 0, ai_run, 10, NULL, + FRAME_charge6, NULL, 0, 0, 0, ai_run, 9, NULL, + FRAME_charge7, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_charge8, NULL, 0, 0, 0, ai_run, 10, NULL, +}; +animmove_t ogle_move_charge5 = {8, ogle_frames_charge5, ogle_pause}; + +/*---------------------------------------------------- + ogle attack anims + + attack1 - picking away at enemy + attack2 - running attack + attack3 - running attack 2 +----------------------------------------------------*/ + +animframe_t ogle_frames_attack1[] = +{ + FRAME_pikxup2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_pikxup3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_pikxup4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_pikxup5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_pikxup6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_pikxup7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_pikxup1, NULL, 0, 0, 0, ai_charge, 0, ogle_strike, +}; +animmove_t ogle_move_attack1 = {7,ogle_frames_attack1, ogle_pause}; + +animframe_t ogle_frames_attack2[] = +{ + FRAME_rnatka2, NULL, 0, 0, 0, ai_charge, 12, NULL, + FRAME_rnatka3, NULL, 0, 0, 0, ai_charge, 11, NULL, + FRAME_rnatka4, NULL, 0, 0, 0, ai_charge, 10, NULL, + FRAME_rnatka5, NULL, 0, 0, 0, ai_charge, 12, NULL, + FRAME_rnatka6, NULL, 0, 0, 0, ai_charge, 11, NULL, + FRAME_rnatka7, NULL, 0, 0, 0, ai_charge, 10, NULL, + FRAME_rnatka8, NULL, 0, 0, 0, ai_charge, 11, NULL, + FRAME_rnatka1, NULL, 0, 0, 0, ai_charge, 12, ogle_strike, +}; +animmove_t ogle_move_attack2 = {8,ogle_frames_attack2, ogle_pause}; + +animframe_t ogle_frames_attack3[] = +{ + FRAME_rnatkb2, NULL, 0, 0, 0, ai_charge, 12, NULL, + FRAME_rnatkb3, NULL, 0, 0, 0, ai_charge, 11, NULL, + FRAME_rnatkb4, NULL, 0, 0, 0, ai_charge, 10, NULL, + FRAME_rnatkb5, NULL, 0, 0, 0, ai_charge, 12, NULL, + FRAME_rnatkb6, NULL, 0, 0, 0, ai_charge, 11, NULL, + FRAME_rnatkb7, NULL, 0, 0, 0, ai_charge, 10, NULL, + FRAME_rnatkb8, NULL, 0, 0, 0, ai_charge, 11, NULL, + FRAME_rnatkb1, NULL, 0, 0, 0, ai_charge, 12, ogle_strike, +}; +animmove_t ogle_move_attack3 = {8,ogle_frames_attack3, ogle_pause}; + + +animframe_t ogle_frames_death1[] = +{ + FRAME_deatha1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha14, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_death1 = {14,ogle_frames_death1, M_EndDeath}; + +animframe_t ogle_frames_death2[] = +{ + FRAME_deathb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb14, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_move_death2 = {14,ogle_frames_death2, M_EndDeath}; + +/*---------------------------------------------------- + ogle actions +----------------------------------------------------*/ +animframe_t ogle_c_frames_action1[] = +{ + FRAME_hamupa2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupa3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupa4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupa5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupa1, ai_c_move, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_c_move_action1 = {5,ogle_c_frames_action1, ai_c_cycleend}; + +animframe_t ogle_c_frames_action2[] = +{ + FRAME_hamupb2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamupb1, ai_c_move, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_c_move_action2 = {9,ogle_c_frames_action2, ai_c_cycleend}; + +animframe_t ogle_c_frames_action3[] = +{ + FRAME_hamdwn2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamdwn1, ai_c_move, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_c_move_action3 = {9,ogle_c_frames_action3, ai_c_cycleend}; + +animframe_t ogle_c_frames_action4[] = +{ + FRAME_pikxup2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup1, ai_c_move, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_c_move_action4 = {7,ogle_c_frames_action4, ai_c_cycleend}; + +animframe_t ogle_c_frames_action5[] = +{ + FRAME_pikxdn2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxdn1, ai_c_move, 0, 0, 0, NULL, 0, ogle_pick_dust, +}; +animmove_t ogle_c_move_action5 = {7,ogle_c_frames_action5, ai_c_cycleend}; + + +animframe_t ogle_c_frames_action6[] = +{ + FRAME_cela1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cela2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cela3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cela4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cela5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cela6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action6 = {6, ogle_c_frames_action6, ai_c_cycleend}; + +animframe_t ogle_c_frames_action7[] = +{ + FRAME_celb1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celb2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celb3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celb4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celb5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celb6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celb7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celb8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celb9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celb10, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action7 = {10, ogle_c_frames_action7, ai_c_cycleend}; + + +animframe_t ogle_c_frames_action8[] = +{ + FRAME_celc3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celc4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celc5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celc6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celc7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celc8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action8 = {6, ogle_c_frames_action8, ai_c_cycleend}; + +animframe_t ogle_c_frames_action9[] = +{ + FRAME_celd5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celd6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celd7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celd8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celd9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celd10, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action9 = {6, ogle_c_frames_action9, ai_c_cycleend}; + +animframe_t ogle_c_frames_action10[] = +{ + FRAME_cele5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cele6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cele7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cele8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action10 = {4, ogle_c_frames_action10, ai_c_cycleend}; + + + +animframe_t ogle_c_frames_action11[] = +{ + FRAME_charga1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_charga2, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_charga3, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_charga4, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_charga5, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_charga6, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_charga7, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_charga8, ai_c_move, 10, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action11 = {8, ogle_c_frames_action11, ai_c_cycleend}; + +animframe_t ogle_c_frames_action12[] = +{ + FRAME_chargb1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_chargb2, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_chargb3, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_chargb4, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_chargb5, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_chargb6, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_chargb7, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_chargb8, ai_c_move, 10, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action12 = {8, ogle_c_frames_action12, ai_c_cycleend}; + +animframe_t ogle_c_frames_action13[] = +{ + FRAME_chargc1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_chargc2, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_chargc3, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_chargc4, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_chargc5, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_chargc6, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_chargc7, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_chargc8, ai_c_move, 10, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action13 = {8, ogle_c_frames_action13, ai_c_cycleend}; + +animframe_t ogle_c_frames_action14[] = +{ + FRAME_chargd1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_chargd2, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_chargd3, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_chargd4, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_chargd5, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_chargd6, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_chargd7, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_chargd8, ai_c_move, 10, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action14 = {8, ogle_c_frames_action14, ai_c_cycleend}; + +animframe_t ogle_c_frames_action15[] = +{ + FRAME_charge1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_charge2, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_charge3, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_charge4, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_charge5, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_charge6, ai_c_move, 9, 0, 0, NULL, 0, NULL, + FRAME_charge7, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_charge8, ai_c_move, 10, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_action15 = {8, ogle_c_frames_action15, ai_c_cycleend}; + + + + +animframe_t ogle_c_frames_attack1[] = +{ + FRAME_pikxup2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pikxup1, ai_c_move, 0, 0, 0, NULL, 0, ogle_strike, +}; +animmove_t ogle_c_move_attack1 = {7,ogle_c_frames_attack1, ai_c_cycleend}; + +animframe_t ogle_c_frames_attack2[] = +{ + FRAME_rnatka2, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_rnatka3, ai_c_move, 11, 0, 0, NULL, 0, NULL, + FRAME_rnatka4, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_rnatka5, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_rnatka6, ai_c_move, 11, 0, 0, NULL, 0, NULL, + FRAME_rnatka7, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_rnatka8, ai_c_move, 11, 0, 0, NULL, 0, NULL, + FRAME_rnatka1, ai_c_move, 12, 0, 0, NULL, 0, ogle_strike, +}; +animmove_t ogle_c_move_attack2 = {8,ogle_c_frames_attack2, ai_c_cycleend}; + +animframe_t ogle_c_frames_attack3[] = +{ + FRAME_rnatkb2, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_rnatkb3, ai_c_move, 11, 0, 0, NULL, 0, NULL, + FRAME_rnatkb4, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_rnatkb5, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_rnatkb6, ai_c_move, 11, 0, 0, NULL, 0, NULL, + FRAME_rnatkb7, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_rnatkb8, ai_c_move, 11, 0, 0, NULL, 0, NULL, + FRAME_rnatkb1, ai_c_move, 12, 0, 0, NULL, 0, ogle_strike, +}; +animmove_t ogle_c_move_attack3 = {8,ogle_c_frames_attack3, ai_c_cycleend}; + +/*---------------------------------------------------- + ogle death +----------------------------------------------------*/ +animframe_t ogle_c_frames_death1[] = +{ + FRAME_deatha1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha14, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_death1 = {14,ogle_c_frames_death1, ai_c_cycleend}; + +animframe_t ogle_c_frames_death2[] = +{ + FRAME_deathb1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb14, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_death2 = {14,ogle_c_frames_death2, ai_c_cycleend}; + +/*---------------------------------------------------- + ogle standing - temp +----------------------------------------------------*/ +animframe_t ogle_c_frames_idle1[] = +{ + FRAME_walk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_walk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_idle1 = {2,ogle_c_frames_idle1, ai_c_cycleend}; + + +animframe_t ogle_c_frames_idle2[] = +{ + FRAME_rstaid1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstaid8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_idle2 = {8,ogle_c_frames_idle2, ai_c_cycleend}; + +animframe_t ogle_c_frames_idle3[] = +{ + FRAME_rstawp1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp10,ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstawp11,ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_idle3 = {11,ogle_c_frames_idle3, ai_c_cycleend}; + +animframe_t ogle_c_frames_idle4[] = +{ + FRAME_pkaxwp1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pkaxwp10,ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_idle4 = {10,ogle_c_frames_idle4, ai_c_cycleend}; + +animframe_t ogle_c_frames_idle5[] = +{ + FRAME_hamwp1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp10,ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp11,ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp12,ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_hamwp13,ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_idle5 = {13,ogle_c_frames_idle5, ai_c_cycleend}; + +animframe_t ogle_c_frames_idle6[] = +{ + FRAME_brkidl1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkidl8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_idle6 = {8, ogle_c_frames_idle6, ai_c_cycleend}; + + +/*---------------------------------------------------- + ogle pain +----------------------------------------------------*/ +animframe_t ogle_c_frames_pain1[] = +{ + FRAME_paina1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_paina2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_paina3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_paina4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_pain1 = {4,ogle_c_frames_pain1, ai_c_cycleend}; + +animframe_t ogle_c_frames_pain2[] = +{ + FRAME_rstapn1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rstapn8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_pain2 = {8,ogle_c_frames_pain2, ai_c_cycleend}; + +animframe_t ogle_c_frames_pain3[] = +{ + FRAME_brkpn1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkpn6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_pain3 = {6,ogle_c_frames_pain3, ai_c_cycleend}; + + +/*---------------------------------------------------- + ogle transitions +----------------------------------------------------*/ +animframe_t ogle_c_frames_trans1[] = +{ + FRAME_rsta1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_rsta6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_trans1 = {6,ogle_c_frames_trans1, ai_c_cycleend}; + + +animframe_t ogle_c_frames_trans2[] = +{ + FRAME_brka1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brka2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brka3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brka4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brka5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brka6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brka7, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_trans2 = {7,ogle_c_frames_trans2, ai_c_cycleend}; + +animframe_t ogle_c_frames_trans3[] = +{ + FRAME_brkb1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_brkb6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_trans3 = {6,ogle_c_frames_trans3, ai_c_cycleend}; + +animframe_t ogle_c_frames_trans4[] = +{ + FRAME_celc1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celc2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_trans4 = {2, ogle_c_frames_trans4, ai_c_cycleend}; + +animframe_t ogle_c_frames_trans5[] = +{ + FRAME_celd1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celd2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celd3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_celd4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_trans5 = {4, ogle_c_frames_trans5, ai_c_cycleend}; + +animframe_t ogle_c_frames_trans6[] = +{ + FRAME_cele1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_cele2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_trans6 = {2, ogle_c_frames_trans6, ai_c_cycleend}; + + +/*---------------------------------------------------- + ogle walking +----------------------------------------------------*/ +animframe_t ogle_c_frames_walk1[] = +{ + FRAME_walk1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk2, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk3, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk4, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk6, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk7, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_walk8, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_walk1 = {8,ogle_c_frames_walk1, ai_c_cycleend}; + + +animframe_t ogle_c_frames_walk2[] = +{ + FRAME_pusha1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pusha2, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pusha3, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pusha4, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pusha5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pusha6, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pusha7, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pusha8, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_walk2 = {8,ogle_c_frames_walk2, ai_c_cycleend}; + +animframe_t ogle_c_frames_walk3[] = +{ + FRAME_pushb1, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pushb2, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pushb3, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pushb4, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pushb5, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pushb6, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pushb7, ai_c_move, 2, 0, 0, NULL, 0, NULL, + FRAME_pushb8, ai_c_move, 2, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_walk3 = {8,ogle_c_frames_walk3, ai_c_cycleend}; + +animframe_t ogle_c_frames_walk4[] = +{ + FRAME_pushc1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pushc2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pushc3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pushc4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pushc5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pushc6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pushc7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pushc8, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ogle_c_move_walk4 = {8,ogle_c_frames_walk4, ai_c_cycleend}; + + + diff --git a/Toolkit/Programming/GameCode/game/m_ogle_anim.h b/Toolkit/Programming/GameCode/game/m_ogle_anim.h new file mode 100644 index 0000000..efe3f48 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_ogle_anim.h @@ -0,0 +1,310 @@ +// R:\Art\models/monsters\ogle\work + +// This file generated by qdata - Do NOT Modify + +#define FRAME_prtfly 0 +#define FRAME_brka1 1 +#define FRAME_brka2 2 +#define FRAME_brka3 3 +#define FRAME_brka4 4 +#define FRAME_brka5 5 +#define FRAME_brka6 6 +#define FRAME_brka7 7 +#define FRAME_brkb1 8 +#define FRAME_brkb2 9 +#define FRAME_brkb3 10 +#define FRAME_brkb4 11 +#define FRAME_brkb5 12 +#define FRAME_brkb6 13 +#define FRAME_brkidl1 14 +#define FRAME_brkidl2 15 +#define FRAME_brkidl3 16 +#define FRAME_brkidl4 17 +#define FRAME_brkidl5 18 +#define FRAME_brkidl6 19 +#define FRAME_brkidl7 20 +#define FRAME_brkidl8 21 +#define FRAME_brkpn1 22 +#define FRAME_brkpn2 23 +#define FRAME_brkpn3 24 +#define FRAME_brkpn4 25 +#define FRAME_brkpn5 26 +#define FRAME_brkpn6 27 +#define FRAME_cela1 28 +#define FRAME_cela2 29 +#define FRAME_cela3 30 +#define FRAME_cela4 31 +#define FRAME_cela5 32 +#define FRAME_cela6 33 +#define FRAME_celb1 34 +#define FRAME_celb2 35 +#define FRAME_celb3 36 +#define FRAME_celb4 37 +#define FRAME_celb5 38 +#define FRAME_celb6 39 +#define FRAME_celb7 40 +#define FRAME_celb8 41 +#define FRAME_celb9 42 +#define FRAME_celb10 43 +#define FRAME_celc1 44 +#define FRAME_celc2 45 +#define FRAME_celc3 46 +#define FRAME_celc4 47 +#define FRAME_celc5 48 +#define FRAME_celc6 49 +#define FRAME_celc7 50 +#define FRAME_celc8 51 +#define FRAME_celd1 52 +#define FRAME_celd2 53 +#define FRAME_celd3 54 +#define FRAME_celd4 55 +#define FRAME_celd5 56 +#define FRAME_celd6 57 +#define FRAME_celd7 58 +#define FRAME_celd8 59 +#define FRAME_celd9 60 +#define FRAME_celd10 61 +#define FRAME_cele1 62 +#define FRAME_cele2 63 +#define FRAME_cele3 64 +#define FRAME_cele4 65 +#define FRAME_cele5 66 +#define FRAME_cele6 67 +#define FRAME_cele7 68 +#define FRAME_cele8 69 +#define FRAME_charga1 70 +#define FRAME_charga2 71 +#define FRAME_charga3 72 +#define FRAME_charga4 73 +#define FRAME_charga5 74 +#define FRAME_charga6 75 +#define FRAME_charga7 76 +#define FRAME_charga8 77 +#define FRAME_chargb1 78 +#define FRAME_chargb2 79 +#define FRAME_chargb3 80 +#define FRAME_chargb4 81 +#define FRAME_chargb5 82 +#define FRAME_chargb6 83 +#define FRAME_chargb7 84 +#define FRAME_chargb8 85 +#define FRAME_chargc1 86 +#define FRAME_chargc2 87 +#define FRAME_chargc3 88 +#define FRAME_chargc4 89 +#define FRAME_chargc5 90 +#define FRAME_chargc6 91 +#define FRAME_chargc7 92 +#define FRAME_chargc8 93 +#define FRAME_chargd1 94 +#define FRAME_chargd2 95 +#define FRAME_chargd3 96 +#define FRAME_chargd4 97 +#define FRAME_chargd5 98 +#define FRAME_chargd6 99 +#define FRAME_chargd7 100 +#define FRAME_chargd8 101 +#define FRAME_charge1 102 +#define FRAME_charge2 103 +#define FRAME_charge3 104 +#define FRAME_charge4 105 +#define FRAME_charge5 106 +#define FRAME_charge6 107 +#define FRAME_charge7 108 +#define FRAME_charge8 109 +#define FRAME_hamdwn1 110 +#define FRAME_hamdwn2 111 +#define FRAME_hamdwn3 112 +#define FRAME_hamdwn4 113 +#define FRAME_hamdwn5 114 +#define FRAME_hamdwn6 115 +#define FRAME_hamdwn7 116 +#define FRAME_hamdwn8 117 +#define FRAME_hamdwn9 118 +#define FRAME_hamupa1 119 +#define FRAME_hamupa2 120 +#define FRAME_hamupa3 121 +#define FRAME_hamupa4 122 +#define FRAME_hamupa5 123 +#define FRAME_hamupb1 124 +#define FRAME_hamupb2 125 +#define FRAME_hamupb3 126 +#define FRAME_hamupb4 127 +#define FRAME_hamupb5 128 +#define FRAME_hamupb6 129 +#define FRAME_hamupb7 130 +#define FRAME_hamupb8 131 +#define FRAME_hamupb9 132 +#define FRAME_hamwp1 133 +#define FRAME_hamwp2 134 +#define FRAME_hamwp3 135 +#define FRAME_hamwp4 136 +#define FRAME_hamwp5 137 +#define FRAME_hamwp6 138 +#define FRAME_hamwp7 139 +#define FRAME_hamwp8 140 +#define FRAME_hamwp9 141 +#define FRAME_hamwp10 142 +#define FRAME_hamwp11 143 +#define FRAME_hamwp12 144 +#define FRAME_hamwp13 145 +#define FRAME_paina1 146 +#define FRAME_paina2 147 +#define FRAME_paina3 148 +#define FRAME_paina4 149 +#define FRAME_pikxdn1 150 +#define FRAME_pikxdn2 151 +#define FRAME_pikxdn3 152 +#define FRAME_pikxdn4 153 +#define FRAME_pikxdn5 154 +#define FRAME_pikxdn6 155 +#define FRAME_pikxdn7 156 +#define FRAME_pikxup1 157 +#define FRAME_pikxup2 158 +#define FRAME_pikxup3 159 +#define FRAME_pikxup4 160 +#define FRAME_pikxup5 161 +#define FRAME_pikxup6 162 +#define FRAME_pikxup7 163 +#define FRAME_pkaxwp1 164 +#define FRAME_pkaxwp2 165 +#define FRAME_pkaxwp3 166 +#define FRAME_pkaxwp4 167 +#define FRAME_pkaxwp5 168 +#define FRAME_pkaxwp6 169 +#define FRAME_pkaxwp7 170 +#define FRAME_pkaxwp8 171 +#define FRAME_pkaxwp9 172 +#define FRAME_pkaxwp10 173 +#define FRAME_pusha1 174 +#define FRAME_pusha2 175 +#define FRAME_pusha3 176 +#define FRAME_pusha4 177 +#define FRAME_pusha5 178 +#define FRAME_pusha6 179 +#define FRAME_pusha7 180 +#define FRAME_pusha8 181 +#define FRAME_pushb1 182 +#define FRAME_pushb2 183 +#define FRAME_pushb3 184 +#define FRAME_pushb4 185 +#define FRAME_pushb5 186 +#define FRAME_pushb6 187 +#define FRAME_pushb7 188 +#define FRAME_pushb8 189 +#define FRAME_pushc1 190 +#define FRAME_pushc2 191 +#define FRAME_pushc3 192 +#define FRAME_pushc4 193 +#define FRAME_pushc5 194 +#define FRAME_pushc6 195 +#define FRAME_pushc7 196 +#define FRAME_pushc8 197 +#define FRAME_rstaid1 198 +#define FRAME_rstaid2 199 +#define FRAME_rstaid3 200 +#define FRAME_rstaid4 201 +#define FRAME_rstaid5 202 +#define FRAME_rstaid6 203 +#define FRAME_rstaid7 204 +#define FRAME_rstaid8 205 +#define FRAME_rstapn1 206 +#define FRAME_rstapn2 207 +#define FRAME_rstapn3 208 +#define FRAME_rstapn4 209 +#define FRAME_rstapn5 210 +#define FRAME_rstapn6 211 +#define FRAME_rstapn7 212 +#define FRAME_rstapn8 213 +#define FRAME_rstawp1 214 +#define FRAME_rstawp10 215 +#define FRAME_rstawp11 216 +#define FRAME_rstawp12 217 +#define FRAME_rstawp13 218 +#define FRAME_rstawp14 219 +#define FRAME_rstawp2 220 +#define FRAME_rstawp3 221 +#define FRAME_rstawp4 222 +#define FRAME_rstawp5 223 +#define FRAME_rstawp6 224 +#define FRAME_rstawp7 225 +#define FRAME_rstawp8 226 +#define FRAME_rstawp9 227 +#define FRAME_rsta1 228 +#define FRAME_rsta2 229 +#define FRAME_rsta3 230 +#define FRAME_rsta4 231 +#define FRAME_rsta5 232 +#define FRAME_rsta6 233 +#define FRAME_walk1 234 +#define FRAME_walk2 235 +#define FRAME_walk3 236 +#define FRAME_walk4 237 +#define FRAME_walk5 238 +#define FRAME_walk6 239 +#define FRAME_walk7 240 +#define FRAME_walk8 241 +#define FRAME_rnatka1 242 +#define FRAME_rnatka2 243 +#define FRAME_rnatka3 244 +#define FRAME_rnatka4 245 +#define FRAME_rnatka5 246 +#define FRAME_rnatka6 247 +#define FRAME_rnatka7 248 +#define FRAME_rnatka8 249 +#define FRAME_rnatkb1 250 +#define FRAME_rnatkb2 251 +#define FRAME_rnatkb3 252 +#define FRAME_rnatkb4 253 +#define FRAME_rnatkb5 254 +#define FRAME_rnatkb6 255 +#define FRAME_rnatkb7 256 +#define FRAME_rnatkb8 257 +#define FRAME_deatha1 258 +#define FRAME_deatha2 259 +#define FRAME_deatha3 260 +#define FRAME_deatha4 261 +#define FRAME_deatha5 262 +#define FRAME_deatha6 263 +#define FRAME_deatha7 264 +#define FRAME_deatha8 265 +#define FRAME_deatha9 266 +#define FRAME_deatha10 267 +#define FRAME_deatha11 268 +#define FRAME_deatha12 269 +#define FRAME_deatha13 270 +#define FRAME_deatha14 271 +#define FRAME_deathb1 272 +#define FRAME_deathb2 273 +#define FRAME_deathb3 274 +#define FRAME_deathb4 275 +#define FRAME_deathb5 276 +#define FRAME_deathb6 277 +#define FRAME_deathb7 278 +#define FRAME_deathb8 279 +#define FRAME_deathb9 280 +#define FRAME_deathb10 281 +#define FRAME_deathb11 282 +#define FRAME_deathb12 283 +#define FRAME_deathb13 284 +#define FRAME_deathb14 285 +#define FRAME_deathb15 286 +#define FRAME_deathb16 287 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 13 + +#define MESH__GRANDDADDY 0 +#define MESH__DADDY 1 +#define MESH__TORSO 2 +#define MESH__NAIL 3 +#define MESH__PICK 4 +#define MESH__RUPARM 5 +#define MESH__RLEG 6 +#define MESH__R4ARM 7 +#define MESH__LLEG 8 +#define MESH__LUPARM 9 +#define MESH__L4ARM 10 +#define MESH__HAMMER 11 +#define MESH__HANDLE 12 diff --git a/Toolkit/Programming/GameCode/game/m_plagueElf.c b/Toolkit/Programming/GameCode/game/m_plagueElf.c new file mode 100644 index 0000000..d739279 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_plagueElf.c @@ -0,0 +1,2256 @@ +//============================================================================== +// +// m_plagueElf.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// +// AI : +// +// STAND1 : Looking straight ahead +// +// WALK1 : a normal straight line +// WALK2 : another normal straight line +// +// MELEE1 : Attack +// MELEE2 : Attack +// +// RUNATTACK : Running and swinging +// RUN1 : chasing an enemy straight ahead +// SHAKE : stand and spaz +// DIE1 : Fall back dead +// LEAN1 : lean agains the wall +// FIST1 : Beat against the wall in rage and desperation +// +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "m_plagueElf.h" +#include "m_plagueElf_anim.h" +#include "g_HitLocation.h" +#include "g_misc.h" +#include "angles.h" +#include "c_ai.h" +#include "m_stats.h" + + +/*---------------------------------------------------------------------- + plagueElf Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + &plagueElf_move_stand1, + &plagueElf_move_walk1, + &plagueElf_move_walk2, + &plagueElf_move_run1, + &plagueElf_move_runatk1, + &plagueElf_move_fjump, + &plagueElf_move_inair, + &plagueElf_move_land, + &plagueElf_move_melee1, + &plagueElf_move_melee2, + &plagueElf_move_death1, + &plagueElf_move_death2, + &plagueElf_move_death3, + &plagueElf_move_death4, + &plagueElf_fist1, + &plagueElf_lean1, + &plagueElf_shake1, + &plagueElf_move_pain1, + &plagueElf_delay, + &plagueElf_move_missile, +// + &plagueElf_move_kdeath_go, + &plagueElf_move_kdeath_loop, + &plagueElf_move_kdeath_end, + + &plagueElf_crazy_A, + &plagueElf_crazy_B, + &plagueElf_cursing, + &plagueElf_point, + &plagueElf_scared, + + // Cinematics + &plagueElf_move_c_idle1, + &plagueElf_move_c_idle2, + &plagueElf_move_c_idle3, + &plagueElf_move_c_walk, + &plagueElf_move_c_walk2, + &plagueElf_move_c_run, + &plagueElf_move_c_attack1, + &plagueElf_move_c_attack2, + &plagueElf_move_c_attack3, + &plagueElf_move_c_attack4, + &plagueElf_move_c_pain1, + &plagueElf_move_c_death1, + &plagueElf_move_c_death2, + &plagueElf_move_c_death3, + &plagueElf_move_c_death4, + &plagueElf_move_run1, + +// &plagueElf_move_stand1, + +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + +int Bit_for_MeshNode_pe [12] = +{ + BIT_BASE, + BIT_HANDLE, + BIT_HOE, + BIT_GAFF, + BIT_HAMMER, + BIT_BODY, + BIT_L_LEG, + BIT_R_LEG, + BIT_R_ARM, + BIT_L_ARM, + BIT_HEAD +}; + +float pelf_VoiceTimes[] = +{ + 0.0, //FIRST_SIGHT_GROUP + 1.0, //VOICE_SIGHT_AFTER_HIM1 + 0.6, //VOICE_SIGHT_AFTER_HIM2 + 1.3, //VOICE_SIGHT_CUT_HIM2 + 1.0, //VOICE_SIGHT_CUT_HIM1 + 1.2, //VOICE_SIGHT_EAT_FLESH1 + 1.2, //VOICE_SIGHT_EAT_FLESH2 + 0.9, //VOICE_SIGHT_GET_HIM1 + 0.9, //VOICE_SIGHT_GET_HIM2 + 0.9, //VOICE_SIGHT_GET_HIM3 + 1.0, //VOICE_SIGHT_KILL_HIM1 + 0.9, //VOICE_SIGHT_KILL_HIM2 + 1.3, //VOICE_SIGHT_KILL_HIM3 + 1.2, //VOICE_SIGHT_OVER_THERE + 1.2, //VOICE_SIGHT_THERES_ONE + 0.7, //VOICE_SUPPORT_FOLLOW_ME + 1.5, //VOICE_SUPPORT_CURE + 1.6, //VOICE_SUPPORT_LIVER + 2.0, //VOICE_SUPPORT_SLASH + 1.1, //VOICE_SUPPORT_SURROUND_HIM + 1.8, //VOICE_SUPPORT_UNAFFECTED1 + 2.0, //VOICE_SUPPORT_UNAFFECTED2 + 1.3, //VOICE_SUPPORT_YEAH_GET_HIM1 + 1.0, //VOICE_SUPPORT_YEAH_GET_HIM2 + 0.0, //VOICE_FIRST_ALONE + 1.1, //VOICE_MISC_DIE + 1.3, //VOICE_MISC_FLESH + 1.1, //VOICE_SUPPORT_GONNA_DIE1 + 1.5, //VOICE_SUPPORT_GONNA_DIE2 + 1.5, //VOICE_SUPPORT_GONNA_DIE3 + 1.2, //VOICE_SUPPORT_GONNA_DIE4 + 2.0, //VOICE_MISC_MUST_KILL + 1.1, //VOICE_SUPPORT_MUST_DIE + 1.1, //VOICE_SUPPORT_YES + 0.0, //VOICE_LAST_GROUP + 1.6, //VOICE_MISC_GET_AWAY1 + 0.9, //VOICE_MISC_GET_AWAY2 + 1.2, //VOICE_MISC_GO_AWAY + 0.6, //VOICE_MISC_HELP_ME1 + 2.3, //VOICE_MISC_HELP_ME2 + 2.2, //VOICE_MISC_HELP_ME3 + 1.5, //VOICE_MISC_LEAVE_ME1 + 1.0, //VOICE_MISC_LEAVE_ME2 + 0.6, //VOICE_MISC_NO + 0.9, //VOICE_MISC_TRAPPED + 0.8, //VOICE_MISC_COME_BACK1 + 1.0, //VOICE_MISC_COME_BACK2 + 0.9, //VOICE_MISC_DONT_HURT +}; + + +void dying_elf_sounds (edict_t *self, int type); +/*---------------------------------------------------------------------- + Cinematic Functions for the monster +-----------------------------------------------------------------------*/ + +void plagueElf_c_gib(edict_t *self, G_Message_t *msg) +{ + gi.sound(self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + self->think = BecomeDebris; + self->nextthink = level.time + 0.1; +} + +/*------------------------------------------------------------------------- + plagueElf_c_anims +-------------------------------------------------------------------------*/ +void plagueElf_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ATTACK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_ATTACK1; + break; + case MSG_C_ATTACK2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK2; + break; + case MSG_C_ATTACK3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK3; + break; + case MSG_C_ATTACK4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK4; + break; + case MSG_C_DEATH1: + self->monsterinfo.c_anim_flag |= C_ANIM_DONE; + curr_anim = ANIM_C_DEATH1; + break; + case MSG_C_DEATH2: + self->monsterinfo.c_anim_flag |= C_ANIM_DONE; + curr_anim = ANIM_C_DEATH2; + break; + case MSG_C_DEATH3: + self->monsterinfo.c_anim_flag |= C_ANIM_DONE; + curr_anim = ANIM_C_DEATH3; + break; + case MSG_C_DEATH4: + self->monsterinfo.c_anim_flag |= C_ANIM_DONE; + curr_anim = ANIM_C_DEATH4; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_PAIN1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PAIN1; + break; + case MSG_C_RUN1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_RUN1; + break; + case MSG_C_THINKAGAIN: // Think for yourself, elf. + self->monsterinfo.c_mode = 0; + self->enemy = self->monsterinfo.c_ent; + FoundTarget(self, true); +// self->takedamage = DAMAGE_YES; + curr_anim = ANIM_C_THINKAGAIN; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + case MSG_C_WALK2: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK2; + break; + default: + break; + } + + SetAnim(self, curr_anim); +} + + + + +/*------------------------------------------------------------------------- + plagueelf_death_loop +-------------------------------------------------------------------------*/ + +void plagueelf_death_loop ( edict_t *self ) +{ + SetAnim(self, ANIM_KDEATH_LOOP); +} + +/*------------------------------------------------------------------------- + plagueelf_check_land +-------------------------------------------------------------------------*/ + +void plagueelf_check_land ( edict_t *self ) +{ + vec3_t endpos; + trace_t trace; + + if(self->s.frame == FRAME_death7) + MG_NoBlocking(self); + + M_ChangeYaw(self); + + VectorCopy(self->s.origin, endpos); + endpos[2] -= 48; + + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&trace); + + if ( ( trace.fraction < 1 || trace.allsolid || trace.startsolid ) && self->curAnimID != ANIM_KDEATH_END && self->curAnimID != ANIM_KDEATH_GO) + { + self->elasticity = 1.25; + self->friction = 0.5; + SetAnim(self, ANIM_KDEATH_END); + } +} + +/*------------------------------------------------------------------------- + plagueElf_strike +-------------------------------------------------------------------------*/ +void plagueElf_strike (edict_t *self) +{ + trace_t trace; + edict_t *victim; + vec3_t soff, eoff, mins, maxs, bloodDir, direction; + int damage; + + //FIXME: Account for weapon being knocked out of hand? + if(self->s.fmnodeinfo[MESH__HANDLE].flags & FMNI_NO_DRAW) + return; + + switch ( self->curAnimID ) + { + case ANIM_MELEE1: + VectorSet(soff, -8, 0, 32); + VectorSet(eoff, 36, 8, 16); + break; + + case ANIM_MELEE2: + VectorSet(soff, -8, -16, 32); + VectorSet(eoff, 36, 0, 0); + break; + + case ANIM_RUNATK1: + VectorSet(soff, 2, -4, 24); + VectorSet(eoff, 50, 4, 4); + break; + } + + VectorSet(mins, -4, -4, -4); + VectorSet(maxs, 4, 4, 4); + + VectorSubtract(soff, eoff, bloodDir); + VectorNormalize(bloodDir); + + victim = M_CheckMeleeLineHit(self, soff, eoff, mins, maxs, &trace, direction); + + if (victim) + { + if (victim == self) + { + //Create a spark effect + gi.CreateEffect(NULL, FX_SPARKS, 0, trace.endpos, "d", bloodDir); + } + else + { + if (!(self->s.fmnodeinfo[MESH__GAFF].flags & FMNI_NO_DRAW) || !(self->s.fmnodeinfo[MESH__HOE].flags & FMNI_NO_DRAW)) + {//it's the hoe or the hook + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACKHIT1], 1, ATTN_NORM, 0); + } + else //it's the hammer or handle + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACKHIT2], 1, ATTN_NORM, 0); + + damage = irand(PLAGUEELF_DMG_MIN, PLAGUEELF_DMG_MAX); + + if(!(self->s.fmnodeinfo[MESH__HOE].flags & FMNI_NO_DRAW)) + damage+=PLAGUEELF_DMG_HOE; + else if(!(self->s.fmnodeinfo[MESH__GAFF].flags & FMNI_NO_DRAW)) + damage+=PLAGUEELF_DMG_GAFF; + else if(self->s.fmnodeinfo[MESH__HAMMER].flags & FMNI_NO_DRAW) + damage+=PLAGUEELF_DMG_HAMMER; + + //Hurt whatever we were whacking away at + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, damage, damage*2, DAMAGE_DISMEMBER,MOD_DIED); + } + } + else + { + //Play a swish sound + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACKMISS1], 1, ATTN_NORM, 0); + } +} + +/*------------------------------------------------------------------------- + plagueElf_death +-------------------------------------------------------------------------*/ +void plagueElf_death(edict_t *self, G_Message_t *msg) +{ + edict_t *targ, *inflictor, *attacker; + float damage; + vec3_t dVel, vf, yf; + int chance; + + pelf_init_phase_in(self); + + ParseMsgParms(msg, "eeei", &targ, &inflictor, &attacker, &damage); + + // Big enough death to be thrown back + if(self->monsterinfo.aiflags&AI_DONT_THINK) + { + if (irand(0,10) < 5) + SetAnim(self, ANIM_DIE2); + else + SetAnim(self, ANIM_DIE1); + return; + } + + self->msgHandler = DeadMsgHandler; + + //Dead but still being hit + if(self->deadflag == DEAD_DEAD) + return; + + self->deadflag = DEAD_DEAD; + + plagueElf_dropweapon (self, (int)self->health*-1); + + if (self->health <= -80)//gib death + { + gi.sound(self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + BecomeDebris(self); + return; + } + else if (self->health < -10) + { + self->svflags |= SVF_DEADMONSTER; + SetAnim(self, ANIM_KDEATH_GO); + + VectorCopy(targ->velocity, vf); + VectorNormalize(vf); + + VectorScale(vf, -1, yf); + + self->ideal_yaw = vectoyaw( yf ); + self->yaw_speed = 48; + + VectorScale(vf, 250, dVel); + dVel[2] = irand(150,200); + + VectorCopy(dVel, self->velocity); +// self->groundentity = NULL; + return; + } + + //regular death + if(self->count == 0) + { + chance = irand(0,3); + if(chance == 0) + SetAnim(self, ANIM_DIE1); + else if(chance == 1) + SetAnim(self, ANIM_DIE2); + else if(chance == 2) + SetAnim(self, ANIM_DIE3); + else + SetAnim(self, ANIM_DIE4); + } + else + { + if(self->count == 1) + SetAnim(self, ANIM_DIE1); + else if(self->count == 2) + SetAnim(self, ANIM_DIE2); + else if(self->count == 3) + SetAnim(self, ANIM_DIE3); + else + SetAnim(self, ANIM_DIE4); + } +} + + +/*------------------------------------------------------------------------- + plagueElfdeathsqueal +-------------------------------------------------------------------------*/ +void plagueElfdeathsqueal (edict_t *self) +{ + int sound; + + sound = irand(SND_DIE1, SND_DIE3); + + gi.sound(self, CHAN_VOICE, sounds[sound], 1, ATTN_NORM, 0); + return; +} + +/*------------------------------------------------------------------------- + plagueElfgrowl +-------------------------------------------------------------------------*/ +void plagueElfgrowl (edict_t *self) +{ + int chance; + + chance = irand(0, 10); + + if (chance <= 2 ) + { + chance = irand(0, 12); + if (chance < 3) + return; + //gi.sound (self, CHAN_WEAPON, sounds[SND_GASP], 1, ATTN_IDLE, 0); + else if ( chance < 6) + gi.sound (self, CHAN_VOICE, sounds[SND_PANT], 1, ATTN_IDLE, 0); + else if (chance < 9) + gi.sound(self, CHAN_VOICE, sounds[SND_MOAN1], 1, ATTN_IDLE, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_MOAN2], 1, ATTN_IDLE, 0); + } +} + +void plagueElfattack(edict_t *self) +{ + int chance, sound; + + chance = irand(0, 10); + + if (chance < 5) + { + sound = irand(SND_ATTACK1, SND_ATTACK2); + gi.sound (self, CHAN_VOICE, sounds[sound], 1, ATTN_IDLE, 0); + } +} + +void create_pe_spell(edict_t *Spell) +{ + Spell->movetype=MOVETYPE_FLYMISSILE; + Spell->solid=SOLID_BBOX; + Spell->classname="plagueElf_Spell"; + Spell->touch=plagueElfSpellTouch; + Spell->enemy=NULL; + Spell->clipmask=MASK_MONSTERSOLID|MASK_PLAYERSOLID|MASK_SHOT; + Spell->s.scale = 0.5; + Spell->s.effects |= EF_MARCUS_FLAG1|EF_CAMERA_NO_CLIP; + Spell->svflags |= SVF_ALWAYS_SEND; +} + +// the spell needs to bounce +void make_pe_spell_reflect(edict_t *self, edict_t *spell) +{ + create_pe_spell(spell); + spell->s.modelindex = self->s.modelindex; + VectorCopy(self->s.origin, spell->s.origin); + spell->owner = self->owner; + spell->enemy = self->enemy; + spell->touch=self->touch; + spell->nextthink=self->nextthink; + spell->think=G_FreeEdict; + spell->health = self->health; + spell->red_rain_count = self->red_rain_count; + + Create_rand_relect_vect(self->velocity, spell->velocity); + + vectoangles(spell->velocity, spell->s.angles); + spell->s.angles[YAW]+=90; + + Vec3ScaleAssign(500, spell->velocity); + + G_LinkMissile(spell); +} + +void plagueElfSpellTouch (edict_t *self, edict_t *Other, cplane_t *Plane, csurface_t *Surface) +{ + vec3_t normal; + edict_t *Spell; + + if(Surface&&(Surface->flags&SURF_SKY)) + { + SkyFly(self); + return; + } + + if(EntReflecting(Other, true, true)) + { + Spell = G_Spawn(); + + make_pe_spell_reflect(self,Spell); + + gi.CreateEffect(&Spell->s, + FX_PE_SPELL, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + self->red_rain_count, + Spell->velocity); + + G_SetToFree(self); + + return; + } + + VectorNormalize(self->velocity); + switch(self->red_rain_count) + { + case FX_PE_MAKE_SPELL: + gi.CreateEffect(NULL, + FX_PE_SPELL, + 0, + self->s.origin, + "bv", + FX_PE_EXPLODE_SPELL, + self->velocity); + self->dmg = irand(PLAGUEELF_DMG_SPELL_MIN, PLAGUEELF_DMG_SPELL_MAX) + skill->value; + break; + case FX_PE_MAKE_SPELL2: + gi.CreateEffect(NULL, + FX_PE_SPELL, + 0, + self->s.origin, + "bv", + FX_PE_EXPLODE_SPELL2, + self->velocity); + self->dmg = irand(PLAGUEELF_GUARD_DMG_SPELL_MIN, PLAGUEELF_GUARD_DMG_SPELL_MAX); + break; + case FX_PE_MAKE_SPELL3: + gi.CreateEffect(NULL, + FX_PE_SPELL, + 0, + self->s.origin, + "bv", + FX_PE_EXPLODE_SPELL3, + self->velocity); + self->dmg = irand(PLAGUEELF_GUARD_DMG_SPELL_MIN+2, PLAGUEELF_GUARD_DMG_SPELL_MAX+2); + self->dmg_radius = 40; + break; + } + + if(Other->takedamage) + { + VectorSet(normal, 0, 0, 1); + if(Plane) + { + if(Plane->normal) + { + VectorCopy(Plane->normal, normal); + } + } + T_Damage(Other,self,self->owner,self->movedir,self->s.origin,normal,self->dmg,0,DAMAGE_SPELL,MOD_DIED); + } + + if(self->dmg_radius) + T_DamageRadius(self, self->owner, self->owner, self->dmg_radius, self->dmg, 0, DAMAGE_SPELL,MOD_DIED); + + VectorClear(self->velocity); + + G_FreeEdict(self); +} + +void plagueElf_spell(edict_t *self) +{//fixme; adjust for up/down + vec3_t Forward, right, firedir; + edict_t *Spell; + + if (M_ValidTarget(self, self->enemy)) + { + if(self->s.fmnodeinfo[MESH__R_ARM].flags&FMNI_NO_DRAW) + return; + +// gi.sound(self, CHAN_WEAPON, Sounds[SND_SPELL], 1, ATTN_NORM, 0); + self->monsterinfo.attack_finished = level.time + 0.4; + Spell = G_Spawn(); + + create_pe_spell(Spell); + + Spell->touch=plagueElfSpellTouch; + + Spell->owner=self; + Spell->enemy=self->enemy; + + Spell->health = 0; // tell the touch function what kind of Spell we are; + + AngleVectors(self->s.angles, Forward, right, NULL); + VectorCopy(self->s.origin,Spell->s.origin); + VectorMA(Spell->s.origin, 4, Forward, Spell->s.origin); + VectorMA(Spell->s.origin, 8, right, Spell->s.origin); + Spell->s.origin[2] += 12; + + VectorCopy(self->movedir,Spell->movedir); + vectoangles(Forward,Spell->s.angles); + + VectorSubtract(self->enemy->s.origin, Spell->s.origin, firedir); + VectorNormalize(firedir); + Forward[2] = firedir[2]; + VectorNormalize(Forward); + VectorScale(Forward, 400, Spell->velocity); + + VectorCopy(Spell->velocity, Spell->movedir); + VectorNormalize(Spell->movedir); + vectoangles(Spell->movedir, Spell->s.angles); + Spell->s.angles[PITCH] = anglemod(Spell->s.angles[PITCH] * -1); + + if(stricmp(self->classname, "monster_plagueElf"))//one of the special dudes + { + if(irand(0, 3) || skill->value < 2 || !stricmp(self->classname, "monster_palace_plague_guard_invisible")) + Spell->red_rain_count = FX_PE_MAKE_SPELL2; + else + Spell->red_rain_count = FX_PE_MAKE_SPELL3; + } + else + Spell->red_rain_count = FX_PE_MAKE_SPELL; + + gi.CreateEffect(&Spell->s, + FX_PE_SPELL, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + Spell->red_rain_count, + Spell->velocity); + + G_LinkMissile(Spell); + + Spell->nextthink=level.time+3; + Spell->think=G_FreeEdict;//plagueElfSpellThink; + } + else//If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + +} + + +void plagueElf_c_spell(edict_t *self) +{//fixme; adjust for up/down + vec3_t Forward, right, firedir, holdpos; + edict_t *Spell; + + if(self->s.fmnodeinfo[MESH__R_ARM].flags&FMNI_NO_DRAW) // Was his arm lopped off? + return; + + self->monsterinfo.attack_finished = level.time + 0.4; + Spell = G_Spawn(); + + create_pe_spell(Spell); + + Spell->touch=plagueElfSpellTouch; + + Spell->owner=self; +// Spell->enemy=self->enemy; + + Spell->health = 0; // tell the touch function what kind of Spell we are; + + AngleVectors(self->s.angles, Forward, right, NULL); + VectorCopy(self->s.origin,Spell->s.origin); + VectorMA(Spell->s.origin, 4, Forward, Spell->s.origin); + VectorMA(Spell->s.origin, 8, right, Spell->s.origin); + Spell->s.origin[2] += 12; + + VectorCopy(self->movedir,Spell->movedir); + vectoangles(Forward,Spell->s.angles); + + + VectorCopy(self->s.origin,holdpos); + VectorMA(Spell->s.origin, 40, Forward, Spell->s.origin); + + VectorSubtract(holdpos, Spell->s.origin, firedir); + VectorNormalize(firedir); + Forward[2] = firedir[2]; + VectorNormalize(Forward); + VectorScale(Forward, 500, Spell->velocity); + + VectorCopy(Spell->velocity, Spell->movedir); + VectorNormalize(Spell->movedir); + vectoangles(Spell->movedir, Spell->s.angles); + Spell->s.angles[PITCH] = anglemod(Spell->s.angles[PITCH] * -1); + + if(stricmp(self->classname, "monster_plagueElf"))//one of the special dudes + { + if(irand(0, 3)) + Spell->red_rain_count = FX_PE_MAKE_SPELL2; + else + Spell->red_rain_count = FX_PE_MAKE_SPELL3; + } + else + Spell->red_rain_count = FX_PE_MAKE_SPELL; + + gi.CreateEffect(&Spell->s, + FX_PE_SPELL, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + Spell->red_rain_count, + Spell->velocity); + + G_LinkMissile(Spell); + + Spell->nextthink=level.time+3; + Spell->think=G_FreeEdict;//plagueElfSpellThink; + +} + +void plagueElf_runaway (edict_t *self, G_Message_t *msg) +{ + if(self->spawnflags&MSF_FIXED) + return; + + self->monsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + flrand(2, 4); +} + +void plagueElf_missile(edict_t *self, G_Message_t *msg) +{ + pelf_init_phase_in(self); + + SetAnim(self, ANIM_MISSILE); +} + +/*------------------------------------------------------------------------- + plagueElf_melee +-------------------------------------------------------------------------*/ +void plagueElf_melee(edict_t *self, G_Message_t *msg) +{ + vec3_t attackVel, vf; + int ret; + + if (M_ValidTarget(self, self->enemy)) + {//A monster in melee will continue too long if the player backs away, this prevents it + if(self->spawnflags&MSF_FIXED||self->monsterinfo.aiflags&AI_NO_MELEE) + { + SetAnim(self, ANIM_MISSILE); + return; + } + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(vf, 1, vf, attackVel); + ret = M_PredictTargetEvasion( self, self->enemy, attackVel, self->enemy->velocity, self->melee_range, 5 ); + + if (ret) + { + if(irand(0,10)<5) + SetAnim(self, ANIM_MELEE1); + else + SetAnim(self, ANIM_MELEE2); + } + else + { + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_RUNATK1); + } + } + else//If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +/*------------------------------------------------------------------------- + plagueElf_pain +-------------------------------------------------------------------------*/ + +void pelf_dismember_sound(edict_t *self) +{ + if(self->health <= 0) + return; + + if(irand(0, 1)) + gi.sound(self, CHAN_BODY, sounds[SND_DISMEMBER1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_BODY, sounds[SND_DISMEMBER2], 1, ATTN_NORM, 0); +} + +qboolean canthrownode_pe (edict_t *self, int BP, int *throw_nodes) +{//see if it's on, if so, add it to throw_nodes + //turn it off on thrower + if(!(self->s.fmnodeinfo[BP].flags & FMNI_NO_DRAW)) + { + *throw_nodes |= Bit_for_MeshNode_pe[BP]; + self->s.fmnodeinfo[BP].flags |= FMNI_NO_DRAW; + return true; + } + return false; +} + +void plagueElf_chicken (edict_t *self, int coward, int flee, float fleetime) +{ + float chance; + + chance = flrand(0, 20 + skill->value * 10); + + if(chancemonsterinfo.aiflags |= AI_COWARD; + return; + } + + if(chancemonsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + fleetime; + } +} + +void plagueElf_dead_pain (edict_t *self, G_Message_t *msg) +{ + if(msg) + if(!(self->svflags & SVF_PARTS_GIBBED)) + MG_parse_dismember_msg(self, msg); +} + +//THROWS weapon, turns off those nodes, sets that weapon as gone +qboolean plagueElf_dropweapon (edict_t *self, int damage) +{//NO PART FLY FRAME! + vec3_t handspot, forward, right, up; + float chance; + + if(self->s.fmnodeinfo[MESH__HANDLE].flags & FMNI_NO_DRAW) + return false; + + VectorClear(handspot); + AngleVectors(self->s.angles,forward,right,up); + VectorMA(handspot,5,forward,handspot); + VectorMA(handspot,8,right,handspot); + VectorMA(handspot,-6,up,handspot); + + if(self->deadflag == DEAD_DEAD||(self->s.fmnodeinfo[MESH__R_ARM].flags & FMNI_NO_DRAW)) + chance = 0; + else + chance = 3; + if(!(self->s.fmnodeinfo[MESH__HOE].flags & FMNI_NO_DRAW)) + { + if(irand(0,10)s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + plagueElf_chicken(self,2,5,flrand(2,7)); + } + else + { + ThrowWeapon(self, &handspot, BIT_HANDLE|BIT_HOE, 0, FRAME_partfly); + self->s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + plagueElf_chicken(self,4,8,flrand(3,8)); + } + return true; + } + if(!(self->s.fmnodeinfo[MESH__GAFF].flags & FMNI_NO_DRAW)) + { + if(irand(0,10)s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + plagueElf_chicken(self,2,6,flrand(2,7)); + } + else + { + ThrowWeapon(self, &handspot, BIT_HANDLE|BIT_GAFF, 0, FRAME_partfly); + self->s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + plagueElf_chicken(self,4,8,flrand(3,8)); + } + return true; + } + if(!(self->s.fmnodeinfo[MESH__HAMMER].flags & FMNI_NO_DRAW)) + { + if(irand(0,10)s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + plagueElf_chicken(self,2,6,flrand(2,7)); + } + else + { + ThrowWeapon(self, &handspot, BIT_HANDLE|BIT_HAMMER, 0, FRAME_partfly); + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + plagueElf_chicken(self,4,8,flrand(3,8)); + } + return true; + } + ThrowWeapon(self, &handspot, BIT_HANDLE, 0, FRAME_partfly); + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + if(self->deadflag != DEAD_DEAD) + plagueElf_chicken(self,6,8,flrand(5,10)); + return true; +} + +void plagueElf_dismember(edict_t *self, int damage, int HitLocation) +{//fixme: throw current weapon +//fixme - make part fly dir the vector from hit loc to sever loc +//remember- turn on caps! + int throw_nodes = 0; + vec3_t gore_spot, right; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; +// gi.dprintf("HL: %d",HitLocation); + + if(self->curAnimID==ANIM_MELEE1||self->curAnimID==ANIM_MELEE1) + {//Hit chest during melee, may have hit arms + if(HitLocation == hl_TorsoFront&&irand(0,10)<4) + { + if(irand(0,10)<7) + HitLocation = hl_ArmLowerRight; + else + HitLocation = hl_ArmLowerLeft; + } + } + + if( + (HitLocation == hl_ArmUpperLeft&& self->s.fmnodeinfo[MESH__L_ARM].flags & FMNI_NO_DRAW) || + (HitLocation == hl_ArmUpperRight&& self->s.fmnodeinfo[MESH__R_ARM].flags & FMNI_NO_DRAW)|| + ( + (HitLocation == hl_TorsoFront|| HitLocation == hl_TorsoBack) && + self->s.fmnodeinfo[MESH__R_ARM].flags & FMNI_NO_DRAW && + self->s.fmnodeinfo[MESH__L_ARM].flags & FMNI_NO_DRAW && + irand(0,10)<4) + ) + HitLocation = hl_Head;//Decap + + VectorCopy(vec3_origin,gore_spot); + switch(HitLocation) + { + case hl_Head: + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)health)s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,8,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { + self->s.fmnodeinfo[MESH__HEAD].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__HEAD].skin = self->s.skinnum+1; + } + break; + case hl_TorsoFront://split in half? + case hl_TorsoBack://split in half? + if(self->s.fmnodeinfo[MESH__BODY].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__BODY].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(self->health > 0 && flrand(0,self->health)s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,12,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { + if(flrand(0,self->health)s.fmnodeinfo[MESH__BODY].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__BODY].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperLeft: + case hl_ArmLowerLeft://left arm + if(self->s.fmnodeinfo[MESH__L_ARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__L_ARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + plagueElf_chicken(self,6,8,flrand(7,15)); + pelf_dismember_sound(self); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + } + else + { + self->s.fmnodeinfo[MESH__L_ARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__L_ARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperRight: + case hl_ArmLowerRight://right arm + //Knock weapon out of hand? + if(self->s.fmnodeinfo[MESH__R_ARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__R_ARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + plagueElf_dropweapon (self, (int)damage); + pelf_dismember_sound(self); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + } + else + { + if(flrand(0,self->health)s.fmnodeinfo[MESH__R_ARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__R_ARM].skin = self->s.skinnum+1; + } + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft://left leg + if(self->health>0) + {//still alive + if(self->s.fmnodeinfo[MESH__L_LEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__L_LEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__L_LEG].skin = self->s.skinnum+1; + } + else + { + if(self->s.fmnodeinfo[MESH__L_LEG].flags & FMNI_NO_DRAW) + break; + if(canthrownode_pe(self, MESH__L_LEG, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + break; + case hl_LegUpperRight: + case hl_LegLowerRight://right leg + if(self->health>0) + {//still alive + if(self->s.fmnodeinfo[MESH__R_LEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__R_LEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__R_LEG].skin = self->s.skinnum+1; + } + else + { + if(self->s.fmnodeinfo[MESH__R_LEG].flags & FMNI_NO_DRAW) + break; + if(canthrownode_pe(self, MESH__R_LEG, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + break; + + default: + if(flrand(0,self->health)pain_debounce_time = 0; + + if(self->s.fmnodeinfo[MESH__R_ARM].flags&FMNI_NO_DRAW) + { + self->monsterinfo.aiflags |= AI_NO_MELEE; + self->monsterinfo.aiflags |= AI_NO_MISSILE; + } + else if(self->s.fmnodeinfo[MESH__HANDLE].flags & FMNI_NO_DRAW) + { + self->monsterinfo.aiflags |= AI_NO_MELEE; + if(self->missile_range) + { + if(!(self->s.fmnodeinfo[MESH__R_ARM].flags&FMNI_NO_DRAW)) + { + self->monsterinfo.aiflags &= ~AI_NO_MISSILE; + self->melee_range = 0; + } + else + self->monsterinfo.aiflags |= AI_NO_MISSILE; + } + } + + if(self->monsterinfo.aiflags&AI_NO_MISSILE && + self->monsterinfo.aiflags&AI_NO_MELEE) + self->monsterinfo.aiflags |= AI_COWARD; +} + + +void plagueElf_pain(edict_t *self, G_Message_t *msg) +{ + int temp, damage; + qboolean force_pain; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_pain, &damage, &temp); + + pelf_init_phase_in(self); + + if(!(self->monsterinfo.aiflags & AI_COWARD) && !(self->monsterinfo.aiflags & AI_FLEE)) + if(!force_pain) + if(flrand(0,self->health)>damage) + return; + + if(self->fire_damage_time > level.time) + self->monsterinfo.aiflags |= AI_COWARD; + + if (self->pain_debounce_time < level.time) + { + self->pain_debounce_time = level.time + 1; + SetAnim(self, ANIM_PAIN1); + } +} + +void plagueElfApplyJump (edict_t *self) +{ + self->jump_time = level.time + 0.5; + VectorCopy(self->movedir, self->velocity); + VectorNormalize(self->movedir); +} + +/*------------------------------------------------------------------------- + plagueElf_pause +-------------------------------------------------------------------------*/ +void pelf_phase_out (edict_t *self); +void pelf_phase_in (edict_t *self); +void plagueElf_pause (edict_t *self) +{ + self->monsterinfo.misc_debounce_time = 0; + + if(self->ai_mood == AI_MOOD_FLEE) + { + if(self->s.color.a != 255 && self->pre_think!=pelf_phase_in) + pelf_init_phase_in(self); + } + else + { + if(!skill->value) + { + if(self->s.color.a > 50 && self->pre_think!=pelf_phase_out) + pelf_init_phase_out(self); + } + else if(self->s.color.a && self->pre_think!=pelf_phase_out) + pelf_init_phase_out(self); + } + + if(self->spawnflags & MSF_FIXED && self->curAnimID == ANIM_DELAY && self->enemy) + { + self->monsterinfo.searchType = SEARCH_COMMON; + MG_FaceGoal(self, true); + } + + self->mood_think(self); + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + if(self->ai_mood_flags & AI_MOOD_FLAG_MISSILE) + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_PURSUE: + if(self->ai_mood_flags&AI_MOOD_FLAG_DUMB_FLEE) + SetAnim(self, ANIM_SCARED); + else + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_NAVIGATE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_WALK: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_FLEE: + if(self->ai_mood_flags&AI_MOOD_FLAG_DUMB_FLEE || (!(self->ai_mood_flags&AI_MOOD_FLAG_FORCED_BUOY) && !irand(0, 20))) + { + if(self->enemy) + { + if(M_DistanceToTarget(self, self->enemy) < 100) + { + if(self->curAnimID == ANIM_SCARED) + dying_elf_sounds (self, DYING_ELF_PAIN_VOICE); + if(irand(0,1)) + SetAnim(self, ANIM_CRAZY_A); + else + SetAnim(self, ANIM_CRAZY_B); + break; + } + } + SetAnim(self, ANIM_SCARED); + } + else if(irand(0,1)) + SetAnim(self, ANIM_CRAZY_A); + else + SetAnim(self, ANIM_CRAZY_B); + break; + + case AI_MOOD_STAND: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_DELAY: + SetAnim(self, ANIM_DELAY); + break; + + case AI_MOOD_WANDER: + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_WALK1); + break; + + case AI_MOOD_BACKUP: + QPostMessage(self, MSG_FALLBACK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_JUMP: + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_FJUMP); + break; + + default : +#ifdef _DEVEL + // gi.dprintf("plague elf: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } +} + +void pelf_land(edict_t *self) +{ + gi.sound(self, CHAN_BODY, gi.soundindex("misc/land.wav"), 1, ATTN_NORM, 0); + gi.CreateEffect(&self->s, + FX_DUST_PUFF, + CEF_OWNERS_ORIGIN, + self->s.origin, + NULL); +} + +void pelf_go_inair(edict_t *self) +{ + SetAnim(self, ANIM_INAIR); +} + +void pelf_jump (edict_t *self, G_Message_t *msg) +{ + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_FJUMP); +} + +void pelf_check_mood (edict_t *self, G_Message_t *msg) +{ + ParseMsgParms(msg, "i", &self->ai_mood); + + plagueElf_pause(self); +} + +/*------------------------------------------------------------------------- + plagueElf_run +-------------------------------------------------------------------------*/ +void plagueElf_run(edict_t *self, G_Message_t *msg) +{ + if(self->curAnimID == ANIM_CURSING || self->curAnimID == ANIM_POINT) + return; + + if (M_ValidTarget(self, self->enemy)) + { + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_RUN1); + } + else//If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +/*---------------------------------------------------------------------- + plagueElf runorder - order the plagueElf to choose an run animation +-----------------------------------------------------------------------*/ +void plagueElf_runorder(edict_t *self) +{ + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); +} + + +/*------------------------------------------------------------------------- + plagueElfsqueal +-------------------------------------------------------------------------*/ +void plagueElfsqueal (edict_t *self) +{ + if(self->monsterinfo.aiflags & AI_COWARD || self->monsterinfo.aiflags & AI_FLEE) + dying_elf_sounds (self, DYING_ELF_PAIN_VOICE); + else + { + int sound = irand(SND_PAIN1, SND_PAIN3); + + gi.sound(self, CHAN_VOICE, sounds[sound], 1, ATTN_NORM, 0); + } +} + +/*------------------------------------------------------------------------- + plagueElf_stand +-------------------------------------------------------------------------*/ +void plagueElf_stand(edict_t *self, G_Message_t *msg) +{ + if (self->ai_mood == AI_MOOD_DELAY) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_SHAKE1); + + return; +} + +/*------------------------------------------------------------------------- + plagueElf_walk +-------------------------------------------------------------------------*/ +void plagueElf_walk(edict_t *self, G_Message_t *msg) +{ + if(self->curAnimID == ANIM_CURSING || self->curAnimID == ANIM_POINT) + return; + + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else if(irand(0, 1)) + SetAnim(self, ANIM_WALK1); + else + SetAnim(self, ANIM_WALK2); + return; +} + +void plagueElf_go_run(edict_t *self) +{ + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_RUN1); +} + +/* + + Plagued Elf voice support functions + +*/ + +/*----------------------------------------------- + pelf_ChooseSightSound +-----------------------------------------------*/ + +#define SE_ALONE 0 +#define SE_PAIR 1 +#define SE_GROUP 2 + +int pelf_ChooseSightSound ( edict_t *self, int event ) +{ + int sound; + + switch (event) + { + case SE_ALONE: + sound = irand( FIRST_SIGHT_ALONE, LAST_SIGHT_ALONE); + break; + + case SE_PAIR: + case SE_GROUP: + sound = irand( FIRST_SIGHT_GROUP, LAST_SIGHT_GROUP ); + break; + } + + return sound; +} + +/*----------------------------------------------- + pelf_ChooseReponseSound +-----------------------------------------------*/ + +int pelf_ChooseResponseSound ( edict_t *self, int event, int sound_id ) +{ + int sound; + + switch (event) + { + case SE_PAIR: + case SE_GROUP: + sound = irand( FIRST_SIGHT_GROUP, LAST_SIGHT_GROUP); + break; + } + + return sound; +} +//plague elf has seen first target (usually player) + +/*----------------------------------------------- + pelf_SightSound +-----------------------------------------------*/ +#define PLAGUEELF_SUPPORT_RADIUS 200 + +void pelf_SightSound ( edict_t *self, G_Message_t *msg ) +{ + edict_t *enemy = NULL; + byte sight_type; + int support, sound; + + if(self->targetname || self->monsterinfo.c_mode) + return;//cinematic waiting to be activated, don't do this + + //Have we already said something? + if (self->monsterinfo.supporters != -1) + return; + + ParseMsgParms(msg, "be", &sight_type, &enemy); + + //Find out how many elves are around (save this if we want it later) + support = self->monsterinfo.supporters = M_FindSupport(self, PLAGUEELF_SUPPORT_RADIUS); + + //See if we are the first to see the player + if(M_CheckAlert(self, PLAGUEELF_SUPPORT_RADIUS)) + { + //gi.dprintf("pelf_SightSound: elf has %d supporters\n", support); + + if (support < 1) //Loner + { + sound = pelf_ChooseSightSound(self, SE_ALONE); + gi.sound(self, CHAN_VOICE, sounds[sound], 1, ATTN_NORM, 0); + } + else if (support < 2) //Paired + { + sound = pelf_ChooseSightSound(self, SE_PAIR); + self->monsterinfo.sound_finished = level.time + pelf_VoiceTimes[sound]; + gi.sound(self, CHAN_VOICE, sounds[sound], 1, ATTN_NORM, 0); + + pelf_PollResponse( self, SE_PAIR, sound, self->monsterinfo.sound_finished - flrand(0.5, 0.25) ); + } + else //Grouped + { + sound = pelf_ChooseSightSound(self, SE_GROUP); + self->monsterinfo.sound_finished = level.time + pelf_VoiceTimes[sound]; + gi.sound(self, CHAN_VOICE, sounds[sound], 1, ATTN_NORM, 0); + + pelf_PollResponse( self, SE_GROUP, sound, self->monsterinfo.sound_finished - flrand(0.5, 0.25) ); + } + + if(support) + {//FIXME: make sure enemy is far enough away to anim! + if(irand(0, 1)) + SetAnim(self, ANIM_CURSING); + else + SetAnim(self, ANIM_POINT); + } + } +} + +//The plague elf has said something and is looking for a response +void pelf_PollResponse ( edict_t *self, int sound_event, int sound_id, float time ) +{ + edict_t *ent = NULL, *last_valid = NULL; + int numSupport = 0; + + while((ent = findradius(ent, self->s.origin, PLAGUEELF_SUPPORT_RADIUS)) != NULL) + { + //Not us + if (ent==self) + continue; + + //Same class + if (ent->classID != self->classID) + continue; + + //Not already talking + if (ent->monsterinfo.sound_pending || ent->monsterinfo.sound_finished > level.time) + continue; + + //Not going after different goals + if ((ent->enemy) && ent->enemy != self->enemy) + continue; + + //Alive + if (ent->health <= 0) + continue; + + if(!ok_to_wake(ent, false, false)) + continue; + + //Save this as valid! + last_valid = ent; + + //Random chance to continue on + if (irand(0,1)) + continue; + + if(!ent->enemy) + { + ent->enemy = self->enemy; + FoundTarget(ent, false); + } + + //This is the elf to respond, so post the message + QPostMessage(ent, MSG_VOICE_POLL, PRI_DIRECTIVE, "bbf", sound_event, sound_id, time); + last_valid = NULL; + break; + } + + //We skipped the last valid elf, so just make the last valid one talk + if (last_valid) + { + QPostMessage(last_valid, MSG_VOICE_POLL, PRI_DIRECTIVE, "bbf", sound_event, sound_id, time); + last_valid = NULL; + } +} + +//A plague elf has been polled for a response, now choose a reply and echo it back +void pelf_EchoResponse ( edict_t *self, G_Message_t *msg ) +{ + float time; + int sound_event, sound_id; + + if(self->targetname || self->monsterinfo.c_mode) + return;//cinematic waiting to be activated, don't do this + + //gi.dprintf("pelf_EchoResponse: Echoing alert response\n"); + + ParseMsgParms(msg, "bbf", &sound_event, &sound_id, &time); + + switch ( sound_event ) + { + case SE_PAIR: + self->monsterinfo.sound_pending = pelf_ChooseResponseSound( self, SE_PAIR, sound_id ); + self->monsterinfo.sound_start = time; + self->monsterinfo.sound_finished = level.time + pelf_VoiceTimes[self->monsterinfo.sound_pending]; + + if(irand(0, 4)) + {//FIXME: make sure enemy is far enough away to anim! + if(irand(0, 1)) + SetAnim(self, ANIM_CURSING); + else + SetAnim(self, ANIM_POINT); + } + break; + + case SE_GROUP: + self->monsterinfo.sound_pending = pelf_ChooseResponseSound( self, SE_GROUP, sound_id ); + self->monsterinfo.sound_start = time; + self->monsterinfo.sound_finished = level.time + pelf_VoiceTimes[self->monsterinfo.sound_pending]; + + if (irand(0,2)) + pelf_PollResponse( self, SE_GROUP, self->monsterinfo.sound_pending, self->monsterinfo.sound_finished ); + + if(irand(0, 2)) + {//FIXME: make sure enemy is far enough away to anim! + if(irand(0, 1)) + SetAnim(self, ANIM_CURSING); + else + SetAnim(self, ANIM_POINT); + + } + break; + + default: + self->monsterinfo.sound_pending = pelf_ChooseResponseSound( self, SE_GROUP, sound_id ); + self->monsterinfo.sound_start = time; + self->monsterinfo.sound_finished = level.time + pelf_VoiceTimes[self->monsterinfo.sound_pending]; + + if (irand(0,2)) + pelf_PollResponse( self, SE_GROUP, self->monsterinfo.sound_pending, self->monsterinfo.sound_finished ); + + break; + } +} + +//Play a sound from a trigger or a pending sound event +void pelf_EchoSound ( edict_t *self, G_Message_t *msg ) +{ + int sound; + + ParseMsgParms(msg, "i", &sound); + + gi.sound(self, CHAN_VOICE, sounds[sound], 1, ATTN_NORM, 0); +} + +// +void pelf_check_too_close(edict_t *self) +{ + if(!self->enemy) + return; + + if(M_DistanceToTarget(self, self->enemy) < flrand(0, 100)) + { + if(irand(0,1)) + SetAnim(self, ANIM_CRAZY_A); + else + SetAnim(self, ANIM_CRAZY_B); + } +} + + +void pelf_phase_out (edict_t *self) +{ + int interval = 60; + + if(self->s.color.a > interval) + { + self->s.color.a -= irand(interval/2, interval); + self->pre_think = pelf_phase_out; + self->next_pre_think = level.time + 0.05; + } + else + { + if(!skill->value) + self->s.color.a = 50; + else + self->s.color.a = 0; + self->pre_think = NULL; + self->next_pre_think = -1; + } +} + +void pelf_init_phase_out (edict_t *self); +void pelf_phase_in (edict_t *self) +{ + int interval = 60; + + if(self->s.color.a < 255 - interval) + { + self->s.color.a += irand(interval/2, interval); + self->pre_think = pelf_phase_in; + self->next_pre_think = level.time + 0.05; + } + else + { + self->svflags &= ~SVF_NO_AUTOTARGET; + self->s.color.c = 0xffffffff; + if(self->health <= 0) + { + self->pre_think = NULL; + self->next_pre_think = -1; + } + else + pelf_init_phase_out(self); + } +} + +void pelf_init_phase_out (edict_t *self) +{ + if(stricmp(self->classname, "monster_palace_plague_guard_invisible")) + return; + +// gi.dprintf("Elf phasing out\n"); + self->pre_think = pelf_phase_out; + self->next_pre_think = level.time + FRAMETIME; + self->svflags |= SVF_NO_AUTOTARGET; +} + +void pelf_init_phase_in (edict_t *self) +{ + if(stricmp(self->classname, "monster_palace_plague_guard_invisible")) + return; + +// gi.dprintf("Elf phasing in\n"); + self->pre_think = pelf_phase_in; + self->next_pre_think = level.time + FRAMETIME; +} +/*------------------------------------------------------------------------- + PlagueElfStaticsInit +-------------------------------------------------------------------------*/ +void PlagueElfStaticsInit() +{ + classStatics[CID_PLAGUEELF].msgReceivers[MSG_STAND] = plagueElf_stand; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_WALK] = plagueElf_walk; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_RUN] = plagueElf_run; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_MELEE] = plagueElf_melee; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_MISSILE] = plagueElf_missile; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_PAIN] = plagueElf_pain; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_DEATH] = plagueElf_death; +// classStatics[CID_PLAGUEELF].msgReceivers[MSG_BLOCKED] = plagueElf_blocked; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_JUMP] = pelf_jump; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_DEATH_PAIN] = plagueElf_dead_pain; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_FALLBACK] = plagueElf_run;//away + classStatics[CID_PLAGUEELF].msgReceivers[MSG_CHECK_MOOD] = pelf_check_mood; + + //Sound support + classStatics[CID_PLAGUEELF].msgReceivers[MSG_VOICE_SIGHT] = pelf_SightSound; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_VOICE_POLL] = pelf_EchoResponse; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_VOICE_PUPPET] = pelf_EchoSound; + + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_IDLE1] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_IDLE2] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_IDLE3] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_WALK1] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_WALK2] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_RUN1] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_ATTACK1] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_ATTACK2] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_ATTACK3] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_ATTACK4] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_DEATH1] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_DEATH2] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_DEATH3] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_DEATH4] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_THINKAGAIN] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_PAIN1] = plagueElf_c_anims; + classStatics[CID_PLAGUEELF].msgReceivers[MSG_C_GIB1] = plagueElf_c_gib; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + //note that the name is different in the path + resInfo.modelIndex = gi.modelindex("models/monsters/plaguelf/tris.fm"); + + sounds[SND_PAIN1] = gi.soundindex("monsters/plagueElf/pain1.wav"); + sounds[SND_PAIN2] = gi.soundindex("monsters/plagueElf/pain2.wav"); + sounds[SND_PAIN3] = gi.soundindex("monsters/plagueElf/pain3.wav"); + sounds[SND_DIE1] = gi.soundindex("monsters/plagueElf/death1.wav"); + sounds[SND_DIE2] = gi.soundindex("monsters/plagueElf/death2.wav"); + sounds[SND_DIE3] = gi.soundindex("monsters/plagueElf/death3.wav"); + sounds[SND_GIB] = gi.soundindex("monsters/plagueElf/gib2.wav"); + sounds[SND_ATTACKHIT1] = gi.soundindex("monsters/plagueElf/hookhit.wav"); + sounds[SND_ATTACKHIT2] = gi.soundindex("monsters/plagueElf/hamhit.wav"); + sounds[SND_ATTACKMISS1] = gi.soundindex("weapons/staffswing.wav"); + sounds[SND_MOAN1] = gi.soundindex("monsters/plagueElf/pelfgrn1.wav"); + sounds[SND_MOAN2] = gi.soundindex("monsters/plagueElf/pelfgron.wav"); + sounds[SND_SHIVER] = gi.soundindex("monsters/plagueElf/pelfshiv.wav"); + sounds[SND_PANT] = gi.soundindex("monsters/plagueElf/pelfpant.wav"); + sounds[SND_GASP] = gi.soundindex("monsters/plagueElf/pelfgasp.wav"); + sounds[SND_SIGH] = gi.soundindex("monsters/plagueElf/pelfsigh.wav"); + sounds[SND_ATTACK1] = gi.soundindex("monsters/plagueElf/attack1.wav"); + sounds[SND_ATTACK2] = gi.soundindex("monsters/plagueElf/attack2.wav"); + sounds[SND_DISMEMBER1] = gi.soundindex("monsters/plagueElf/loselimb1.wav"); + sounds[SND_DISMEMBER2] = gi.soundindex("monsters/plagueElf/loselimb2.wav"); + + //Plague elf voices + sounds[VOICE_SIGHT_EAT_FLESH1] = gi.soundindex("monsters/plagueElf/voices/eatfleshb.wav"); + sounds[VOICE_SIGHT_GET_HIM1] = gi.soundindex("monsters/plagueElf/voices/gethimb.wav"); + sounds[VOICE_SIGHT_GET_HIM2] = gi.soundindex("monsters/plagueElf/voices/gethimk.wav"); + sounds[VOICE_SIGHT_GET_HIM3] = gi.soundindex("monsters/plagueElf/voices/gethimm.wav"); + sounds[VOICE_SIGHT_THERES_ONE] = gi.soundindex("monsters/plagueElf/voices/theresonep.wav"); + + sounds[VOICE_SUPPORT_GONNA_DIE1] = gi.soundindex("monsters/plagueElf/voices/gonnadieb.wav"); + sounds[VOICE_SUPPORT_LIVER] = gi.soundindex("monsters/plagueElf/voices/liverm.wav"); + sounds[VOICE_SUPPORT_YES] = gi.soundindex("monsters/plagueElf/voices/yesb.wav"); + + sounds[VOICE_MISC_LEAVE_ME1] = gi.soundindex("monsters/plagueElf/voices/leavemeb.wav"); + sounds[VOICE_MISC_NO] = gi.soundindex("monsters/plagueElf/voices/nomrj.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_PLAGUEELF].resInfo = &resInfo; +} + +/*QUAKED monster_plagueElf (1 .5 0) (-17 -25 -1) (22 12 63) AMBUSH ASLEEP WALKING CINEMATIC Missile 32 64 FIXED WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +Missile - can fire a ranged attack + +The plagueElf + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING - use WANDER instead + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS(melee P.E.): +mintel = 16 +melee_range = 0 +missile_range = 512 +min_missile_range = 0 +bypass_missile_chance = 0 +jump_chance = 50 +wakeup_distance = 1024 + +DEFAULTS(missile P.E.): +mintel = 16 +melee_range = 0 +missile_range = 512 +min_missile_range = 0 +bypass_missile_chance = 60 +jump_chance = 50 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ + +#define PALACE_ELF_SKIN 4 +/*------------------------------------------------------------------------- + SP_monster_plagueElf +-------------------------------------------------------------------------*/ +void SP_monster_plagueElf (edict_t *self) +{ + int chance;//, scale; + + if(self->spawnflags & MSF_WALKING) + { + self->spawnflags |= MSF_WANDER; + self->spawnflags &= ~MSF_WALKING; + } + + self->classID = CID_PLAGUEELF; + + if (!walkmonster_start(self)) // Failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->monsterinfo.dismember = plagueElf_dismember; + + if (!self->health) + { + self->health = PLAGUEELF_HEALTH; + } + + //Apply to the end result (whether designer set or not) + self->health = MonsterHealth(self->health); + + self->mass = PLAGUEELF_MASS; + self->yaw_speed = 20; + + self->movetype = PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + if(irand(0,1)) + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + //FIXME: Hack to account for new origin with old QuakEd header + self->s.origin[2] += 32; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + self->viewheight = self->maxs[2]*0.8; + + self->s.modelindex = classStatics[CID_PLAGUEELF].resInfo->modelIndex; + + // All skins are even numbers, pain skins are skin+1. + if (!self->s.skinnum) + { // If the skin hasn't been touched, set it. + if (irand(0,1)) + self->s.skinnum = 0; + else + self->s.skinnum = 2; + } + + if (!self->s.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + self->materialtype = MAT_FLESH; + + + //FIXME (somewhere: otherenemy should be more than just *one* kind + self->monsterinfo.otherenemyname = "monster_box"; + + if(self->spawnflags & MSF_WANDER) + { + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + } + else if(self->spawnflags & MSF_PELF_CINEMATIC) + { + self->svflags|=SVF_FLOAT; + self->monsterinfo.c_mode = 1; +// self->takedamage = DAMAGE_NO; + QPostMessage(self, MSG_C_IDLE1, PRI_DIRECTIVE, "iiige",0,0,0,NULL,NULL); + } + else + { + QPostMessage(self,MSG_STAND,PRI_DIRECTIVE, NULL); + } + + if(self->spawnflags&MSF_FIXED || self->spawnflags&MSF_PELF_MISSILE) + { +// if(!self->melee_range) + self->melee_range = 0; + + if(!self->missile_range) + self->missile_range = 512; + +// if(!self->min_missile_range) + self->min_missile_range = 0; + + if(!self->bypass_missile_chance) + self->bypass_missile_chance = 60; + + self->s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HANDLE].flags |= FMNI_NO_DRAW; + + self->monsterinfo.aiflags |= AI_NO_MELEE; + } + else + { + //turn on/off the weapons that aren't used + chance = irand(0, 3); + if(chance < 1) + { + //show the hammer + self->s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + } + else if(chance < 2) + { + //show the hoe + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GAFF].flags |= FMNI_NO_DRAW; + } + else + { + //show the gaff (that hook thingie) + self->s.fmnodeinfo[MESH__HAMMER].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__HOE].flags |= FMNI_NO_DRAW; + } + + self->monsterinfo.aiflags |= AI_NO_MISSILE; + } + + self->monsterinfo.supporters = -1; + + //set up my mood function + MG_InitMoods(self); + self->svflags |= SVF_WAIT_NOTSOLID; + + if(!stricmp(self->classname, "monster_palace_plague_guard_invisible")) + { + self->melee_range = -64; + self->min_missile_range = 30; + self->bypass_missile_chance = 80; + } +} + +// + +/*QUAKED monster_palace_plague_guard (1 .5 0) (-17 -25 -1) (22 12 63) AMBUSH ASLEEP WALKING CINEMATIC Missile 32 64 FIXED WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +Can fire 2 ranged attacks, has a new skin, toucgher, has armor? + +The plagueElf + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING - use WANDER instead + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 16 +melee_range = 0 +missile_range = 512 +min_missile_range = 0 +bypass_missile_chance = 60 +jump_chance = 50 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +/*------------------------------------------------------------------------- + SP_monster_palace_plague_guard +-------------------------------------------------------------------------*/ +void SP_monster_palace_plague_guard (edict_t *self) +{ + if(!self->health) + self->health = PLAGUEELF_HEALTH * 2; + + self->spawnflags |= MSF_PELF_MISSILE; + + if (!self->s.scale) + self->monsterinfo.scale = self->s.scale = flrand(1.0, 1.3); + + SP_monster_plagueElf(self); + + self->s.skinnum = PALACE_ELF_SKIN; +} + +/*QUAKED monster_palace_plague_guard_invisible (1 .5 0) (-17 -25 -1) (22 12 63) AMBUSH ASLEEP WALKING CINEMATIC Missile 32 64 FIXED WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 StartVisible + +Can fire 2 ranged attacks, has a new skin, toucgher, has armor? + +Is invisible unless firing or hit + +The plagueElf + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING - use WANDER instead + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 16 +melee_range = -64 +missile_range = 512 +min_missile_range = 30 +bypass_missile_chance = 80 +jump_chance = 50 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +/*------------------------------------------------------------------------- + SP_monster_palace_plague_guard_invisible +-------------------------------------------------------------------------*/ +void SP_monster_palace_plague_guard_invisible (edict_t *self) +{ + if(!self->health) + self->health = PLAGUEELF_HEALTH * 2; + + self->spawnflags |= MSF_PELF_MISSILE; + + SP_monster_plagueElf(self); + + self->s.skinnum = PALACE_ELF_SKIN; + + self->s.color.c = 0xFFFFFFFF; + + if(!(self->spawnflags&MSF_EXTRA4))//these guys start visible + pelf_init_phase_out(self); + +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/m_plagueElf.h b/Toolkit/Programming/GameCode/game/m_plagueElf.h new file mode 100644 index 0000000..23fb874 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_plagueElf.h @@ -0,0 +1,238 @@ +#ifndef __PLAGUEELF__ +#define __PLAGUEELF__ + +typedef enum AnimID_e +{ + ANIM_STAND1, + ANIM_WALK1, + ANIM_WALK2, + ANIM_RUN1, + ANIM_RUNATK1, + ANIM_FJUMP, + ANIM_INAIR, + ANIM_LAND, + ANIM_MELEE1, + ANIM_MELEE2, + ANIM_DIE1, + ANIM_DIE2, + ANIM_DIE3, + ANIM_DIE4, + ANIM_FIST1, + ANIM_LEAN1, + ANIM_SHAKE1, + ANIM_PAIN1, + ANIM_DELAY, + ANIM_MISSILE, + //kDEATH + ANIM_KDEATH_GO, + ANIM_KDEATH_LOOP, + ANIM_KDEATH_END, + //NEW ANIMS + ANIM_CRAZY_A,//check + ANIM_CRAZY_B,//check + ANIM_CURSING, + ANIM_POINT, + ANIM_SCARED,//check + + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_WALK1, + ANIM_C_WALK2, + ANIM_C_RUN1, + ANIM_C_ATTACK1, + ANIM_C_ATTACK2, + ANIM_C_ATTACK3, + ANIM_C_ATTACK4, + ANIM_C_PAIN1, + ANIM_C_DEATH1, + ANIM_C_DEATH2, + ANIM_C_DEATH3, + ANIM_C_DEATH4, + ANIM_C_THINKAGAIN, + + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PAIN1, + SND_PAIN2, + SND_PAIN3, + SND_DIE1, + SND_DIE2, + SND_DIE3, + SND_GIB, + SND_ATTACKHIT1, + SND_ATTACKHIT2, + SND_ATTACKMISS1, + SND_MOAN1, + SND_MOAN2, + SND_SHIVER, + SND_PANT, + SND_GASP, + SND_SIGH, + SND_ATTACK1, + SND_ATTACK2, + SND_ATTACK3, + SND_DISMEMBER1, + SND_DISMEMBER2, + + //Sight + VOICE_FIRST_GROUP, + VOICE_SIGHT_EAT_FLESH1, + VOICE_SIGHT_GET_HIM1, + VOICE_SIGHT_GET_HIM2, + VOICE_SIGHT_GET_HIM3, + VOICE_SIGHT_THERES_ONE, + + //Support + VOICE_SUPPORT_LIVER, + + //Valid single sight + VOICE_FIRST_ALONE, + VOICE_MISC_DIE, + VOICE_MISC_FLESH, + VOICE_SUPPORT_GONNA_DIE1, + VOICE_SUPPORT_YES, + VOICE_LAST_GROUP, + + VOICE_MISC_LEAVE_ME1, + VOICE_MISC_NO, + + NUM_SOUNDS +}; + +//Helper defines +#define FIRST_SIGHT_ALONE VOICE_FIRST_ALONE + 1 +#define LAST_SIGHT_ALONE VOICE_LAST_GROUP - 1 + +#define FIRST_SIGHT_GROUP VOICE_FIRST_GROUP + 1 +#define LAST_SIGHT_GROUP VOICE_LAST_GROUP - 1 + +#define NUM_VOICES ((NUM_SOUNDS - FIRST_SIGHT_GROUP) - 3) + +enum +{ + FX_PE_MAKE_SPELL, + FX_PE_EXPLODE_SPELL, + FX_PE_MAKE_SPELL2, + FX_PE_EXPLODE_SPELL2, + FX_PE_MAKE_SPELL3, + FX_PE_EXPLODE_SPELL3, +}; + +typedef struct pelfConversation_s +{ + float responseDelay; +} pelfConversation_t; + +extern animmove_t plagueElf_move_death1; +extern animmove_t plagueElf_move_death2; +extern animmove_t plagueElf_move_death3; +extern animmove_t plagueElf_move_death4; +extern animmove_t plagueElf_move_pain1; +extern animmove_t plagueElf_move_melee1; +extern animmove_t plagueElf_move_melee2; +extern animmove_t plagueElf_move_run1; +extern animmove_t plagueElf_move_runatk1; +extern animmove_t plagueElf_move_fjump; +extern animmove_t plagueElf_move_inair; +extern animmove_t plagueElf_move_land; +extern animmove_t plagueElf_move_walk1; +extern animmove_t plagueElf_move_walk2; +extern animmove_t plagueElf_move_stand1; +extern animmove_t plagueElf_fist1; +extern animmove_t plagueElf_lean1; +extern animmove_t plagueElf_shake1; +extern animmove_t plagueElf_delay; +extern animmove_t plagueElf_move_missile; + +extern animmove_t plagueElf_move_kdeath_go; +extern animmove_t plagueElf_move_kdeath_loop; +extern animmove_t plagueElf_move_kdeath_end; + +extern animmove_t plagueElf_crazy_A; +extern animmove_t plagueElf_crazy_B; +extern animmove_t plagueElf_cursing; +extern animmove_t plagueElf_point; +extern animmove_t plagueElf_scared; + + +extern animmove_t plagueElf_move_c_idle1; +extern animmove_t plagueElf_move_c_idle2; +extern animmove_t plagueElf_move_c_idle3; +extern animmove_t plagueElf_move_c_walk; +extern animmove_t plagueElf_move_c_walk2; +extern animmove_t plagueElf_move_c_run; +extern animmove_t plagueElf_move_c_attack1; +extern animmove_t plagueElf_move_c_attack2; +extern animmove_t plagueElf_move_c_attack3; +extern animmove_t plagueElf_move_c_attack4; +extern animmove_t plagueElf_move_c_pain1; +extern animmove_t plagueElf_move_c_death1; +extern animmove_t plagueElf_move_c_death2; +extern animmove_t plagueElf_move_c_death3; +extern animmove_t plagueElf_move_c_death4; +void plagueElf_c_spell(edict_t *self); + +void plagueElf_blocked(edict_t *self, G_Message_t *msg); +void plagueElf_death(edict_t *self, G_Message_t *msg); +void plagueElf_run(edict_t *self, G_Message_t *msg); +void plagueElf_walk(edict_t *self, G_Message_t *msg); +void plagueElf_melee(edict_t *self, G_Message_t *msg); +void plagueElf_stand(edict_t *self, G_Message_t *msg); +void plagueElf_pain(edict_t *self, G_Message_t *msg); +void plagueElf_dismember_msg(edict_t *self, G_Message_t *msg); +void plagueElf_dismember(edict_t *self, int damage, int HitLocation); + +//void plagueElf_dead(edict_t *self); +void plagueElfdeathsqueal(edict_t *self); +void plagueElfsqueal(edict_t *self); +void plagueElfgrowl(edict_t *self); +void plagueElf_strike(edict_t *self); +void plagueElf_think_pain(edict_t *self); +void plagueElf_pause (edict_t *self); +qboolean plagueElf_dropweapon (edict_t *self, int damage); +void ai_charge2 (edict_t *self, float dist); +void plagueElfattack(edict_t *self); + +void plagueelf_death_loop( edict_t *self ); +void plagueelf_check_land( edict_t *self ); +void plagueElf_spell(edict_t *self); +void plagueElfApplyJump(edict_t *self); + +void SP_monster_plagueElf (edict_t *self); +void MG_InitMoods(edict_t *self); +qboolean ok_to_wake (edict_t *monster, qboolean gorgon_roar, qboolean ignore_ambush); + +void plagueElfSpellTouch (edict_t *self, edict_t *Other, cplane_t *Plane, csurface_t *Surface); + +//Voice support +void pelf_SightSound ( edict_t *self, G_Message_t *msg ); +void pelf_PollResponse ( edict_t *self, int sound_event, int sound_id, float time ); +void pelf_EchoResponse ( edict_t *self, G_Message_t *msg ); +void pelf_EchoSound ( edict_t *self, G_Message_t *msg ); + +void pelf_init_phase_out (edict_t *self); +void pelf_init_phase_in (edict_t *self); +void pelf_check_too_close(edict_t *self); +void pelf_land(edict_t *self); +void pelf_go_inair(edict_t *self); +void MG_CheckLanded (edict_t *self, float next_anim); +void plagueElf_go_run(edict_t *self); + + +#define BIT_BASE 0 +#define BIT_HANDLE 1 +#define BIT_HOE 2 +#define BIT_GAFF 4 +#define BIT_HAMMER 8 +#define BIT_BODY 16 +#define BIT_L_LEG 32 +#define BIT_R_LEG 64 +#define BIT_R_ARM 128 +#define BIT_L_ARM 256 +#define BIT_HEAD 512 + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/m_plagueElf_anim.c b/Toolkit/Programming/GameCode/game/m_plagueElf_anim.c new file mode 100644 index 0000000..2d98913 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_plagueElf_anim.c @@ -0,0 +1,954 @@ +//============================================================================== +// +// m_plagueElf_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_plagueElf_anim.h" +#include "m_plagueElf.h" + +#include "g_monster.h" +#include "c_ai.h" + +//all of the anim frames that used to live in m_plagueElf.h + +/*---------------------------------------------------------------------- +// +// Non - Cinematic frames +// +/*---------------------------------------------------------------------- + + +/*---------------------------------------------------------------------- + plagueElf Death 1 - the big death, flying backwards and flipping over +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_death1 [] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, plagueElfdeathsqueal, + FRAME_death2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death7, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_death8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t plagueElf_move_death1 = {13, plagueElf_frames_death1, M_EndDeath}; + +/*------------------------------------------------------------------------- + plagueElf_frames_death2 +-------------------------------------------------------------------------*/ +animframe_t plagueElf_frames_death2 [] = +{ + FRAME_deathb1, NULL, 0, 0, 0, NULL, 0, plagueElfdeathsqueal, + FRAME_deathb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb7, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_deathb8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb13, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_death2 = {14, plagueElf_frames_death2, M_EndDeath}; + +/*------------------------------------------------------------------------- + plagueElf_frames_death3 +-------------------------------------------------------------------------*/ +animframe_t plagueElf_frames_death3 [] = +{ + FRAME_deathc1, NULL, 0, 0, 0, NULL, 0, plagueElfdeathsqueal, + FRAME_deathc2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc7, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_deathc8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc13, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_death3 = {14, plagueElf_frames_death3, M_EndDeath}; + +/*------------------------------------------------------------------------- + plagueElf_frames_death4 +-------------------------------------------------------------------------*/ +animframe_t plagueElf_frames_death4 [] = +{ + FRAME_deathd1, NULL, 0, 0, 0, NULL, 0, plagueElfdeathsqueal, + FRAME_deathd2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd7, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_deathd8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd13, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_death4 = {14, plagueElf_frames_death4, M_EndDeath}; + + +/*---------------------------------------------------------------------- + plagueElf Pain - plagueElf gets hit <<-- FIXME + this is not a real animation, this is recycling other anims +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_pain1 [] = +{ + FRAME_painA1, NULL, 0, 0, 0, NULL, 0, plagueElfsqueal, + FRAME_painA2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painA3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painA4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painA5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painA6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_painA7, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t plagueElf_move_pain1 = {7, plagueElf_frames_pain1, plagueElf_pause}; + + +/*---------------------------------------------------------------------- + plagueElf Melee - plagueElf attacking one hand forehand swing +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_melee1 [] = +{ + FRAME_attckA1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckA2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckA3, NULL, 0, 0, 0, ai_charge, 0, plagueElfattack, + FRAME_attckA4, NULL, 0, 0, 0, ai_charge, 0, plagueElf_strike, + FRAME_attckA5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckA6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckA7, NULL, 0, 0, 0, ai_charge, 0, NULL +}; +animmove_t plagueElf_move_melee1 = {7, plagueElf_frames_melee1, plagueElf_pause}; + + +/*---------------------------------------------------------------------- + plagueElf Melee - plagueElf attacking two handed chop +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_melee2 [] = +{ + FRAME_attckB1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckB2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckB3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckB4, NULL, 0, 0, 0, ai_charge, 0, plagueElfattack, + FRAME_attckB5, NULL, 0, 0, 0, ai_charge, 0, plagueElf_strike, + FRAME_attckB6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckB7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckB8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckB9, NULL, 0, 0, 0, ai_charge, 0, NULL +}; +animmove_t plagueElf_move_melee2 = {9, plagueElf_frames_melee2, plagueElf_pause}; + +/*---------------------------------------------------------------------- + plagueElf Missile +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_missile [] = +{ + FRAME_attckA1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckA2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckA3, NULL, 0, 0, 0, ai_charge, 0, plagueElfattack, + FRAME_attckA4, NULL, 0, 0, 0, ai_charge, 0, plagueElf_spell, + FRAME_attckA5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckA6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attckA7, NULL, 0, 0, 0, ai_charge, 0, NULL +}; +animmove_t plagueElf_move_missile = {7, plagueElf_frames_missile, plagueElf_pause}; + +/*---------------------------------------------------------------------- + plagueElf Running - plagueElf running +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_run1 [] = +{ + FRAME_runA1, NULL, 0, 0, 0, ai_run, 12, plagueElfgrowl, + FRAME_runA2, NULL, 0, 0, 0, ai_run, 13, plagueElf_pause, + FRAME_runA3, NULL, 0, 0, 0, ai_run, 14, plagueElf_pause, + FRAME_runA4, NULL, 0, 0, 0, ai_run, 14, plagueElf_pause, + FRAME_runA5, NULL, 0, 0, 0, ai_run, 14, plagueElf_pause, + FRAME_runA6, NULL, 0, 0, 0, ai_run, 14, plagueElf_pause, + FRAME_runA7, NULL, 0, 0, 0, ai_run, 14, plagueElf_pause, + FRAME_runA8, NULL, 0, 0, 0, ai_run, 11, plagueElf_pause +}; +animmove_t plagueElf_move_run1 = {8, plagueElf_frames_run1, plagueElf_pause}; + +/*---------------------------------------------------------------------- + plagueElf Running & Attack - plagueElf running n swinging +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_runatk1 [] = +{ + FRAME_runatk1, NULL, 0, 0, 0, ai_charge, 10, NULL, + FRAME_runatk2, NULL, 0, 0, 0, ai_charge, 11, plagueElfattack, + FRAME_runatk3, NULL, 0, 0, 0, ai_charge, 12, plagueElf_strike, + FRAME_runatk4, NULL, 0, 0, 0, ai_charge, 12, NULL, + FRAME_runatk5, NULL, 0, 0, 0, ai_charge, 12, NULL, + FRAME_runatk6, NULL, 0, 0, 0, ai_charge, 12, NULL, + FRAME_runatk7, NULL, 0, 0, 0, ai_charge, 12, NULL, + FRAME_runatk8, NULL, 0, 0, 0, ai_charge, 9, NULL +}; +animmove_t plagueElf_move_runatk1 = {8, plagueElf_frames_runatk1, plagueElf_pause}; + +/*---------------------------------------------------------------------- + plagueElf landing +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_land [] = +{ + FRAME_recover1, NULL, 0, 0, 0, NULL, 0, pelf_land, + FRAME_recover2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_recover3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_recover4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_recover5, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t plagueElf_move_land = {5, plagueElf_frames_land, plagueElf_pause}; + +/*---------------------------------------------------------------------- + plagueElf in air +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_inair [] = +{ + FRAME_jump20, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, 0, +}; +animmove_t plagueElf_move_inair = {1, plagueElf_frames_inair, NULL}; + +/*---------------------------------------------------------------------- + plagueElf jump from buoy +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_fjump [] = +{ + FRAME_jump1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, NULL, 0, plagueElfgrowl, + FRAME_jump3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, NULL, 0, plagueElfApplyJump, + FRAME_jump6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump11, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump12, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump13, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump14, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump15, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump16, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump17, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump18, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump19, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump20, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, +}; +animmove_t plagueElf_move_fjump = {20, plagueElf_frames_fjump, pelf_go_inair}; + +/*---------------------------------------------------------------------- + plagueElf Walking - plagueElf walking +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_walk1 [] = +{ + FRAME_walkA1, NULL, 0, 0, 0, ai_walk, 6, plagueElfgrowl, + FRAME_walkA2, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA3, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA4, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA5, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA6, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA7, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA8, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA9, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA10, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA11, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walkA12, NULL, 0, 0, 0, ai_walk, 6, NULL +}; +animmove_t plagueElf_move_walk1 = {12, plagueElf_frames_walk1, plagueElf_pause}; + +/*---------------------------------------------------------------------- + plagueElf Walking - plagueElf walking +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_walk2 [] = +{ + FRAME_walkA1, NULL, 0, 0, 0, ai_walk, 4, plagueElfgrowl, + FRAME_walkA2, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA3, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA4, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA5, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA6, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA7, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA8, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA9, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA10, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA11, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walkA12, NULL, 0, 0, 0, ai_walk, 4, NULL +}; +animmove_t plagueElf_move_walk2 = {12, plagueElf_frames_walk2, plagueElf_pause}; + + +/*---------------------------------------------------------------------- + plagueElf Standing - +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_stand1 [] = +{ + FRAME_shake1, NULL, 0, 0, 0, ai_stand, 0, NULL +}; +animmove_t plagueElf_move_stand1 = {1, plagueElf_frames_stand1, plagueElf_pause}; + +/*---------------------------------------------------------------------- + plagueElf shake - standing and having spasms +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_shakeA1 [] = +{ + FRAME_shake1, NULL, 0, 0, 0, ai_stand, 0, plagueElfgrowl, + FRAME_shake2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_shake5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_shake8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_shake11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_shake15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_shake18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake20, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_shake21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake23, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_shake24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shake25, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_shake1 = { 25, plagueElf_frames_shakeA1, plagueElf_pause}; + + +//============================================================================ +//U N U S E D + +/*---------------------------------------------------------------------- + plagueElf fist - beating the wall +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_fist1[] = +{ + FRAME_fist1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_fist2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fist3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fist4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fist5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_fist6, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_fist1 = { 6, plagueElf_frames_fist1, plagueElf_pause}; + +/*---------------------------------------------------------------------- + plagueElf leaning - swooning against the wall +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_lean1 [] = +{ + FRAME_lean1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_lean4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_lean10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_lean19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_lean25, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t plagueElf_lean1 = { 25, plagueElf_frames_lean1, plagueElf_pause}; + +animframe_t plagueElf_frames_delay [] = +{ + FRAME_shake1, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake2, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake3, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake4, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake5, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake6, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake7, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake8, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake9, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake10, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake11, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake12, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake13, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake14, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake15, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake16, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake17, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake18, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake19, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake20, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake21, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake22, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake23, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake24, NULL, 0, 0, 0, NULL, 0, plagueElf_pause, + FRAME_shake25, NULL, 0, 0, 0, NULL, 0, plagueElf_pause +}; +animmove_t plagueElf_delay = { 25, plagueElf_frames_delay, plagueElf_pause}; + +//New plague elf knock back death (tm) -- jweier + +animframe_t plagueElf_frames_kdeath_go [] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, plagueElfdeathsqueal, + FRAME_death2, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, + FRAME_death3, NULL, 0, 0, 0, NULL, 0, plagueelf_death_loop, +}; +animmove_t plagueElf_move_kdeath_go = {3, plagueElf_frames_kdeath_go, NULL}; + +//Loop until the ground is hit +animframe_t plagueElf_frames_kdeath_loop [] = +{ + FRAME_death4, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, +}; +animmove_t plagueElf_move_kdeath_loop = {1, plagueElf_frames_kdeath_loop, NULL}; + +//All done +animframe_t plagueElf_frames_kdeath_end [] = +{ + FRAME_death5, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, + FRAME_death6, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, + FRAME_death7, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, + FRAME_death8, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, + FRAME_death9, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, + FRAME_death10, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, + FRAME_death11, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, + FRAME_death12, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, + FRAME_death13, NULL, 0, 0, 0, NULL, 0, plagueelf_check_land, +}; +animmove_t plagueElf_move_kdeath_end = {9, plagueElf_frames_kdeath_end, M_EndDeath}; + +//NEW ANIMS + +animframe_t plagueElf_frames_crazy_A [] = +{ + FRAME_crazyA1, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyA2, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyA3, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyA4, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyA5, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyA6, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyA7, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyA8, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyA9, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyA10, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyA11, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyA12, NULL, 0, 0, 0, ai_run, 8, NULL, +}; +animmove_t plagueElf_crazy_A = { 6, plagueElf_frames_crazy_A, plagueElf_pause}; + +animframe_t plagueElf_frames_crazy_B [] = +{ + FRAME_crazyB1, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyB2, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyB3, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyB4, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyB5, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyB6, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyB7, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyB8, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyB9, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyB10, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_crazyB11, NULL, 0, 0, 0, ai_run, 16, NULL, +// FRAME_crazyB12, NULL, 0, 0, 0, ai_run, 8, NULL, +}; +animmove_t plagueElf_crazy_B = { 6, plagueElf_frames_crazy_B, plagueElf_pause}; + +animframe_t plagueElf_frames_cursing [] = +{ + FRAME_cursing1 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing2 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing3 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing4 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing5 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing6 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing7 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing8 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing9 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing10 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing11 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing12 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing13 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing14 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing15 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing16 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing17 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing18 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing19 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing20 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing21 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing22 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing23 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing24 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing25 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing26 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing27 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing28 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing29 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing30 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing31 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing32 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing33 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing34 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing35 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing36 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing37 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing38 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing39 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing40 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing41 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing42 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing43 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing44 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing45 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing46 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing47 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing48 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing49 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing50 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing51 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing52 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing53 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing54 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing55 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing56 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing57 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing58 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing59 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing60 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_cursing61 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing62 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing63 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_cursing64 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t plagueElf_cursing = { 16, plagueElf_frames_cursing, plagueElf_go_run}; + +animframe_t plagueElf_frames_point [] = +{ + FRAME_point1 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point2 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point3 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_point4 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point5 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point6 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point7 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_point8 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point9 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point10 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point11 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_point12 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point13 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point14 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point15 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_point16 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point17 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point18 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point19 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_point20 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point21 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point22 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point23 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_point24 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point25 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point26 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point27 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +// FRAME_point28 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point29 , NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_point30 , NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t plagueElf_point = { 23, plagueElf_frames_point, plagueElf_go_run}; + +animframe_t plagueElf_frames_scared [] = +{ + FRAME_scared1 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared2 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared3 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared4 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared5 , NULL, 0, 0, 0, NULL, 0, pelf_check_too_close, + FRAME_scared6 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared7 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared8 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared9 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared10 , NULL, 0, 0, 0, NULL, 0, pelf_check_too_close, + FRAME_scared11 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared12 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared13 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared14 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared15 , NULL, 0, 0, 0, NULL, 0, pelf_check_too_close, + FRAME_scared16 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared17 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared18 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared19 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared20 , NULL, 0, 0, 0, NULL, 0, pelf_check_too_close, + FRAME_scared21 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared22 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared23 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared24 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared25 , NULL, 0, 0, 0, NULL, 0, pelf_check_too_close, + FRAME_scared26 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared27 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared28 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared29 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared30 , NULL, 0, 0, 0, NULL, 0, pelf_check_too_close, + FRAME_scared31 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared32 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared33 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared34 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared35 , NULL, 0, 0, 0, NULL, 0, pelf_check_too_close, + FRAME_scared36 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared37 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared38 , NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_scared39 , NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t plagueElf_scared = { 39, plagueElf_frames_scared, plagueElf_pause}; + + +/************************************************************************ +/************************************************************************ +// +// Cinematic Frames +// +/************************************************************************ +/*************************************************************************/ + +/*---------------------------------------------------------------------- + plagueElf Standing - +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_idle3 [] = +{ + FRAME_fist1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_fist2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_fist3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_fist4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_fist5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_fist6, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_idle3 = {6, plagueElf_frames_c_idle3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + plagueElf leaning - swooning against the wall +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_idle2 [] = +{ + FRAME_lean1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_lean25, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t plagueElf_move_c_idle2 = { 25, plagueElf_frames_c_idle2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + plagueElf shake - standing and having spasms +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_idle1 [] = +{ + FRAME_shake1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shake25, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_idle1 = { 25, plagueElf_frames_c_idle1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + plagueElf Walking - plagueElf walking +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_walk [] = +{ + FRAME_walkA1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA12, ai_c_move, 4, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_walk = {12, plagueElf_frames_c_walk, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + plagueElf Walking - plagueElf walking2 +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_walk2 [] = +{ + FRAME_walkA1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_walkA12, ai_c_move, 4, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_walk2 = {12, plagueElf_frames_c_walk2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + plagueElf Running - plagueElf running +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_run [] = +{ + FRAME_runA1, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_runA2, ai_c_move, 13, 0, 0, NULL, 0, NULL, + FRAME_runA3, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_runA4, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_runA5, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_runA6, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_runA7, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_runA8, ai_c_move, 11, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_run = {8, plagueElf_frames_c_run, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + plagueElf Running & Attack - plagueElf running n swinging +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_attack1 [] = +{ + FRAME_runatk1, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_runatk2, ai_c_move, 11, 0, 0, NULL, 0, NULL, + FRAME_runatk3, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_runatk4, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_runatk5, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_runatk6, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_runatk7, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_runatk8, ai_c_move, 9, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_attack1 = {8, plagueElf_frames_c_attack1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + plagueElf Melee - plagueElf attacking one hand forehand swing +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_attack2 [] = +{ + FRAME_attckA1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA7, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_attack2 = {7, plagueElf_frames_c_attack2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + plagueElf Melee - plagueElf attacking two handed chop +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_attack3 [] = +{ + FRAME_attckB1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckB2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckB3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckB4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckB5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckB6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckB7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckB8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckB9, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_attack3 = {9, plagueElf_frames_c_attack3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + plagueElf Missile +-----------------------------------------------------------------------*/ +animframe_t plagueElf_c_frames_attack4 [] = +{ + FRAME_attckA1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA4, ai_c_move, 0, 0, 0, NULL, 0, plagueElf_c_spell, + FRAME_attckA5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_attckA7, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_attack4 = {7, plagueElf_c_frames_attack4,ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + plagueElf Death 1 - the big death, flying backwards and flipping over +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_death1 [] = +{ + FRAME_death1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t plagueElf_move_c_death1 = {13, plagueElf_frames_c_death1, ai_c_cycleend}; + + +/*------------------------------------------------------------------------- + plagueElf_frames_death2 +-------------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_death2 [] = +{ + FRAME_deathb1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathb13, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_death2 = {13, plagueElf_frames_c_death2, ai_c_cycleend}; + +/*------------------------------------------------------------------------- + plagueElf_frames_death3 +-------------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_death3 [] = +{ + FRAME_deathc1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathc13, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_death3 = {13, plagueElf_frames_c_death3, ai_c_cycleend}; + +/*------------------------------------------------------------------------- + plagueElf_frames_death4 +-------------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_death4 [] = +{ + FRAME_deathd1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathd13, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_death4 = {13, plagueElf_frames_c_death4,ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + plagueElf Pain - plagueElf gets hit <<-- FIXME + this is not a real animation, this is recycling other anims +-----------------------------------------------------------------------*/ +animframe_t plagueElf_frames_c_pain1 [] = +{ + FRAME_death3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death1, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t plagueElf_move_c_pain1 = {3, plagueElf_frames_c_pain1, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/m_plagueElf_anim.h b/Toolkit/Programming/GameCode/game/m_plagueElf_anim.h new file mode 100644 index 0000000..eb949ff --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_plagueElf_anim.h @@ -0,0 +1,451 @@ +// R:\Art\models/monsters\plaguelf + +// This file generated by qdata - Do NOT Modify + +#define FRAME_partfly 0 +#define FRAME_torsooff 1 +#define FRAME_attckA1 2 +#define FRAME_attckA2 3 +#define FRAME_attckA3 4 +#define FRAME_attckA4 5 +#define FRAME_attckA5 6 +#define FRAME_attckA6 7 +#define FRAME_attckA7 8 +#define FRAME_attckB1 9 +#define FRAME_attckB2 10 +#define FRAME_attckB3 11 +#define FRAME_attckB4 12 +#define FRAME_attckB5 13 +#define FRAME_attckB6 14 +#define FRAME_attckB7 15 +#define FRAME_attckB8 16 +#define FRAME_attckB9 17 +#define FRAME_crazyA1 18 +#define FRAME_crazyA2 19 +#define FRAME_crazyA3 20 +#define FRAME_crazyA4 21 +#define FRAME_crazyA5 22 +#define FRAME_crazyA6 23 +#define FRAME_crazyA7 24 +#define FRAME_crazyA8 25 +#define FRAME_crazyA9 26 +#define FRAME_crazyA10 27 +#define FRAME_crazyA11 28 +#define FRAME_crazyA12 29 +#define FRAME_crazyB1 30 +#define FRAME_crazyB2 31 +#define FRAME_crazyB3 32 +#define FRAME_crazyB4 33 +#define FRAME_crazyB5 34 +#define FRAME_crazyB6 35 +#define FRAME_crazyB7 36 +#define FRAME_crazyB8 37 +#define FRAME_crazyB9 38 +#define FRAME_crazyB10 39 +#define FRAME_crazyB11 40 +#define FRAME_crazyB12 41 +#define FRAME_cursing1 42 +#define FRAME_cursing2 43 +#define FRAME_cursing3 44 +#define FRAME_cursing4 45 +#define FRAME_cursing5 46 +#define FRAME_cursing6 47 +#define FRAME_cursing7 48 +#define FRAME_cursing8 49 +#define FRAME_cursing9 50 +#define FRAME_cursing10 51 +#define FRAME_cursing11 52 +#define FRAME_cursing12 53 +#define FRAME_cursing13 54 +#define FRAME_cursing14 55 +#define FRAME_cursing15 56 +#define FRAME_cursing16 57 +#define FRAME_cursing17 58 +#define FRAME_cursing18 59 +#define FRAME_cursing19 60 +#define FRAME_cursing20 61 +#define FRAME_cursing21 62 +#define FRAME_cursing22 63 +#define FRAME_cursing23 64 +#define FRAME_cursing24 65 +#define FRAME_cursing25 66 +#define FRAME_cursing26 67 +#define FRAME_cursing27 68 +#define FRAME_cursing28 69 +#define FRAME_cursing29 70 +#define FRAME_cursing30 71 +#define FRAME_cursing31 72 +#define FRAME_cursing32 73 +#define FRAME_cursing33 74 +#define FRAME_cursing34 75 +#define FRAME_cursing35 76 +#define FRAME_cursing36 77 +#define FRAME_cursing37 78 +#define FRAME_cursing38 79 +#define FRAME_cursing39 80 +#define FRAME_cursing40 81 +#define FRAME_cursing41 82 +#define FRAME_cursing42 83 +#define FRAME_cursing43 84 +#define FRAME_cursing44 85 +#define FRAME_cursing45 86 +#define FRAME_cursing46 87 +#define FRAME_cursing47 88 +#define FRAME_cursing48 89 +#define FRAME_cursing49 90 +#define FRAME_cursing50 91 +#define FRAME_cursing51 92 +#define FRAME_cursing52 93 +#define FRAME_cursing53 94 +#define FRAME_cursing54 95 +#define FRAME_cursing55 96 +#define FRAME_cursing56 97 +#define FRAME_cursing57 98 +#define FRAME_cursing58 99 +#define FRAME_cursing59 100 +#define FRAME_cursing60 101 +#define FRAME_cursing61 102 +#define FRAME_cursing62 103 +#define FRAME_cursing63 104 +#define FRAME_cursing64 105 +#define FRAME_deathb1 106 +#define FRAME_deathb10 107 +#define FRAME_deathb11 108 +#define FRAME_deathb12 109 +#define FRAME_deathb13 110 +#define FRAME_deathb2 111 +#define FRAME_deathb3 112 +#define FRAME_deathb4 113 +#define FRAME_deathb5 114 +#define FRAME_deathb6 115 +#define FRAME_deathb7 116 +#define FRAME_deathb8 117 +#define FRAME_deathb9 118 +#define FRAME_deathc1 119 +#define FRAME_deathc10 120 +#define FRAME_deathc11 121 +#define FRAME_deathc12 122 +#define FRAME_deathc13 123 +#define FRAME_deathc2 124 +#define FRAME_deathc3 125 +#define FRAME_deathc4 126 +#define FRAME_deathc5 127 +#define FRAME_deathc6 128 +#define FRAME_deathc7 129 +#define FRAME_deathc8 130 +#define FRAME_deathc9 131 +#define FRAME_deathd1 132 +#define FRAME_deathd10 133 +#define FRAME_deathd11 134 +#define FRAME_deathd12 135 +#define FRAME_deathd13 136 +#define FRAME_deathd2 137 +#define FRAME_deathd3 138 +#define FRAME_deathd4 139 +#define FRAME_deathd5 140 +#define FRAME_deathd6 141 +#define FRAME_deathd7 142 +#define FRAME_deathd8 143 +#define FRAME_deathd9 144 +#define FRAME_death1 145 +#define FRAME_death2 146 +#define FRAME_death3 147 +#define FRAME_death4 148 +#define FRAME_death5 149 +#define FRAME_death6 150 +#define FRAME_death7 151 +#define FRAME_death8 152 +#define FRAME_death9 153 +#define FRAME_death10 154 +#define FRAME_death11 155 +#define FRAME_death12 156 +#define FRAME_death13 157 +#define FRAME_death14 158 +#define FRAME_fist1 159 +#define FRAME_fist2 160 +#define FRAME_fist3 161 +#define FRAME_fist4 162 +#define FRAME_fist5 163 +#define FRAME_fist6 164 +#define FRAME_fist7 165 +#define FRAME_handslid1 166 +#define FRAME_handslid2 167 +#define FRAME_handslid3 168 +#define FRAME_handslid4 169 +#define FRAME_handslid5 170 +#define FRAME_handslid6 171 +#define FRAME_handslid7 172 +#define FRAME_handslid8 173 +#define FRAME_lean1 174 +#define FRAME_lean2 175 +#define FRAME_lean3 176 +#define FRAME_lean4 177 +#define FRAME_lean5 178 +#define FRAME_lean6 179 +#define FRAME_lean7 180 +#define FRAME_lean8 181 +#define FRAME_lean9 182 +#define FRAME_lean10 183 +#define FRAME_lean11 184 +#define FRAME_lean12 185 +#define FRAME_lean13 186 +#define FRAME_lean14 187 +#define FRAME_lean15 188 +#define FRAME_lean16 189 +#define FRAME_lean17 190 +#define FRAME_lean18 191 +#define FRAME_lean19 192 +#define FRAME_lean20 193 +#define FRAME_lean21 194 +#define FRAME_lean22 195 +#define FRAME_lean23 196 +#define FRAME_lean24 197 +#define FRAME_lean25 198 +#define FRAME_lean26 199 +#define FRAME_lean27 200 +#define FRAME_lean28 201 +#define FRAME_lean29 202 +#define FRAME_lean30 203 +#define FRAME_lean31 204 +#define FRAME_lean32 205 +#define FRAME_lean33 206 +#define FRAME_lean34 207 +#define FRAME_painA1 208 +#define FRAME_painA2 209 +#define FRAME_painA3 210 +#define FRAME_painA4 211 +#define FRAME_painA5 212 +#define FRAME_painA6 213 +#define FRAME_painA7 214 +#define FRAME_point1 215 +#define FRAME_point2 216 +#define FRAME_point3 217 +#define FRAME_point4 218 +#define FRAME_point5 219 +#define FRAME_point6 220 +#define FRAME_point7 221 +#define FRAME_point8 222 +#define FRAME_point9 223 +#define FRAME_point10 224 +#define FRAME_point11 225 +#define FRAME_point12 226 +#define FRAME_point13 227 +#define FRAME_point14 228 +#define FRAME_point15 229 +#define FRAME_point16 230 +#define FRAME_point17 231 +#define FRAME_point18 232 +#define FRAME_point19 233 +#define FRAME_point20 234 +#define FRAME_point21 235 +#define FRAME_point22 236 +#define FRAME_point23 237 +#define FRAME_point24 238 +#define FRAME_point25 239 +#define FRAME_point26 240 +#define FRAME_point27 241 +#define FRAME_point28 242 +#define FRAME_point29 243 +#define FRAME_point30 244 +#define FRAME_runatk1 245 +#define FRAME_runatk2 246 +#define FRAME_runatk3 247 +#define FRAME_runatk4 248 +#define FRAME_runatk5 249 +#define FRAME_runatk6 250 +#define FRAME_runatk7 251 +#define FRAME_runatk8 252 +#define FRAME_runA1 253 +#define FRAME_runA2 254 +#define FRAME_runA3 255 +#define FRAME_runA4 256 +#define FRAME_runA5 257 +#define FRAME_runA6 258 +#define FRAME_runA7 259 +#define FRAME_runA8 260 +#define FRAME_scared1 261 +#define FRAME_scared2 262 +#define FRAME_scared3 263 +#define FRAME_scared4 264 +#define FRAME_scared5 265 +#define FRAME_scared6 266 +#define FRAME_scared7 267 +#define FRAME_scared8 268 +#define FRAME_scared9 269 +#define FRAME_scared10 270 +#define FRAME_scared11 271 +#define FRAME_scared12 272 +#define FRAME_scared13 273 +#define FRAME_scared14 274 +#define FRAME_scared15 275 +#define FRAME_scared16 276 +#define FRAME_scared17 277 +#define FRAME_scared18 278 +#define FRAME_scared19 279 +#define FRAME_scared20 280 +#define FRAME_scared21 281 +#define FRAME_scared22 282 +#define FRAME_scared23 283 +#define FRAME_scared24 284 +#define FRAME_scared25 285 +#define FRAME_scared26 286 +#define FRAME_scared27 287 +#define FRAME_scared28 288 +#define FRAME_scared29 289 +#define FRAME_scared30 290 +#define FRAME_scared31 291 +#define FRAME_scared32 292 +#define FRAME_scared33 293 +#define FRAME_scared34 294 +#define FRAME_scared35 295 +#define FRAME_scared36 296 +#define FRAME_scared37 297 +#define FRAME_scared38 298 +#define FRAME_scared39 299 +#define FRAME_shake1 300 +#define FRAME_shake2 301 +#define FRAME_shake3 302 +#define FRAME_shake4 303 +#define FRAME_shake5 304 +#define FRAME_shake6 305 +#define FRAME_shake7 306 +#define FRAME_shake8 307 +#define FRAME_shake9 308 +#define FRAME_shake10 309 +#define FRAME_shake11 310 +#define FRAME_shake12 311 +#define FRAME_shake13 312 +#define FRAME_shake14 313 +#define FRAME_shake15 314 +#define FRAME_shake16 315 +#define FRAME_shake17 316 +#define FRAME_shake18 317 +#define FRAME_shake19 318 +#define FRAME_shake20 319 +#define FRAME_shake21 320 +#define FRAME_shake22 321 +#define FRAME_shake23 322 +#define FRAME_shake24 323 +#define FRAME_shake25 324 +#define FRAME_walkA1 325 +#define FRAME_walkA2 326 +#define FRAME_walkA3 327 +#define FRAME_walkA4 328 +#define FRAME_walkA5 329 +#define FRAME_walkA6 330 +#define FRAME_walkA7 331 +#define FRAME_walkA8 332 +#define FRAME_walkA9 333 +#define FRAME_walkA10 334 +#define FRAME_walkA11 335 +#define FRAME_walkA12 336 +#define FRAME_death13end 337 +#define FRAME_deathb13end 338 +#define FRAME_deathc13end 339 +#define FRAME_deathd13end 340 +#define FRAME_skewered 341 +#define FRAME_jump1 342 +#define FRAME_jump2 343 +#define FRAME_jump3 344 +#define FRAME_jump4 345 +#define FRAME_jump5 346 +#define FRAME_jump6 347 +#define FRAME_jump7 348 +#define FRAME_jump8 349 +#define FRAME_jump9 350 +#define FRAME_jump10 351 +#define FRAME_jump11 352 +#define FRAME_jump12 353 +#define FRAME_jump13 354 +#define FRAME_jump14 355 +#define FRAME_jump15 356 +#define FRAME_jump16 357 +#define FRAME_jump17 358 +#define FRAME_jump18 359 +#define FRAME_jump19 360 +#define FRAME_jump20 361 +#define FRAME_recover1 362 +#define FRAME_recover2 363 +#define FRAME_recover3 364 +#define FRAME_recover4 365 +#define FRAME_recover5 366 +#define FRAME_fetal1 367 +#define FRAME_fetal2 368 +#define FRAME_fetal3 369 +#define FRAME_fetal4 370 +#define FRAME_fetal5 371 +#define FRAME_fetal6 372 +#define FRAME_fetal7 373 +#define FRAME_fetal8 374 +#define FRAME_fetal9 375 +#define FRAME_fetal10 376 +#define FRAME_fetal11 377 +#define FRAME_fetal12 378 +#define FRAME_fetal13 379 +#define FRAME_fetal14 380 +#define FRAME_fetal15 381 +#define FRAME_fetal16 382 +#define FRAME_fetal17 383 +#define FRAME_fetal18 384 +#define FRAME_fetal19 385 +#define FRAME_fetal20 386 +#define FRAME_fetal21 387 +#define FRAME_fetal22 388 +#define FRAME_fetal23 389 +#define FRAME_fetal24 390 +#define FRAME_fetal25 391 +#define FRAME_fetal26 392 +#define FRAME_reach1 393 +#define FRAME_reach2 394 +#define FRAME_reach3 395 +#define FRAME_reach4 396 +#define FRAME_reach5 397 +#define FRAME_reach6 398 +#define FRAME_reach7 399 +#define FRAME_reach8 400 +#define FRAME_reach9 401 +#define FRAME_reach10 402 +#define FRAME_reach11 403 +#define FRAME_reach12 404 +#define FRAME_reach13 405 +#define FRAME_reach14 406 +#define FRAME_reach15 407 +#define FRAME_reach16 408 +#define FRAME_reach17 409 +#define FRAME_reach18 410 +#define FRAME_reach19 411 +#define FRAME_reach20 412 +#define FRAME_reach21 413 +#define FRAME_reach22 414 +#define FRAME_reach23 415 +#define FRAME_reach24 416 +#define FRAME_reach25 417 +#define FRAME_reach26 418 +#define FRAME_reach27 419 +#define FRAME_reach28 420 +#define FRAME_reach29 421 +#define FRAME_reach30 422 +#define FRAME_reach31 423 +#define FRAME_reach32 424 +#define FRAME_reach33 425 +#define FRAME_reach34 426 +#define FRAME_reach35 427 +#define FRAME_reach36 428 +#define FRAME_reach37 429 +#define FRAME_reach38 430 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 11 + +#define MESH_BASEPOLY 0 +#define MESH__HANDLE 1 +#define MESH__HOE 2 +#define MESH__GAFF 3 +#define MESH__HAMMER 4 +#define MESH__BODY 5 +#define MESH__L_LEG 6 +#define MESH__R_LEG 7 +#define MESH__R_ARM 8 +#define MESH__L_ARM 9 +#define MESH__HEAD 10 diff --git a/Toolkit/Programming/GameCode/game/m_plaguessithra.c b/Toolkit/Programming/GameCode/game/m_plaguessithra.c new file mode 100644 index 0000000..c62e51e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_plaguessithra.c @@ -0,0 +1,3226 @@ +//============================================================================== +// +// m_plagueSsitra.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "m_plaguessithra.h" +#include "m_plaguessithra_anim.h" +#include "g_misc.h" +#include "g_HitLocation.h" +#include "m_stats.h" + + +void extrapolateFiredir (edict_t *self,vec3_t p1,float pspeed,edict_t *targ,float accept,vec3_t vec2); +void ssithra_blocked (edict_t *self, trace_t *trace); +qboolean visible_pos (edict_t *self, vec3_t spot2); +void create_ssith_arrow(edict_t *Arrow); +qboolean ssithraCheckInWater (edict_t *self); + +enum +{ + FX_SS_MAKE_ARROW, + FX_SS_MAKE_ARROW2, + FX_SS_EXPLODE_ARROW, + FX_SS_EXPLODE_ARROW2 +}; + +int Bit_for_MeshNode [16] = +{ + BIT_POLY, + BIT_LOWERTORSO, + BIT_CAPLOWERTORSO, + BIT_LEFTLEG, + BIT_RIGHTLEG, + BIT_UPPERTORSO, + BIT_CAPTOPUPPERTORSO, + BIT_CAPBOTTOMUPPERTORSO, + BIT_LEFTARM, + BIT_RIGHTARM, + BIT_HEAD, + BIT_CENTERSPIKE, + BIT_LEFT1SPIKE, + BIT_RIGHT1SPIKE, + BIT_RIGHT2SPIKE, + BIT_CAPHEAD +}; + +//======================================== +//INITIALIZE +//======================================== +static animmove_t *animations[NUM_ANIMS] = +{ + &ssithra_move_idle1, + &ssithra_move_walk1, + &ssithra_move_backpedal1, + &ssithra_move_bound1, + &ssithra_move_death_a1, + &ssithra_move_death_b1, + &ssithra_move_dive1, + &ssithra_move_duckshoot1, + &ssithra_move_duck1, + &ssithra_move_gallop1, + &ssithra_move_fjump, + &ssithra_move_idlebasic1, + &ssithra_move_idleright1, + &ssithra_move_melee1, + &ssithra_move_meleest, + &ssithra_move_namor1, + &ssithra_move_pain_a1, + &ssithra_move_shoot1, + &ssithra_move_startle1, + &ssithra_move_swimforward1, + &ssithra_move_swimwander, + &ssithra_move_water_death1,//19 + &ssithra_move_water_idle1, + &ssithra_move_water_pain_a1, + &ssithra_move_water_pain_b1, + &ssithra_move_water_shoot1, + &ssithra_move_run1, + &ssithra_move_spinright, + &ssithra_move_spinright_go, + &ssithra_move_spinleft, + &ssithra_move_spinleft_go, + &ssithra_move_faceandnamor, + &ssithra_move_dead_a, + &ssithra_move_lookright, + &ssithra_move_lookleft, + &ssithra_move_transup, + &ssithra_move_transdown, + &ssithra_move_headless, + &ssithra_move_headlessloop, + &ssithra_move_death_c, + &ssithra_move_dead_b, + &ssithra_move_dead_water, + &ssithra_move_sliced, + &ssithra_move_delay, + &ssithra_move_duckloop, + &ssithra_move_unduck, + &ssithra_move_lunge +}; + +static int Sounds[NUM_SOUNDS]; + +static ClassResourceInfo_t resInfo; + + +void ssithra_blocked (edict_t *self, trace_t *trace) +{ + vec3_t hitdir; + float strength; + + if(trace->ent == NULL) + return; + + if(trace->ent->movetype==PHYSICSTYPE_NONE|| + trace->ent->movetype==PHYSICSTYPE_PUSH) + return; + + strength = VectorLength(self->velocity); + + if(strength<50) + return; + +// gi.dprintf("ssithra shove!\n"); + VectorCopy(self->velocity, hitdir); + +// if(!stricmp(trace->ent->classname, "player")) +// KnockDownPlayer(&trace->ent->client->playerinfo); + if(hitdir[2] < 0) + hitdir[2] = 0; + VectorNormalize(hitdir); + VectorScale(hitdir, strength, hitdir); + VectorAdd(trace->ent->velocity, hitdir, trace->ent->knockbackvel); + + if(!(self->spawnflags & MSF_FIXED)) + ssithraJump(self, 150, 200, 0); +} + +//======================================== +//MOVEMENT +//======================================== + +void ssithra_stand(edict_t *self, G_Message_t *msg) +{ + int inwater; + + if (self->ai_mood == AI_MOOD_DELAY) + { + SetAnim(self, ANIM_DELAY); + return; + } + + inwater = ssithraCheckInWater(self); + + if(inwater) + { + SetAnim(self, ANIM_WATER_IDLE); + } + else + { + if(self->curAnimID == ANIM_STAND1) + { + if(flrand(0,10)<8)//9 + SetAnim(self, ANIM_STAND1); + else + SetAnim(self, ANIM_IDLEBASIC); + } + else if(self->curAnimID == ANIM_IDLEBASIC) + { + SetAnim(self, ANIM_STAND1); + } + else if(self->curAnimID == ANIM_IDLERIGHT) + { + if(flrand(0,10)<6)//7 + SetAnim(self, ANIM_STAND1); + else + SetAnim(self, ANIM_IDLEBASIC); + } + else + SetAnim(self, ANIM_STAND1); + } +} + +void ssithra_walk(edict_t *self, G_Message_t *msg) +{ + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_WALK1); +} + +void ssithra_spinright_go(edict_t *self) +{//ANIM_STARTLE? +// gi.dprintf("GO: Spinning right\n"); + SetAnim(self,ANIM_SPINRIGHT_GO); +} + +void ssithra_spinleft_go(edict_t *self) +{//ANIM_STARTLE? +// gi.dprintf("GO: Spinning right\n"); + SetAnim(self,ANIM_SPINLEFT_GO); +} + +void ssithraStartle (edict_t *self) +{ +// gi.dprintf("Startled!\n"); + SetAnim(self,ANIM_STARTLE); +} + +void ssithraLookRight (edict_t *self) +{ +// gi.dprintf("Startled to right!\n"); + SetAnim(self,ANIM_IDLERIGHT); +} + +void ssithra_gallop(edict_t *self, G_Message_t *msg) +{ + if(self->curAnimID == ANIM_SPINRIGHT) + { + SetAnim(self, ANIM_SPINRIGHT_GO); + return; + } + + if(self->curAnimID == ANIM_SPINLEFT) + { + SetAnim(self, ANIM_SPINLEFT_GO); + return; + } + + if(!self->enemy) + { + SetAnim(self,ANIM_STAND1); + return; + } + + if(self->enemy->health<=0) + { + SetAnim(self,ANIM_STAND1); + return; + } + + if(self->spawnflags&MSF_FIXED) + { + SetAnim(self, ANIM_DELAY); + return; + } + + if(self->spawnflags&MSF_SSITHRA_NAMOR)//Namor + { + self->spawnflags &= ~MSF_SSITHRA_NAMOR; + SetAnim(self,ANIM_NAMOR); + } + else if(self->spawnflags&MSF_SSITHRA_SPIN)//Spin + { + self->spawnflags &= ~MSF_SSITHRA_SPIN; + if(irand(0,1)) + { +// gi.dprintf("Spinning right\n"); + SetAnim(self,ANIM_SPINRIGHT); + } + else + { +// gi.dprintf("Spinning leftt\n"); + SetAnim(self,ANIM_SPINLEFT); + } + } + else + SetAnim(self, ANIM_RUN1); +} + +void ssithra_idlebasic(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_IDLEBASIC); +} + +void ssithra_decide_stand(edict_t *self) +{ + int inwater; + + inwater = ssithraCheckInWater(self); + + if(inwater) + { + SetAnim(self, ANIM_WATER_IDLE); + } + else + { + if((self->curAnimID == ANIM_STAND1)||(self->curAnimID == ANIM_IDLEBASIC)) + { + if(flrand(0,10)<7)//9 + SetAnim(self, ANIM_STAND1); + else if(flrand(0,10)<7)//9 + SetAnim(self, ANIM_IDLERIGHT); + else if(flrand(0,10)<5)//9 + SetAnim(self, ANIM_LOOKRIGHT); + else + SetAnim(self, ANIM_LOOKLEFT); + } + else if(self->curAnimID == ANIM_IDLERIGHT|| + self->curAnimID == ANIM_LOOKLEFT|| + self->curAnimID == ANIM_LOOKRIGHT) + { + if(flrand(0,10)<6)//7 + SetAnim(self, ANIM_STAND1); + else + SetAnim(self, ANIM_IDLEBASIC); + } + else + SetAnim(self, ANIM_STAND1); + } +} + +void ssithra_decide_gallop(edict_t *self) +{ + if(self->spawnflags & MSF_FIXED) + { + SetAnim(self, ANIM_DELAY); + return; + } + + VectorClear(self->velocity); + self->count = false; + + if(ssithraCheckInWater(self)) + { + SetAnim(self, ANIM_SWIMFORWARD); + } + else + { + SetAnim(self, ANIM_RUN1); + } + + SsithraCheckMood(self); +} + +void ssithra_decide_swimforward(edict_t *self) +{//fixme: climb out of water check! + self->count = false; + VectorClear(self->velocity); + + if(!ssithraCheckInWater(self)) + {//Not actually in water! + SetAnim(self, ANIM_RUN1); + } + else if(self->curAnimID == ANIM_WATER_SHOOT) + SetAnim(self, ANIM_TRANSDOWN); + + SsithraCheckMood(self); +} + +void ssithra_decide_backpedal(edict_t *self) +{ + SsithraCheckMood(self); +} + +void ssithraCheckRipple (edict_t *self) +{ + vec3_t top, bottom; + vec3_t dir; + trace_t trace; + byte angle_byte; + + VectorCopy(self->s.origin, top); + VectorCopy(top, bottom); + top[2] += self->maxs[2] * 0.75; + bottom[2] += self->mins[2]; + + gi.trace(top, vec3_origin, vec3_origin, bottom, self, MASK_WATER,&trace); + + if(trace.fraction >= 1.0) + return; + + AngleVectors(self->s.angles,dir,NULL,NULL); + VectorScale(dir,200,dir); + angle_byte = Q_ftol(((self->s.angles[YAW] + DEGREE_180)/360.0) * 255.0); + + gi.CreateEffect(NULL, FX_WATER_WAKE, 0, trace.endpos, "sbv", self->s.number, + angle_byte, dir); +} + +//======================================== +//SUPPORT CODE +//======================================== + +qboolean ssithraCheckInWater (edict_t *self) +{ + qboolean inwater = false; + + if(self->flags & FL_INWATER) + { + if(!(self->flags & FL_INLAVA)) + { + if(!(self->flags & FL_INSLIME)) + { + if(self->waterlevel > 2 || !self->groundentity)//??? + { + inwater = true; + } + } + } + } + + if(inwater) + { + self->monsterinfo.aiflags |= AI_NO_MELEE; + return true; + } + else + { + if(!(self->s.fmnodeinfo[MESH__LEFTARM].flags&FMNI_NO_DRAW)) + self->monsterinfo.aiflags &= ~AI_NO_MELEE; + return false; + } +} + +void ssithraNamorTriggered (edict_t *self, edict_t *other, edict_t *activator) +{//FIXME: might work anyway? + SetAnim(self, ANIM_NAMOR); + monster_use(self, other, activator); +} + +void ssithraVOfs(edict_t *self, float pofs, float yofs, float rofs) +{ + self->v_angle_ofs[PITCH] = pofs; + self->v_angle_ofs[YAW] = yofs; + self->v_angle_ofs[ROLL] = rofs; +} + + +//======================================== +//JUMPS +//make a find_water_top function... pass a vector +//======================================== + +qboolean ssithraWaterLedgeNearEnemy (edict_t *self) +{ + vec3_t enemy_dir, endpos, targ_org; + trace_t trace; + + if(self->spawnflags & MSF_FIXED) + return false; + + if(!MG_GetTargOrg(self, targ_org)) + return false; + + VectorSubtract(targ_org,self->s.origin,enemy_dir); + + VectorNormalize(enemy_dir); + VectorMA(self->s.origin,128,enemy_dir,endpos); + gi.trace(self->s.origin,self->mins,self->maxs,endpos,self,MASK_SOLID,&trace); + if(trace.fraction<1.0) + return true; + //no ledge to jump up on + return false; +} + +void ssithra_check_namor(edict_t *self) +{//fixme: climb out of water check! + qboolean enemy_inwater = false; + vec3_t targ_org; + + if(self->spawnflags & MSF_FIXED) + return; + + if(!MG_GetTargOrg(self, targ_org)) + return; + + enemy_inwater = (gi.pointcontents(targ_org)&CONTENTS_WATER); + + if(!enemy_inwater) + { + if(visible_pos(self, targ_org)) + { + if(ssithraWaterLedgeNearEnemy(self)) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Ssithra facing and namor\n"); +#endif + SetAnim(self,ANIM_FACEANDNAMOR); + } + } + } +} + +void ssithraWhichJump(edict_t *self) +{ + vec3_t Forward, movedir; + vec3_t targ_org; + + if(self->spawnflags & MSF_FIXED) + return; + + if(!MG_GetTargOrg(self, targ_org)) + return; + + if(ssithraCheckInWater(self)&&!(gi.pointcontents(targ_org)&CONTENTS_WATER)) + { + if(MGAI_DEBUG) + gi.dprintf("Ssithra_whichjump->namor\n"); + SetAnim(self,ANIM_NAMOR); + } + else + { + int inwater; + + inwater = ssithraCheckInWater(self); + + if(inwater) + return; + +// gi.dprintf("Bound\n"); + SetAnim(self,ANIM_BOUND); + VectorCopy(self->s.angles, movedir); + //VectorSet(movedir, 0, yaw, 0); + //movedir[YAW] = yaw; + AngleVectors(movedir,Forward,NULL,NULL); + VectorScale(Forward,SSITHRA_HOP_VELOCITY,self->velocity); + self->velocity[2]=SSITHRA_HOP_VELOCITY + 32; +// self->movetype=MOVETYPE_TOSS; + } +} + +void ssithraMsgJump(edict_t *self, G_Message_t *msg) +{ + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + ssithraWhichJump(self); +} + +void ssithraBoundCheck (edict_t *self) +{//fixme: do checks and traces first + vec3_t forward, up, startpos, endpos, mins, maxs; + trace_t trace; + int inwater; + + if(self->spawnflags & MSF_FIXED) + return; + + inwater = ssithraCheckInWater(self); + + if(inwater) + { + if(self->curAnimID!=ANIM_SWIMFORWARD) + SetAnim(self,ANIM_SWIMFORWARD); + return; + } + + AngleVectors(self->s.angles,forward,NULL,up); + VectorCopy(self->s.origin,startpos); + + VectorMA(startpos,48,forward,endpos);//forward + gi.trace(startpos,self->mins,self->maxs,endpos,self,MASK_SOLID,&trace); + + VectorCopy(trace.endpos,startpos); + VectorMA(startpos,-128,up,endpos);//down + gi.trace(startpos,self->mins,self->maxs,endpos,self,MASK_SOLID|MASK_WATER,&trace); + + //If it's a step down or less, no jumpie + if(Q_fabs(trace.endpos[2] - self->s.origin[2]) <= 18) + return; + + if(trace.fraction == 1.0 || trace.allsolid || trace.startsolid) + return;//too far to jump down, or in solid + + if(trace.contents&CONTENTS_WATER||trace.contents&CONTENTS_SLIME) + { + VectorCopy(trace.endpos,startpos); + VectorMA(startpos,-64,up,endpos);//down from water surf + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + mins[2] = 0; + maxs[2] = 1; + + gi.trace(startpos, mins, maxs, endpos, self, MASK_SOLID,&trace); + if(trace.fraction<1.0 || trace.allsolid || trace.startsolid) + ssithraWhichJump(self); + else + SetAnim(self,ANIM_DIVE); + } + else + SetAnim(self,ANIM_GALLOP); + //ssithraJump(self,100,50,0); +} + +void ssithraDiveCheck (edict_t *self) +{//fixme: do checks and traces first + vec3_t forward, up, startpos, endpos, mins, maxs; + trace_t trace; + int inwater; + vec3_t targ_org, targ_mins; + + if(self->spawnflags & MSF_FIXED) + return; + + if (self->monsterinfo.searchType == SEARCH_BUOY) + { + if(self->buoy_index < 0 || self->buoy_index > level.active_buoys) + return; + + VectorCopy(level.buoy_list[self->buoy_index].origin, targ_org); + + VectorClear(targ_mins); + } + else + { + if(!self->goalentity) + return; + + VectorCopy(self->goalentity->s.origin, targ_org); + VectorCopy(self->goalentity->mins, targ_mins); + } + + inwater = ssithraCheckInWater(self); + + if(inwater) + { + SetAnim(self,ANIM_SWIMFORWARD); + return; + } + + if(!infront_pos(self, targ_org)) + return; + + //make sure the enemy isn't right here and accessible before diving in + if(vhlen(targ_org,self->s.origin)<96)//close + if(Q_fabs((targ_org[2]+targ_mins[2]) - (self->s.origin[2] + self->mins[2]))<18)//relatively same stephieght + if(!(gi.pointcontents(targ_org)&CONTENTS_WATER)) + if(!(self->monsterinfo.aiflags & AI_FLEE)) + return; + + AngleVectors(self->s.angles,forward,NULL,up); + VectorCopy(self->s.origin,startpos); + + VectorMA(startpos,48,forward,endpos);//forward + gi.trace(startpos,self->mins,self->maxs,endpos,self,MASK_SOLID,&trace); + + VectorCopy(trace.endpos,startpos); + VectorMA(startpos,-128,up,endpos);//down + gi.trace(startpos,self->mins,self->maxs,endpos,self,MASK_SOLID|MASK_WATER,&trace); + + if(trace.fraction == 1||trace.allsolid||trace.startsolid) + return;//too far to jump down, or in solid + + if(trace.contents&CONTENTS_WATER||trace.contents&CONTENTS_SLIME) + { + VectorCopy(trace.endpos, startpos); + VectorMA(startpos, -64, up, endpos);//down from water surf + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + mins[2] = 0; + maxs[2] = 1; + + gi.trace(startpos, mins, maxs, endpos, self, MASK_SOLID,&trace); + + if(trace.fraction<1.0 || trace.allsolid || trace.startsolid) + ssithraWhichJump(self); + else + SetAnim(self, ANIM_DIVE); + } +} + +void ssithraApplyJump (edict_t *self) +{ + if(self->spawnflags & MSF_FIXED) + return; + + self->jump_time = level.time + 1; + VectorCopy(self->movedir, self->velocity); + VectorNormalize(self->movedir); +} + +void ssithraJump (edict_t *self, float upspd,float fwdspd,float rtspd) +{//fixme: do checks and traces first + vec3_t up, forward, right; + + if(self->spawnflags & MSF_FIXED) + return; + + if((self->s.fmnodeinfo[MESH__LEFTLEG].flags & FMNI_NO_DRAW)|| + (self->s.fmnodeinfo[MESH__RIGHTLEG].flags & FMNI_NO_DRAW)) + { + upspd*=2; + fwdspd/=2; + } + + AngleVectors(self->s.angles,forward,right,up); + VectorMA(self->velocity,upspd,up,self->velocity); + VectorMA(self->velocity,fwdspd,forward,self->velocity); + VectorMA(self->velocity,rtspd,right,self->velocity); +} + +void ssithraNamorJump (edict_t *self) +{ + trace_t trace; + vec3_t top; + float watersurfdist, enemyzdiff; + vec3_t targ_org; + + if(self->spawnflags & MSF_FIXED) + return; + + if(!MG_GetTargOrg(self, targ_org)) + return; + + if(MGAI_DEBUG) + gi.dprintf("Namor Jump\n"); + + //FIXME: jumps too high sometimes? + self->count = false; + VectorCopy(self->s.origin,top); + top[2]+=512; + gi.trace(self->s.origin, vec3_origin, vec3_origin, top, self, MASK_SOLID, &trace); + VectorCopy(trace.endpos,top); + gi.trace(top, vec3_origin, vec3_origin, self->s.origin, self, MASK_SOLID|MASK_WATER, &trace); + + //How far above my feet is waterlevel? + VectorSubtract(trace.endpos, self->s.origin, top); + watersurfdist = VectorLength(top) - self->mins[2];//adjust for my feet + + //how high above water level is player? + enemyzdiff = targ_org[2] - trace.endpos[2]; + + //FIXME: aim a little to side if enemy close so don't + //land on top of him? Or hit him if land on top? + ssithraJump(self,watersurfdist*2 + enemyzdiff*2 + 200, 100, 0); +} + + + +void ssithraCheckJump (edict_t *self) +{ + vec3_t vf, source, source2; + vec3_t maxs, mins, save_org; + trace_t trace; + float hgt_diff, jump_fdist; + qboolean jump_up_check = false; + qboolean check_down = false; + qboolean can_move = false; + vec3_t targ_org, targ_mins; + + if(self->spawnflags & MSF_FIXED) + return; + + if (self->monsterinfo.searchType == SEARCH_BUOY) + { + if(self->buoy_index < 0 || self->buoy_index > level.active_buoys) + return; + + VectorCopy(level.buoy_list[self->buoy_index].origin, targ_org); + + VectorClear(targ_mins); + } + else + { + if(!self->goalentity) + return; + + VectorCopy(self->goalentity->s.origin, targ_org); + VectorCopy(self->goalentity->mins, targ_mins); + } + + if (!(infront_pos(self, targ_org))) + return; + + if (targ_org[2] < self->s.origin[2] - 28) + { + check_down = true; + } + else + { + check_down = false; + } + + if (check_down) + {//jumping down + //Setup the trace + int inwater; + + inwater = ssithraCheckInWater(self); + + if(MGAI_DEBUG) + gi.dprintf("checking jump down: "); + + if(inwater) + { + if(MGAI_DEBUG) + gi.dprintf("checkdown allsolid\n"); + return; + } + + VectorCopy(self->maxs, maxs); + VectorCopy(self->s.origin, source); + AngleVectors(self->s.angles, vf, NULL, NULL); + + if(self->monsterinfo.aiflags&AI_FLEE||self->monsterinfo.aiflags&AI_COWARD) + jump_fdist = 128; + else + jump_fdist = vhlen(targ_org, self->s.origin); + + if(jump_fdist > 128) + jump_fdist = 128; + + VectorMA(source, 128, vf, source); + + maxs[2] += 32; + gi.trace (self->s.origin, self->mins, maxs, source, self, MASK_MONSTERSOLID,&trace); + + if (trace.fraction == 1) + {//clear ahead and above + VectorCopy(source, source2); + + source2[2] -= 1024; + //trace down + gi.trace (source, self->mins, self->maxs, source2, self, MASK_ALL,&trace); + + if (trace.allsolid || trace.startsolid) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("checkdown allsolid\n"); +#endif + return; + } + + if (trace.fraction == 1) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("checkdown- too far\n"); +#endif + return; + } + else + { +// if (trace.ent == (struct edict_s *)-1) +// return; + + if (trace.contents != CONTENTS_SOLID) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("checkjump trying to jump into water\n"); +#endif + if ((trace.contents&CONTENTS_WATER||trace.contents&CONTENTS_SLIME)||trace.ent == self->enemy) + {//jumping into water + VectorSubtract(trace.endpos, self->s.origin, source2); + VectorNormalize(source2); + self->ideal_yaw = vectoyaw(source2); + + if (self->monsterinfo.jump_time < level.time) + {//check depth + VectorCopy(trace.endpos, source); + VectorCopy(source, source2); + source2[2] -= 64; + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + mins[2] = 0; + maxs[2] = 1; + + gi.trace (source, mins, maxs, source2, self, MASK_SOLID,&trace); + if(trace.fraction < 1.0 || trace.startsolid || trace.allsolid) + ssithraWhichJump(self); + else + SetAnim(self,ANIM_DIVE); + self->monsterinfo.jump_time = level.time + 1; + } + } + } + else + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("checkjump down->whichjump\n"); +#endif + VectorSubtract(trace.endpos, self->s.origin, source2); + VectorNormalize(source2); + self->ideal_yaw = vectoyaw(source2); + + if (self->monsterinfo.jump_time < level.time) + { + ssithraWhichJump(self); + self->monsterinfo.jump_time = level.time + 1; + } + } + } + } +#ifdef _DEVEL + else if(MGAI_DEBUG) + gi.dprintf("checkdown: not clear infront\n"); +#endif + } + else + { + if(vhlen(self->s.origin, targ_org)<200) + jump_up_check = true; + else + { + VectorCopy(self->s.origin,source); + source[2]-=10; + if(gi.pointcontents(source)&CONTENTS_WATER) + {//FIXME: swimming can bring origin out of water! in water + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(self->s.origin, 72, vf, source); + gi.trace (self->s.origin, self->mins, self->maxs, source, self, MASK_SOLID,&trace); + if(trace.fraction<1.0) + jump_up_check = true; + //shore is within 72 units of me + } + else//enemy far away, in front, and water in front of me + {//check if water in front + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(self->s.origin, 48, vf, source); + gi.trace (self->s.origin, self->mins, self->maxs, source, self, MASK_SOLID,&trace); + VectorCopy(trace.endpos,source); + source[2]-=128; + gi.trace (trace.endpos, self->mins, self->maxs, source, self, MASK_SOLID|MASK_WATER,&trace); + if(trace.fraction<1.0&&trace.contents&CONTENTS_WATER) + { + VectorCopy(trace.endpos, source); + VectorCopy(source, source2); + source[2] -= 64; + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + mins[2] = 0; + maxs[2] = 1; + + gi.trace(source, mins, maxs, source2, self, MASK_SOLID,&trace); + if(trace.fraction<1.0 || trace.allsolid || trace.startsolid) + ssithraWhichJump(self); + else + SetAnim(self,ANIM_DIVE); + + return; + } + } + } + + if(jump_up_check) + { + if(targ_org[2] > self->s.origin[2]+28|| + !(self->monsterinfo.aiflags & AI_FLEE))//||override_dist) + {//jumping up + //Setup the trace +// gi.dprintf("checking for jump up or into water\n"); + VectorCopy(self->maxs, maxs); + VectorCopy(self->s.origin, source); + + //um,. what about if runing away? + hgt_diff = (targ_org[2] + targ_mins[2]) - (self->s.origin[2] + self->mins[2]) + 32; + source[2] += hgt_diff; + gi.trace (self->s.origin, self->mins, self->maxs, source, self, MASK_ALL,&trace); + + if (trace.fraction == 1) + {//clear above + VectorCopy(source, source2); + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(source, 64, vf, source2); + source2[2] -= 24; + //trace forward and down a little + gi.trace (source, self->mins, self->maxs, source2, self, MASK_ALL,&trace); + + if (trace.allsolid || trace.startsolid) + return; + + if (trace.fraction < 0.1) + { +// gi.dprintf("Can't jump up, no ledge\n"); + return; + } + // { + // if (stricmp(trace.ent->classname, "worldspawn")) + // return; + // } + else + { + if (trace.ent == (struct edict_s *)-1) + return; + + // if (trace.contents != CONTENTS_SOLID) + // return; + // else + { + VectorSubtract(trace.endpos, self->s.origin, source2); + VectorNormalize(source2); + self->ideal_yaw = vectoyaw(source2); + + if (self->monsterinfo.jump_time < level.time) + { +// gi.dprintf("checkjump up ->whichjump\n"); + ssithraWhichJump(self); + self->monsterinfo.jump_time = level.time + 1; + } + } + } + } + } + else + {//check to jump over something + VectorCopy(self->s.origin, save_org); + can_move = M_walkmove (self, self->s.angles[YAW], 64); + VectorCopy(save_org, self->s.origin); + + if(can_move) + return; + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorCopy(self->s.origin, source); + VectorMA(source, 128, vf, source2); + VectorCopy(self->mins, mins); + mins[2]+=24;//can clear it + gi.trace(source, mins, self->maxs, source2, self, MASK_SOLID,&trace); + + if(trace.allsolid||trace.startsolid) + return; + + if(trace.fraction<1 && trace.ent != self->enemy) + return; + + //Go for it! + ssithraJump(self, 128, 200*trace.fraction, 0); + SetAnim(self, ANIM_BOUND); + } + + } + } +} + +void ssithraForward (edict_t *self, float forwarddist) +{//simple addition of velocity, if on ground or not +vec3_t forward; + + ssithraCheckInWater(self); + + if(self->groundentity)//on ground + { + VectorClear(self->velocity); + return; + } + + AngleVectors(self->s.angles,forward,NULL,NULL); + VectorScale(forward,forwarddist,forward); + forward[2] = self->velocity[2]; + VectorCopy(forward,self->velocity); +} + +void ssithraCheckLeaveWaterSplash (edict_t *self) +{ + vec3_t dir, endpos; + trace_t trace; + + if(self->count) + return; + + VectorCopy(self->s.origin,endpos); + endpos[2]+=12; + if(!ssithraCheckInWater(self)) + { + VectorCopy(self->velocity,dir); + VectorNormalize(dir); + VectorMA(self->s.origin,-256,dir,endpos); + gi.trace(self->s.origin,vec3_origin,vec3_origin,endpos,self,MASK_WATER,&trace); + if(trace.fraction>=1.0) + return;//?! +// gi.dprintf("Out water splash\n"); + gi.sound(self,CHAN_BODY,Sounds[SND_NAMOR],1,ATTN_NORM,0); + dir[0]=dir[1]=0; + dir[2]=300; + // FIXME: Size propn. to exit velocity. + gi.CreateEffect(NULL, FX_WATER_ENTRYSPLASH, 0, + trace.endpos, "bd", 128|96, dir); + self->count= true; + } +} + +void ssithraCheckHitWaterSplash (edict_t *self) +{ + vec3_t dir, endpos; + trace_t trace; + + if(self->count) + return; + + if(Q_fabs(self->velocity[0])+Q_fabs(self->velocity[1])<200) + { + VectorCopy(self->s.origin, endpos); + endpos[2] -= 128; + gi.trace(self->s.origin,self->mins,self->maxs,endpos,self,MASK_ALL,&trace); + if(trace.fraction<1&& + !trace.allsolid&& + !trace.startsolid&& + !(trace.contents & CONTENTS_WATER)&& + !(trace.contents & CONTENTS_SLIME)) + { + //not going to hit water! + SetAnim(self, ANIM_BOUND); + return; + } + } + + if(self->flags&FL_INWATER) + { + VectorCopy(self->velocity,dir); + VectorNormalize(dir); + VectorMA(self->s.origin,-256,dir,endpos); + gi.trace(self->s.origin,vec3_origin,vec3_origin,endpos,self,MASK_WATER,&trace); + gi.trace(trace.endpos,vec3_origin,vec3_origin,self->s.origin,self,MASK_WATER,&trace); + if(trace.fraction>=1.0) + return;//?! +// gi.dprintf("In water splash\n"); + gi.sound(self,CHAN_BODY,Sounds[SND_INWATER],1,ATTN_NORM,0); + gi.sound (self, CHAN_BODY, gi.soundindex("player/Water Enter.wav"), 1, ATTN_NORM, 0); + VectorCopy(self->velocity,dir); + dir[0]=dir[1]=0; + VectorNormalize(dir); + // FIXME: Size propn. to entry velocity. + gi.CreateEffect(NULL, FX_WATER_ENTRYSPLASH, 0, + trace.endpos, "bd", 128|96, dir); + self->count= true; + } +} + +void ssithraCheckFacedNamor (edict_t *self) +{ + if(self->spawnflags & MSF_FIXED) + return; + + if(Q_fabs(self->ideal_yaw - self->s.angles[YAW])yaw_speed) + SetAnim(self,ANIM_NAMOR); +} + +//======================================== +//PAINS +//======================================== + +void ssithraSlideFall (edict_t *self) +{ + if(self->mins[2]<0) + { +// if(Vec3IsZero(self->velocity)) +// self->groundentity = NULL; + if(self->mins[2]<=-6) + self->mins[2]+=6; + else + self->mins[2]=0; +// gi.dprintf("ssithra top's mins: %f\n",self->mins[2]); + self->think = ssithraSlideFall; + self->nextthink = level.time + FRAMETIME; + } + else + { + self->friction = 1; + self->owner->msgHandler=DefaultMsgHandler; + self->owner->nextthink = level.time; + SetAnim(self->owner,ANIM_SLICED); + self->owner->msgHandler=DyingMsgHandler; + self->think = NULL; + self->nextthink = -1; + } +} + +void ssithraSlideOff (edict_t *self) +{ + vec3_t right; + + AngleVectors(self->s.angles,NULL,right,NULL); + VectorScale(right,100,self->velocity); + self->think = ssithraSlideFall; + self->nextthink = level.time + FRAMETIME; +} + +void ssithraSplit (edict_t *self, int BodyPart) +{//blood stripe + vec3_t p1, p2, dir, up, right; + edict_t *tophalf; + int whichnode, node_num; + + AngleVectors(self->s.angles, NULL, right, up); + VectorClear(p1); + VectorMA(p1,6,up,p1); + VectorMA(p1,10,right,p1); + VectorClear(p2); + VectorMA(p2,-6,up,p2); + VectorMA(p2,-10,right,p2); + VectorSubtract(p2,p1,dir); + VectorNormalize(dir); + VectorScale(dir, 40.0, dir); + + //Why doesn't this work? + gi.CreateEffect(&self->s, FX_BLOOD, 0, p1, "ub", dir, 20); + VectorAdd(self->s.origin,p2,p2); + SprayDebris(self,p2, 6,200); + +// gi.dprintf("sliding in half- making top\n"); + + tophalf = G_Spawn(); + + tophalf->nextthink = level.time + FRAMETIME*10; + tophalf->think = ssithraSlideOff; + tophalf->svflags |= SVF_MONSTER; + tophalf->s.renderfx |= RF_FRAMELERP; + tophalf->takedamage = DAMAGE_AIM; + tophalf->max_health = tophalf->health = 25; + tophalf->clipmask = MASK_MONSTERSOLID; + tophalf->s.effects |= EF_CAMERA_NO_CLIP; + + tophalf->s.skinnum = self->s.skinnum; + tophalf->deadflag = DEAD_DEAD; + tophalf->deadState = DEAD_DEAD; + tophalf->svflags |= SVF_DEADMONSTER; + tophalf->monsterinfo.thinkinc = MONSTER_THINK_INC;//FRAMETIME; + tophalf->monsterinfo.nextframeindex = -1; + tophalf->friction = 0.1; + + VectorCopy (self->s.origin, tophalf->s.origin); + VectorCopy (tophalf->s.origin, tophalf->s.old_origin); + VectorCopy (self->s.angles, tophalf->s.angles); + + if(!self->s.frame)//?!?! + tophalf->s.frame = FRAME_startle32; + else + tophalf->s.frame = self->s.frame; + + tophalf->materialtype = MAT_FLESH; + tophalf->mass = self->mass = 300; + + tophalf->movetype = PHYSICSTYPE_STEP; + + tophalf->solid=SOLID_BBOX; + tophalf->owner = self; + + VectorSet(tophalf->mins,-16,-16,self->mins[2]); + VectorSet(tophalf->maxs,16,16,16); + VectorSet(self->maxs,16,16,0); + tophalf->s.origin[2] += 10; + +//Fixm: sometimes top half appears too low and forward? + VectorClear(self->knockbackvel); + VectorClear(self->velocity); + + tophalf->s.modelindex = self->s.modelindex; + + tophalf->s.scale = tophalf->s.scale; + + tophalf->monsterinfo.otherenemyname = "obj_barrel"; + + for(whichnode = 1, node_num = 0; whichnode<=16384; whichnode*=2)//bitwise + { + node_num++; + if(!((int)(BodyPart)&(int)(whichnode))) + {//turn off this node on top + tophalf->s.fmnodeinfo[node_num].flags |= FMNI_NO_DRAW; + } + else + {//turn on this node on top and keep them + tophalf->s.fmnodeinfo[node_num] = self->s.fmnodeinfo[node_num];//copy skins and flags and colors + tophalf->s.fmnodeinfo[node_num].flags &= ~FMNI_NO_DRAW; + self->s.fmnodeinfo[node_num].flags |= FMNI_NO_DRAW; + } + } + tophalf->s.fmnodeinfo[MESH__CAPBOTTOMUPPERTORSO].flags &= ~FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__CAPLOWERTORSO].flags &= ~FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__RIGHT2SPIKE].flags |= FMNI_NO_DRAW; + + self->nextthink = 9999999999999999; +} + +/* +-1 hl_Null = -1, +0 hl_NoneSpecific = 0, +1 hl_Head, +2 hl_TorsoFront, +3 hl_TorsoBack, +4 hl_ArmUpperLeft, +5 hl_ArmLowerLeft, +6 hl_ArmUpperRight, +7 hl_ArmLowerRight, +8 hl_LegUpperLeft, +9 hl_LegLowerLeft, +10 hl_LegUpperRight, +11 hl_LegLowerRight, +12 hl_Max, +*/ +qboolean canthrownode (edict_t *self, int BP, int *throw_nodes) +{//see if it's on, if so, add it to throw_nodes + //turn it off on thrower + if(!(self->s.fmnodeinfo[BP].flags & FMNI_NO_DRAW)) + { + *throw_nodes |= Bit_for_MeshNode[BP]; + self->s.fmnodeinfo[BP].flags |= FMNI_NO_DRAW; + return true; + } + return false; +} + +int ssithra_convert_hitloc_dead(edict_t *self, int hl) +{ + qboolean fellback = false; + + if(self->curAnimID == ANIM_DEATH_A) + fellback = true; + + switch(hl) + { + case hl_Head: + if(fellback) + return hl_TorsoFront; + else + return hl_TorsoBack; + break; + + case hl_TorsoFront://split in half? + if(fellback) + { + if(!irand(0,1)) + return hl_LegUpperRight; + else + return hl_LegUpperLeft; + } + else + return hl_Head; + break; + + case hl_TorsoBack://split in half? + if(fellback) + return hl_Head; + else + { + if(!irand(0,1)) + return hl_LegUpperRight; + else + return hl_LegUpperLeft; + } + break; + + case hl_ArmUpperLeft: + return hl_ArmLowerLeft; + break; + + case hl_ArmLowerLeft://left arm + return hl_ArmUpperLeft; + break; + + case hl_ArmUpperRight: + return hl_ArmLowerRight; + break; + + case hl_ArmLowerRight://right arm + return hl_ArmUpperRight; + break; + + case hl_LegUpperLeft: + return hl_LegLowerLeft; + break; + + case hl_LegLowerLeft://left leg + return hl_LegUpperLeft; + break; + + case hl_LegUpperRight: + return hl_LegLowerRight; + break; + + case hl_LegLowerRight://right leg + return hl_LegUpperRight; + break; + + default: + return irand(hl_Head, hl_LegLowerRight); + break; + } + +} + +void ssithra_dismember(edict_t *self, int damage, int HitLocation) +{//fixme - make part fly dir the vector from hit loc to sever loc +//remember- turn on caps! + int throw_nodes = 0; + vec3_t gore_spot, right; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; + + if(self->health>0) + { + switch (self->curAnimID) + {//Hit front chest during shoot or melee, may have hit arms + case ANIM_DUCKSHOOT: + case ANIM_SHOOT: + case ANIM_WATER_SHOOT: + case ANIM_HEADLESS: + case ANIM_HEADLESSLOOP: + if(HitLocation == hl_TorsoFront&&irand(0,10)<4) + HitLocation = hl_ArmLowerRight; + break; + + case ANIM_MELEE: + case ANIM_MELEE_STAND: + if(HitLocation == hl_TorsoFront&&irand(0,10)<4) + HitLocation = hl_ArmLowerLeft; + break; + + default: + break; + } + + if((HitLocation == hl_ArmUpperLeft&& self->s.fmnodeinfo[MESH__LEFTARM].flags & FMNI_NO_DRAW) || + (HitLocation == hl_ArmUpperRight&& self->s.fmnodeinfo[MESH__RIGHTARM].flags & FMNI_NO_DRAW)|| + ((HitLocation == hl_TorsoFront|| HitLocation == hl_TorsoBack) && + self->s.fmnodeinfo[MESH__RIGHTARM].flags & FMNI_NO_DRAW && + self->s.fmnodeinfo[MESH__LEFTARM].flags & FMNI_NO_DRAW)&& + irand(0,10)<4) + HitLocation = hl_Head;//Decap + } + else + HitLocation = ssithra_convert_hitloc_dead(self, HitLocation); + + VectorClear(gore_spot); + switch(HitLocation) + { + case hl_Head: + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_NO_DRAW) + break; + // Is the pain skin engaged? + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.fmnodeinfo[MESH__CAPTOPUPPERTORSO].flags &= ~FMNI_NO_DRAW; + + gore_spot[2]+=18; + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + + VectorAdd(self->s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,8,damage); + + if(self->health > 0 && irand(0,10)<3&&!(self->s.fmnodeinfo[MESH__RIGHTARM].flags & FMNI_NO_DRAW)) + {//shooting blind, headless, FIX: make it so can still chop off arms or legs here + SetAnim(self,ANIM_HEADLESS); + self->msgHandler=DyingMsgHandler; + } + else + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, gore_spot, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { + // Set the pain skin + self->s.fmnodeinfo[MESH__HEAD].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__HEAD].skin = self->s.skinnum+1; + + if(flrand(0,self->health/4)s.fmnodeinfo[MESH__UPPERTORSO].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__UPPERTORSO].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.fmnodeinfo[MESH__CAPBOTTOMUPPERTORSO].flags &= ~FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__CAPLOWERTORSO].flags &= ~FMNI_NO_DRAW; + + canthrownode(self, MESH__UPPERTORSO,&throw_nodes); + canthrownode(self, MESH__CAPBOTTOMUPPERTORSO,&throw_nodes); + canthrownode(self, MESH__CAPTOPUPPERTORSO,&throw_nodes); + canthrownode(self, MESH__LEFTARM,&throw_nodes); + canthrownode(self, MESH__RIGHTARM,&throw_nodes); + canthrownode(self, MESH__HEAD,&throw_nodes); + canthrownode(self, MESH__CENTERSPIKE,&throw_nodes); + canthrownode(self, MESH__LEFT1SPIKE,&throw_nodes); + canthrownode(self, MESH__RIGHT1SPIKE,&throw_nodes); + canthrownode(self, MESH__RIGHT2SPIKE,&throw_nodes); + + if(self->health > 0 && irand(0,10)<3)//Slide off + ssithraSplit(self, throw_nodes); + else + { + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partrest1); + + VectorAdd(self->s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,12,damage); + SetAnim(self,ANIM_SLICED); + } + self->msgHandler=DyingMsgHandler; + } + else + { + // Set the pain skin + self->s.fmnodeinfo[MESH__UPPERTORSO].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__UPPERTORSO].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperLeft: + case hl_ArmLowerLeft://left arm + if(self->s.fmnodeinfo[MESH__LEFTARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__LEFTARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + } + else + { + // Set the pain skin + self->s.fmnodeinfo[MESH__LEFTARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LEFTARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperRight: + case hl_ArmLowerRight://right arm + if(self->s.fmnodeinfo[MESH__RIGHTARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__RIGHTARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + } + else + { + // Set the pain skin + self->s.fmnodeinfo[MESH__RIGHTARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RIGHTARM].skin = self->s.skinnum+1; + } + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft://left leg + if(self->health>0) + {//still alive + if(self->s.fmnodeinfo[MESH__LEFTLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__LEFTLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LEFTLEG].skin = self->s.skinnum+1; + break; + } + else + { + if(self->s.fmnodeinfo[MESH__LEFTLEG].flags & FMNI_NO_DRAW) + break; + if(canthrownode(self, MESH__LEFTLEG, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + case hl_LegUpperRight: + case hl_LegLowerRight://right leg + if(self->health>0) + {//still alive + if(self->s.fmnodeinfo[MESH__RIGHTLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__RIGHTLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RIGHTLEG].skin = self->s.skinnum+1; + break; + } + else + { + if(self->s.fmnodeinfo[MESH__RIGHTLEG].flags & FMNI_NO_DRAW) + break; + if(canthrownode(self, MESH__RIGHTLEG, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + default: + break; + } + + if(throw_nodes) + self->pain_debounce_time = 0; + + if(self->s.fmnodeinfo[MESH__LEFTARM].flags&FMNI_NO_DRAW&& + self->s.fmnodeinfo[MESH__RIGHTARM].flags&FMNI_NO_DRAW) + { + self->monsterinfo.aiflags |= AI_COWARD; + self->ai_mood_flags &= ~AI_MOOD_FLAG_BACKSTAB; + self->spawnflags &= ~MSF_FIXED; + } + else + { + if(self->s.fmnodeinfo[MESH__LEFTARM].flags&FMNI_NO_DRAW) + { + self->monsterinfo.aiflags |= AI_NO_MELEE; + self->ai_mood_flags &= ~AI_MOOD_FLAG_BACKSTAB; + } + if(self->s.fmnodeinfo[MESH__RIGHTARM].flags&FMNI_NO_DRAW) + { + self->monsterinfo.aiflags |= AI_NO_MISSILE; + self->ai_mood_flags &= ~AI_MOOD_FLAG_BACKSTAB; + self->spawnflags &= ~MSF_FIXED; + } + } +} + +void ssithra_dead_pain (edict_t *self, G_Message_t *msg) +{ + if(msg) + if(!(self->svflags & SVF_PARTS_GIBBED)) + MG_parse_dismember_msg(self, msg); +} + +void ssithra_pain(edict_t *self, G_Message_t *msg) +{//fixme - make part fly dir the vector from hit loc to sever loc + int inwater; + int temp, damage; + qboolean force_pain; + + + if(self->deadflag == DEAD_DEAD) //Dead but still being hit + return; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_pain, &damage, &temp); + + if(!force_pain) + { + if(self->pain_debounce_time) + if(irand(0,10)<5||!self->groundentity) + return; + + if(self->pain_debounce_time > level.time) + return; + } + + ssithraUnCrouch(self); + + self->pain_debounce_time = level.time + 2; + + if(irand(0,10)<5) + gi.sound (self, CHAN_VOICE, Sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_VOICE, Sounds[SND_PAIN2], 1, ATTN_NORM, 0); + + + inwater = ssithraCheckInWater(self); + + if(inwater) + {//underwater pain sound? + if(self->curAnimID!=ANIM_SWIMFORWARD) + SetAnim(self, ANIM_WATER_PAIN_A); + else//swimming + SetAnim(self, ANIM_WATER_PAIN_B); + } + else + { + SetAnim(self, ANIM_PAIN_A); + } +} + +void ssithra_pain_react (edict_t *self) +{ + if(!self->enemy) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("No react to pain\n"); +#endif + ssithra_decide_stand(self); + return; + } + + if(self->enemy->health<=0||self->enemy == self||!self->enemy->takedamage) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("No react to pain\n"); +#endif + self->enemy=NULL; + ssithra_decide_stand(self); + return; + } + //go get him! +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("pain_react -> run\n"); +#endif + ssithra_decide_gallop(self); +} + +//=========================================== +//DEATHS +//=========================================== + +void ssithra_death(edict_t *self, G_Message_t *msg) +{//FIXME: still cut off limbs as dying? + int inwater; + + if(self->monsterinfo.aiflags&AI_DONT_THINK) + { + gi.sound(self,CHAN_BODY,Sounds[SND_DIE],1,ATTN_NORM,0); + if (irand(0,10) < 5) + SetAnim(self, ANIM_DEATH_B); + else + SetAnim(self, ANIM_DEATH_A); + return; + } + self->msgHandler=DyingMsgHandler; + + if(self->deadflag == DEAD_DEAD) //Dead but still being hit + { +// gi.dprintf("already dead!\n"); + return; + } + + self->deadflag = DEAD_DEAD; + + if(self->health <= -80) //gib death + { + int i, num_limbs; + + num_limbs = irand(1, 3); + for(i = 0; i < num_limbs; i++) + ssithra_dismember(self, flrand(80, 160), irand(hl_Head, hl_LegLowerRight) | hl_MeleeHit); + + gi.sound(self,CHAN_BODY,Sounds[SND_GIB],1,ATTN_NORM,0); + self->think = BecomeDebris; + self->nextthink = level.time + 0.1; + return; + } + + ssithraUnCrouch(self); + inwater = ssithraCheckInWater(self); + + if(inwater) + { + SetAnim(self, ANIM_WATER_DEATH); + } + else + { + if (self->health == -69) + {//maybe allow dead bodies to be chopped? Make BBOX small? + self->deadState = DEAD_DEAD; + + gi.linkentity(self); + + self->flags |= FL_DONTANIMATE; + + self->msgHandler = DeadMsgHandler; + + self->svflags |= SVF_DEADMONSTER; // now treat as a different content type + + SetAnim(self, ANIM_DEAD_B); + } + else if (self->health == -33) + SetAnim(self, ANIM_DEATH_C); + else if (irand(0,10) < 4 || self->health > -10)//barely dead + SetAnim(self, ANIM_DEATH_B); + else + SetAnim(self, ANIM_DEATH_A); + } +} + +void ssithra_dead(edict_t *self) +{//maybe allow dead bodies to be chopped? Make BBOX small? + self->msgHandler = DeadMsgHandler; + self->svflags |= SVF_DEADMONSTER; // now treat as a different content type + self->deadState = DEAD_DEAD; + + self->flags |= FL_DONTANIMATE; + + M_EndDeath(self); +} + +float hold_z; +void fish_deadfloat(edict_t *self); +void ssithraWaterDead(edict_t *self) +{ + self->deadflag = DEAD_DEAD; + self->takedamage = DAMAGE_YES; + + self->think = fish_deadfloat; + self->nextthink = level.time + 0.1; + + gi.linkentity (self); +} + +void ssithraCollapse (edict_t *self) +{ + vec3_t gore_spot; + + if(irand(0,10)<5) + { + self->msgHandler = DefaultMsgHandler; + SetAnim(self,ANIM_HEADLESSLOOP); + self->msgHandler = DyingMsgHandler; + return; + } + else + { + self->svflags &= ~SVF_DEADMONSTER; // now treat as a different content type + self->msgHandler = DefaultMsgHandler; + VectorCopy(self->s.origin,gore_spot); + gore_spot[2]+=self->maxs[2]*0.75; + self->health = 1; + T_Damage (self, self, self, vec3_origin, gore_spot, vec3_origin, 10, 20,0,MOD_DIED); + self->health = -33; + } +} + +void ssithraKillSelf (edict_t *self) +{ + vec3_t gore_spot; + + self->svflags &= ~SVF_DEADMONSTER; // now treat as a different content type + self->msgHandler = DefaultMsgHandler; + self->deadflag = false; + VectorCopy(self->s.origin,gore_spot); + gore_spot[2]+=12; + self->health = 1; + T_Damage (self, self, self, vec3_origin, gore_spot, vec3_origin, 10, 20,0,MOD_DIED); + self->health = -69; +} + +//=========================================== +//SOUNDS +//=========================================== + +void ssithraSound(edict_t *self, float soundnum, float channel, float attenuation) +{ + if(!channel) + channel = CHAN_AUTO; + + if(!attenuation) + attenuation = ATTN_NORM; + else if(attenuation == -1) + attenuation = ATTN_NONE; + + if(soundnum == SND_SWIM) + if(irand(0,10)<5) + soundnum = SND_SWIM2; + + gi.sound(self,channel,Sounds[(int)(soundnum)],1,attenuation,0); +} + +void ssithraGrowlSound(edict_t *self) +{ + if(!irand(0, 3)) + gi.sound(self,CHAN_VOICE,Sounds[irand(SND_GROWL1, SND_GROWL3)],1,ATTN_IDLE,0); +} +//=========================================== +//ATTACKS + //=========================================== + +void ssithra_melee(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + if(ssithraCheckInWater(self)) + { + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + return; + } + + if(!(self->monsterinfo.aiflags & AI_NO_MISSILE) && !(self->spawnflags&MSF_FIXED)) + { + if(vhlen(self->enemy->s.origin, self->s.origin) - 16 < flrand(0, self->melee_range)) + { + SetAnim(self, ANIM_BACKPEDAL); + return; + } + } + + if(M_DistanceToTarget(self, self->enemy) > self->melee_range*2 &&!(self->spawnflags&MSF_FIXED)) + SetAnim(self, ANIM_MELEE); + else + SetAnim(self, ANIM_MELEE_STAND); + } + else + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void ssithra_missile(edict_t *self, G_Message_t *msg) +{ + int chance; + + if (M_ValidTarget(self, self->enemy)) + { + if (ssithraCheckInWater(self)) + { + if(M_DistanceToTarget(self, self->enemy) < self->melee_range) + { + if(self->curAnimID == ANIM_SWIMFORWARD) + SetAnim(self, ANIM_TRANSUP); + else + SetAnim(self, ANIM_WATER_SHOOT); + } + else + ssithraArrow(self); + } + else + { + if(self->spawnflags & MSF_SSITHRA_CLOTHED) + chance = 20; + else + chance = 80; + + if (irand(0, skill->value * 100) > chance) + SetAnim(self, ANIM_DUCKSHOOT); + else + SetAnim(self, ANIM_SHOOT); + } + } + else + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } +} + +void ssithra_backup(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + if(self->spawnflags&MSF_FIXED) + { + SetAnim(self, ANIM_DELAY); + return; + } + + if (ssithraCheckInWater(self)) + { + SetAnim(self, ANIM_WATER_SHOOT); + } + else + { + SetAnim(self, ANIM_BACKPEDAL); + } + } + else + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } +} + +void ssithraSwipe (edict_t *self) +{//use melee swipe functoin in g_monster + trace_t trace; + edict_t *victim; + vec3_t soff, eoff, mins, maxs, bloodDir, direction; + + VectorSet(soff, 16, -16, 24); + VectorSet(eoff, 50, 0, -8); + + VectorSet(mins, -2, -2, -2); + VectorSet(maxs, 2, 2, 2); + + VectorSubtract(soff, eoff, bloodDir); + VectorNormalize(bloodDir); + + victim = M_CheckMeleeLineHit(self, soff, eoff, mins, maxs, &trace, direction); + + if (victim) + { + if (victim == self) + { + //Create a puff effect + //gi.CreateEffect(NULL, FX_SPARKS, 0, hitPos, "db", vec3_origin, irand(1,3)); + } + else + { + //Hurt whatever we were whacking away at + gi.sound (self, CHAN_WEAPON, Sounds[SND_SWIPEHIT], 1, ATTN_NORM, 0); + if(self->spawnflags&MSF_SSITHRA_ALPHA) + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, irand(SSITHRA_DMG_MIN*1.2, SSITHRA_DMG_MAX*1.2), 10, 0,MOD_DIED); + else + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, irand(SSITHRA_DMG_MIN, SSITHRA_DMG_MAX), 0, 0,MOD_DIED); + } + } + else + { + //Play swoosh sound? + } +} + +// the arrow needs to bounce +void make_arrow_reflect(edict_t *self, edict_t *Arrow) +{ + create_ssith_arrow(Arrow); + Arrow->s.modelindex = self->s.modelindex; + VectorCopy(self->s.origin, Arrow->s.origin); + Arrow->owner = self->owner; + Arrow->enemy = self->enemy; + + Arrow->touch=self->touch; + Arrow->nextthink=self->nextthink; + Arrow->think=G_FreeEdict; + Arrow->health = self->health; + + Create_rand_relect_vect(self->velocity, Arrow->velocity); + + vectoangles(Arrow->velocity, Arrow->s.angles); + Arrow->s.angles[YAW]+=90; + + Vec3ScaleAssign(SSITHRA_SPOO_SPEED/2,Arrow->velocity); + + G_LinkMissile(Arrow); +} + +void ssithraAlphaArrowTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + float damage; + vec3_t normal; + edict_t *Arrow; + + // are we reflecting ? + if(EntReflecting(other, true, true)) + { + Arrow = G_Spawn(); + + make_arrow_reflect(self,Arrow); + + gi.CreateEffect(&Arrow->s, + FX_SSITHRA_ARROW, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + FX_SS_MAKE_ARROW2, + Arrow->velocity); + + G_SetToFree(self); + + return; + } + + + VectorSet(normal, 0, 0, 1); + if(plane) + { + if(plane->normal) + { + VectorCopy(plane->normal, normal); + } + } + + if(other->takedamage) + { + damage = flrand(SSITHRA_DMG_MIN,SSITHRA_DMG_MAX); + T_Damage(other,self,self->owner,self->movedir,self->s.origin,normal,damage,0,0,MOD_DIED); + } + else + damage = 0; + + T_DamageRadius(self, self->owner, self->owner, SSITHRA_DMG_ARROW_RADIUS, + (20 - damage*2), (30 - damage), DAMAGE_ATTACKER_IMMUNE,MOD_DIED); + + VectorNormalize(self->velocity); + + gi.CreateEffect(NULL, + FX_SSITHRA_ARROW, + 0, + self->s.origin, + "bv", + FX_SS_EXPLODE_ARROW2, + self->velocity); + + VectorClear(self->velocity); + + G_FreeEdict(self); +} + +void ssithraArrowTouch (edict_t *self,edict_t *Other,cplane_t *Plane,csurface_t *Surface) +{ + float damage; + vec3_t normal; + edict_t *Arrow; + + if(Surface&&(Surface->flags&SURF_SKY)) + { + SkyFly(self); + return; + } + + if(EntReflecting(Other, true, true)) + { + Arrow = G_Spawn(); + + make_arrow_reflect(self,Arrow); + + gi.CreateEffect( NULL, + FX_M_EFFECTS, + CEF_FLAG6, + self->s.origin, + "bv", + FX_MSSITHRA_EXPLODE, + self->movedir); + /* + gi.CreateEffect(&Arrow->s, + FX_SSITHRA_ARROW, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + FX_SS_MAKE_ARROW, + Arrow->velocity); + */ + + G_SetToFree(self); + + return; + } + + if(Other->takedamage) + { + VectorSet(normal, 0, 0, 1); + if(Plane) + { + if(Plane->normal) + { + VectorCopy(Plane->normal, normal); + } + } + damage = flrand(SSITHRA_DMG_MIN,SSITHRA_DMG_MAX); + T_Damage(Other,self,self->owner,self->movedir,self->s.origin,normal,damage,0,0,MOD_DIED); + } + + VectorNormalize(self->velocity); + + gi.CreateEffect( NULL, + FX_M_EFFECTS, + CEF_FLAG6, + self->s.origin, + "bv", + FX_MSSITHRA_EXPLODE, + self->movedir); + + /* + gi.CreateEffect(NULL, + FX_SSITHRA_ARROW, + 0, + self->s.origin, + "bv", + FX_SS_EXPLODE_ARROW, + self->velocity); + */ + + VectorClear(self->velocity); + + G_FreeEdict(self); +} + +void ssithraArrowExplode(edict_t *self) +{ + int damage = irand(SSITHRA_BIGARROW_DMG_MIN, SSITHRA_BIGARROW_DMG_MAX); + + //TODO: Spawn an explosion effect + gi.CreateEffect( NULL, + FX_M_EFFECTS, + 0, + self->s.origin, + "bv", + FX_MSSITHRA_EXPLODE, + self->movedir); + + T_DamageRadius(self, self->owner, self->owner, 64, damage, damage/2, DAMAGE_ATTACKER_IMMUNE, MOD_DIED); + + G_FreeEdict(self); +} + +void ssithraDuckArrowTouch (edict_t *self,edict_t *other,cplane_t *plane,csurface_t *surface) +{ + if(surface&&(surface->flags&SURF_SKY)) + { + SkyFly(self); + return; + } + + //NOTENOTE: NO REFLECTION FOR THIS MISSILE! + + if(other->takedamage) + { + if (plane->normal) + VectorCopy(plane->normal, self->movedir); + + self->dmg = irand(SSITHRA_DMG_MIN*2, SSITHRA_DMG_MAX*2); + ssithraArrowExplode(self); + } + else + { + VectorClear(self->velocity); + + self->s.effects |= EF_MARCUS_FLAG1; + + if (plane->normal) + VectorCopy(plane->normal, self->movedir); + + self->dmg = irand(SSITHRA_DMG_MIN, SSITHRA_DMG_MAX); + + self->think = ssithraArrowExplode; + self->nextthink = level.time + flrand(0.5, 1.5); + } +} + +void create_ssith_arrow(edict_t *Arrow) +{ + Arrow->movetype = MOVETYPE_FLYMISSILE; + Arrow->solid = SOLID_BBOX; + Arrow->classname = "Ssithra_Arrow"; + Arrow->touch = ssithraArrowTouch; + Arrow->enemy = NULL; + Arrow->clipmask = MASK_SHOT; + Arrow->s.scale = 0.75; + Arrow->s.effects |= EF_CAMERA_NO_CLIP; + Arrow->svflags |= SVF_ALWAYS_SEND; + Arrow->s.modelindex = gi.modelindex("models/objects/exarrow/tris.fm"); +} + +void ssithraDoArrow(edict_t *self, float z_offs) +{ + vec3_t Forward,check_lead, right, enemy_dir; + edict_t *Arrow; + + if(self->s.fmnodeinfo[MESH__RIGHTARM].flags&FMNI_NO_DRAW) + return; + + gi.sound(self,CHAN_WEAPON,Sounds[SND_ARROW1],1,ATTN_NORM,0); + self->monsterinfo.attack_finished = level.time + 0.4; + Arrow = G_Spawn(); + + create_ssith_arrow(Arrow); + + if(self->spawnflags & MSF_SSITHRA_ALPHA) + Arrow->touch=ssithraArrowTouch; + else + Arrow->touch=ssithraArrowTouch; + + Arrow->owner=self; + Arrow->enemy=self->enemy; + + Arrow->health = 0; // tell the touch function what kind of arrow we are; + + AngleVectors(self->s.angles, Forward, right, NULL); + + VectorCopy(self->s.origin,Arrow->s.origin); + VectorMA(Arrow->s.origin, 16, Forward, Arrow->s.origin); + VectorMA(Arrow->s.origin, -4, right, Arrow->s.origin); + Arrow->s.origin[2] += 16; + + VectorCopy(self->movedir,Arrow->movedir); + vectoangles(Forward,Arrow->s.angles); + + VectorClear(check_lead); + if(skill->value > 1) + { + extrapolateFiredir(self, Arrow->s.origin, + SSITHRA_SPOO_SPEED, self->enemy, 0.3, check_lead); + } + else + { + VectorSubtract(self->enemy->s.origin, Arrow->s.origin, enemy_dir); + VectorNormalize(enemy_dir); + if(DotProduct(enemy_dir, Forward) >= 0.3) + { + Forward[2] = enemy_dir[2]; + } + } + + if(Vec3IsZero(check_lead)) + { + VectorScale(Forward,SSITHRA_SPOO_SPEED,Arrow->velocity); + } + else + { + VectorScale(check_lead,SSITHRA_SPOO_SPEED,Arrow->velocity); + } + + VectorCopy(Arrow->velocity, Arrow->movedir); + VectorNormalize(Arrow->movedir); + vectoangles(Arrow->movedir, Arrow->s.angles); + Arrow->s.angles[PITCH] = anglemod(Arrow->s.angles[PITCH] * -1); + Arrow->s.angles[YAW] += 90; + + gi.CreateEffect(&Arrow->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + Arrow->s.origin, + "bv", + FX_MSSITHRA_ARROW, + Arrow->velocity); + + G_LinkMissile(Arrow); + + Arrow->nextthink=level.time+3; + Arrow->think=G_FreeEdict;//ssithraArrowThink; +} + +void ssithraDoDuckArrow(edict_t *self, float z_offs) +{ + vec3_t Forward,check_lead, right, enemy_dir; + edict_t *Arrow; + + if(self->s.fmnodeinfo[MESH__RIGHTARM].flags&FMNI_NO_DRAW) + return; + + gi.sound(self, CHAN_WEAPON, Sounds[SND_ARROW_FIRE] , 1, ATTN_NORM, 0); + + self->monsterinfo.attack_finished = level.time + 0.4; + Arrow = G_Spawn(); + + create_ssith_arrow(Arrow); + + Arrow->touch=ssithraDuckArrowTouch; + + Arrow->owner=self; + Arrow->enemy=self->enemy; + + Arrow->health = 0; // tell the touch function what kind of arrow we are; + + AngleVectors(self->s.angles, Forward, right, NULL); + + VectorCopy(self->s.origin,Arrow->s.origin); + VectorMA(Arrow->s.origin, 12*self->s.scale, Forward, Arrow->s.origin); + VectorMA(Arrow->s.origin, 4*self->s.scale, right, Arrow->s.origin); + Arrow->s.origin[2] += z_offs; + + Arrow->s.scale = 1.5; + + VectorCopy(self->movedir,Arrow->movedir); + vectoangles(Forward,Arrow->s.angles); + + VectorClear(check_lead); + if(skill->value > 1) + { + extrapolateFiredir(self, Arrow->s.origin, + SSITHRA_SPOO_SPEED, self->enemy, 0.3, check_lead); + } + else + { + VectorSubtract(self->enemy->s.origin, Arrow->s.origin, enemy_dir); + VectorNormalize(enemy_dir); + if(DotProduct(enemy_dir, Forward) >= 0.3) + { + Forward[2] = enemy_dir[2]; + } + } + + if(Vec3IsZero(check_lead)) + { + VectorScale(Forward,SSITHRA_SPOO_SPEED*1.5,Arrow->velocity); + } + else + { + VectorScale(check_lead,SSITHRA_SPOO_SPEED*1.5,Arrow->velocity); + } + + VectorCopy(Arrow->velocity, Arrow->movedir); + VectorNormalize(Arrow->movedir); + vectoangles(Arrow->movedir, Arrow->s.angles); + Arrow->s.angles[PITCH] = anglemod(Arrow->s.angles[PITCH] * -1); + Arrow->s.angles[YAW] += 90; + + gi.CreateEffect(&Arrow->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN | CEF_FLAG6, + Arrow->s.origin, + "bv", + FX_MSSITHRA_ARROW, + Arrow->velocity); + + G_LinkMissile(Arrow); + + Arrow->nextthink=level.time+5; + Arrow->think=ssithraArrowExplode; +} + +void ssithraStartDuckArrow(edict_t *self) +{ + vec3_t startpos, vf, vr; + + AngleVectors(self->s.angles, vf, vr, NULL); + VectorMA(self->s.origin, 18*self->s.scale, vf, startpos); + VectorMA(startpos, 4*self->s.scale, vr, startpos); + + gi.sound(self, CHAN_WEAPON, Sounds[SND_ARROW_CHARGE] , 1, ATTN_NORM, 0); + + gi.CreateEffect(NULL, + FX_M_EFFECTS, + 0, + self->s.origin, + "bv", + FX_MSSITHRA_ARROW_CHARGE, + startpos); +} + +void ssithraArrow(edict_t *self) +{//fixme; adjust for up/down + if(!self->enemy) + { + ssithra_decide_stand(self); + return; + } + + if(self->enemy->health<=0) + { + self->enemy=NULL; + ssithra_decide_stand(self); + return; + } + + if(self->monsterinfo.attack_finished>level.time) + return; + + if(self->spawnflags & MSF_SSITHRA_ALPHA) + ssithraDoDuckArrow(self, self->maxs[2] * 0.8); + else + ssithraDoArrow(self, 8); +} + +void ssithraPanicArrow(edict_t *self) +{//fixme; adjust for up/down + vec3_t Forward,firedir;//, up; + edict_t *Arrow; + + if(self->s.fmnodeinfo[MESH__RIGHTARM].flags&FMNI_NO_DRAW) + { + if(self->curAnimID == ANIM_HEADLESS || self->curAnimID == ANIM_HEADLESSLOOP) + ssithraKillSelf(self); + return; + } + +// gi.dprintf("Ssithra fire panic arrow\n"); + gi.sound(self,CHAN_WEAPON,Sounds[SND_ARROW2],1,ATTN_NORM,0); + self->monsterinfo.attack_finished = level.time + 0.4; + Arrow = G_Spawn(); + +// Arrow->s.modelindex=gi.modelindex("models/objects/projectiles/sitharrow/tris.fm"); + + create_ssith_arrow(Arrow); + + Arrow->owner=self; + + Arrow->health = 1; // tell the touch function what kind of arrow we are; + + VectorAdd(self->s.angles,self->v_angle_ofs,firedir); + AngleVectors(firedir,Forward,NULL,NULL); + VectorCopy(self->s.origin,Arrow->s.origin); + VectorMA(Arrow->s.origin,12,Forward,Arrow->s.origin); + VectorCopy(self->movedir,Arrow->movedir); + vectoangles(Forward,Arrow->s.angles); + + VectorScale(Forward,SSITHRA_SPOO_SPEED,Arrow->velocity); + + vectoangles(Arrow->velocity, Arrow->s.angles); + Arrow->s.angles[YAW]+=90; +//fixme: redo these- make them look like squid ink? + gi.CreateEffect(&Arrow->s, + FX_SSITHRA_ARROW, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + FX_SS_MAKE_ARROW, + Arrow->velocity); + + G_LinkMissile(Arrow); + + Arrow->nextthink=level.time+3; + Arrow->think=G_FreeEdict;//ssithraArrowThink; +} + +void ssithra_water_shoot (edict_t *self) +{ + SetAnim(self,ANIM_WATER_SHOOT); +} + +void ssithraCheckLoop (edict_t *self) +{//see if should fire again + vec3_t v; + float len, melee_range, min_seperation, jump_range; + + if(!self->enemy) + return; + + if(!visible(self, self->enemy)) + return; + + if(!infront(self, self->enemy)) + return; + + if(irand(0, 100) < self->bypass_missile_chance) + return; + + VectorSubtract (self->enemy->s.origin, self->s.origin, v); + len = VectorLength (v); + melee_range = 64; + jump_range = 128; + min_seperation = self->maxs[0] + self->enemy->maxs[0]; + + if (infront(self, self->enemy)) + {//don't loop if enemy close enough + if (len < min_seperation + melee_range) + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + return; + } + else if (len < min_seperation + jump_range && irand(0,10)<3) + { + VectorScale(v, 3, self->movedir); + self->movedir[2] += 150; + SetAnim(self, ANIM_LUNGE); + return; + } + } + + self->monsterinfo.currframeindex = self->monsterinfo.currframeindex - 2; +} + +//======================================== +//EVASION +//======================================== +void ssithraCheckDuckArrow (edict_t *self) +{ + if(M_ValidTarget(self, self->enemy)) + { + if(ahead(self, self->enemy)) + { +// if(M_DistanceToTarget(self, self->enemy)missile_range) +// { +// if(clear_visible(self, self->enemy)) +// { + ssithraDoDuckArrow(self, -18); +// } +// } + } + } +} + +void ssithraCheckUnDuck (edict_t *self) +{ + if(self->evade_debounce_time < level.time) + SetAnim(self, ANIM_UNDUCK); + else + SetAnim(self, ANIM_DUCKLOOP); +} + +void ssithraJumpEvade (edict_t *self) +{ + vec3_t forward; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorSet(self->movedir, 0, 0, 300); + VectorMA(self->movedir, 200, forward, self->movedir); + SetAnim(self, ANIM_FJUMP); +} + +void ssithraCrouch (edict_t *self) +{ + self->maxs[2] = 0; + self->viewheight = -6; + gi.linkentity(self); + SetAnim(self, ANIM_DUCKSHOOT); +} + +void ssithraUnCrouch(edict_t *self) +{ + self->maxs[2] = STDMaxsForClass[self->classID][2] * self->s.scale; + gi.linkentity(self); + self->viewheight = self->maxs[2]*0.8; +} + +void ssithra_evade (edict_t *self, G_Message_t *msg) +{ + edict_t *projectile; + HitLocation_t HitLocation; + int duck_chance, jump_chance; + int chance; + float eta; + + ParseMsgParms(msg, "eif", &projectile, &HitLocation, &eta); + + switch(HitLocation) + { + case hl_Head: + duck_chance = 90; + jump_chance = 0; + break; + case hl_TorsoFront://split in half? + duck_chance = 70; + jump_chance = 0; + break; + case hl_TorsoBack://split in half? + duck_chance = 70; + jump_chance = 0; + break; + case hl_ArmUpperLeft: + duck_chance = 60; + jump_chance = 0; + break; + case hl_ArmLowerLeft://left arm + duck_chance = 20; + jump_chance = 30; + break; + case hl_ArmUpperRight: + duck_chance = 60; + jump_chance = 0; + break; + case hl_ArmLowerRight://right arm + duck_chance = 20; + jump_chance = 30; + break; + case hl_LegUpperLeft: + duck_chance = 0; + jump_chance = 50; + break; + case hl_LegLowerLeft://left leg + duck_chance = 0; + jump_chance = 90; + break; + case hl_LegUpperRight: + duck_chance = 0; + jump_chance = 50; + break; + case hl_LegLowerRight://right leg + duck_chance = 0; + jump_chance = 90; + break; + default: + duck_chance = 20; + jump_chance = 10; + break; + } + + if(!(self->spawnflags&MSF_FIXED)) + { + chance = irand(0, 100); + if(chance < jump_chance) + { + ssithraJumpEvade(self); + return; + } + } + + chance = irand(0, 100); + if(chance < duck_chance) + { + self->evade_debounce_time = level.time + eta; + ssithraCrouch(self); + return; + } +} + + +//======================================== +//MOODS +//======================================== +qboolean SsithraCheckMood (edict_t *self) +{ + if(self->spawnflags & MSF_FIXED && self->curAnimID == ANIM_DELAY && self->enemy) + { + self->monsterinfo.searchType = SEARCH_COMMON; + MG_FaceGoal(self, true); + } + + self->mood_think(self); + + if(self->ai_mood == AI_MOOD_NORMAL) + return false; + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + if(self->ai_mood_flags & AI_MOOD_FLAG_MISSILE) + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + return true; + break; + case AI_MOOD_PURSUE: + case AI_MOOD_NAVIGATE: + //gi.dprintf("Pursue- Nav\n"); + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + return true; + break; + case AI_MOOD_WALK: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + return true; + break; + case AI_MOOD_STAND: + ssithra_decide_stand(self); + return true; + break; + + case AI_MOOD_DELAY: +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Delay on frame %d\n", self->monsterinfo.currframeindex); +#endif + SetAnim(self, ANIM_DELAY); + return true; + break; + + case AI_MOOD_WANDER: + if(ssithraCheckInWater(self)) + SetAnim(self, ANIM_SWIMWANDER); + else + SetAnim(self, ANIM_WALK1); + return true; + break; + + case AI_MOOD_BACKUP: + QPostMessage(self, MSG_FALLBACK, PRI_DIRECTIVE, NULL); + return true; + break; + + case AI_MOOD_JUMP: + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_FJUMP); + return true; + break; + + default : +#ifdef _DEVEL +// if(MGAI_DEBUG) + gi.dprintf("ssithra: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } + return false; +} + +void ssithra_check_mood (edict_t *self, G_Message_t *msg) +{ + ParseMsgParms(msg, "i", &self->ai_mood); + + SsithraCheckMood(self); +} + +/*----------------------------------------------- + ssithra_sight +-----------------------------------------------*/ +#define SSITHRA_SUPPORT_RADIUS 200 + +void ssithra_sight (edict_t *self, G_Message_t *msg) +{ + edict_t *enemy = NULL; + byte sight_type; + int sound; + + if(self->targetname || self->monsterinfo.c_mode) + return;//cinematic waiting to be activated, don't do this + + //Have we already said something? + if (self->monsterinfo.supporters != -1) + return; + + ParseMsgParms(msg, "be", &sight_type, &enemy); + + //See if we are the first to see the player + if(M_CheckAlert(self, SSITHRA_SUPPORT_RADIUS)) + { + sound = irand(SND_SIGHT1, SND_SIGHT6); + gi.sound(self, CHAN_BODY, Sounds[sound], 1, ATTN_NORM, 0); + } +} + +qboolean ssithraAlerted (edict_t *self, alertent_t *alerter, edict_t *enemy) +{ + alertent_t *checkent = NULL; + vec3_t saveangles; + + if(self->alert_time < level.time) + {//not looking around + if(!(alerter->alert_svflags&SVF_ALERT_NO_SHADE) && skill->value < 3.0 && !(self->monsterinfo.aiflags & AI_NIGHTVISION)) + {//not a sound-alert, + if(enemy->light_level < flrand(6, 77)) + { + return false; + } + } + } + + //the alert action happened in front of me, but the enemy is behind or the alert is behind me + if(!infront_pos(self, alerter->origin)) + { + if(irand(0, 1)&&self->curAnimID!=ANIM_IDLEBASIC) + {//50% chance of startling them up if not already in startle anim + //startle me, but don't wake up just yet + if(alerter->lifetime < level.time + 4) + self->alert_time = level.time + 4;//be ready for 4 seconds to wake up if alerted again + else + self->alert_time = alerter->lifetime;//be alert as long as the alert sticks around + VectorCopy(self->v_angle_ofs, saveangles); + VectorClear(self->v_angle_ofs); + self->v_angle_ofs[YAW]=-90; + + if(infront_pos(self, alerter->origin))//fancy way of seeing if explosion was to right + { + VectorCopy(saveangles,self->v_angle_ofs); + ssithraLookRight(self);//fixme: if already looking right, see you + } + else + { + VectorCopy(saveangles,self->v_angle_ofs); + ssithraStartle(self); + } + return false; + } + else//spin around and wake up! + self->spawnflags |= MSF_SSITHRA_SPIN; + } + else if(!infront(self,enemy)) + { + if(irand(0, 1)&&self->curAnimID!=ANIM_IDLEBASIC) + {//50% chance of startling them up if not already in startle anim + //startle me, but don't wake up just yet + self->alert_time = level.time + 4;//be ready to wake up for next 4 seconds + VectorCopy(self->v_angle_ofs, saveangles); + VectorClear(self->v_angle_ofs); + self->v_angle_ofs[YAW]=-90; + + if(infront(self, enemy))//fancy way of seeing if explosion was to right + { + VectorCopy(saveangles,self->v_angle_ofs); + ssithraLookRight(self);//fixme: if already looking right, see you + } + else + { + VectorCopy(saveangles,self->v_angle_ofs); + ssithraStartle(self); + } + return false; + } + else//spin around and wake up! + self->spawnflags |= MSF_SSITHRA_SPIN; + } + + if(checkent) + {//enemy of alert is behind me + } + + if(enemy->svflags&SVF_MONSTER) + self->enemy = alerter->enemy; + else + self->enemy = enemy; + + FoundTarget(self, true); + + return true; +} +//================================================================================ + + +void SsithraStaticsInit() +{ + classStatics[CID_SSITHRA].msgReceivers[MSG_STAND] = ssithra_stand; + classStatics[CID_SSITHRA].msgReceivers[MSG_WALK] = ssithra_walk; + classStatics[CID_SSITHRA].msgReceivers[MSG_RUN] = ssithra_gallop; + classStatics[CID_SSITHRA].msgReceivers[MSG_MELEE] = ssithra_melee; + classStatics[CID_SSITHRA].msgReceivers[MSG_MISSILE] = ssithra_missile; + classStatics[CID_SSITHRA].msgReceivers[MSG_WATCH] = ssithra_idlebasic; + classStatics[CID_SSITHRA].msgReceivers[MSG_PAIN] = ssithra_pain; + classStatics[CID_SSITHRA].msgReceivers[MSG_DEATH] = ssithra_death; + classStatics[CID_SSITHRA].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_SSITHRA].msgReceivers[MSG_JUMP] = ssithraMsgJump; + classStatics[CID_SSITHRA].msgReceivers[MSG_FALLBACK] = ssithra_backup; + classStatics[CID_SSITHRA].msgReceivers[MSG_DEATH_PAIN] = ssithra_dead_pain; + classStatics[CID_SSITHRA].msgReceivers[MSG_EVADE] = ssithra_evade; + classStatics[CID_SSITHRA].msgReceivers[MSG_CHECK_MOOD] = ssithra_check_mood; + classStatics[CID_SSITHRA].msgReceivers[MSG_VOICE_SIGHT] = ssithra_sight; + + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/ssithra/tris.fm"); + + Sounds[SND_PAIN1]=gi.soundindex("monsters/pssithra/pain1.wav"); + Sounds[SND_PAIN2]=gi.soundindex("monsters/pssithra/pain2.wav"); + Sounds[SND_DIE]=gi.soundindex("monsters/pssithra/die.wav"); + Sounds[SND_GIB]=gi.soundindex("monsters/pssithra/gib.wav"); + Sounds[SND_SWIPEHIT]=gi.soundindex("monsters/pssithra/swipehit.wav"); + Sounds[SND_ARROW1]=gi.soundindex("monsters/pssithra/arrow1.wav"); + Sounds[SND_ARROW2]=gi.soundindex("monsters/pssithra/arrow2.wav"); + Sounds[SND_GROWL1]=gi.soundindex("monsters/pssithra/growl1.wav"); + Sounds[SND_GROWL2] = gi.soundindex ("monsters/pssithra/growl2.wav"); + Sounds[SND_GROWL3] = gi.soundindex ("monsters/pssithra/growl3.wav"); + Sounds[SND_INWATER] = gi.soundindex ("monsters/pssithra/inwater.wav"); + Sounds[SND_NAMOR] = gi.soundindex ("monsters/pssithra/namor.wav"); + Sounds[SND_LAND] = gi.soundindex ("monsters/pssithra/land.wav"); + Sounds[SND_SWIPE] = gi.soundindex ("monsters/pssithra/swipe.wav"); + Sounds[SND_SWIM] = gi.soundindex ("monsters/pssithra/swim.wav"); + Sounds[SND_SWIM2] = gi.soundindex ("monsters/pssithra/swim2.wav"); + + Sounds[SND_SIGHT1] = gi.soundindex ("monsters/pssithra/ssithvoice1.wav"); + Sounds[SND_SIGHT2] = gi.soundindex ("monsters/pssithra/ssithvoice2.wav"); + Sounds[SND_SIGHT3] = gi.soundindex ("monsters/pssithra/ssithvoice3.wav"); + Sounds[SND_SIGHT4] = gi.soundindex ("monsters/pssithra/ssithvoice4.wav"); + Sounds[SND_SIGHT5] = gi.soundindex ("monsters/pssithra/ssithvoice5.wav"); + Sounds[SND_SIGHT6] = gi.soundindex ("monsters/pssithra/ssithvoice6.wav"); + + Sounds[SND_ARROW_CHARGE] = gi.soundindex ("monsters/pssithra/guncharge.wav"); + Sounds[SND_ARROW_FIRE] = gi.soundindex ("monsters/pssithra/gunfire.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = Sounds; + + classStatics[CID_SSITHRA].resInfo = &resInfo; +} + +/*QUAKED monster_ssithra (1 .5 0) (-16 -16 -32) (16 16 26) AMBUSH ASLEEP 4 Namor Spin ToughGuy Clothed FIXED WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +The plague ssithra + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING- Use WANDER instead + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 28 +melee_range = 48 +missile_range = 512 +min_missile_range = 48 +bypass_missile_chance = 25 +jump_chance = 100 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +void SP_monster_plague_ssithra (edict_t *self) +{ + qboolean alpha = true; + + if(!skill->value) + { + if(!irand(0, 2))//30% - but won't fire explosives + self->spawnflags |= MSF_SSITHRA_CLOTHED; + } + else if (skill->value == 1) + { + if(!irand(0, 3))//25% + self->spawnflags |= MSF_SSITHRA_CLOTHED; + } + else + { + if(irand(0, 1))//50% + self->spawnflags |= MSF_SSITHRA_CLOTHED; + } + + if(self->spawnflags&MSF_SSITHRA_NAMOR) + self->spawnflags |= MSF_AMBUSH; + + // Generic Monster Initialization + if (!monster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->monsterinfo.alert = ssithraAlerted; + self->classID = CID_SSITHRA; + self->think = walkmonster_start_go; + self->monsterinfo.dismember = ssithra_dismember; + + self->materialtype = MAT_FLESH; +// self->monsterinfo.aiflags |= AI_SWIM_OK; + self->flags |= FL_IMMUNE_SLIME; + + ssithraCheckInWater(self); + + self->isBlocked = ssithra_blocked; + + if(self->health<=0) + self->health = SSITHRA_HEALTH; + + //Apply to the end result (whether designer set or not) + self->health = MonsterHealth(self->health); + + self->mass = SSITHRA_MASS; + self->yaw_speed = 20; + + self->movetype = PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + self->monsterinfo.supporters = -1; + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + self->viewheight = self->maxs[2]*0.8; + + self->s.modelindex = classStatics[CID_SSITHRA].resInfo->modelIndex; + + self->touch = M_Touch; + + if(self->spawnflags & MSF_SSITHRA_CLOTHED) + self->s.skinnum = 2; + else + self->s.skinnum = 0; + + //scaling them up in code like this is bad for designers + self->s.scale = self->monsterinfo.scale = (MODEL_SCALE)+0.1;// + flrand(0.1, 0.3)); + // Note that at less than 110% of the size + + //Turn off dismemberment caps, can't see them, so save some polys + self->s.fmnodeinfo[MESH__CAPLOWERTORSO].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__CAPTOPUPPERTORSO].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__CAPBOTTOMUPPERTORSO].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__CAPHEAD].flags |= FMNI_NO_DRAW; + if(!(self->spawnflags&MSF_SSITHRA_ALPHA)) + { + if(irand(0,10)<6) + { + if(irand(0,10)<5) + { + self->s.fmnodeinfo[MESH__CENTERSPIKE].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__CENTERSPIKE].skin = self->s.skinnum+1; + } + else + self->s.fmnodeinfo[MESH__CENTERSPIKE].flags |= FMNI_NO_DRAW; + alpha = false; + } + if(irand(0,10)<6) + { + if(irand(0,10)<5) + { + self->s.fmnodeinfo[MESH__LEFT1SPIKE].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LEFT1SPIKE].skin = self->s.skinnum+1; + } + else + self->s.fmnodeinfo[MESH__LEFT1SPIKE].flags |= FMNI_NO_DRAW; + alpha = false; + } + if(irand(0,10)<6) + { + if(irand(0,10)<5) + { + self->s.fmnodeinfo[MESH__RIGHT1SPIKE].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RIGHT1SPIKE].skin = self->s.skinnum+1; + } + else + self->s.fmnodeinfo[MESH__RIGHT1SPIKE].flags |= FMNI_NO_DRAW; + alpha = false; + } + if(irand(0,10)<6) + { + if(irand(0,10)<5) + { + self->s.fmnodeinfo[MESH__RIGHT2SPIKE].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RIGHT2SPIKE].skin = self->s.skinnum+1; + } + else + self->s.fmnodeinfo[MESH__RIGHT2SPIKE].flags |= FMNI_NO_DRAW; + alpha = false; + } + } + + self->s.color.a = 255; + if(alpha)//tough guy! + {//TODO: other ssithras won't attack this guy and will follow him + self->health += 75; + self->s.scale = self->monsterinfo.scale = MODEL_SCALE + 0.5; + self->spawnflags|=MSF_SSITHRA_ALPHA; + self->s.color.r = 255; + self->s.color.g = 255; + self->s.color.b = 128; + } + else + { + self->s.color.r = 200 + irand(-50, 50); + self->s.color.g = 200 + irand(-50, 50); + self->s.color.b = 200 + irand(-50, 50); + } + + self->monsterinfo.otherenemyname = "obj_barrel"; + + //set up my mood function + MG_InitMoods(self); + if(!irand(0,2)) + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + self->svflags |= SVF_WAIT_NOTSOLID; + self->flags |= FL_AMPHIBIAN; + +// if(self->spawnflags & MSF_SSITHRA_NAMOR) +// self->use = ssithraNamorTriggered; +} + + +/*QUAKED obj_corpse_ssithra (1 .5 0) (-30 -12 -2) (30 12 2) INVULNERABLE ANIMATE EXPLODING NOPUSH +A dead plague ssithra +---------- KEYS ----------------- +style - skin of ssithra (default 0) +0 - damage skin +1 - some bad bad skin. (not used) +2 - normal skin +------- FIELDS ------------------ +INVULNERABLE - it can't be hurt +ANIMATE - N/A +EXPLODING - N/A +NOPUSH - N/A (corpse can't be pushed) +----------------------------------- +*/ +void SP_obj_corpse_ssithra(edict_t *self) +{ + self->s.origin[2] += 26.0; + + VectorSet(self->mins,-30,-12,-2); + VectorSet(self->maxs,30,12,2); + + self->s.modelindex = gi.modelindex("models/monsters/ssithra/tris.fm"); + + self->s.frame = FRAME_death_a12; //Ths is the reason the function can't be put in g_obj.c + + // Setting the skinnum correctly + if (!self->style) + self->s.skinnum = 1; + else + self->s.skinnum = 0; + + self->spawnflags |= OBJ_NOPUSH; // Can't be pushed + self->svflags |= SVF_DEADMONSTER;//doesn't block walking + + ObjectInit(self,120,80,MAT_FLESH,SOLID_BBOX); +} + diff --git a/Toolkit/Programming/GameCode/game/m_plaguessithra.h b/Toolkit/Programming/GameCode/game/m_plaguessithra.h new file mode 100644 index 0000000..6cc17b5 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_plaguessithra.h @@ -0,0 +1,211 @@ +//m_plagueSsithra.h + + +typedef enum AnimID_e +{ + ANIM_STAND1, + ANIM_WALK1, + ANIM_BACKPEDAL, + ANIM_BOUND, + ANIM_DEATH_A, + ANIM_DEATH_B, + ANIM_DIVE, + ANIM_DUCKSHOOT, + ANIM_DUCK, + ANIM_GALLOP, + ANIM_FJUMP, + ANIM_IDLEBASIC, + ANIM_IDLERIGHT, + ANIM_MELEE, + ANIM_MELEE_STAND, + ANIM_NAMOR, + ANIM_PAIN_A, + ANIM_SHOOT, + ANIM_STARTLE, + ANIM_SWIMFORWARD, + ANIM_SWIMWANDER, + ANIM_WATER_DEATH,//19 + ANIM_WATER_IDLE,// + ANIM_WATER_PAIN_A, + ANIM_WATER_PAIN_B, + ANIM_WATER_SHOOT, + ANIM_RUN1, + ANIM_SPINRIGHT, + ANIM_SPINRIGHT_GO, + ANIM_SPINLEFT, + ANIM_SPINLEFT_GO, + ANIM_FACEANDNAMOR, + ANIM_DEAD_A, + ANIM_LOOKRIGHT, + ANIM_LOOKLEFT, + ANIM_TRANSUP, + ANIM_TRANSDOWN, + ANIM_HEADLESS, + ANIM_HEADLESSLOOP, + ANIM_DEATH_C, + ANIM_DEAD_B, + ANIM_DEAD_WATER, + ANIM_SLICED, + ANIM_DELAY, + ANIM_DUCKLOOP, + ANIM_UNDUCK, + ANIM_LUNGE, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PAIN1,// + SND_PAIN2,// + SND_DIE,// + SND_GIB,// + SND_SWIPE,// + SND_SWIPEHIT,// + SND_ARROW1,// + SND_ARROW2,// + SND_GROWL1,//hiss + SND_GROWL2,//shriek + SND_GROWL3,//grunt + SND_INWATER,// + SND_NAMOR,// + SND_LAND,//??? + SND_SWIM,// + SND_SWIM2, + + //Voices + SND_SIGHT1, + SND_SIGHT2, + SND_SIGHT3, + SND_SIGHT4, + SND_SIGHT5, + SND_SIGHT6, + + SND_ARROW_CHARGE, + SND_ARROW_FIRE, + + NUM_SOUNDS +} SoundID_t; + +extern animmove_t ssithra_move_idle1; +extern animmove_t ssithra_move_walk1; +extern animmove_t ssithra_move_backpedal1; +extern animmove_t ssithra_move_bound1; +extern animmove_t ssithra_move_death_a1; +extern animmove_t ssithra_move_death_b1; +extern animmove_t ssithra_move_dive1; +extern animmove_t ssithra_move_duckshoot1; +extern animmove_t ssithra_move_duck1; +extern animmove_t ssithra_move_gallop1; +extern animmove_t ssithra_move_fjump; +extern animmove_t ssithra_move_idlebasic1; +extern animmove_t ssithra_move_idleright1; +extern animmove_t ssithra_move_melee1; +extern animmove_t ssithra_move_meleest; +extern animmove_t ssithra_move_namor1; +extern animmove_t ssithra_move_pain_a1; +extern animmove_t ssithra_move_shoot1; +extern animmove_t ssithra_move_startle1; +extern animmove_t ssithra_move_swimforward1; +extern animmove_t ssithra_move_swimwander; +extern animmove_t ssithra_move_water_death1; +extern animmove_t ssithra_move_water_idle1; +extern animmove_t ssithra_move_water_pain_a1; +extern animmove_t ssithra_move_water_pain_b1; +extern animmove_t ssithra_move_water_shoot1; +extern animmove_t ssithra_move_run1; +extern animmove_t ssithra_move_spinright; +extern animmove_t ssithra_move_spinright_go; +extern animmove_t ssithra_move_spinleft; +extern animmove_t ssithra_move_spinleft_go; +extern animmove_t ssithra_move_faceandnamor; +extern animmove_t ssithra_move_dead; +extern animmove_t ssithra_move_lookright; +extern animmove_t ssithra_move_lookleft; +extern animmove_t ssithra_move_transup; +extern animmove_t ssithra_move_transdown; +extern animmove_t ssithra_move_headless; +extern animmove_t ssithra_move_headlessloop; +extern animmove_t ssithra_move_death_c; +extern animmove_t ssithra_move_dead_a; +extern animmove_t ssithra_move_dead_b; +extern animmove_t ssithra_move_dead_water; +extern animmove_t ssithra_move_sliced; +extern animmove_t ssithra_move_delay; +extern animmove_t ssithra_move_duckloop; +extern animmove_t ssithra_move_unduck; +extern animmove_t ssithra_move_lunge; + +void ssithra_stand(edict_t *self, G_Message_t *msg); +void ssithra_walk(edict_t *self, G_Message_t *msg); +void ssithra_gallop(edict_t *self, G_Message_t *msg); +void ssithra_melee(edict_t *self, G_Message_t *msg); +void ssithra_idlebasic(edict_t *self, G_Message_t *msg); +void ssithra_dismember(edict_t *self, int damage, int HitLocation); +void ssithra_dismember_msg(edict_t *self, G_Message_t *msg); +void ssithra_pain(edict_t *self, G_Message_t *msg); +void ssithra_death(edict_t *self, G_Message_t *msg); +void ssithra_swimforward(edict_t *self, G_Message_t *msg); + +void ssithra_dead(edict_t *self); + +void ssithra_decide_stand(edict_t *self); +void ssithra_decide_gallop(edict_t *self); +void ssithra_decide_swimforward(edict_t *self); +void ssithra_decide_backpedal(edict_t *self); +//void ssithra_decide_walk(edict_t *self); +void ssithra_startle_go(edict_t *self); +//Actions +void ssithraSwipe(edict_t *self); +void ssithraArrow(edict_t *self); +void ssithraJump (edict_t *self, float upspd,float fwdspd,float rtspd); +void ssithraBoundCheck (edict_t *self); +void ssithraDiveCheck (edict_t *self); +void ssithraWaterDead(edict_t *self); +void ssithraForward (edict_t *self, float forwarddist); +void ssithraCheckLeaveWaterSplash (edict_t *self); +void ssithraCheckHitWaterSplash (edict_t *self); +void ssithraNamorJump (edict_t *self); +void ssithraCheckRipple (edict_t *self); +qboolean ai_checkattack (edict_t *self, float dist); +void ai_spin (edict_t *self, float amount); +void ssithra_spinright_go(edict_t *self); +void ssithra_spinleft_go(edict_t *self); +void ssithraCheckFacedNamor (edict_t *self); +void ssithra_check_namor(edict_t *self); +void ssithraVOfs(edict_t *self, float pofs, float yofs, float rofs); +void ssithraPanicArrow(edict_t *self); +void ssithra_pain_react (edict_t *self); +void ssithra_water_shoot (edict_t *self); +void ssithraCollapse(edict_t *self); +void ssithraKillSelf (edict_t *self); +void ssithraSound(edict_t *self, float soundnum, float channel, float attenuation); +qboolean SsithraCheckMood (edict_t *self); +void ssithraMsgJump(edict_t *self, G_Message_t *msg); +void MG_InitMoods(edict_t *self); +void ssithraApplyJump (edict_t *self); +void ssithraCheckDuckArrow (edict_t *self); +void ssithraCheckUnDuck (edict_t *self); +void ssithraJumpEvade (edict_t *self); +void ssithraCrouch (edict_t *self); +void ssithraUnCrouch(edict_t *self); +void ssithraCheckLoop (edict_t *self); +void ssithraGrowlSound(edict_t *self); +void ssithraStartDuckArrow(edict_t *self); + + +#define BIT_POLY 0 +#define BIT_LOWERTORSO 1 +#define BIT_CAPLOWERTORSO 2 +#define BIT_LEFTLEG 4 +#define BIT_RIGHTLEG 8 +#define BIT_UPPERTORSO 16 +#define BIT_CAPTOPUPPERTORSO 32 +#define BIT_CAPBOTTOMUPPERTORSO 64 +#define BIT_LEFTARM 128 +#define BIT_RIGHTARM 256 +#define BIT_HEAD 512 +#define BIT_CENTERSPIKE 1024 +#define BIT_LEFT1SPIKE 2048 +#define BIT_RIGHT1SPIKE 4096 +#define BIT_RIGHT2SPIKE 8192 +#define BIT_CAPHEAD 16384 diff --git a/Toolkit/Programming/GameCode/game/m_plaguessithra_anim.c b/Toolkit/Programming/GameCode/game/m_plaguessithra_anim.c new file mode 100644 index 0000000..c6fe9cc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_plaguessithra_anim.c @@ -0,0 +1,1822 @@ +//============================================================================== +// +// m_plagueSsitra_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_plaguessithra_anim.h" +#include "m_plaguessithra.h" +#include "g_monster.h" +#include "c_ai.h" +#include "vector.h" + +void old_ai_run (edict_t *self, float dist); +void ai_run (edict_t *self, float dist); +void ai_charge2 (edict_t *self, float dist); +qboolean ssithraCheckInWater (edict_t *self); +void MG_Pathfind(edict_t *self, qboolean check_clear_path); +void MG_SwimFlyToGoal (edict_t *self, float dist); + + +void ssithra_ai_run (edict_t *self, float dist) +{ + if(ssithraCheckInWater(self)) + { + MG_SwimFlyToGoal(self, dist);//really need to get rid of this! + MG_Pathfind(self, false); + } + else + ai_run(self, dist); +} + +/*---------------------------------------------------------------------- + Ssithra Idle - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_idle1 [] = +{ + FRAME_idle01, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle02, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle03, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle04, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle05, NULL, 0, 0, 0, ai_stand, 0, ssithraGrowlSound, + FRAME_idle06, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle07, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle08, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle09, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle16, NULL, 0, 0, 0, ai_stand, 0, ssithraGrowlSound, + FRAME_idle17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle20, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle21, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle22, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle23, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle24, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle25, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle26, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle27, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle28, NULL, 0, 0, 0, ai_stand, 0, ssithraGrowlSound, + FRAME_idle29, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle30, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle31, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle32, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle33, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle34, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle35, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle36, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle37, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle38, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle39, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle40, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t ssithra_move_idle1 = {40, ssithra_frames_idle1, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra Walk - walking along +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_walk1 [] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk2, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_walk, 3, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk7, NULL, 0, 0, 0, ai_walk, 5, ssithraGrowlSound, + FRAME_walk8, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk9, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk10, NULL, 0, 0, 0, ai_walk, 7, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk12, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk13, NULL, 0, 0, 0, ai_walk, 2, NULL, + FRAME_walk14, NULL, 0, 0, 0, ai_walk, 5, NULL, +}; +animmove_t ssithra_move_walk1 = {14, ssithra_frames_walk1, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra backpedal - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_backpedal1 [] = +{ + FRAME_backpedal1, NULL, 0, 0, 0, ai_charge2, -5, NULL, + FRAME_backpedal2, NULL, 0, 0, 0, ai_charge2, -5, NULL, + FRAME_backpedal3, NULL, 0, 0, 0, ai_charge2, -5, ssithraArrow, + FRAME_backpedal4, NULL, 0, 0, 0, ai_charge2, -7, NULL, + FRAME_backpedal5, NULL, 0, 0, 0, ai_charge2, -7, NULL, + FRAME_backpedal6, NULL, 0, 0, 0, ai_charge2, -7, NULL, + FRAME_backpedal7, NULL, 0, 0, 0, ai_charge2, -7, ssithraArrow, + FRAME_backpedal8, NULL, 0, 0, 0, ai_charge2, -5, NULL, + FRAME_backpedal9, NULL, 0, 0, 0, ai_charge2, -5, NULL, + FRAME_backpedal10, NULL, 0, 0, 0, ai_charge2, -5, NULL, +}; +animmove_t ssithra_move_backpedal1 = {10, ssithra_frames_backpedal1, ssithra_decide_backpedal}; + +/*---------------------------------------------------------------------- + Ssithra bound - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_bound1 [] = +{ + FRAME_bound09, NULL, 0, 0, 0, ssithra_ai_run, 16, NULL,//ssithraBoundCheck, + FRAME_bound10, NULL, 0, 0, 0, ssithra_ai_run, 16, NULL, + FRAME_bound11, NULL, 0, 0, 0, ssithra_ai_run, 20, NULL, + FRAME_bound12, NULL, 0, 0, 0, ssithra_ai_run, 20, NULL, + FRAME_bound13, NULL, 0, 0, 0, ssithra_ai_run, 24, NULL, + FRAME_bound14, NULL, 0, 0, 0, ssithra_ai_run, 20, NULL, + FRAME_bound15, NULL, 0, 0, 0, ssithra_ai_run, 16, NULL, + FRAME_bound16, NULL, 0, 0, 0, ssithra_ai_run, 12, NULL, +}; +animmove_t ssithra_move_bound1 = {8, ssithra_frames_bound1, SsithraCheckMood}; + + +/*---------------------------------------------------------------------- + Ssithra death_a +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_death_a1 [] = +{ + FRAME_death_a1, ssithraSound, SND_DIE, CHAN_VOICE, 0, NULL, 0, NULL, + FRAME_death_a2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a4, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_death_a5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_death_a1 = {12, ssithra_frames_death_a1, ssithra_dead}; + +/*---------------------------------------------------------------------- + Ssithra death_b - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_death_b1 [] = +{ + FRAME_death_b1, ssithraSound, SND_DIE, CHAN_VOICE, 0, NULL, 0, NULL, + FRAME_death_b2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b11, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_death_b12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b32, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b33, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b34, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b35, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b36, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_death_b1 = {36, ssithra_frames_death_b1, ssithra_dead}; + +/*---------------------------------------------------------------------- + Ssithra dive - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_dive1 [] = +{ + FRAME_dive1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive4, ssithraJump, 400, 100, 0, NULL, 0, NULL, + FRAME_dive5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dive9, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive10, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive11, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive12, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive13, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive14, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive15, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive16, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive17, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive18, NULL, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash,//fixme- check to make sure hit water + FRAME_dive19, NULL, 0, 0, 0, ai_move , 22, ssithraCheckHitWaterSplash,//in water, go forward + FRAME_dive20, NULL, 0, 0, 0, ai_move , 20, ssithraCheckHitWaterSplash, + FRAME_dive21, NULL, 0, 0, 0, ai_move , 17, ssithraCheckHitWaterSplash, + FRAME_dive22, NULL, 0, 0, 0, ai_move , 15, ssithraCheckHitWaterSplash, + FRAME_dive23, NULL, 0, 0, 0, ai_move , 12, ssithraCheckHitWaterSplash, + FRAME_dive24, NULL, 0, 0, 0, ai_move , 9, ssithraCheckHitWaterSplash, + FRAME_dive25, NULL, 0, 0, 0, ai_move , 6, ssithraCheckHitWaterSplash, + FRAME_dive26, NULL, 0, 0, 0, ai_move , 3, ssithraCheckHitWaterSplash, +}; +animmove_t ssithra_move_dive1 = {26, ssithra_frames_dive1, ssithra_decide_swimforward}; + +/*---------------------------------------------------------------------- + Ssithra duckshoot +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_unduck [] = +{ + FRAME_duckshoot3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duckshoot2, NULL, 0, 0, 0, ai_charge2, 0, ssithraUnCrouch, + FRAME_duckshoot1, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t ssithra_move_unduck = {3, ssithra_frames_unduck, ssithra_decide_gallop}; + +animframe_t ssithra_frames_duckloop [] = +{ + FRAME_duckshoot6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_duckloop = {1, ssithra_frames_duckloop, ssithraCheckUnDuck}; + +animframe_t ssithra_frames_duckshoot1 [] = +{ + FRAME_duckshoot1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duckshoot2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duckshoot3, NULL, 0, 0, 0, ai_charge2, 0, ssithraCrouch, + FRAME_duckshoot4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + //Wait + FRAME_duckshoot5, NULL, 0, 0, 0, ai_charge2, 0, ssithraStartDuckArrow, + FRAME_duckshoot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duckshoot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duckshoot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duckshoot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + //Fire + FRAME_duckshoot5, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckDuckArrow, + FRAME_duckshoot6, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t ssithra_move_duckshoot1 = {11, ssithra_frames_duckshoot1, ssithraCheckUnDuck}; + +/*---------------------------------------------------------------------- + Ssithra duck +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_duck1 [] = +{//oops, duckframes same as duckshoot? + FRAME_duckshoot1, ssithraSound, SND_GROWL3, CHAN_VOICE, ATTN_IDLE, NULL, 0, ssithraGrowlSound, + FRAME_duckshoot2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot3, NULL, 0, 0, 0, NULL, 0, ssithraCrouch, + FRAME_duckshoot4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_duck1 = {6, ssithra_frames_duck1, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra gallop - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_gallop1 [] = +{ + FRAME_gallop1, ssithraJump, 100, 50, 0, ssithra_ai_run, 20, NULL, +// FRAME_gallop1, NULL, 0, 0, 0, ssithra_ai_run, 20, NULL, + FRAME_gallop2, NULL, 0, 0, 0, ssithra_ai_run, 24, NULL, + FRAME_gallop3, NULL, 0, 0, 0, ssithra_ai_run, 32, NULL, + FRAME_gallop4, NULL, 0, 0, 0, ssithra_ai_run, 30, NULL, + FRAME_gallop5, NULL, 0, 0, 0, ssithra_ai_run, 28, NULL, + FRAME_gallop6, NULL, 0, 0, 0, ssithra_ai_run, 26, NULL, + FRAME_gallop7, NULL, 0, 0, 0, ssithra_ai_run, 24, NULL, + FRAME_gallop8, NULL, 0, 0, 0, ssithra_ai_run, 22, NULL, +}; +animmove_t ssithra_move_gallop1 = {8, ssithra_frames_gallop1, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra jump from buoy +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_fjump[] = +{ + FRAME_bound09, NULL, 0, 0, 0, NULL, 0, ssithraApplyJump, + FRAME_bound10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bound11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bound12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bound13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bound14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bound15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_bound16, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_fjump = {8, ssithra_frames_fjump, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra idlebasic - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_idlebasic1 [] = +{ + FRAME_idlebasic01, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic02, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic03, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic04, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic05, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic06, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic07, NULL, 0, 0, 0, ai_stand, 0, ssithraGrowlSound, + FRAME_idlebasic08, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic09, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic19, NULL, 0, 0, 0, ai_stand, 0, ssithraGrowlSound, + FRAME_idlebasic20, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic21, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic22, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic23, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic24, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic25, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic26, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic27, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic28, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic29, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic30, NULL, 0, 0, 0, ai_stand, 0, ssithraGrowlSound, + FRAME_idlebasic31, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic32, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic33, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic34, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic35, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic36, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic37, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic38, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic39, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic40, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t ssithra_move_idlebasic1 = {40, ssithra_frames_idlebasic1, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra idleright - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_idleright1 [] = +{ + FRAME_idleright01, ssithraSound, SND_GROWL2, CHAN_VOICE, ATTN_IDLE, ai_stand, 0, ssithraGrowlSound, + FRAME_idleright02, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright03, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright04, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright05, ssithraVOfs, 0, -20, 0, ai_stand, 0, NULL, + FRAME_idleright06, ssithraVOfs, 0, -30, 0, ai_stand, 0, NULL, + FRAME_idleright07, ssithraVOfs, 0, -50, 0, ai_stand, 0, NULL, + FRAME_idleright08, ssithraVOfs, 0, -70, 0, ai_stand, 0, NULL, + FRAME_idleright09, ssithraVOfs, 0, -80, 0, ai_stand, 0, NULL, + FRAME_idleright10, ssithraVOfs, 0, -90, 0, ai_stand, 0, NULL,//ssithraPanicArrow, + FRAME_idleright10, NULL, 0, 0, 0, ai_stand, 0, NULL,//keep looking here a bit + FRAME_idleright10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright11, ssithraVOfs, 0, -70, 0, ai_stand, 0, NULL, + FRAME_idleright12, ssithraVOfs, 0, -50, 0, ai_stand, 0, NULL, + FRAME_idleright13, ssithraVOfs, 0, -40, 0, ai_stand, 0, NULL, + FRAME_idleright14, ssithraVOfs, 0, -30, 0, ai_stand, 0, NULL, + FRAME_idleright15, ssithraVOfs, 0, -20, 0, ai_stand, 0, NULL, + FRAME_idleright16, ssithraVOfs, 0, -10, 0, ai_stand, 0, NULL, + FRAME_idleright17, ssithraVOfs, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idleright20, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t ssithra_move_idleright1 = {24, ssithra_frames_idleright1, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra melee - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_melee1 [] = +{ + FRAME_melee1, ssithraSound, SND_SWIPE, CHAN_WEAPON, 0, ai_charge2, 20, NULL, + FRAME_melee2, NULL, 0, 0, 0, ai_charge2, 10, NULL, + FRAME_melee3, NULL, 0, 0, 0, ai_charge2, 8, NULL, + FRAME_melee4, NULL, 0, 0, 0, ai_charge2, 6, NULL, + FRAME_melee5, NULL, 0, 0, 0, ai_charge2, 4, ssithraSwipe, + FRAME_melee6, NULL, 0, 0, 0, ai_charge2, 3, NULL, + FRAME_melee7, NULL, 0, 0, 0, ai_charge2, 3, NULL, +}; +animmove_t ssithra_move_melee1 = {7, ssithra_frames_melee1, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra melee - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_meleest [] = +{ + FRAME_Melee_stand1, ssithraSound, SND_SWIPE, CHAN_WEAPON, 0, NULL, 0, NULL, + FRAME_Melee_stand2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_Melee_stand3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_Melee_stand4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_Melee_stand5, NULL, 0, 0, 0, ai_charge2, 0, ssithraSwipe, + FRAME_Melee_stand6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_Melee_stand7, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t ssithra_move_meleest = {7, ssithra_frames_meleest, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra namor - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_namor1 [] = +{ + FRAME_namor1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_namor2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_namor3, NULL, 0, 0, 0, NULL, 0, ssithraNamorJump, + FRAME_namor4, NULL, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor5, NULL, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor6, NULL, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor7, NULL, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor8, NULL, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor9, NULL, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor10, NULL, 0, 0, 0, ssithraForward, 120, ssithraCheckLeaveWaterSplash, + FRAME_namor11, NULL, 0, 0, 0, ssithraForward, 130, ssithraCheckLeaveWaterSplash, + FRAME_namor12, NULL, 0, 0, 0, ssithraForward, 140, ssithraCheckLeaveWaterSplash, + FRAME_namor13, NULL, 0, 0, 0, ssithraForward, 150, ssithraCheckLeaveWaterSplash, + FRAME_namor14, NULL, 0, 0, 0, ssithraForward, 160, ssithraCheckLeaveWaterSplash, + FRAME_namor15, NULL, 0, 0, 0, ssithraForward, 170, ssithraCheckLeaveWaterSplash, + FRAME_namor16, NULL, 0, 0, 0, ssithraForward, 180, ssithraCheckLeaveWaterSplash, + FRAME_namor17, NULL, 0, 0, 0, ssithraForward, 190, ssithraCheckLeaveWaterSplash, + FRAME_namor18, NULL, 0, 0, 0, ssithraForward, 200, ssithraCheckLeaveWaterSplash,//fixme- check to make sure out of water + FRAME_namor19, NULL, 0, 0, 0, ssithraForward, 200, ssithraCheckLeaveWaterSplash, + FRAME_namor20, NULL, 0, 0, 0, ssithraForward, 200, ssithraCheckLeaveWaterSplash, + FRAME_namor21, NULL, 0, 0, 0, ssithraForward, 200, ssithraCheckLeaveWaterSplash, + FRAME_namor22, NULL, 0, 0, 0, ssithraForward, 200, ssithraCheckLeaveWaterSplash, + FRAME_namor23, NULL, 0, 0, 0, ssithraForward, 180, ssithraCheckLeaveWaterSplash, + FRAME_namor24, NULL, 0, 0, 0, ssithraForward, 120, ssithraCheckLeaveWaterSplash, + FRAME_namor25, NULL, 0, 0, 0, ssithraForward, 60, ssithraCheckLeaveWaterSplash, +}; +animmove_t ssithra_move_namor1 = {25, ssithra_frames_namor1, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra pain_a - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_pain_a1 [] = +{ + FRAME_pain_a1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain_a2, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_pain_a1 = {2, ssithra_frames_pain_a1, ssithra_pain_react}; + +/*---------------------------------------------------------------------- + Ssithra shoot +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_shoot1 [] = +{ + FRAME_shoot1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot6, NULL, 0, 0, 0, ai_charge2, 0, ssithraArrow, + FRAME_shoot6, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckLoop, + FRAME_shoot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, +};//7 - 11 not used- weird anim for turning while shooting only! +animmove_t ssithra_move_shoot1 = {8, ssithra_frames_shoot1, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra lunge from shooting +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_lunge [] = +{ + FRAME_shoot12, NULL, 0, 0, 0, ai_charge2, 0, ssithraApplyJump, + FRAME_shoot13, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot14, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot15, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot16, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot17, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot18, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot19, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot20, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot21, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t ssithra_move_lunge = {10, ssithra_frames_lunge, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra startle - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_startle1 [] = +{ + FRAME_startle2, ssithraSound, SND_GROWL3, CHAN_VOICE, ATTN_IDLE, ai_stand, 0, ssithraGrowlSound, + FRAME_startle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle20, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle21, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle22, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle23, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle24, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle25, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle26, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle27, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle28, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle29, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle30, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle31, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle32, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle33, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle34, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle35, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle36, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle37, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle38, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_startle39, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t ssithra_move_startle1 = {38, ssithra_frames_startle1, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra startle - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_spinleft_go [] = +{ + FRAME_idlebasic41, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_spinleft_go = {1, ssithra_frames_spinleft_go, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra startle - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_spinleft [] = +{ + FRAME_idlebasic41, ssithraSound, SND_GROWL1, CHAN_VOICE, ATTN_IDLE, NULL, 0, NULL, + FRAME_idlebasic42, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic43, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic44, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic45, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic46, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic47, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic48, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic49, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic50, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic51, NULL, 0, 0, 0, ai_spin, 6, NULL, + FRAME_idlebasic52, NULL, 0, 0, 0, ai_spin, 9, NULL, + FRAME_idlebasic53, NULL, 0, 0, 0, ai_spin, 13, NULL, + FRAME_idlebasic54, NULL, 0, 0, 0, ai_spin, 16, NULL, + FRAME_idlebasic55, NULL, 0, 0, 0, ai_spin, 18, NULL, + FRAME_idlebasic56, NULL, 0, 0, 0, ai_spin, 20, NULL, + FRAME_idlebasic57, NULL, 0, 0, 0, ai_spin, 23, NULL, + FRAME_idlebasic58, NULL, 0, 0, 0, ai_spin, 27, NULL, + FRAME_idlebasic59, NULL, 0, 0, 0, ai_spin, 30, NULL, + FRAME_idlebasic60, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_spinleft = {20, ssithra_frames_spinleft, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra startle - turn left as you aniimate turn around +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_spinright_go [] = +{ + FRAME_idlebasic41, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_spinright_go = {1, ssithra_frames_spinright_go, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra startle - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_spinright [] = +{ + FRAME_idlebasic61, ssithraSound, SND_GROWL1, CHAN_VOICE, ATTN_IDLE, NULL, 0, NULL, + FRAME_idlebasic62, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic63, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic64, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic65, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic66, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic67, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic68, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic69, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic70, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic71, NULL, 0, 0, 0, ai_spin, -6, NULL, + FRAME_idlebasic72, NULL, 0, 0, 0, ai_spin, -9, NULL, + FRAME_idlebasic73, NULL, 0, 0, 0, ai_spin, -13, NULL, + FRAME_idlebasic74, NULL, 0, 0, 0, ai_spin, -16, NULL, + FRAME_idlebasic75, NULL, 0, 0, 0, ai_spin, -18, NULL, + FRAME_idlebasic76, NULL, 0, 0, 0, ai_spin, -20, NULL, + FRAME_idlebasic77, NULL, 0, 0, 0, ai_spin, -23, NULL, + FRAME_idlebasic78, NULL, 0, 0, 0, ai_spin, -27, NULL, + FRAME_idlebasic79, NULL, 0, 0, 0, ai_spin, -30, NULL, + FRAME_idlebasic80, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_spinright = {20, ssithra_frames_spinright, ssithra_decide_gallop}; + + +/*---------------------------------------------------------------------- + Ssithra swimforward - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_swimforward1 [] = +{ + FRAME_swimforward01, NULL, 0, 0, 0, ssithra_ai_run, 10, ssithraCheckRipple, + FRAME_swimforward02, NULL, 0, 0, 0, ssithra_ai_run, 10, NULL, + FRAME_swimforward03, NULL, 0, 0, 0, ssithra_ai_run, 10, ssithraCheckRipple, + FRAME_swimforward04, ssithraSound, SND_SWIM, CHAN_BODY, 0, ssithra_ai_run, 12, ssithra_check_namor, + FRAME_swimforward05, NULL, 0, 0, 0, ssithra_ai_run, 12, ssithraCheckRipple, + FRAME_swimforward06, NULL, 0, 0, 0, ssithra_ai_run, 12, ssithraCheckRipple, + FRAME_swimforward07, NULL, 0, 0, 0, ssithra_ai_run, 12, ssithraCheckRipple, + FRAME_swimforward08, NULL, 0, 0, 0, ssithra_ai_run, 12, ssithra_check_namor, + FRAME_swimforward09, NULL, 0, 0, 0, ssithra_ai_run, 16, ssithraCheckRipple, + FRAME_swimforward10, ssithraSound, SND_SWIM, CHAN_BODY, 0, ssithra_ai_run, 16, NULL, + FRAME_swimforward11, NULL, 0, 0, 0, ssithra_ai_run, 12, ssithraCheckRipple, + FRAME_swimforward12, NULL, 0, 0, 0, ssithra_ai_run, 12, ssithra_check_namor, + FRAME_swimforward13, NULL, 0, 0, 0, ssithra_ai_run, 12, ssithraCheckRipple, + FRAME_swimforward14, NULL, 0, 0, 0, ssithra_ai_run, 10, ssithraCheckRipple, + FRAME_swimforward15, NULL, 0, 0, 0, ssithra_ai_run, 10, ssithraCheckRipple, +}; +animmove_t ssithra_move_swimforward1 = {15, ssithra_frames_swimforward1, ssithra_decide_swimforward}; + +/*---------------------------------------------------------------------- + Ssithra swimwander - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_swimwander [] = +{ + FRAME_swimforward01, NULL, 0, 0, 0, ai_walk, 10, ssithraCheckRipple, + FRAME_swimforward02, NULL, 0, 0, 0, ai_walk, 10, ssithraCheckRipple, + FRAME_swimforward03, NULL, 0, 0, 0, ai_walk, 10, ssithraCheckRipple, + FRAME_swimforward04, ssithraSound, SND_SWIM, CHAN_BODY, 0, ai_walk, 12, ssithra_check_namor, + FRAME_swimforward05, NULL, 0, 0, 0, ai_walk, 12, ssithraCheckRipple, + FRAME_swimforward06, NULL, 0, 0, 0, ai_walk, 12, ssithraCheckRipple, + FRAME_swimforward07, NULL, 0, 0, 0, ai_walk, 12, ssithraCheckRipple, + FRAME_swimforward08, NULL, 0, 0, 0, ai_walk, 12, ssithra_check_namor, + FRAME_swimforward09, NULL, 0, 0, 0, ai_walk, 16, ssithraCheckRipple, + FRAME_swimforward10, ssithraSound, SND_SWIM, CHAN_BODY, 0, ai_walk, 16, NULL, + FRAME_swimforward11, NULL, 0, 0, 0, ai_walk, 12, ssithraCheckRipple, + FRAME_swimforward12, NULL, 0, 0, 0, ai_walk, 12, ssithra_check_namor, + FRAME_swimforward13, NULL, 0, 0, 0, ai_walk, 12, ssithraCheckRipple, + FRAME_swimforward14, NULL, 0, 0, 0, ai_walk, 10, ssithraCheckRipple, + FRAME_swimforward15, NULL, 0, 0, 0, ai_walk, 10, ssithraCheckRipple, +}; +animmove_t ssithra_move_swimwander = {15, ssithra_frames_swimwander, ssithra_decide_swimforward}; + +/*---------------------------------------------------------------------- + Ssithra water_death - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_water_death1 [] = +{ + FRAME_water_death1, ssithraSound, SND_DIE, CHAN_VOICE, 0, NULL, 0, NULL, + FRAME_water_death2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death32, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death33, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death34, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death35, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death36, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death37, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death38, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death39, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death40, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death41, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death42, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death43, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death44, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death45, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death46, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death47, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death48, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death49, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t ssithra_move_water_death1 = {49, ssithra_frames_water_death1, ssithraWaterDead}; + +/*---------------------------------------------------------------------- + Ssithra water_idle - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_water_idle1 [] = +{//water idle sound? + FRAME_water_idle1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_water_idle20, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t ssithra_move_water_idle1 = {20, ssithra_frames_water_idle1, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra water_pain_a - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_water_pain_a1 [] = +{ + FRAME_water_pain_a1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_pain_a2, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_water_pain_a1 = {2, ssithra_frames_water_pain_a1, ssithra_pain_react}; + +/*---------------------------------------------------------------------- + Ssithra water_pain_b - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_water_pain_b1 [] = +{ + FRAME_water_pain_b1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_water_pain_b2, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_water_pain_b1 = {2, ssithra_frames_water_pain_b1, ssithra_pain_react}; + +/*---------------------------------------------------------------------- + Ssithra water_shoot - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_water_shoot1 [] = +{ + FRAME_water_shoot01, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot6, NULL, 0, 0, 0, ai_charge2, 0, ssithraArrow, + FRAME_water_shoot7, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot8, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot9, NULL, 0, 0, 0, ai_charge2, 0, ssithraArrow, + FRAME_water_shoot10, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot11, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot12, NULL, 0, 0, 0, ai_charge2, 0, ssithraArrow, + FRAME_water_shoot13, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot14, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot15, NULL, 0, 0, 0, ai_charge2, 0, ssithraArrow, + FRAME_water_shoot16, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_water_shoot17, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t ssithra_move_water_shoot1 = {17, ssithra_frames_water_shoot1, ssithra_decide_swimforward}; + +animframe_t ssithra_frames_run1 [] = +{ + FRAME_run1, NULL, 0, 0, 0, ssithra_ai_run, 16, ssithraBoundCheck, + FRAME_run2, NULL, 0, 0, 0, ssithra_ai_run, 18, ssithraDiveCheck, + FRAME_run3, NULL, 0, 0, 0, ssithra_ai_run, 20, NULL, + FRAME_run4, NULL, 0, 0, 0, ssithra_ai_run, 18, NULL, + FRAME_run5, NULL, 0, 0, 0, ssithra_ai_run, 16, NULL, + FRAME_run6, NULL, 0, 0, 0, ssithra_ai_run, 18, NULL, + FRAME_run7, NULL, 0, 0, 0, ssithra_ai_run, 20, NULL, + FRAME_run8, NULL, 0, 0, 0, ssithra_ai_run, 18, NULL, +}; +animmove_t ssithra_move_run1 = {8, ssithra_frames_run1, ssithra_decide_gallop}; + +/*---------------------------------------------------------------------- + Ssithra face and namor +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_faceandnamor [] = +{ + FRAME_water_idle1, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle2, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle3, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle4, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle5, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle6, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle7, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle8, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle9, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle10, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle11, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle12, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle13, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle14, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle15, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle16, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle17, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle18, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle19, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, + FRAME_water_idle20, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckFacedNamor, +}; +animmove_t ssithra_move_faceandnamor = {20, ssithra_frames_faceandnamor, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra look left +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_lookleft [] = +{ + FRAME_idlebasic41, ssithraSound, SND_GROWL1, CHAN_VOICE, ATTN_IDLE, ai_stand, 0, NULL, + FRAME_idlebasic42, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic43, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic44, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic45, ssithraVOfs, 20, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic46, ssithraVOfs, 40, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic47, ssithraVOfs, 60, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic48, ssithraVOfs, 80, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic49, ssithraVOfs, 100, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic50, ssithraVOfs, 120, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic51, ssithraVOfs, 160, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic52, ssithraVOfs, 120, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic53, ssithraVOfs, 80, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic54, ssithraVOfs, 60, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic55, ssithraVOfs, 40, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic56, ssithraVOfs, 20, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic57, ssithraVOfs, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic58, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic59, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic60, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t ssithra_move_lookleft = {20, ssithra_frames_lookleft, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra look right +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_lookright [] = +{ + FRAME_idlebasic61, ssithraSound, SND_GROWL1, CHAN_VOICE, ATTN_IDLE, ai_stand, 0, NULL, + FRAME_idlebasic62, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic63, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic64, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic65, ssithraVOfs, -20, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic66, ssithraVOfs, -40, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic67, ssithraVOfs, -60, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic68, ssithraVOfs, -80, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic69, ssithraVOfs, -100, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic70, ssithraVOfs, -120, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic71, ssithraVOfs, -160, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic72, ssithraVOfs, -120, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic73, ssithraVOfs, -80, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic74, ssithraVOfs, -60, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic75, ssithraVOfs, -40, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic76, ssithraVOfs, -20, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic77, ssithraVOfs, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic78, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic79, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idlebasic80, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t ssithra_move_lookright = {20, ssithra_frames_lookright, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra trans up +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_transup [] = +{ + FRAME_Water_trans1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Water_trans2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Water_trans3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Water_trans4, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_transup = {4, ssithra_frames_transup, ssithra_water_shoot}; + +/*---------------------------------------------------------------------- + Ssithra trans down +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_transdown [] = +{ + FRAME_Water_trans4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Water_trans3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Water_trans2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_Water_trans1, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_transdown = {4, ssithra_frames_transdown, ssithra_decide_swimforward}; + +/* +Headless +*/ + +/*---------------------------------------------------------------------- + Ssithra death_b - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_death_c [] = +{ + FRAME_shoot5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b11, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_death_b12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b32, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b33, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b34, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b35, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b36, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_death_c = {41, ssithra_frames_death_c, ssithra_dead}; + +animframe_t ssithra_frames_headlessloop [] = +{ + FRAME_shoot8, NULL, 0, 0, 0, ai_spin, -5, NULL, + FRAME_shoot9, NULL, 0, 0, 0, ai_spin, -4, ssithraPanicArrow, + FRAME_shoot10, NULL, 0, 0, 0, ai_spin, -2, NULL, + FRAME_shoot11, NULL, 0, 0, 0, ai_spin, -2, NULL, + FRAME_shoot12, NULL, 0, 0, 0, ai_spin, -3, NULL, + FRAME_shoot13, NULL, 0, 0, 0, ai_spin, -4, NULL, +}; +animmove_t ssithra_move_headlessloop = {6, ssithra_frames_headlessloop, ssithraCollapse}; + +animframe_t ssithra_frames_headless [] = +{ + FRAME_shoot1, NULL, 0, 0, 0, ai_spin, -20, NULL, + FRAME_shoot2, NULL, 0, 0, 0, ai_spin, -12, NULL, + FRAME_shoot3, NULL, 0, 0, 0, ai_spin, -10, NULL, + FRAME_shoot4, NULL, 0, 0, 0, ai_spin, -9, NULL, + FRAME_shoot5, NULL, 0, 0, 0, ai_spin, -8, NULL, + FRAME_shoot6, NULL, 0, 0, 0, ai_spin, -7, ssithraPanicArrow, + FRAME_shoot7, NULL, 0, 0, 0, ai_spin, -7, NULL, + FRAME_shoot8, NULL, 0, 0, 0, ai_spin, -7, ssithraPanicArrow, + FRAME_shoot9, NULL, 0, 0, 0, ai_spin, -6, NULL, + FRAME_shoot10, NULL, 0, 0, 0, ai_spin, -6, NULL, + FRAME_shoot11, NULL, 0, 0, 0, ai_spin, -6, NULL, + FRAME_shoot12, NULL, 0, 0, 0, ai_spin, -5, NULL, + FRAME_shoot13, NULL, 0, 0, 0, ai_spin, -5, NULL, +}; +animmove_t ssithra_move_headless = {13, ssithra_frames_headless, ssithraCollapse}; + +/*---------------------------------------------------------------------- + Ssithra dead +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_dead_a [] = +{ + FRAME_death_a12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_dead_a = {1, ssithra_frames_dead_a, NULL}; + +animframe_t ssithra_frames_dead_b [] = +{ + FRAME_death_b36, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_dead_b = {1, ssithra_frames_dead_b, NULL}; + +animframe_t ssithra_frames_dead_water [] = +{ + FRAME_water_death49, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_dead_water = {1, ssithra_frames_dead_water, NULL}; + +/*---------------------------------------------------------------------- + Ssithra sliced +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_sliced [] = +{ + FRAME_death_b1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b11, NULL, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_death_b12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b32, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b33, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b34, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b35, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b36, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_sliced = {36, ssithra_frames_sliced, ssithraKillSelf}; + + +/*---------------------------------------------------------------------- + Ssithra delay - stop and look around +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_delay [] = +{ + FRAME_startle2, ssithraSound, SND_GROWL3, CHAN_VOICE, ATTN_IDLE, NULL, 0, SsithraCheckMood, + FRAME_startle3, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle4, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle5, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle6, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle7, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle8, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle9, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle10, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle11, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle12, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle13, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle14, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle15, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle16, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle17, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle18, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle19, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle20, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle21, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle22, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle23, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle24, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle25, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle26, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle27, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle28, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle29, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle30, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle31, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle32, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle33, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle34, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle35, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle36, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle37, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle38, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, + FRAME_startle39, NULL, 0, 0, 0, NULL, 0, SsithraCheckMood, +}; +animmove_t ssithra_move_delay = {38, ssithra_frames_delay, SsithraCheckMood}; + +/*---------------------------------------------------------------------- + Ssithra Idle - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_idle1 [] = +{ + FRAME_idle01, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle02, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle03, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle04, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle05, ai_c_move, 0, 0, 0, NULL, 0, ssithraGrowlSound, + FRAME_idle06, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle07, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle08, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle09, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle16, ai_c_move, 0, 0, 0, NULL, 0, ssithraGrowlSound, + FRAME_idle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle28, ai_c_move, 0, 0, 0, NULL, 0, ssithraGrowlSound, + FRAME_idle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle40, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t ssithra_c_move_idle1 = {40, ssithra_c_frames_idle1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra Walk - walking along +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_walk1 [] = +{ + FRAME_walk1, ai_c_move, 0, 0, 0, NULL, 2, NULL, + FRAME_walk2, ai_c_move, 0, 0, 0, NULL, 3, NULL, + FRAME_walk3, ai_c_move, 0, 0, 0, NULL, 3, NULL, + FRAME_walk4, ai_c_move, 0, 0, 0, NULL, 3, NULL, + FRAME_walk5, ai_c_move, 0, 0, 0, NULL, 2, NULL, + FRAME_walk6, ai_c_move, 0, 0, 0, NULL, 2, NULL, + FRAME_walk7, ai_c_move, 0, 0, 0, NULL, 2, ssithraGrowlSound, + FRAME_walk8, ai_c_move, 0, 0, 0, NULL, 3, NULL, + FRAME_walk9, ai_c_move, 0, 0, 0, NULL, 3, NULL, + FRAME_walk10, ai_c_move, 0, 0, 0, NULL, 3, NULL, + FRAME_walk11, ai_c_move, 0, 0, 0, NULL, 3, NULL, + FRAME_walk12, ai_c_move, 0, 0, 0, NULL, 3, NULL, + FRAME_walk13, ai_c_move, 0, 0, 0, NULL, 2, NULL, + FRAME_walk14, ai_c_move, 0, 0, 0, NULL, 2, NULL +}; +animmove_t ssithra_c_move_walk1 = {14, ssithra_c_frames_walk1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra backpedal - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_backpedal1 [] = +{ + FRAME_backpedal1, ai_c_move, -5, 0, 0, NULL, 0, NULL, + FRAME_backpedal2, ai_c_move, -5, 0, 0, NULL, 0, NULL, + FRAME_backpedal3, ai_c_move, -5, 0, 0, NULL, 0, ssithraArrow, + FRAME_backpedal4, ai_c_move, -7, 0, 0, NULL, 0, NULL, + FRAME_backpedal5, ai_c_move, -7, 0, 0, NULL, 0, NULL, + FRAME_backpedal6, ai_c_move, -7, 0, 0, NULL, 0, NULL, + FRAME_backpedal7, ai_c_move, -7, 0, 0, NULL, 0, ssithraArrow, + FRAME_backpedal8, ai_c_move, -5, 0, 0, NULL, 0, NULL, + FRAME_backpedal9, ai_c_move, -5, 0, 0, NULL, 0, NULL, + FRAME_backpedal10, ai_c_move, -5, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_backpedal1 = {10, ssithra_c_frames_backpedal1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Ssithra bound - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action1 [] = +{ + FRAME_bound09, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_bound10, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_bound11, ai_c_move, 20, 0, 0, NULL, 0, NULL, + FRAME_bound12, ai_c_move, 20, 0, 0, NULL, 0, NULL, + FRAME_bound13, ai_c_move, 24, 0, 0, NULL, 0, NULL, + FRAME_bound14, ai_c_move, 20, 0, 0, NULL, 0, NULL, + FRAME_bound15, ai_c_move, 16, 0, 0, NULL, 0, NULL, + FRAME_bound16, ai_c_move, 12, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action1 = {8, ssithra_c_frames_action1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra death_a +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_death2 [] = +{ + FRAME_death_a1, ssithraSound, SND_DIE, CHAN_VOICE, 0, NULL, 0, NULL, + FRAME_death_a2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a4, ai_c_move, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_death_a5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a10,ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a11,ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_a12,ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_death2 = {12, ssithra_c_frames_death2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra death_b - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_death3 [] = +{ + FRAME_death_b1, ssithraSound, SND_DIE, CHAN_VOICE, 0, NULL, 0, NULL, + FRAME_death_b2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b11, ai_c_move, 0, 0, 0, NULL, 0, MG_NoBlocking, + FRAME_death_b12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_death_b36, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_death3 = {36, ssithra_c_frames_death3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra dive - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action2 [] = +{ + FRAME_dive1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_dive2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_dive3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_dive4, ssithraJump, 400, 100, 0, NULL, 0, NULL, + FRAME_dive5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_dive6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_dive7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_dive8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_dive9, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive10, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive11, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive12, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive13, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive14, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive15, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive16, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive17, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash, + FRAME_dive18, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckHitWaterSplash,//fixme- check to make sure hit water + FRAME_dive19, ai_c_move, 0, 0, 0, ai_move , 22, ssithraCheckHitWaterSplash,//in water, go forward + FRAME_dive20, ai_c_move, 0, 0, 0, ai_move , 20, ssithraCheckHitWaterSplash, + FRAME_dive21, ai_c_move, 0, 0, 0, ai_move , 17, ssithraCheckHitWaterSplash, + FRAME_dive22, ai_c_move, 0, 0, 0, ai_move , 15, ssithraCheckHitWaterSplash, + FRAME_dive23, ai_c_move, 0, 0, 0, ai_move , 12, ssithraCheckHitWaterSplash, + FRAME_dive24, ai_c_move, 0, 0, 0, ai_move , 9, ssithraCheckHitWaterSplash, + FRAME_dive25, ai_c_move, 0, 0, 0, ai_move , 6, ssithraCheckHitWaterSplash, + FRAME_dive26, ai_c_move, 0, 0, 0, ai_move , 3, ssithraCheckHitWaterSplash, +}; +animmove_t ssithra_c_move_action2 = {26, ssithra_c_frames_action2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra duckshoot +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action3 [] = +{ + FRAME_duckshoot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot2, ai_c_move, 0, 0, 0, NULL, 0, ssithraUnCrouch, + FRAME_duckshoot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action3 = {3, ssithra_c_frames_action3, ai_c_cycleend}; + +animframe_t ssithra_c_frames_action4 [] = +{ + FRAME_duckshoot6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action4 = {1, ssithra_c_frames_action4, ai_c_cycleend}; + +animframe_t ssithra_c_frames_action5 [] = +{ + FRAME_duckshoot1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot5, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckDuckArrow, + FRAME_duckshoot6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action5 = {6, ssithra_c_frames_action5, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra duck +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action6 [] = +{//oops, duckframes same as duckshoot? + FRAME_duckshoot1, ssithraSound, SND_GROWL3, CHAN_VOICE, ATTN_IDLE, NULL, 0, NULL, + FRAME_duckshoot2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_duckshoot6, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action6 = {6, ssithra_c_frames_action6, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra gallop - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_run1 [] = +{ + FRAME_gallop1, ai_c_move, 20, 0, 0, NULL, 0, NULL, + FRAME_gallop2, ai_c_move, 24, 0, 0, NULL, 0, NULL, + FRAME_gallop3, ai_c_move, 32, 0, 0, NULL, 0, NULL, + FRAME_gallop4, ai_c_move, 30, 0, 0, NULL, 0, NULL, + FRAME_gallop5, ai_c_move, 28, 0, 0, NULL, 0, NULL, + FRAME_gallop6, ai_c_move, 26, 0, 0, NULL, 0, NULL, + FRAME_gallop7, ai_c_move, 24, 0, 0, NULL, 0, NULL, + FRAME_gallop8, ai_c_move, 22, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_run1 = {8, ssithra_c_frames_run1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra jump from buoy +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action7[] = +{ + FRAME_bound09, ai_c_move, 0, 0, 0, NULL, 0, ssithraApplyJump, + FRAME_bound10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bound11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bound12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bound13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bound14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bound15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_bound16, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action7 = {8, ssithra_c_frames_action7, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra idle2 - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_idle2 [] = +{ + FRAME_idlebasic01, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic02, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic03, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic04, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic05, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic06, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic07, ai_c_move, 0, 0, 0, NULL, 0, ssithraGrowlSound, + FRAME_idlebasic08, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic09, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic19, ai_c_move, 0, 0, 0, NULL, 0, ssithraGrowlSound, + FRAME_idlebasic20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic30, ai_c_move, 0, 0, 0, NULL, 0, ssithraGrowlSound, + FRAME_idlebasic31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic40, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_idle2 = {40, ssithra_c_frames_idle2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra idle3 - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_idle3 [] = +{ + FRAME_idleright01, ssithraSound, SND_GROWL2, CHAN_VOICE, ATTN_IDLE, NULL, 0, NULL, + FRAME_idleright02, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright03, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright04, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright05, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright06, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright07, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright08, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright09, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright10, ai_c_move, 0, 0, 0, NULL, 0, NULL,//ssithraPanicArrow, + FRAME_idleright10, ai_c_move, 0, 0, 0, NULL, 0, NULL,//keep looking here a bit + FRAME_idleright10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idleright20, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_idle3 = {24, ssithra_c_frames_idle3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra attack1 - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_attack1 [] = +{ + FRAME_melee1, ai_c_move, 20, 0, 0, NULL, 0, NULL, + FRAME_melee2, ai_c_move, 10, 0, 0, NULL, 0, NULL, + FRAME_melee3, ai_c_move, 8, 0, 0, NULL, 0, NULL, + FRAME_melee4, ai_c_move, 6, 0, 0, NULL, 0, NULL, + FRAME_melee5, ai_c_move, 4, 0, 0, NULL, 0, ssithraSwipe, + FRAME_melee6, ai_c_move, 3, 0, 0, NULL, 0, NULL, + FRAME_melee7, ai_c_move, 3, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_attack1 = {7, ssithra_c_frames_attack1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra melee - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_attack2 [] = +{ + FRAME_Melee_stand1, ssithraSound, SND_SWIPE, CHAN_WEAPON, 0, NULL, 0, NULL, + FRAME_Melee_stand2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Melee_stand3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Melee_stand4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Melee_stand5, ai_c_move, 0, 0, 0, NULL, 0, ssithraSwipe, + FRAME_Melee_stand6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_Melee_stand7, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_attack2 = {7, ssithra_c_frames_attack2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra namor - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action8 [] = +{ + FRAME_namor1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_namor2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_namor3, ai_c_move, 0, 0, 0, NULL, 0, ssithraNamorJump, + FRAME_namor4, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor5, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor6, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor7, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor8, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor9, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor10, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor11, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor12, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor13, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor14, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor15, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor16, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor17, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor18, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor19, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor20, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor21, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor22, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor23, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor24, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, + FRAME_namor25, ai_c_move, 0, 0, 0, NULL, 0, ssithraCheckLeaveWaterSplash, +}; +animmove_t ssithra_c_move_action8 = {25, ssithra_c_frames_action8, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra pain_a - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_pain1 [] = +{ + FRAME_pain_a1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_pain_a2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_pain1 = {2, ssithra_c_frames_pain1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra shoot +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_attack3 [] = +{ + FRAME_shoot1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_shoot6, NULL, 0, 0, 0, ai_charge2, 0, ssithraArrow, + FRAME_shoot6, NULL, 0, 0, 0, ai_charge2, 0, ssithraCheckLoop, + FRAME_shoot5, NULL, 0, 0, 0, ai_charge2, 0, NULL, +}; +animmove_t ssithra_c_move_attack3 = {8, ssithra_c_frames_attack3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra lunge from shooting +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action9 [] = +{ + FRAME_shoot12, ai_c_move, 0, 0, 0, NULL, 0, ssithraApplyJump, + FRAME_shoot13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_shoot21, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action9 = {10, ssithra_c_frames_action9, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra startle - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action10 [] = +{ + FRAME_startle2, ssithraSound, SND_GROWL3, CHAN_VOICE, ATTN_IDLE, NULL, 0, NULL, + FRAME_startle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_startle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action10 = {38, ssithra_c_frames_action10, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra startle - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action11 [] = +{ + FRAME_idlebasic41, ssithraSound, SND_GROWL1, CHAN_VOICE, ATTN_IDLE, NULL, 0, NULL, + FRAME_idlebasic42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic60, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action11 = {20, ssithra_c_frames_action11, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra startle - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_action12 [] = +{ + FRAME_idlebasic61, ssithraSound, SND_GROWL1, CHAN_VOICE, ATTN_IDLE, NULL, 0, NULL, + FRAME_idlebasic62, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic63, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic64, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic65, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic66, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic67, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic68, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic69, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic70, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic71, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic72, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic73, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic74, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic75, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic76, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic77, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic78, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic79, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idlebasic80, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_action12 = {20, ssithra_c_frames_action12, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + Ssithra swimforward - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_swim1 [] = +{ + FRAME_swimforward01, ai_c_move, 16, 0, 0, NULL, 16, ssithraCheckRipple, + FRAME_swimforward02, ai_c_move, 16, 0, 0, NULL, 16, NULL, + FRAME_swimforward03, ai_c_move, 16, 0, 0, NULL, 16, ssithraCheckRipple, + FRAME_swimforward04, ssithraSound, SND_SWIM, CHAN_BODY, 0, NULL, 20, ssithra_check_namor, + FRAME_swimforward05, ai_c_move, 20, 0, 0, NULL, 20, ssithraCheckRipple, + FRAME_swimforward06, ai_c_move, 20, 0, 0, NULL, 20, ssithraCheckRipple, + FRAME_swimforward07, ai_c_move, 20, 0, 0, NULL, 20, ssithraCheckRipple, + FRAME_swimforward08, ai_c_move, 24, 0, 0, NULL, 24, ssithra_check_namor, + FRAME_swimforward09, ai_c_move, 24, 0, 0, NULL, 24, ssithraCheckRipple, + FRAME_swimforward10, ssithraSound, SND_SWIM, CHAN_BODY, 0, NULL, 24, NULL, + FRAME_swimforward11, ai_c_move, 20, 0, 0, NULL, 20, ssithraCheckRipple, + FRAME_swimforward12, ai_c_move, 20, 0, 0, NULL, 20, ssithra_check_namor, + FRAME_swimforward13, ai_c_move, 20, 0, 0, NULL, 20, ssithraCheckRipple, + FRAME_swimforward14, ai_c_move, 16, 0, 0, NULL, 16, ssithraCheckRipple, + FRAME_swimforward15, ai_c_move, 16, 0, 0, NULL, 16, ssithraCheckRipple, +}; +animmove_t ssithra_c_move_swim1 = {15, ssithra_c_frames_swim1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra water_death - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_death1 [] = +{ + FRAME_water_death1, ssithraSound, SND_DIE, CHAN_VOICE, 0, NULL, 0, NULL, + FRAME_water_death2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_death49, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t ssithra_c_move_death1 = {49, ssithra_c_frames_death1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra water_idle - looking around and standing +-----------------------------------------------------------------------*/ +animframe_t ssithra_frames_idle4 [] = +{//water idle sound? + FRAME_water_idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_idle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_move_idle4 = {20, ssithra_frames_idle4, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra water_pain_a - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_pain2 [] = +{ + FRAME_water_pain_a1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_pain_a2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_pain2 = {2, ssithra_c_frames_pain2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + Ssithra water_pain_b - +-----------------------------------------------------------------------*/ +animframe_t ssithra_c_frames_pain3 [] = +{ + FRAME_water_pain_b1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_water_pain_b2, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t ssithra_c_move_pain3 = {2, ssithra_c_frames_pain3, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/m_plaguessithra_anim.h b/Toolkit/Programming/GameCode/game/m_plaguessithra_anim.h new file mode 100644 index 0000000..c3b31f0 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_plaguessithra_anim.h @@ -0,0 +1,504 @@ +// R:\Art\models/monsters\ssithra + +// This file generated by qdata - Do NOT Modify + +#define FRAME_Part_fly1 0 +#define FRAME_partrest1 1 +#define FRAME_backpedal1 2 +#define FRAME_backpedal2 3 +#define FRAME_backpedal3 4 +#define FRAME_backpedal4 5 +#define FRAME_backpedal5 6 +#define FRAME_backpedal6 7 +#define FRAME_backpedal7 8 +#define FRAME_backpedal8 9 +#define FRAME_backpedal9 10 +#define FRAME_backpedal10 11 +#define FRAME_bound09 12 +#define FRAME_bound10 13 +#define FRAME_bound11 14 +#define FRAME_bound12 15 +#define FRAME_bound13 16 +#define FRAME_bound14 17 +#define FRAME_bound15 18 +#define FRAME_bound16 19 +#define FRAME_death_a1 20 +#define FRAME_death_a2 21 +#define FRAME_death_a3 22 +#define FRAME_death_a4 23 +#define FRAME_death_a5 24 +#define FRAME_death_a6 25 +#define FRAME_death_a7 26 +#define FRAME_death_a8 27 +#define FRAME_death_a9 28 +#define FRAME_death_a10 29 +#define FRAME_death_a11 30 +#define FRAME_death_a12 31 +#define FRAME_death_b1 32 +#define FRAME_death_b2 33 +#define FRAME_death_b3 34 +#define FRAME_death_b4 35 +#define FRAME_death_b5 36 +#define FRAME_death_b6 37 +#define FRAME_death_b7 38 +#define FRAME_death_b8 39 +#define FRAME_death_b9 40 +#define FRAME_death_b10 41 +#define FRAME_death_b11 42 +#define FRAME_death_b12 43 +#define FRAME_death_b13 44 +#define FRAME_death_b14 45 +#define FRAME_death_b15 46 +#define FRAME_death_b16 47 +#define FRAME_death_b17 48 +#define FRAME_death_b18 49 +#define FRAME_death_b19 50 +#define FRAME_death_b20 51 +#define FRAME_death_b21 52 +#define FRAME_death_b22 53 +#define FRAME_death_b23 54 +#define FRAME_death_b24 55 +#define FRAME_death_b25 56 +#define FRAME_death_b26 57 +#define FRAME_death_b27 58 +#define FRAME_death_b28 59 +#define FRAME_death_b29 60 +#define FRAME_death_b30 61 +#define FRAME_death_b31 62 +#define FRAME_death_b32 63 +#define FRAME_death_b33 64 +#define FRAME_death_b34 65 +#define FRAME_death_b35 66 +#define FRAME_death_b36 67 +#define FRAME_dive1 68 +#define FRAME_dive2 69 +#define FRAME_dive3 70 +#define FRAME_dive4 71 +#define FRAME_dive5 72 +#define FRAME_dive6 73 +#define FRAME_dive7 74 +#define FRAME_dive8 75 +#define FRAME_dive9 76 +#define FRAME_dive10 77 +#define FRAME_dive11 78 +#define FRAME_dive12 79 +#define FRAME_dive13 80 +#define FRAME_dive14 81 +#define FRAME_dive15 82 +#define FRAME_dive16 83 +#define FRAME_dive17 84 +#define FRAME_dive18 85 +#define FRAME_dive19 86 +#define FRAME_dive20 87 +#define FRAME_dive21 88 +#define FRAME_dive22 89 +#define FRAME_dive23 90 +#define FRAME_dive24 91 +#define FRAME_dive25 92 +#define FRAME_dive26 93 +#define FRAME_duckshoot1 94 +#define FRAME_duckshoot2 95 +#define FRAME_duckshoot3 96 +#define FRAME_duckshoot4 97 +#define FRAME_duckshoot5 98 +#define FRAME_duckshoot6 99 +#define FRAME_gallop1 100 +#define FRAME_gallop2 101 +#define FRAME_gallop3 102 +#define FRAME_gallop4 103 +#define FRAME_gallop5 104 +#define FRAME_gallop6 105 +#define FRAME_gallop7 106 +#define FRAME_gallop8 107 +#define FRAME_idlebasic01 108 +#define FRAME_idlebasic02 109 +#define FRAME_idlebasic03 110 +#define FRAME_idlebasic04 111 +#define FRAME_idlebasic05 112 +#define FRAME_idlebasic06 113 +#define FRAME_idlebasic07 114 +#define FRAME_idlebasic08 115 +#define FRAME_idlebasic09 116 +#define FRAME_idlebasic10 117 +#define FRAME_idlebasic11 118 +#define FRAME_idlebasic12 119 +#define FRAME_idlebasic13 120 +#define FRAME_idlebasic14 121 +#define FRAME_idlebasic15 122 +#define FRAME_idlebasic16 123 +#define FRAME_idlebasic17 124 +#define FRAME_idlebasic18 125 +#define FRAME_idlebasic19 126 +#define FRAME_idlebasic20 127 +#define FRAME_idlebasic21 128 +#define FRAME_idlebasic22 129 +#define FRAME_idlebasic23 130 +#define FRAME_idlebasic24 131 +#define FRAME_idlebasic25 132 +#define FRAME_idlebasic26 133 +#define FRAME_idlebasic27 134 +#define FRAME_idlebasic28 135 +#define FRAME_idlebasic29 136 +#define FRAME_idlebasic30 137 +#define FRAME_idlebasic31 138 +#define FRAME_idlebasic32 139 +#define FRAME_idlebasic33 140 +#define FRAME_idlebasic34 141 +#define FRAME_idlebasic35 142 +#define FRAME_idlebasic36 143 +#define FRAME_idlebasic37 144 +#define FRAME_idlebasic38 145 +#define FRAME_idlebasic39 146 +#define FRAME_idlebasic40 147 +#define FRAME_idlebasic41 148 +#define FRAME_idlebasic42 149 +#define FRAME_idlebasic43 150 +#define FRAME_idlebasic44 151 +#define FRAME_idlebasic45 152 +#define FRAME_idlebasic46 153 +#define FRAME_idlebasic47 154 +#define FRAME_idlebasic48 155 +#define FRAME_idlebasic49 156 +#define FRAME_idlebasic50 157 +#define FRAME_idlebasic51 158 +#define FRAME_idlebasic52 159 +#define FRAME_idlebasic53 160 +#define FRAME_idlebasic54 161 +#define FRAME_idlebasic55 162 +#define FRAME_idlebasic56 163 +#define FRAME_idlebasic57 164 +#define FRAME_idlebasic58 165 +#define FRAME_idlebasic59 166 +#define FRAME_idlebasic60 167 +#define FRAME_idlebasic61 168 +#define FRAME_idlebasic62 169 +#define FRAME_idlebasic63 170 +#define FRAME_idlebasic64 171 +#define FRAME_idlebasic65 172 +#define FRAME_idlebasic66 173 +#define FRAME_idlebasic67 174 +#define FRAME_idlebasic68 175 +#define FRAME_idlebasic69 176 +#define FRAME_idlebasic70 177 +#define FRAME_idlebasic71 178 +#define FRAME_idlebasic72 179 +#define FRAME_idlebasic73 180 +#define FRAME_idlebasic74 181 +#define FRAME_idlebasic75 182 +#define FRAME_idlebasic76 183 +#define FRAME_idlebasic77 184 +#define FRAME_idlebasic78 185 +#define FRAME_idlebasic79 186 +#define FRAME_idlebasic80 187 +#define FRAME_idleright01 188 +#define FRAME_idleright02 189 +#define FRAME_idleright03 190 +#define FRAME_idleright04 191 +#define FRAME_idleright05 192 +#define FRAME_idleright06 193 +#define FRAME_idleright07 194 +#define FRAME_idleright08 195 +#define FRAME_idleright09 196 +#define FRAME_idleright10 197 +#define FRAME_idleright11 198 +#define FRAME_idleright12 199 +#define FRAME_idleright13 200 +#define FRAME_idleright14 201 +#define FRAME_idleright15 202 +#define FRAME_idleright16 203 +#define FRAME_idleright17 204 +#define FRAME_idleright18 205 +#define FRAME_idleright19 206 +#define FRAME_idleright20 207 +#define FRAME_idle01 208 +#define FRAME_idle02 209 +#define FRAME_idle03 210 +#define FRAME_idle04 211 +#define FRAME_idle05 212 +#define FRAME_idle06 213 +#define FRAME_idle07 214 +#define FRAME_idle08 215 +#define FRAME_idle09 216 +#define FRAME_idle10 217 +#define FRAME_idle11 218 +#define FRAME_idle12 219 +#define FRAME_idle13 220 +#define FRAME_idle14 221 +#define FRAME_idle15 222 +#define FRAME_idle16 223 +#define FRAME_idle17 224 +#define FRAME_idle18 225 +#define FRAME_idle19 226 +#define FRAME_idle20 227 +#define FRAME_idle21 228 +#define FRAME_idle22 229 +#define FRAME_idle23 230 +#define FRAME_idle24 231 +#define FRAME_idle25 232 +#define FRAME_idle26 233 +#define FRAME_idle27 234 +#define FRAME_idle28 235 +#define FRAME_idle29 236 +#define FRAME_idle30 237 +#define FRAME_idle31 238 +#define FRAME_idle32 239 +#define FRAME_idle33 240 +#define FRAME_idle34 241 +#define FRAME_idle35 242 +#define FRAME_idle36 243 +#define FRAME_idle37 244 +#define FRAME_idle38 245 +#define FRAME_idle39 246 +#define FRAME_idle40 247 +#define FRAME_Melee_stand1 248 +#define FRAME_Melee_stand2 249 +#define FRAME_Melee_stand3 250 +#define FRAME_Melee_stand4 251 +#define FRAME_Melee_stand5 252 +#define FRAME_Melee_stand6 253 +#define FRAME_Melee_stand7 254 +#define FRAME_melee1 255 +#define FRAME_melee2 256 +#define FRAME_melee3 257 +#define FRAME_melee4 258 +#define FRAME_melee5 259 +#define FRAME_melee6 260 +#define FRAME_melee7 261 +#define FRAME_namor1 262 +#define FRAME_namor2 263 +#define FRAME_namor3 264 +#define FRAME_namor4 265 +#define FRAME_namor5 266 +#define FRAME_namor6 267 +#define FRAME_namor7 268 +#define FRAME_namor8 269 +#define FRAME_namor9 270 +#define FRAME_namor10 271 +#define FRAME_namor11 272 +#define FRAME_namor12 273 +#define FRAME_namor13 274 +#define FRAME_namor14 275 +#define FRAME_namor15 276 +#define FRAME_namor16 277 +#define FRAME_namor17 278 +#define FRAME_namor18 279 +#define FRAME_namor19 280 +#define FRAME_namor20 281 +#define FRAME_namor21 282 +#define FRAME_namor22 283 +#define FRAME_namor23 284 +#define FRAME_namor24 285 +#define FRAME_namor25 286 +#define FRAME_pain_a1 287 +#define FRAME_pain_a2 288 +#define FRAME_run1 289 +#define FRAME_run2 290 +#define FRAME_run3 291 +#define FRAME_run4 292 +#define FRAME_run5 293 +#define FRAME_run6 294 +#define FRAME_run7 295 +#define FRAME_run8 296 +#define FRAME_shoot1 297 +#define FRAME_shoot2 298 +#define FRAME_shoot3 299 +#define FRAME_shoot4 300 +#define FRAME_shoot5 301 +#define FRAME_shoot6 302 +#define FRAME_shoot7 303 +#define FRAME_shoot8 304 +#define FRAME_shoot9 305 +#define FRAME_shoot10 306 +#define FRAME_shoot11 307 +#define FRAME_shoot12 308 +#define FRAME_shoot13 309 +#define FRAME_shoot14 310 +#define FRAME_shoot15 311 +#define FRAME_shoot16 312 +#define FRAME_shoot17 313 +#define FRAME_shoot18 314 +#define FRAME_shoot19 315 +#define FRAME_shoot20 316 +#define FRAME_shoot21 317 +#define FRAME_startle2 318 +#define FRAME_startle3 319 +#define FRAME_startle4 320 +#define FRAME_startle5 321 +#define FRAME_startle6 322 +#define FRAME_startle7 323 +#define FRAME_startle8 324 +#define FRAME_startle9 325 +#define FRAME_startle10 326 +#define FRAME_startle11 327 +#define FRAME_startle12 328 +#define FRAME_startle13 329 +#define FRAME_startle14 330 +#define FRAME_startle15 331 +#define FRAME_startle16 332 +#define FRAME_startle17 333 +#define FRAME_startle18 334 +#define FRAME_startle19 335 +#define FRAME_startle20 336 +#define FRAME_startle21 337 +#define FRAME_startle22 338 +#define FRAME_startle23 339 +#define FRAME_startle24 340 +#define FRAME_startle25 341 +#define FRAME_startle26 342 +#define FRAME_startle27 343 +#define FRAME_startle28 344 +#define FRAME_startle29 345 +#define FRAME_startle30 346 +#define FRAME_startle31 347 +#define FRAME_startle32 348 +#define FRAME_startle33 349 +#define FRAME_startle34 350 +#define FRAME_startle35 351 +#define FRAME_startle36 352 +#define FRAME_startle37 353 +#define FRAME_startle38 354 +#define FRAME_startle39 355 +#define FRAME_swimforward01 356 +#define FRAME_swimforward02 357 +#define FRAME_swimforward03 358 +#define FRAME_swimforward04 359 +#define FRAME_swimforward05 360 +#define FRAME_swimforward06 361 +#define FRAME_swimforward07 362 +#define FRAME_swimforward08 363 +#define FRAME_swimforward09 364 +#define FRAME_swimforward10 365 +#define FRAME_swimforward11 366 +#define FRAME_swimforward12 367 +#define FRAME_swimforward13 368 +#define FRAME_swimforward14 369 +#define FRAME_swimforward15 370 +#define FRAME_walk1 371 +#define FRAME_walk2 372 +#define FRAME_walk3 373 +#define FRAME_walk4 374 +#define FRAME_walk5 375 +#define FRAME_walk6 376 +#define FRAME_walk7 377 +#define FRAME_walk8 378 +#define FRAME_walk9 379 +#define FRAME_walk10 380 +#define FRAME_walk11 381 +#define FRAME_walk12 382 +#define FRAME_walk13 383 +#define FRAME_walk14 384 +#define FRAME_water_death1 385 +#define FRAME_water_death2 386 +#define FRAME_water_death3 387 +#define FRAME_water_death4 388 +#define FRAME_water_death5 389 +#define FRAME_water_death6 390 +#define FRAME_water_death7 391 +#define FRAME_water_death8 392 +#define FRAME_water_death9 393 +#define FRAME_water_death10 394 +#define FRAME_water_death11 395 +#define FRAME_water_death12 396 +#define FRAME_water_death13 397 +#define FRAME_water_death14 398 +#define FRAME_water_death15 399 +#define FRAME_water_death16 400 +#define FRAME_water_death17 401 +#define FRAME_water_death18 402 +#define FRAME_water_death19 403 +#define FRAME_water_death20 404 +#define FRAME_water_death21 405 +#define FRAME_water_death22 406 +#define FRAME_water_death23 407 +#define FRAME_water_death24 408 +#define FRAME_water_death25 409 +#define FRAME_water_death26 410 +#define FRAME_water_death27 411 +#define FRAME_water_death28 412 +#define FRAME_water_death29 413 +#define FRAME_water_death30 414 +#define FRAME_water_death31 415 +#define FRAME_water_death32 416 +#define FRAME_water_death33 417 +#define FRAME_water_death34 418 +#define FRAME_water_death35 419 +#define FRAME_water_death36 420 +#define FRAME_water_death37 421 +#define FRAME_water_death38 422 +#define FRAME_water_death39 423 +#define FRAME_water_death40 424 +#define FRAME_water_death41 425 +#define FRAME_water_death42 426 +#define FRAME_water_death43 427 +#define FRAME_water_death44 428 +#define FRAME_water_death45 429 +#define FRAME_water_death46 430 +#define FRAME_water_death47 431 +#define FRAME_water_death48 432 +#define FRAME_water_death49 433 +#define FRAME_water_idle1 434 +#define FRAME_water_idle2 435 +#define FRAME_water_idle3 436 +#define FRAME_water_idle4 437 +#define FRAME_water_idle5 438 +#define FRAME_water_idle6 439 +#define FRAME_water_idle7 440 +#define FRAME_water_idle8 441 +#define FRAME_water_idle9 442 +#define FRAME_water_idle10 443 +#define FRAME_water_idle11 444 +#define FRAME_water_idle12 445 +#define FRAME_water_idle13 446 +#define FRAME_water_idle14 447 +#define FRAME_water_idle15 448 +#define FRAME_water_idle16 449 +#define FRAME_water_idle17 450 +#define FRAME_water_idle18 451 +#define FRAME_water_idle19 452 +#define FRAME_water_idle20 453 +#define FRAME_water_pain_a1 454 +#define FRAME_water_pain_a2 455 +#define FRAME_water_pain_b1 456 +#define FRAME_water_pain_b2 457 +#define FRAME_water_shoot01 458 +#define FRAME_water_shoot2 459 +#define FRAME_water_shoot3 460 +#define FRAME_water_shoot4 461 +#define FRAME_water_shoot5 462 +#define FRAME_water_shoot6 463 +#define FRAME_water_shoot7 464 +#define FRAME_water_shoot8 465 +#define FRAME_water_shoot9 466 +#define FRAME_water_shoot10 467 +#define FRAME_water_shoot11 468 +#define FRAME_water_shoot12 469 +#define FRAME_water_shoot13 470 +#define FRAME_water_shoot14 471 +#define FRAME_water_shoot15 472 +#define FRAME_water_shoot16 473 +#define FRAME_water_shoot17 474 +#define FRAME_Water_trans1 475 +#define FRAME_Water_trans2 476 +#define FRAME_Water_trans3 477 +#define FRAME_Water_trans4 478 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_POLY 0 +#define MESH__LOWERTORSO 1 +#define MESH__CAPLOWERTORSO 2 +#define MESH__LEFTLEG 3 +#define MESH__RIGHTLEG 4 +#define MESH__UPPERTORSO 5 +#define MESH__CAPTOPUPPERTORSO 6 +#define MESH__CAPBOTTOMUPPERTORSO 7 +#define MESH__LEFTARM 8 +#define MESH__RIGHTARM 9 +#define MESH__HEAD 10 +#define MESH__CENTERSPIKE 11 +#define MESH__LEFT1SPIKE 12 +#define MESH__RIGHT1SPIKE 13 +#define MESH__RIGHT2SPIKE 14 +#define MESH__CAPHEAD 15 diff --git a/Toolkit/Programming/GameCode/game/m_player.h b/Toolkit/Programming/GameCode/game/m_player.h new file mode 100644 index 0000000..6a5a4eb --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_player.h @@ -0,0 +1,1461 @@ +// R:\Art\models/player/elf + +// This file generated by qdata - Do NOT Modify + +#define FRAME_partfly 0 +#define FRAME_4swim1 1 +#define FRAME_4swim2 2 +#define FRAME_4swim3 3 +#define FRAME_4swim4 4 +#define FRAME_4swim5 5 +#define FRAME_4swim6 6 +#define FRAME_4swim7 7 +#define FRAME_4swim8 8 +#define FRAME_4swim9 9 +#define FRAME_4swim10 10 +#define FRAME_bkflip1 11 +#define FRAME_bkflip2 12 +#define FRAME_bkflip3 13 +#define FRAME_bkflip4 14 +#define FRAME_bkflip5 15 +#define FRAME_bkflip6 16 +#define FRAME_bkflip7 17 +#define FRAME_bkflip8 18 +#define FRAME_bkflip9 19 +#define FRAME_bkflip10 20 +#define FRAME_bkflip11 21 +#define FRAME_bkflip12 22 +#define FRAME_bkflip13 23 +#define FRAME_bkflip14 24 +#define FRAME_bkflip15 25 +#define FRAME_bkflip16 26 +#define FRAME_bkflip17 27 +#define FRAME_bkflip18 28 +#define FRAME_bkflip19 29 +#define FRAME_bkflip20 30 +#define FRAME_bkflip21 31 +#define FRAME_bkflip22 32 +#define FRAME_bkflip23 33 +#define FRAME_bkflip24 34 +#define FRAME_bkflip25 35 +#define FRAME_bkswim1 36 +#define FRAME_bkswim2 37 +#define FRAME_bkswim3 38 +#define FRAME_bkswim4 39 +#define FRAME_bkswim5 40 +#define FRAME_bkswim6 41 +#define FRAME_bkswim7 42 +#define FRAME_breath1 43 +#define FRAME_breath2 44 +#define FRAME_breath3 45 +#define FRAME_breath4 46 +#define FRAME_breath5 47 +#define FRAME_breath6 48 +#define FRAME_breath7 49 +#define FRAME_breath8 50 +#define FRAME_breath9 51 +#define FRAME_breath10 52 +#define FRAME_breath11 53 +#define FRAME_breath12 54 +#define FRAME_breath13 55 +#define FRAME_breath14 56 +#define FRAME_breath15 57 +#define FRAME_breath16 58 +#define FRAME_breath17 59 +#define FRAME_breath18 60 +#define FRAME_breath19 61 +#define FRAME_breath20 62 +#define FRAME_breath21 63 +#define FRAME_breath22 64 +#define FRAME_breath23 65 +#define FRAME_chngsplA1 66 +#define FRAME_chngsplA2 67 +#define FRAME_chngsplA3 68 +#define FRAME_chngsplA4 69 +#define FRAME_chngsplA5 70 +#define FRAME_chngsplA6 71 +#define FRAME_chngsplA7 72 +#define FRAME_chngsplA8 73 +#define FRAME_chngsplA9 74 +#define FRAME_cluster 75 +#define FRAME_conjure1 76 +#define FRAME_conjure2 77 +#define FRAME_conjure3 78 +#define FRAME_conjure4 79 +#define FRAME_conjure5 80 +#define FRAME_conjure6 81 +#define FRAME_conjure7 82 +#define FRAME_conjure8 83 +#define FRAME_conjure9 84 +#define FRAME_conjure10 85 +#define FRAME_conjure11 86 +#define FRAME_conjure12 87 +#define FRAME_conjure13 88 +#define FRAME_conjure14 89 +#define FRAME_conjure15 90 +#define FRAME_creep1 91 +#define FRAME_creep2 92 +#define FRAME_creep3 93 +#define FRAME_creep4 94 +#define FRAME_creep5 95 +#define FRAME_creep6 96 +#define FRAME_creep7 97 +#define FRAME_creep8 98 +#define FRAME_creep9 99 +#define FRAME_creep10 100 +#define FRAME_creep11 101 +#define FRAME_creep12 102 +#define FRAME_draw1 103 +#define FRAME_draw2 104 +#define FRAME_draw3 105 +#define FRAME_draw4 106 +#define FRAME_draw5 107 +#define FRAME_drop1 108 +#define FRAME_drop2 109 +#define FRAME_drop3 110 +#define FRAME_drop4 111 +#define FRAME_dspell1 112 +#define FRAME_dspell2 113 +#define FRAME_getbow1 114 +#define FRAME_getbow2 115 +#define FRAME_getbow3 116 +#define FRAME_getbow4 117 +#define FRAME_getbow5 118 +#define FRAME_getbow6 119 +#define FRAME_getbow7 120 +#define FRAME_getbow8 121 +#define FRAME_getbow9 122 +#define FRAME_getstaff1 123 +#define FRAME_getstaff2 124 +#define FRAME_getstaff3 125 +#define FRAME_getstaff4 126 +#define FRAME_getstaff5 127 +#define FRAME_getstaff6 128 +#define FRAME_getstaff7 129 +#define FRAME_getstaff8 130 +#define FRAME_grab1 131 +#define FRAME_grab2 132 +#define FRAME_grab3 133 +#define FRAME_grab4 134 +#define FRAME_grab5 135 +#define FRAME_grab6 136 +#define FRAME_grab7 137 +#define FRAME_grab8 138 +#define FRAME_idlswm1 139 +#define FRAME_idlswm2 140 +#define FRAME_idlswm3 141 +#define FRAME_idlswm4 142 +#define FRAME_idlswm5 143 +#define FRAME_idlswm6 144 +#define FRAME_idlswm7 145 +#define FRAME_idlswm8 146 +#define FRAME_idlswm9 147 +#define FRAME_idlswm10 148 +#define FRAME_idlswm11 149 +#define FRAME_idlswm12 150 +#define FRAME_idlswm13 151 +#define FRAME_idlswm14 152 +#define FRAME_idlswm15 153 +#define FRAME_jog1 154 +#define FRAME_jog2 155 +#define FRAME_jog3 156 +#define FRAME_jog4 157 +#define FRAME_jog5 158 +#define FRAME_jog6 159 +#define FRAME_jog7 160 +#define FRAME_jog8 161 +#define FRAME_jump1 162 +#define FRAME_jump2 163 +#define FRAME_jump3 164 +#define FRAME_jump4 165 +#define FRAME_jump5 166 +#define FRAME_jump6 167 +#define FRAME_jump7 168 +#define FRAME_jump8 169 +#define FRAME_jump9 170 +#define FRAME_jump10 171 +#define FRAME_jump11 172 +#define FRAME_jump12 173 +#define FRAME_jump13 174 +#define FRAME_jump14 175 +#define FRAME_jump15 176 +#define FRAME_jump16 177 +#define FRAME_jump17 178 +#define FRAME_jump18 179 +#define FRAME_jump19 180 +#define FRAME_jump20 181 +#define FRAME_jump21 182 +#define FRAME_lstair1 183 +#define FRAME_lstair2 184 +#define FRAME_lstair3 185 +#define FRAME_lstair4 186 +#define FRAME_phbuton1 187 +#define FRAME_phbuton2 188 +#define FRAME_phbuton3 189 +#define FRAME_phbuton4 190 +#define FRAME_phbuton5 191 +#define FRAME_phbuton6 192 +#define FRAME_phbuton7 193 +#define FRAME_phbuton8 194 +#define FRAME_phbuton9 195 +#define FRAME_pullup1 196 +#define FRAME_pullup2 197 +#define FRAME_pullup3 198 +#define FRAME_pullup4 199 +#define FRAME_pullup5 200 +#define FRAME_pullup6 201 +#define FRAME_pullup7 202 +#define FRAME_pullup8 203 +#define FRAME_pullup9 204 +#define FRAME_pullup10 205 +#define FRAME_pullup11 206 +#define FRAME_pullup12 207 +#define FRAME_recover1 208 +#define FRAME_recover2 209 +#define FRAME_recover3 210 +#define FRAME_recover4 211 +#define FRAME_recover5 212 +#define FRAME_recover6 213 +#define FRAME_recover7 214 +#define FRAME_redybow1 215 +#define FRAME_redybow2 216 +#define FRAME_redybow3 217 +#define FRAME_redybow4 218 +#define FRAME_redybow5 219 +#define FRAME_rollA1 220 +#define FRAME_rollA2 221 +#define FRAME_rollA3 222 +#define FRAME_rollA4 223 +#define FRAME_rollA5 224 +#define FRAME_rollA6 225 +#define FRAME_rollA7 226 +#define FRAME_rollA8 227 +#define FRAME_rollA9 228 +#define FRAME_rollA10 229 +#define FRAME_rollA11 230 +#define FRAME_rollA12 231 +#define FRAME_rollA13 232 +#define FRAME_rollA14 233 +#define FRAME_rollA15 234 +#define FRAME_rstair1 235 +#define FRAME_rstair2 236 +#define FRAME_rstair3 237 +#define FRAME_rstair4 238 +#define FRAME_run1 239 +#define FRAME_run2 240 +#define FRAME_run3 241 +#define FRAME_run4 242 +#define FRAME_run5 243 +#define FRAME_run6 244 +#define FRAME_shoot1 245 +#define FRAME_shoot2 246 +#define FRAME_shoot3 247 +#define FRAME_shoot4 248 +#define FRAME_shoot5 249 +#define FRAME_spnatk1 250 +#define FRAME_spnatk2 251 +#define FRAME_spnatk3 252 +#define FRAME_spnatk4 253 +#define FRAME_spnatk5 254 +#define FRAME_spnatk6 255 +#define FRAME_spnatk7 256 +#define FRAME_spnatk8 257 +#define FRAME_spnatk9 258 +#define FRAME_spnatk10 259 +#define FRAME_spnatk11 260 +#define FRAME_spnatk12 261 +#define FRAME_spnatk13 262 +#define FRAME_spnatk14 263 +#define FRAME_spnatk15 264 +#define FRAME_spnatk16 265 +#define FRAME_spnatk17 266 +#define FRAME_spnatk18 267 +#define FRAME_spnatk19 268 +#define FRAME_spnatk20 269 +#define FRAME_spnatk21 270 +#define FRAME_spnatk22 271 +#define FRAME_swipea1 272 +#define FRAME_swipea2 273 +#define FRAME_swipea3 274 +#define FRAME_swipea4 275 +#define FRAME_swipea5 276 +#define FRAME_swipea6 277 +#define FRAME_swipea7 278 +#define FRAME_swipea8 279 +#define FRAME_swipea9 280 +#define FRAME_swipea10 281 +#define FRAME_swipea11 282 +#define FRAME_swipeb1 283 +#define FRAME_swipeb2 284 +#define FRAME_swipeb3 285 +#define FRAME_swipeb4 286 +#define FRAME_swipeb5 287 +#define FRAME_swipeb6 288 +#define FRAME_swipeb7 289 +#define FRAME_swipeb8 290 +#define FRAME_swipeb9 291 +#define FRAME_swipeb10 292 +#define FRAME_swipeb11 293 +#define FRAME_swipeb12 294 +#define FRAME_t4swim1 295 +#define FRAME_t4swim2 296 +#define FRAME_tbswim1 297 +#define FRAME_tbswim2 298 +#define FRAME_tbswim3 299 +#define FRAME_tbswim4 300 +#define FRAME_tbswim5 301 +#define FRAME_throw1 302 +#define FRAME_throw2 303 +#define FRAME_throw3 304 +#define FRAME_throw4 305 +#define FRAME_throw5 306 +#define FRAME_throw6 307 +#define FRAME_throw7 308 +#define FRAME_throw8 309 +#define FRAME_throw9 310 +#define FRAME_throw10 311 +#define FRAME_throw11 312 +#define FRAME_unstff1 313 +#define FRAME_unstff2 314 +#define FRAME_unstff3 315 +#define FRAME_unstff4 316 +#define FRAME_unstff5 317 +#define FRAME_unstff6 318 +#define FRAME_vault1 319 +#define FRAME_vault2 320 +#define FRAME_vault3 321 +#define FRAME_vault4 322 +#define FRAME_vault5 323 +#define FRAME_vault6 324 +#define FRAME_vault7 325 +#define FRAME_vault8 326 +#define FRAME_vault9 327 +#define FRAME_vault10 328 +#define FRAME_vault11 329 +#define FRAME_vault12 330 +#define FRAME_vault13 331 +#define FRAME_vault14 332 +#define FRAME_vault15 333 +#define FRAME_vault16 334 +#define FRAME_vault17 335 +#define FRAME_crhpvt1 336 +#define FRAME_crhpvt2 337 +#define FRAME_crhpvt3 338 +#define FRAME_crhpvt4 339 +#define FRAME_Lflip1 340 +#define FRAME_Lflip2 341 +#define FRAME_Lflip3 342 +#define FRAME_Lflip4 343 +#define FRAME_Lflip5 344 +#define FRAME_Lflip6 345 +#define FRAME_Lflip7 346 +#define FRAME_Lflip8 347 +#define FRAME_Lflip9 348 +#define FRAME_Lflip10 349 +#define FRAME_Lflip11 350 +#define FRAME_Lflip12 351 +#define FRAME_Lflip13 352 +#define FRAME_Lflip14 353 +#define FRAME_Rflip1 354 +#define FRAME_Rflip2 355 +#define FRAME_Rflip3 356 +#define FRAME_Rflip4 357 +#define FRAME_Rflip5 358 +#define FRAME_Rflip6 359 +#define FRAME_Rflip7 360 +#define FRAME_Rflip8 361 +#define FRAME_Rflip9 362 +#define FRAME_Rflip10 363 +#define FRAME_Rflip11 364 +#define FRAME_Rflip12 365 +#define FRAME_Rflip13 366 +#define FRAME_Rflip14 367 +#define FRAME_smlpna1 368 +#define FRAME_smlpna2 369 +#define FRAME_smlpna3 370 +#define FRAME_smlpna4 371 +#define FRAME_smlpnb1 372 +#define FRAME_smlpnb2 373 +#define FRAME_smlpnb3 374 +#define FRAME_smlpnb4 375 +#define FRAME_gorun1 376 +#define FRAME_gorun2 377 +#define FRAME_gorun3 378 +#define FRAME_Lstep1 379 +#define FRAME_Lstep2 380 +#define FRAME_Lstep3 381 +#define FRAME_Lstep4 382 +#define FRAME_Lstep5 383 +#define FRAME_Rstep1 384 +#define FRAME_Rstep2 385 +#define FRAME_Rstep3 386 +#define FRAME_Rstep4 387 +#define FRAME_Rstep5 388 +#define FRAME_ready1 389 +#define FRAME_ready2 390 +#define FRAME_ready3 391 +#define FRAME_ready4 392 +#define FRAME_ready5 393 +#define FRAME_ready6 394 +#define FRAME_ready7 395 +#define FRAME_ready8 396 +#define FRAME_ready9 397 +#define FRAME_ready10 398 +#define FRAME_ready11 399 +#define FRAME_ready12 400 +#define FRAME_ready13 401 +#define FRAME_ready14 402 +#define FRAME_ready15 403 +#define FRAME_ready16 404 +#define FRAME_ready17 405 +#define FRAME_ready18 406 +#define FRAME_ready19 407 +#define FRAME_ready20 408 +#define FRAME_ready21 409 +#define FRAME_ready22 410 +#define FRAME_ready23 411 +#define FRAME_ready24 412 +#define FRAME_ready25 413 +#define FRAME_ready26 414 +#define FRAME_lklft1 415 +#define FRAME_lklft2 416 +#define FRAME_lklft3 417 +#define FRAME_lklft4 418 +#define FRAME_lklft5 419 +#define FRAME_lklft6 420 +#define FRAME_lklft7 421 +#define FRAME_lklft8 422 +#define FRAME_lklft9 423 +#define FRAME_lklft10 424 +#define FRAME_lklft11 425 +#define FRAME_lklft12 426 +#define FRAME_lklft13 427 +#define FRAME_lklft14 428 +#define FRAME_lklft15 429 +#define FRAME_lklft16 430 +#define FRAME_lklft17 431 +#define FRAME_lklft18 432 +#define FRAME_lklft19 433 +#define FRAME_lklft20 434 +#define FRAME_lklft21 435 +#define FRAME_lklft22 436 +#define FRAME_lkrt1 437 +#define FRAME_lkrt2 438 +#define FRAME_lkrt3 439 +#define FRAME_lkrt4 440 +#define FRAME_lkrt5 441 +#define FRAME_lkrt6 442 +#define FRAME_lkrt7 443 +#define FRAME_lkrt8 444 +#define FRAME_lkrt9 445 +#define FRAME_lkrt10 446 +#define FRAME_lkrt11 447 +#define FRAME_lkrt12 448 +#define FRAME_lkrt13 449 +#define FRAME_lkrt14 450 +#define FRAME_lkrt15 451 +#define FRAME_lkrt16 452 +#define FRAME_lkrt17 453 +#define FRAME_lkrt18 454 +#define FRAME_lkrt19 455 +#define FRAME_lkrt20 456 +#define FRAME_lkrt21 457 +#define FRAME_lkrt22 458 +#define FRAME_helstf1 459 +#define FRAME_helstf2 460 +#define FRAME_helstf3 461 +#define FRAME_helstf4 462 +#define FRAME_helstf5 463 +#define FRAME_helstf6 464 +#define FRAME_helstf7 465 +#define FRAME_Lpivot1 466 +#define FRAME_Lpivot2 467 +#define FRAME_Lpivot3 468 +#define FRAME_Lpivot4 469 +#define FRAME_pesta1 470 +#define FRAME_pesta2 471 +#define FRAME_pesta3 472 +#define FRAME_pesta4 473 +#define FRAME_pesta5 474 +#define FRAME_pesta6 475 +#define FRAME_pesta7 476 +#define FRAME_pesta8 477 +#define FRAME_pesta9 478 +#define FRAME_pesta10 479 +#define FRAME_pesta11 480 +#define FRAME_pesta12 481 +#define FRAME_pesta13 482 +#define FRAME_pesta14 483 +#define FRAME_pestb1 484 +#define FRAME_pestb2 485 +#define FRAME_pestb3 486 +#define FRAME_pestb4 487 +#define FRAME_pestb5 488 +#define FRAME_pestb6 489 +#define FRAME_pestb7 490 +#define FRAME_pestb8 491 +#define FRAME_pestb9 492 +#define FRAME_pestb10 493 +#define FRAME_pestb11 494 +#define FRAME_pestb12 495 +#define FRAME_pestb13 496 +#define FRAME_pestb14 497 +#define FRAME_pestb15 498 +#define FRAME_pestb16 499 +#define FRAME_pestb17 500 +#define FRAME_pestb18 501 +#define FRAME_pestb19 502 +#define FRAME_pestb20 503 +#define FRAME_pestb21 504 +#define FRAME_pestb22 505 +#define FRAME_subdive1 506 +#define FRAME_subdive2 507 +#define FRAME_subdive3 508 +#define FRAME_subdive4 509 +#define FRAME_subdive5 510 +#define FRAME_subdive6 511 +#define FRAME_subdive7 512 +#define FRAME_subdive8 513 +#define FRAME_subdive9 514 +#define FRAME_undrswmA1 515 +#define FRAME_undrswmA2 516 +#define FRAME_undrswmA3 517 +#define FRAME_undrswmA4 518 +#define FRAME_undrswmA5 519 +#define FRAME_undrswmA6 520 +#define FRAME_undrswmA7 521 +#define FRAME_undrswmA8 522 +#define FRAME_undrswmA9 523 +#define FRAME_deathA1 524 +#define FRAME_deathA2 525 +#define FRAME_deathA3 526 +#define FRAME_deathA4 527 +#define FRAME_deathA5 528 +#define FRAME_deathA6 529 +#define FRAME_deathA7 530 +#define FRAME_deathA8 531 +#define FRAME_deathA9 532 +#define FRAME_deathA10 533 +#define FRAME_deathA11 534 +#define FRAME_deathA12 535 +#define FRAME_deathA13 536 +#define FRAME_deathA14 537 +#define FRAME_lhop1 538 +#define FRAME_lhop2 539 +#define FRAME_lhop3 540 +#define FRAME_rhop1 541 +#define FRAME_rhop2 542 +#define FRAME_rhop3 543 +#define FRAME_rhop4 544 +#define FRAME_rhop5 545 +#define FRAME_rhop6 546 +#define FRAME_rhop7 547 +#define FRAME_slid4d1 548 +#define FRAME_slid4d2 549 +#define FRAME_slid4d3 550 +#define FRAME_slid4d4 551 +#define FRAME_slid4d5 552 +#define FRAME_slid4d6 553 +#define FRAME_slid4d7 554 +#define FRAME_slid4d8 555 +#define FRAME_slid4d9 556 +#define FRAME_slid4d10 557 +#define FRAME_slid4d11 558 +#define FRAME_slid4d12 559 +#define FRAME_slidbak1 560 +#define FRAME_slidbak2 561 +#define FRAME_slidbak3 562 +#define FRAME_slidbak4 563 +#define FRAME_slidbak5 564 +#define FRAME_slidbak6 565 +#define FRAME_slidbak7 566 +#define FRAME_slidbak8 567 +#define FRAME_slidbak9 568 +#define FRAME_slidbak10 569 +#define FRAME_slidbak11 570 +#define FRAME_slidbak12 571 +#define FRAME_tswiml1 572 +#define FRAME_tswiml2 573 +#define FRAME_tswiml3 574 +#define FRAME_tswiml4 575 +#define FRAME_tswimr1 576 +#define FRAME_tswimr2 577 +#define FRAME_tswimr3 578 +#define FRAME_tswimr4 579 +#define FRAME_swiml1 580 +#define FRAME_swiml2 581 +#define FRAME_swiml3 582 +#define FRAME_swiml4 583 +#define FRAME_swiml5 584 +#define FRAME_swimr1 585 +#define FRAME_swimr2 586 +#define FRAME_swimr3 587 +#define FRAME_swimr4 588 +#define FRAME_swimr5 589 +#define FRAME_crepbak1 590 +#define FRAME_crepbak2 591 +#define FRAME_crepbak3 592 +#define FRAME_crepbak4 593 +#define FRAME_crepbak5 594 +#define FRAME_crepbak6 595 +#define FRAME_crepbak7 596 +#define FRAME_crepbak8 597 +#define FRAME_crepbak9 598 +#define FRAME_crepbak10 599 +#define FRAME_crepbak11 600 +#define FRAME_crepbak12 601 +#define FRAME_jogback1 602 +#define FRAME_jogback2 603 +#define FRAME_jogback3 604 +#define FRAME_jogback4 605 +#define FRAME_jogback5 606 +#define FRAME_jogback6 607 +#define FRAME_resurf1 608 +#define FRAME_resurf2 609 +#define FRAME_resurf3 610 +#define FRAME_resurf4 611 +#define FRAME_resurf5 612 +#define FRAME_idlundr1 613 +#define FRAME_idlundr2 614 +#define FRAME_idlundr3 615 +#define FRAME_idlundr4 616 +#define FRAME_idlundr5 617 +#define FRAME_idlundr6 618 +#define FRAME_idlundr7 619 +#define FRAME_idlundr8 620 +#define FRAME_idlundr9 621 +#define FRAME_idlundr10 622 +#define FRAME_idlundr11 623 +#define FRAME_idlundr12 624 +#define FRAME_idlundr13 625 +#define FRAME_idlundr14 626 +#define FRAME_idlundr15 627 +#define FRAME_idlundr16 628 +#define FRAME_idlundr17 629 +#define FRAME_idlundr18 630 +#define FRAME_idlundr19 631 +#define FRAME_idlundr20 632 +#define FRAME_roll1 633 +#define FRAME_roll2 634 +#define FRAME_roll3 635 +#define FRAME_roll4 636 +#define FRAME_roll5 637 +#define FRAME_roll6 638 +#define FRAME_roll7 639 +#define FRAME_roll8 640 +#define FRAME_roll9 641 +#define FRAME_backroll1 642 +#define FRAME_backroll2 643 +#define FRAME_backroll3 644 +#define FRAME_backroll4 645 +#define FRAME_backroll5 646 +#define FRAME_backroll6 647 +#define FRAME_backroll7 648 +#define FRAME_backroll8 649 +#define FRAME_backroll9 650 +#define FRAME_falling1 651 +#define FRAME_falling2 652 +#define FRAME_falling3 653 +#define FRAME_falling4 654 +#define FRAME_falling5 655 +#define FRAME_falling6 656 +#define FRAME_falling7 657 +#define FRAME_falling8 658 +#define FRAME_falling9 659 +#define FRAME_falling10 660 +#define FRAME_falling11 661 +#define FRAME_falling12 662 +#define FRAME_falling13 663 +#define FRAME_falling14 664 +#define FRAME_falling15 665 +#define FRAME_kodown1 666 +#define FRAME_kodown2 667 +#define FRAME_kodown3 668 +#define FRAME_kodown4 669 +#define FRAME_kodown5 670 +#define FRAME_kodown6 671 +#define FRAME_kodown7 672 +#define FRAME_kodown8 673 +#define FRAME_kodown9 674 +#define FRAME_kodown10 675 +#define FRAME_kodown11 676 +#define FRAME_kodown12 677 +#define FRAME_kodown13 678 +#define FRAME_kodown14 679 +#define FRAME_kodown15 680 +#define FRAME_kodown16 681 +#define FRAME_kodown17 682 +#define FRAME_kodown18 683 +#define FRAME_kodown19 684 +#define FRAME_kodown20 685 +#define FRAME_kodown21 686 +#define FRAME_kodown22 687 +#define FRAME_shrine1 688 +#define FRAME_shrine2 689 +#define FRAME_shrine3 690 +#define FRAME_shrine4 691 +#define FRAME_shrine5 692 +#define FRAME_shrine6 693 +#define FRAME_shrine7 694 +#define FRAME_shrine8 695 +#define FRAME_shrine9 696 +#define FRAME_shrine10 697 +#define FRAME_trnshrine1 698 +#define FRAME_trnshrine2 699 +#define FRAME_trnshrine3 700 +#define FRAME_grabrope1 701 +#define FRAME_grabrope2 702 +#define FRAME_grabrope3 703 +#define FRAME_grabrope4 704 +#define FRAME_grabrope5 705 +#define FRAME_grabrope6 706 +#define FRAME_grabrope7 707 +#define FRAME_lhndset1 708 +#define FRAME_lhndset2 709 +#define FRAME_lhndset3 710 +#define FRAME_lhndset4 711 +#define FRAME_lhndset5 712 +#define FRAME_rhndset1 713 +#define FRAME_rhndset2 714 +#define FRAME_rhndset3 715 +#define FRAME_lclimb1 716 +#define FRAME_lclimb2 717 +#define FRAME_lclimb3 718 +#define FRAME_lclimb4 719 +#define FRAME_rclimb1 720 +#define FRAME_rclimb2 721 +#define FRAME_rclimb3 722 +#define FRAME_rclimb4 723 +#define FRAME_rclmbstrt1 724 +#define FRAME_rclmbstrt2 725 +#define FRAME_rclmbstrt3 726 +#define FRAME_lclmbstrt1 727 +#define FRAME_lclmbstrt2 728 +#define FRAME_lclmbstrt3 729 +#define FRAME_lidle1 730 +#define FRAME_lidle2 731 +#define FRAME_lidle3 732 +#define FRAME_lidle4 733 +#define FRAME_lidle5 734 +#define FRAME_lidle6 735 +#define FRAME_lidle7 736 +#define FRAME_lidle8 737 +#define FRAME_lidle9 738 +#define FRAME_lidle10 739 +#define FRAME_lidle11 740 +#define FRAME_lidle12 741 +#define FRAME_lidle13 742 +#define FRAME_lidle14 743 +#define FRAME_lidle15 744 +#define FRAME_lidle16 745 +#define FRAME_lidle17 746 +#define FRAME_lidle18 747 +#define FRAME_lidle19 748 +#define FRAME_lidle20 749 +#define FRAME_lidle21 750 +#define FRAME_ridle1 751 +#define FRAME_ridle2 752 +#define FRAME_ridle3 753 +#define FRAME_ridle4 754 +#define FRAME_ridle5 755 +#define FRAME_ridle6 756 +#define FRAME_ridle7 757 +#define FRAME_ridle8 758 +#define FRAME_ridle9 759 +#define FRAME_ridle10 760 +#define FRAME_ridle11 761 +#define FRAME_ridle12 762 +#define FRAME_ridle13 763 +#define FRAME_ridle14 764 +#define FRAME_ridle15 765 +#define FRAME_ridle16 766 +#define FRAME_ridle17 767 +#define FRAME_ridle18 768 +#define FRAME_ridle19 769 +#define FRAME_ridle20 770 +#define FRAME_ridle21 771 +#define FRAME_pushredy1 772 +#define FRAME_pushredy2 773 +#define FRAME_pushredy3 774 +#define FRAME_pushgo1 775 +#define FRAME_pushgo2 776 +#define FRAME_pushgo3 777 +#define FRAME_pushgo4 778 +#define FRAME_pushgo5 779 +#define FRAME_pushgo6 780 +#define FRAME_pushgo7 781 +#define FRAME_pushgo8 782 +#define FRAME_pushgo9 783 +#define FRAME_pushgo10 784 +#define FRAME_pushgo11 785 +#define FRAME_pushgo12 786 +#define FRAME_pushgo13 787 +#define FRAME_pushing1 788 +#define FRAME_pushing2 789 +#define FRAME_pushing3 790 +#define FRAME_pushing4 791 +#define FRAME_pushing5 792 +#define FRAME_pushing6 793 +#define FRAME_pushing7 794 +#define FRAME_pushing8 795 +#define FRAME_lpushend1 796 +#define FRAME_lpushend2 797 +#define FRAME_lpushend3 798 +#define FRAME_lpushend4 799 +#define FRAME_rpushend1 800 +#define FRAME_rpushend2 801 +#define FRAME_rpushend3 802 +#define FRAME_rpushend4 803 +#define FRAME_letgo1 804 +#define FRAME_letgo2 805 +#define FRAME_letgo3 806 +#define FRAME_letgo4 807 +#define FRAME_letgo5 808 +#define FRAME_retgo1 809 +#define FRAME_retgo2 810 +#define FRAME_retgo3 811 +#define FRAME_retgo4 812 +#define FRAME_retgo5 813 +#define FRAME_swmgrab1 814 +#define FRAME_swmgrab2 815 +#define FRAME_swmgrab3 816 +#define FRAME_swmgrab4 817 +#define FRAME_swmgrab5 818 +#define FRAME_swmgrab6 819 +#define FRAME_swmgrab7 820 +#define FRAME_swmgrab8 821 +#define FRAME_swmgrab9 822 +#define FRAME_swmgrab10 823 +#define FRAME_swmgrab11 824 +#define FRAME_startpull1 825 +#define FRAME_startpull2 826 +#define FRAME_startpull3 827 +#define FRAME_startpull4 828 +#define FRAME_startpull5 829 +#define FRAME_startpull6 830 +#define FRAME_startpull7 831 +#define FRAME_startpull8 832 +#define FRAME_startpull9 833 +#define FRAME_startpull10 834 +#define FRAME_startpull11 835 +#define FRAME_startpull12 836 +#define FRAME_pull1 837 +#define FRAME_pull2 838 +#define FRAME_pull3 839 +#define FRAME_pull4 840 +#define FRAME_pull5 841 +#define FRAME_pull6 842 +#define FRAME_pull7 843 +#define FRAME_pull8 844 +#define FRAME_endpull1 845 +#define FRAME_endpull2 846 +#define FRAME_endpull3 847 +#define FRAME_endpull4 848 +#define FRAME_endpull5 849 +#define FRAME_drown1 850 +#define FRAME_drown2 851 +#define FRAME_drown3 852 +#define FRAME_drown4 853 +#define FRAME_drown5 854 +#define FRAME_drown6 855 +#define FRAME_drown7 856 +#define FRAME_drown8 857 +#define FRAME_drown9 858 +#define FRAME_drown10 859 +#define FRAME_drown11 860 +#define FRAME_drown12 861 +#define FRAME_drown13 862 +#define FRAME_drown14 863 +#define FRAME_drown15 864 +#define FRAME_drown16 865 +#define FRAME_drown17 866 +#define FRAME_drown18 867 +#define FRAME_drown19 868 +#define FRAME_drown20 869 +#define FRAME_drown21 870 +#define FRAME_drown22 871 +#define FRAME_drown23 872 +#define FRAME_drown24 873 +#define FRAME_drown25 874 +#define FRAME_drown26 875 +#define FRAME_drown27 876 +#define FRAME_drown28 877 +#define FRAME_drown29 878 +#define FRAME_drown30 879 +#define FRAME_drown31 880 +#define FRAME_drown32 881 +#define FRAME_drown33 882 +#define FRAME_drown34 883 +#define FRAME_drown35 884 +#define FRAME_drown36 885 +#define FRAME_drown37 886 +#define FRAME_drown38 887 +#define FRAME_drown39 888 +#define FRAME_drown40 889 +#define FRAME_lftflip1 890 +#define FRAME_lftflip2 891 +#define FRAME_lftflip3 892 +#define FRAME_lftflip4 893 +#define FRAME_lftflip5 894 +#define FRAME_lftflip6 895 +#define FRAME_lftflip7 896 +#define FRAME_lftflip8 897 +#define FRAME_lftflip9 898 +#define FRAME_ritflip1 899 +#define FRAME_ritflip2 900 +#define FRAME_ritflip3 901 +#define FRAME_ritflip4 902 +#define FRAME_ritflip5 903 +#define FRAME_ritflip6 904 +#define FRAME_ritflip7 905 +#define FRAME_ritflip8 906 +#define FRAME_ritflip9 907 +#define FRAME_180turn1 908 +#define FRAME_180turn2 909 +#define FRAME_180turn3 910 +#define FRAME_180turn4 911 +#define FRAME_180turn5 912 +#define FRAME_180turn6 913 +#define FRAME_180turn7 914 +#define FRAME_180turn8 915 +#define FRAME_180turn9 916 +#define FRAME_burning1 917 +#define FRAME_burning2 918 +#define FRAME_burning3 919 +#define FRAME_burning4 920 +#define FRAME_burning5 921 +#define FRAME_burning6 922 +#define FRAME_burning7 923 +#define FRAME_burning8 924 +#define FRAME_burning9 925 +#define FRAME_burning10 926 +#define FRAME_burning11 927 +#define FRAME_burning12 928 +#define FRAME_burning13 929 +#define FRAME_burning14 930 +#define FRAME_burning15 931 +#define FRAME_burning16 932 +#define FRAME_burning17 933 +#define FRAME_burning18 934 +#define FRAME_burning19 935 +#define FRAME_burning20 936 +#define FRAME_burning21 937 +#define FRAME_burning22 938 +#define FRAME_burning23 939 +#define FRAME_burning24 940 +#define FRAME_burning25 941 +#define FRAME_burning26 942 +#define FRAME_burning27 943 +#define FRAME_burning28 944 +#define FRAME_burning29 945 +#define FRAME_burning30 946 +#define FRAME_burning31 947 +#define FRAME_burning32 948 +#define FRAME_burning33 949 +#define FRAME_burning34 950 +#define FRAME_burning35 951 +#define FRAME_lstrafe1 952 +#define FRAME_lstrafe2 953 +#define FRAME_lstrafe3 954 +#define FRAME_lstrafe4 955 +#define FRAME_lstrafe5 956 +#define FRAME_lstrafe6 957 +#define FRAME_lstrafe7 958 +#define FRAME_lstrafe8 959 +#define FRAME_rstrafe1 960 +#define FRAME_rstrafe2 961 +#define FRAME_rstrafe3 962 +#define FRAME_rstrafe4 963 +#define FRAME_rstrafe5 964 +#define FRAME_rstrafe6 965 +#define FRAME_rstrafe7 966 +#define FRAME_rstrafe8 967 +#define FRAME_lsprint1 968 +#define FRAME_lsprint2 969 +#define FRAME_lsprint3 970 +#define FRAME_lsprint4 971 +#define FRAME_lsprint5 972 +#define FRAME_lsprint6 973 +#define FRAME_rsprint1 974 +#define FRAME_rsprint2 975 +#define FRAME_rsprint3 976 +#define FRAME_rsprint4 977 +#define FRAME_rsprint5 978 +#define FRAME_rsprint6 979 +#define FRAME_lswichl2r1 980 +#define FRAME_lswichl2r2 981 +#define FRAME_lswichl2r3 982 +#define FRAME_lswichl2r4 983 +#define FRAME_lswichl2r5 984 +#define FRAME_lswichl2r6 985 +#define FRAME_lswichl2r7 986 +#define FRAME_lswichr2l1 987 +#define FRAME_lswichr2l2 988 +#define FRAME_lswichr2l3 989 +#define FRAME_lswichr2l4 990 +#define FRAME_lswichr2l5 991 +#define FRAME_lswichr2l6 992 +#define FRAME_lswichr2l7 993 +#define FRAME_rswichl2r1 994 +#define FRAME_rswichl2r2 995 +#define FRAME_rswichl2r3 996 +#define FRAME_rswichl2r4 997 +#define FRAME_rswichl2r5 998 +#define FRAME_rswichl2r6 999 +#define FRAME_rswichl2r7 1000 +#define FRAME_rswichr2l1 1001 +#define FRAME_rswichr2l2 1002 +#define FRAME_rswichr2l3 1003 +#define FRAME_rswichr2l4 1004 +#define FRAME_rswichr2l5 1005 +#define FRAME_rswichr2l6 1006 +#define FRAME_rswichr2l7 1007 +#define FRAME_ovrhang1 1008 +#define FRAME_ovrhang2 1009 +#define FRAME_ovrhang3 1010 +#define FRAME_ovrhang4 1011 +#define FRAME_ovrhang5 1012 +#define FRAME_ovrhang6 1013 +#define FRAME_ovrhang7 1014 +#define FRAME_ovrhang8 1015 +#define FRAME_ovrhang9 1016 +#define FRAME_ovrhang10 1017 +#define FRAME_ovrhang11 1018 +#define FRAME_ovrhang12 1019 +#define FRAME_ovrhang13 1020 +#define FRAME_ovrhang14 1021 +#define FRAME_ovrhang15 1022 +#define FRAME_ovrhang16 1023 +#define FRAME_ovrhang17 1024 +#define FRAME_swcharo1 1025 +#define FRAME_swcharo2 1026 +#define FRAME_swcharo3 1027 +#define FRAME_swcharo4 1028 +#define FRAME_swcharo5 1029 +#define FRAME_swcharo6 1030 +#define FRAME_swcharo7 1031 +#define FRAME_ballspell1 1032 +#define FRAME_ballspell2 1033 +#define FRAME_ballspell3 1034 +#define FRAME_ballspell4 1035 +#define FRAME_ballspell5 1036 +#define FRAME_ballspell6 1037 +#define FRAME_ballspell7 1038 +#define FRAME_ballspell8 1039 +#define FRAME_Ljogback1 1040 +#define FRAME_Ljogback2 1041 +#define FRAME_Ljogback3 1042 +#define FRAME_Ljogback4 1043 +#define FRAME_Ljogback5 1044 +#define FRAME_Ljogback6 1045 +#define FRAME_Rjogback1 1046 +#define FRAME_Rjogback2 1047 +#define FRAME_Rjogback3 1048 +#define FRAME_Rjogback4 1049 +#define FRAME_Rjogback5 1050 +#define FRAME_Rjogback6 1051 +#define FRAME_Lcrepbck1 1052 +#define FRAME_Lcrepbck2 1053 +#define FRAME_Lcrepbck3 1054 +#define FRAME_Lcrepbck4 1055 +#define FRAME_Lcrepbck5 1056 +#define FRAME_Lcrepbck6 1057 +#define FRAME_Lcrepbck7 1058 +#define FRAME_Lcrepbck8 1059 +#define FRAME_Lcrepbck9 1060 +#define FRAME_Lcrepbck10 1061 +#define FRAME_Lcrepbck11 1062 +#define FRAME_Lcrepbck12 1063 +#define FRAME_Rcrepbck1 1064 +#define FRAME_Rcrepbck2 1065 +#define FRAME_Rcrepbck3 1066 +#define FRAME_Rcrepbck4 1067 +#define FRAME_Rcrepbck5 1068 +#define FRAME_Rcrepbck6 1069 +#define FRAME_Rcrepbck7 1070 +#define FRAME_Rcrepbck8 1071 +#define FRAME_Rcrepbck9 1072 +#define FRAME_Rcrepbck10 1073 +#define FRAME_Rcrepbck11 1074 +#define FRAME_Rcrepbck12 1075 +#define FRAME_blowback1 1076 +#define FRAME_blowback2 1077 +#define FRAME_blowback3 1078 +#define FRAME_blowback4 1079 +#define FRAME_blowback5 1080 +#define FRAME_blowback6 1081 +#define FRAME_blowback7 1082 +#define FRAME_blowback8 1083 +#define FRAME_blowback9 1084 +#define FRAME_blowback10 1085 +#define FRAME_blowback11 1086 +#define FRAME_blowback12 1087 +#define FRAME_blowback13 1088 +#define FRAME_blowback14 1089 +#define FRAME_blowback15 1090 +#define FRAME_blowback16 1091 +#define FRAME_blowback17 1092 +#define FRAME_blowback18 1093 +#define FRAME_blowback19 1094 +#define FRAME_blowback20 1095 +#define FRAME_blowback21 1096 +#define FRAME_blowback22 1097 +#define FRAME_blowback23 1098 +#define FRAME_blowback24 1099 +#define FRAME_fastleft1 1100 +#define FRAME_fastleft2 1101 +#define FRAME_fastleft3 1102 +#define FRAME_fastleft4 1103 +#define FRAME_fastleft5 1104 +#define FRAME_fastleft6 1105 +#define FRAME_fastleft7 1106 +#define FRAME_fastleft8 1107 +#define FRAME_fastrite1 1108 +#define FRAME_fastrite2 1109 +#define FRAME_fastrite3 1110 +#define FRAME_fastrite4 1111 +#define FRAME_fastrite5 1112 +#define FRAME_fastrite6 1113 +#define FRAME_fastrite7 1114 +#define FRAME_fastrite8 1115 +#define FRAME_faceplant1 1116 +#define FRAME_faceplant2 1117 +#define FRAME_faceplant3 1118 +#define FRAME_faceplant4 1119 +#define FRAME_faceplant5 1120 +#define FRAME_faceplant6 1121 +#define FRAME_faceplant7 1122 +#define FRAME_faceplant8 1123 +#define FRAME_faceplant9 1124 +#define FRAME_faceplant10 1125 +#define FRAME_faceplant11 1126 +#define FRAME_faceplant12 1127 +#define FRAME_faceplant13 1128 +#define FRAME_faceplant14 1129 +#define FRAME_faceplant15 1130 +#define FRAME_faceplant16 1131 +#define FRAME_faceplant17 1132 +#define FRAME_faceplant18 1133 +#define FRAME_faceplant19 1134 +#define FRAME_faceplant20 1135 +#define FRAME_faceplant21 1136 +#define FRAME_faceplant22 1137 +#define FRAME_faceplant23 1138 +#define FRAME_faceplant24 1139 +#define FRAME_choking1 1140 +#define FRAME_choking2 1141 +#define FRAME_choking3 1142 +#define FRAME_choking4 1143 +#define FRAME_choking5 1144 +#define FRAME_choking6 1145 +#define FRAME_choking7 1146 +#define FRAME_choking8 1147 +#define FRAME_choking9 1148 +#define FRAME_choking10 1149 +#define FRAME_choking11 1150 +#define FRAME_choking12 1151 +#define FRAME_choking13 1152 +#define FRAME_choking14 1153 +#define FRAME_choking15 1154 +#define FRAME_choking16 1155 +#define FRAME_choking17 1156 +#define FRAME_choking18 1157 +#define FRAME_choking19 1158 +#define FRAME_choking20 1159 +#define FRAME_choking21 1160 +#define FRAME_choking22 1161 +#define FRAME_choking23 1162 +#define FRAME_choking24 1163 +#define FRAME_choking25 1164 +#define FRAME_choking26 1165 +#define FRAME_choking27 1166 +#define FRAME_choking28 1167 +#define FRAME_choking29 1168 +#define FRAME_choking30 1169 +#define FRAME_choking31 1170 +#define FRAME_choking32 1171 +#define FRAME_choking33 1172 +#define FRAME_choking34 1173 +#define FRAME_choking35 1174 +#define FRAME_lookbck1 1175 +#define FRAME_lookbck2 1176 +#define FRAME_lookbck3 1177 +#define FRAME_lookbck4 1178 +#define FRAME_lookbck5 1179 +#define FRAME_lookbck6 1180 +#define FRAME_lookbck7 1181 +#define FRAME_lookbck8 1182 +#define FRAME_lookbck9 1183 +#define FRAME_lookbck10 1184 +#define FRAME_lookbck11 1185 +#define FRAME_lookbck12 1186 +#define FRAME_lookbck13 1187 +#define FRAME_lookbck14 1188 +#define FRAME_lookbck15 1189 +#define FRAME_lookbck16 1190 +#define FRAME_lookbck17 1191 +#define FRAME_lookbck18 1192 +#define FRAME_lookbck19 1193 +#define FRAME_lookbck20 1194 +#define FRAME_lookbck21 1195 +#define FRAME_lookbck22 1196 +#define FRAME_lookbck23 1197 +#define FRAME_lookbck24 1198 +#define FRAME_lookbck25 1199 +#define FRAME_lookbck26 1200 +#define FRAME_lookbck27 1201 +#define FRAME_lookbck28 1202 +#define FRAME_lookbck29 1203 +#define FRAME_asscrtch1 1204 +#define FRAME_asscrtch2 1205 +#define FRAME_asscrtch3 1206 +#define FRAME_asscrtch4 1207 +#define FRAME_asscrtch5 1208 +#define FRAME_asscrtch6 1209 +#define FRAME_asscrtch7 1210 +#define FRAME_asscrtch8 1211 +#define FRAME_asscrtch9 1212 +#define FRAME_asscrtch10 1213 +#define FRAME_asscrtch11 1214 +#define FRAME_asscrtch12 1215 +#define FRAME_asscrtch13 1216 +#define FRAME_asscrtch14 1217 +#define FRAME_asscrtch15 1218 +#define FRAME_asscrtch16 1219 +#define FRAME_asscrtch17 1220 +#define FRAME_asscrtch18 1221 +#define FRAME_asscrtch19 1222 +#define FRAME_asscrtch20 1223 +#define FRAME_asscrtch21 1224 +#define FRAME_asscrtch22 1225 +#define FRAME_asscrtch23 1226 +#define FRAME_asscrtch24 1227 +#define FRAME_asscrtch25 1228 +#define FRAME_wipebrow1 1229 +#define FRAME_wipebrow2 1230 +#define FRAME_wipebrow3 1231 +#define FRAME_wipebrow4 1232 +#define FRAME_wipebrow5 1233 +#define FRAME_wipebrow6 1234 +#define FRAME_wipebrow7 1235 +#define FRAME_wipebrow8 1236 +#define FRAME_wipebrow9 1237 +#define FRAME_wipebrow10 1238 +#define FRAME_wipebrow11 1239 +#define FRAME_wipebrow12 1240 +#define FRAME_wipebrow13 1241 +#define FRAME_wipebrow14 1242 +#define FRAME_wipebrow15 1243 +#define FRAME_wipebrow16 1244 +#define FRAME_wipebrow17 1245 +#define FRAME_wipebrow18 1246 +#define FRAME_wipebrow19 1247 +#define FRAME_jumprite1 1248 +#define FRAME_jumprite2 1249 +#define FRAME_jumprite3 1250 +#define FRAME_jumprite4 1251 +#define FRAME_jumprite5 1252 +#define FRAME_jumprite6 1253 +#define FRAME_jumprite7 1254 +#define FRAME_jumprite8 1255 +#define FRAME_jumprite9 1256 +#define FRAME_jumprite10 1257 +#define FRAME_jumprite11 1258 +#define FRAME_jumprite12 1259 +#define FRAME_jumprite13 1260 +#define FRAME_jumprite14 1261 +#define FRAME_jumprite15 1262 +#define FRAME_jumprite16 1263 +#define FRAME_jumprite17 1264 +#define FRAME_jumprite18 1265 +#define FRAME_jumprite19 1266 +#define FRAME_jumprite20 1267 +#define FRAME_jumprite21 1268 +#define FRAME_jumprite22 1269 +#define FRAME_jumprite23 1270 +#define FRAME_jumprite24 1271 +#define FRAME_jumpleft1 1272 +#define FRAME_jumpleft2 1273 +#define FRAME_jumpleft3 1274 +#define FRAME_jumpleft4 1275 +#define FRAME_jumpleft5 1276 +#define FRAME_jumpleft6 1277 +#define FRAME_jumpleft7 1278 +#define FRAME_jumpleft8 1279 +#define FRAME_jumpleft9 1280 +#define FRAME_jumpleft10 1281 +#define FRAME_jumpleft11 1282 +#define FRAME_jumpleft12 1283 +#define FRAME_jumpleft13 1284 +#define FRAME_jumpleft14 1285 +#define FRAME_jumpleft15 1286 +#define FRAME_jumpleft16 1287 +#define FRAME_jumpleft17 1288 +#define FRAME_jumpleft18 1289 +#define FRAME_jumpleft19 1290 +#define FRAME_jumpleft20 1291 +#define FRAME_jumpleft21 1292 +#define FRAME_jumpleft22 1293 +#define FRAME_jumpleft23 1294 +#define FRAME_jumpleft24 1295 +#define FRAME_jumpback1 1296 +#define FRAME_jumpback2 1297 +#define FRAME_jumpback3 1298 +#define FRAME_jumpback4 1299 +#define FRAME_jumpback5 1300 +#define FRAME_jumpback6 1301 +#define FRAME_jumpback7 1302 +#define FRAME_jumpback8 1303 +#define FRAME_jumpback9 1304 +#define FRAME_jumpback10 1305 +#define FRAME_jumpback11 1306 +#define FRAME_jumpback12 1307 +#define FRAME_jumpback13 1308 +#define FRAME_jumpback14 1309 +#define FRAME_jumpback15 1310 +#define FRAME_jumpback16 1311 +#define FRAME_jumpback17 1312 +#define FRAME_jumpback18 1313 +#define FRAME_jumpback19 1314 +#define FRAME_jumpback20 1315 +#define FRAME_jumpback21 1316 +#define FRAME_jumpback22 1317 +#define FRAME_jumpback23 1318 +#define FRAME_jumpback24 1319 +#define FRAME_creepL1 1320 +#define FRAME_creepL2 1321 +#define FRAME_creepL3 1322 +#define FRAME_creepL4 1323 +#define FRAME_creepL5 1324 +#define FRAME_creepL6 1325 +#define FRAME_creepL7 1326 +#define FRAME_creepL8 1327 +#define FRAME_creepL9 1328 +#define FRAME_creepL10 1329 +#define FRAME_creepL11 1330 +#define FRAME_creepL12 1331 +#define FRAME_creepR1 1332 +#define FRAME_creepR2 1333 +#define FRAME_creepR3 1334 +#define FRAME_creepR4 1335 +#define FRAME_creepR5 1336 +#define FRAME_creepR6 1337 +#define FRAME_creepR7 1338 +#define FRAME_creepR8 1339 +#define FRAME_creepR9 1340 +#define FRAME_creepR10 1341 +#define FRAME_creepR11 1342 +#define FRAME_creepR12 1343 +#define FRAME_gofast1 1344 +#define FRAME_gofast2 1345 +#define FRAME_gofast3 1346 +#define FRAME_gofast4 1347 +#define FRAME_swmfast1 1348 +#define FRAME_swmfast2 1349 +#define FRAME_swmfast3 1350 +#define FRAME_swmfast4 1351 +#define FRAME_swmfast5 1352 +#define FRAME_swmfast6 1353 +#define FRAME_swmfast7 1354 +#define FRAME_drownidle1 1355 +#define FRAME_drownidle2 1356 +#define FRAME_drownidle3 1357 +#define FRAME_drownidle4 1358 +#define FRAME_drownidle5 1359 +#define FRAME_drownidle6 1360 +#define FRAME_drownidle7 1361 +#define FRAME_drownidle8 1362 +#define FRAME_drownidle9 1363 +#define FRAME_drownidle10 1364 +#define FRAME_drownidle11 1365 +#define FRAME_drownidle12 1366 +#define FRAME_drownidle13 1367 +#define FRAME_drownidle14 1368 +#define FRAME_drownidle15 1369 +#define FRAME_drownidle16 1370 +#define FRAME_drownidle17 1371 +#define FRAME_drownidle18 1372 +#define FRAME_drownidle19 1373 +#define FRAME_drownidle20 1374 +#define FRAME_drownidle21 1375 +#define FRAME_drownidle22 1376 +#define FRAME_drownidle23 1377 +#define FRAME_drownidle24 1378 +#define FRAME_drownidle25 1379 +#define FRAME_drownidle26 1380 +#define FRAME_drownidle27 1381 +#define FRAME_drownidle28 1382 +#define FRAME_drownidle29 1383 +#define FRAME_drownidle30 1384 +#define FRAME_drownidle31 1385 +#define FRAME_drownidle32 1386 +#define FRAME_roundbck1 1387 +#define FRAME_roundbck2 1388 +#define FRAME_roundbck3 1389 +#define FRAME_roundbck4 1390 +#define FRAME_roundbck5 1391 +#define FRAME_roundbck6 1392 +#define FRAME_roundbck7 1393 +#define FRAME_roundbck8 1394 +#define FRAME_trnswmL1 1395 +#define FRAME_trnswmL2 1396 +#define FRAME_trnswmR1 1397 +#define FRAME_trnswmR2 1398 +#define FRAME_swmL1 1399 +#define FRAME_swmL2 1400 +#define FRAME_swmL3 1401 +#define FRAME_swmL4 1402 +#define FRAME_swmL5 1403 +#define FRAME_swmL6 1404 +#define FRAME_swmL7 1405 +#define FRAME_swmL8 1406 +#define FRAME_swmL9 1407 +#define FRAME_swmR1 1408 +#define FRAME_swmR2 1409 +#define FRAME_swmR3 1410 +#define FRAME_swmR4 1411 +#define FRAME_swmR5 1412 +#define FRAME_swmR6 1413 +#define FRAME_swmR7 1414 +#define FRAME_swmR8 1415 +#define FRAME_swmR9 1416 +#define FRAME_subckswm1 1417 +#define FRAME_subckswm2 1418 +#define FRAME_subckswm3 1419 +#define FRAME_subckswm4 1420 +#define FRAME_subckswm5 1421 +#define FRAME_subckswm6 1422 +#define FRAME_subckswm7 1423 +#define FRAME_tnsubckswm1 1424 +#define FRAME_tnsubckswm2 1425 +#define FRAME_spining1 1426 +#define FRAME_spining2 1427 +#define FRAME_spining3 1428 +#define FRAME_spining4 1429 +#define FRAME_spining5 1430 +#define FRAME_spining6 1431 +#define FRAME_spining7 1432 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASE2 0 +#define MESH__BACK 1 +#define MESH__STOFF 2 +#define MESH__BOFF 3 +#define MESH__ARMOR 4 +#define MESH__RARM 5 +#define MESH__RHANDHI 6 +#define MESH__STAFACTV 7 +#define MESH__BLADSTF 8 +#define MESH__HELSTF 9 +#define MESH__LARM 10 +#define MESH__LHANDHI 11 +#define MESH__BOWACTV 12 +#define MESH__RLEG 13 +#define MESH__LLEG 14 +#define MESH__HEAD 15 + +#define NUM_PLAYER_NODES 16 + diff --git a/Toolkit/Programming/GameCode/game/m_priestess.c b/Toolkit/Programming/GameCode/game/m_priestess.c new file mode 100644 index 0000000..8a44eb1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_priestess.c @@ -0,0 +1,1699 @@ +//============================================================================== +// +// m_priestess.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "m_priestess.h" +#include "m_priestess_anim.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "fx.h" +#include "g_HitLocation.h" + +#include "m_stats.h" + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + +void create_priestess_proj(edict_t *self,edict_t *proj); + +enum { + HPMISSILE1, + HPMISSILE2, + HPMISSILE3, + HPMISSILE4, + HPMISSILE5, + HPMISSILE1_EXPLODE, + HPMISSILE2_EXPLODE, + HPMISSILE3_EXPLODE, + HPMISSILE4_EXPLODE, + HPMISSILE5_EXPLODE, + HPMISSILE1_LIGHT, + HPMISSILE2_LIGHT, + HPMISSILE3_LIGHT, + HPMISSILE4_LIGHT, + HPMISSILE5_LIGHT, + HPTELEPORT_START, + HPTELEPORT_END, + HPLIGHTNING_BOLT, +}; + +enum { + AS_QUEENS_FURY, + AS_BROODS_SACRIFICE, + AS_HEAVENS_RAIN, + AS_LIGHT_MISSILE, + AS_POUNCE, + AS_JUMP_RIGHT, + AS_JUMP_LEFT, +} HighPriestessAttackStates_e; + +enum +{ + HP_STAFF_INIT, + HP_STAFF_TRAIL, +} HighPriestessStaff_e; + +static animmove_t *animations[NUM_ANIMS] = +{ + &priestess_move_stand1, + &priestess_move_attack1_go, + &priestess_move_attack1_loop, + &priestess_move_attack1_end, + &priestess_move_attack2, + &priestess_move_backup, + &priestess_move_death, + &priestess_move_idle, + &priestess_move_jump, + &priestess_move_pain, + &priestess_move_idle_pose, + &priestess_move_pose_trans, + &priestess_move_shield_go, + &priestess_move_shield_end, + &priestess_move_dodge_left, + &priestess_move_dodge_right, + &priestess_move_walk, + &priestess_move_jump_forward, + &priestess_move_jump_back, + &priestess_move_jump_right, + &priestess_move_jump_left, + &priestess_move_jump_pounce, + &priestess_move_pounce_attack, + &priestess_move_attack3_go, + &priestess_move_attack3_loop, + &priestess_move_attack3_end, + &priestess_move_jump_attack +}; + +/* + + Priestess Teleport Functions + +*/ + +/*----------------------------------------------- + priestess_teleport_go +-----------------------------------------------*/ + +void priestess_teleport_go ( edict_t *self ) +{ + gi.sound (self, CHAN_AUTO, sounds[SND_TPORT_OUT], 1, ATTN_NORM, 0); + + self->takedamage = DAMAGE_NO; + + gi.CreateEffect(NULL, + FX_HP_MISSILE, + 0, + self->s.origin, + "vb", + self->s.origin, + HPTELEPORT_START); +} + +/*----------------------------------------------- + priestess_teleport_end +-----------------------------------------------*/ + +void priestess_teleport_end ( edict_t *self ) +{ + gi.sound (self, CHAN_AUTO, sounds[SND_TPORT_IN], 1, ATTN_NORM, 0); + + gi.CreateEffect(NULL, + FX_HP_MISSILE, + 0, + self->s.origin, + "vb", + self->s.origin, + HPTELEPORT_END); +} + +/*----------------------------------------------- + priestess_teleport_move +-----------------------------------------------*/ + +void blocker_throw ( edict_t *self, trace_t *trace ) +{ +#ifdef _DEVEL + gi.dprintf("ERROR blocker_throw : Entity touched teleport destination!\n"); +#endif +} + +void priestess_teleport_move ( edict_t *self ) +{ + edict_t *moveLocation = NULL, *bestLocation = NULL, *blocker = NULL; + trace_t trace; + vec3_t testPos; + vec3_t mins = { -24, -24, -36 }; + vec3_t maxs = { -24, -24, -36 }; + float bestDist = 9999999; + float dist, startDist; + + while ( (moveLocation = G_Find( moveLocation, FOFS( classname ), "path_corner")) != NULL) + { + if (stricmp(moveLocation->targetname, "priestess")) + continue; + + dist = vhlen(self->enemy->s.origin, moveLocation->s.origin); + + if (dist < 64) + continue; + + startDist = vhlen(self->s.origin, moveLocation->s.origin); + + if (startDist < 64) + continue; + + if ( (dist < bestDist) && (visible(moveLocation, self->enemy)) ) + { + VectorCopy(moveLocation->s.origin, testPos); + testPos[2] += 36; + + gi.trace(testPos, mins, maxs, testPos, self, MASK_MONSTERSOLID,&trace); + + if (trace.startsolid || trace.allsolid) + continue; + + if (trace.ent && !stricmp(trace.ent->classname, "player")) + continue; + + bestDist = dist; + bestLocation = moveLocation; + } + } + + if (bestLocation) + { + //ULTRA HACK! + VectorCopy(bestLocation->s.origin, self->monsterinfo.nav_goal); + self->s.origin[0] += 2000; + gi.linkentity(self); + + //Spawn a fake entity to sit where the priestess will teleport to assure there's no telefragging + blocker = G_Spawn(); + + VectorSet(blocker->mins, -24, -24, -36); + VectorSet(blocker->maxs, 24, 24, 36); + + blocker->solid = SOLID_BBOX; + blocker->movetype = PHYSICSTYPE_NONE; + + //If the player touches this entity somehow, he's thrown back + blocker->isBlocked = blocker_throw; + blocker->isBlocking = blocker_throw; + blocker->bounced = blocker_throw; + + self->movetarget = blocker; + + gi.linkentity(blocker); + } + else + { +#ifdef _DEVEL + gi.dprintf("ERROR priestess_teleport_move :Priestess unable to move to new teleport destination!\n"); +#endif + SetAnim(self, ANIM_SHIELD_END); + } +} + +/*----------------------------------------------- + priestess_teleport_self_effects +-----------------------------------------------*/ + +void priestess_teleport_self_effects( edict_t *self ) +{ + self->s.renderfx |= RF_ALPHA_TEXTURE; + self->s.color.r = 255; + self->s.color.g = 255; + self->s.color.b = 255; + self->s.color.a = 255; +} + +/*----------------------------------------------- + priestess_delta_alpha +-----------------------------------------------*/ + +void priestess_delta_alpha( edict_t *self, float amount ) +{ + if (self->s.color.a + amount > 255) + self->s.color.a = 255; + else if (self->s.color.a + amount < 0) + self->s.color.a = 0; + else + self->s.color.a += amount; +} + +/*----------------------------------------------- + priestess_stop_alpha +-----------------------------------------------*/ + +void priestess_stop_alpha ( edict_t *self ) +{ + self->takedamage = DAMAGE_YES; + + self->s.renderfx &= ~RF_ALPHA_TEXTURE; + self->s.color.r = 255; + self->s.color.g = 255; + self->s.color.b = 255; + self->s.color.a = 255; +} + +/*----------------------------------------------- + priestess_teleport_return +-----------------------------------------------*/ + +void priestess_teleport_return ( edict_t *self ) +{ + trace_t trace; + vec3_t start, end; + + if ( (self->movetarget) && (self->movetarget != self->enemy) ) + G_FreeEdict(self->movetarget); + + VectorCopy(self->monsterinfo.nav_goal, start); + VectorCopy(self->monsterinfo.nav_goal, end); + start[2] += 36; + end[2] -= 128; + + gi.trace(start, self->mins, self->maxs, end, self, MASK_MONSTERSOLID,&trace); + + if (trace.allsolid || trace.startsolid) + { + //The priestess has become lodged in something! + assert(0); + return; + } + + VectorCopy(trace.endpos, end); + + VectorCopy(end, self->s.origin); + gi.linkentity(self); + + SetAnim(self, ANIM_SHIELD_END); +} + +/* + + Priestess Projectile Functions + +*/ + +/*----------------------------------------------- + priestess_proj1_drunken +-----------------------------------------------*/ +void priestess_proj1_drunken( edict_t *self ) +{ + VectorRandomCopy(self->velocity, self->velocity, 64); + + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + priestess_proj1_think +-----------------------------------------------*/ + +void priestess_proj1_think( edict_t *self ) +{ + vec3_t olddir, newdir, huntdir; + float oldvelmult , newveldiv, speed_mod; + + //No enemy, stop tracking + if (!self->enemy) + { + self->think = NULL; + return; + } + + //Enemy is dead, stop tracking + if (self->enemy->health <= 0) + { + self->think = NULL; + return; + } + + //Timeout? + if (self->monsterinfo.attack_finished < level.time) + { + gi.sound (self, CHAN_BODY, sounds[SND_BALLHIT], 1, ATTN_NORM, 0); + + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + HPMISSILE1_EXPLODE); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; + + return; + } + + VectorCopy(self->velocity, olddir); + VectorNormalize(olddir); + + VectorSubtract(self->enemy->s.origin, self->s.origin, huntdir); + VectorNormalize(huntdir); + + oldvelmult = 1.2; + newveldiv = 1/(oldvelmult + 1); + + VectorScale(olddir, oldvelmult, olddir); + VectorAdd(olddir, huntdir, newdir); + VectorScale(newdir, newveldiv, newdir); + + speed_mod = DotProduct( olddir , newdir ); + + if (speed_mod < 0.05) + speed_mod = 0.05; + + newveldiv *= self->ideal_yaw * speed_mod; + + VectorScale(olddir, oldvelmult, olddir); + VectorAdd(olddir, huntdir, newdir); + VectorScale(newdir, newveldiv, newdir); + + VectorCopy(newdir, self->velocity); + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + priestess_proj2_die +-----------------------------------------------*/ + +int priestess_proj2_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ + gi.sound (self, CHAN_AUTO, sounds[SND_BUGHIT], 1, ATTN_NORM, 0); + + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + HPMISSILE3_EXPLODE); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; + + return 1; +} + +/*----------------------------------------------- + priestess_proj2_think +-----------------------------------------------*/ + +void priestess_proj2_think( edict_t *self ) +{ + //Timeout? + if (self->monsterinfo.attack_finished < level.time) + { + gi.sound (self, CHAN_AUTO, sounds[SND_BUGHIT], 1, ATTN_NORM, 0); + + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + HPMISSILE3_EXPLODE); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; + + return; + } + + VectorScale(self->velocity, self->missile_range, self->velocity); + + self->velocity[0] += irand(-8, 8); + self->velocity[1] += irand(-8, 8); + self->velocity[2] += irand(-8, 8); + + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + priestess_proj1_blocked +-----------------------------------------------*/ + +void priestess_proj1_blocked( edict_t *self, trace_t *trace ) +{ + edict_t *proj; + vec3_t hitDir; + int damage; + byte exp; + + if (trace->ent == self->owner) + return; + + if (!stricmp(trace->ent->classname, "HPriestess_Missile")) + return; + + //Reflection stuff + if(EntReflecting(trace->ent, true, true)) + { + proj = G_Spawn(); + + create_priestess_proj(self,proj); + proj->owner = self->owner; + proj->ideal_yaw = self->ideal_yaw; + + Create_rand_relect_vect(self->velocity, proj->velocity); + Vec3ScaleAssign(proj->ideal_yaw,proj->velocity); + vectoangles(proj->velocity, proj->s.angles); + + switch ( self->monsterinfo.attack_state ) + { + case AS_QUEENS_FURY: + case AS_LIGHT_MISSILE: + exp = HPMISSILE1_EXPLODE; + break; + + case AS_BROODS_SACRIFICE: + exp = HPMISSILE3_EXPLODE; + break; + + case AS_HEAVENS_RAIN: + exp = HPMISSILE1_EXPLODE; + break; + } + + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + (unsigned char) exp); + + gi.linkentity(proj); + + G_SetToFree(self); + + return; + } + + //Do the rest of the stuff + switch ( self->monsterinfo.attack_state ) + { + case AS_QUEENS_FURY: + exp = HPMISSILE1_EXPLODE; + damage = irand(HP_DMG_FURY_MIN, HP_DMG_FURY_MAX); + gi.sound (self, CHAN_AUTO, sounds[SND_HOMINGHIT], 1, ATTN_NORM, 0); + break; + + case AS_BROODS_SACRIFICE: + exp = HPMISSILE3_EXPLODE; + damage = irand(HP_DMG_BROOD_MIN, HP_DMG_BROOD_MAX); + gi.sound (self, CHAN_AUTO, sounds[SND_BUGHIT], 1, ATTN_NORM, 0); + break; + + case AS_HEAVENS_RAIN: + exp = HPMISSILE2_EXPLODE; + damage = HP_DMG_RAIN; + gi.sound (self, CHAN_AUTO, sounds[SND_ZAPHIT], 1, ATTN_NORM, 0); + break; + + case AS_LIGHT_MISSILE: + exp = HPMISSILE1_EXPLODE; + damage = irand(HP_DMG_MISSILE_MIN, HP_DMG_MISSILE_MAX); + gi.sound (self, CHAN_AUTO, sounds[SND_BALLHIT], 1, ATTN_NORM, 0); + break; + + default: + assert(0); + break; + } + + if ( trace->ent->takedamage ) + { + VectorCopy( self->velocity, hitDir ); + VectorNormalize( hitDir ); + + T_Damage( trace->ent, self, self->owner, hitDir, self->s.origin, trace->plane.normal, damage, 0, DAMAGE_SPELL | DAMAGE_NO_KNOCKBACK,MOD_DIED ); + } + + gi.CreateEffect(&self->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + self->s.origin, + "vb", + vec3_origin, + (unsigned char) exp); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + priestess_proj1_touch +-----------------------------------------------*/ + +void priestess_proj1_touch( edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface ) +{ + vec3_t hitDir; + byte exp; + int damage; + + if (other == self->owner) + return; + + if (!stricmp(other->classname, "HPriestess_Missile")) + return; + + //Do the rest of the stuff + switch ( self->monsterinfo.attack_state ) + { + case AS_QUEENS_FURY: + exp = HPMISSILE1_EXPLODE; + damage = irand(HP_DMG_FURY_MIN, HP_DMG_FURY_MAX); + gi.sound (self, CHAN_AUTO, sounds[SND_HOMINGHIT], 1, ATTN_NORM, 0); + break; + + case AS_BROODS_SACRIFICE: + exp = HPMISSILE3_EXPLODE; + damage = irand(HP_DMG_BROOD_MIN, HP_DMG_BROOD_MAX); + gi.sound (self, CHAN_AUTO, sounds[SND_BUGHIT], 1, ATTN_NORM, 0); + break; + + case AS_HEAVENS_RAIN: + exp = HPMISSILE2_EXPLODE; + damage = HP_DMG_RAIN; + gi.sound (self, CHAN_AUTO, sounds[SND_ZAPHIT], 1, ATTN_NORM, 0); + break; + + case AS_LIGHT_MISSILE: + exp = HPMISSILE1_EXPLODE; + damage = irand(HP_DMG_MISSILE_MIN, HP_DMG_MISSILE_MAX); + gi.sound (self, CHAN_AUTO, sounds[SND_BALLHIT], 1, ATTN_NORM, 0); + break; + + default: + assert(0); + break; + } + + if ( other->takedamage ) + { + VectorCopy( self->velocity, hitDir ); + VectorNormalize( hitDir ); + + T_Damage( other, self, self->owner, hitDir, self->s.origin, plane->normal, damage, 0, DAMAGE_SPELL | DAMAGE_NO_KNOCKBACK,MOD_DIED ); + } + + if (other == self->owner) + return; + + if (!stricmp(other->classname, "HPriestess_Missile")) + return; + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; +} + +/*----------------------------------------------- + create_priestess_proj +-----------------------------------------------*/ + +// create the guts of the high priestess projectile +void create_priestess_proj(edict_t *self,edict_t *proj) +{ + proj->svflags |= SVF_ALWAYS_SEND; + proj->movetype = PHYSICSTYPE_FLY; + proj->gravity = 0; + proj->solid = SOLID_BBOX; + proj->classname = "HPriestess_Missile"; + proj->dmg = 1.0; + proj->s.scale = 1.0; + proj->clipmask = MASK_SHOT; + proj->nextthink = level.time + 0.1; + + proj->bounced = priestess_proj1_blocked; + proj->isBlocking = priestess_proj1_blocked; + proj->isBlocked = priestess_proj1_blocked; + //proj->touch = priestess_proj1_touch; + + proj->s.effects=EF_MARCUS_FLAG1|EF_CAMERA_NO_CLIP; + proj->enemy = self->enemy; + + VectorSet(proj->mins, -2.0, -2.0, -2.0); + VectorSet(proj->maxs, 2.0, 2.0, 2.0); + VectorCopy(self->s.origin, proj->s.origin); +} + +/*----------------------------------------------- + priestess_fire1 +-----------------------------------------------*/ + +//Hand thrown light missiles +void priestess_fire1( edict_t *self, float pitch_ofs, float yaw_ofs, float roll_ofs ) +{ + edict_t *proj; + vec3_t vf, vr, predPos; + vec3_t ang, vel, startOfs, angles; + int i; + + if (!self->enemy) + return; + + //Only predict once for all the missiles + M_PredictTargetPosition ( self->enemy, self->enemy->velocity, 1, predPos ); + + AngleVectors(self->s.angles, vf, vr, NULL); + + VectorMA(self->s.origin, -8, vf, startOfs); + VectorMA(startOfs, -16, vr, startOfs); + startOfs[2] += 32; + + VectorSubtract(predPos, startOfs, vf); + VectorNormalize(vf); + + vectoangles( vf, angles ); + + i = irand(2,3); + + while (i--) + { + // Spawn the projectile + proj = G_Spawn(); + + proj->monsterinfo.attack_state = AS_LIGHT_MISSILE; + create_priestess_proj(self,proj); + proj->owner = self; + + VectorCopy(startOfs, proj->s.origin); + VectorCopy(angles, ang); + + ang[PITCH] = flrand( -4, 4 ) + -ang[PITCH]; + ang[YAW] += flrand( -4, 4 ); + + AngleVectors( ang, vel, NULL, NULL ); + + VectorScale(vel, irand(500,600), proj->velocity); + + vectoangles(proj->velocity, proj->s.angles); + + gi.sound (self, CHAN_AUTO, sounds[SND_3BALLATK], 1, ATTN_NORM, 0); + + //One in ten wander off drunkenly + if (!irand(0,10)) + proj->think = priestess_proj1_drunken; + + gi.CreateEffect(&proj->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + NULL, + "vb", + proj->velocity, + HPMISSILE2); + + gi.linkentity(proj); + } +} + +/*----------------------------------------------- + priestess_fire2 +-----------------------------------------------*/ + +//Tracking, anime style missiles +void priestess_fire2( edict_t *self, float pitch_ofs, float yaw_ofs, float roll_ofs ) +{ + edict_t *proj; + vec3_t vf, vr, ang; + + // Spawn the projectile + + proj = G_Spawn(); + + create_priestess_proj(self,proj); + + proj->monsterinfo.attack_state = AS_QUEENS_FURY; + proj->owner = self; + + AngleVectors(self->s.angles, vf, vr, NULL); + + VectorCopy(self->s.origin, proj->s.origin); + + VectorMA(self->s.origin, 30, vf, proj->s.origin); + VectorMA(proj->s.origin, 8, vr, proj->s.origin); + proj->s.origin[2] += 56; + + proj->ideal_yaw = 400; + + vectoangles( vf, ang ); + + ang[PITCH] -= irand( 5, 75 ); + ang[YAW] += irand( -60, 60 ); + + AngleVectors( ang, vf, NULL, NULL ); + + VectorScale( vf, proj->ideal_yaw, proj->velocity ); + + proj->monsterinfo.attack_finished= level.time + 2; + + vectoangles(proj->velocity, proj->s.angles); + + if (!irand(0,15)) + proj->think = priestess_proj1_drunken; + else + proj->think=priestess_proj1_think; + + gi.sound (self, CHAN_AUTO, sounds[SND_HOMINGATK], 1, ATTN_NORM, 0); + + gi.CreateEffect(&proj->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + proj->s.origin, + "vb", + proj->s.origin, + HPMISSILE1); + + gi.linkentity(proj); +} + +/*----------------------------------------------- + priestess_fire3 +-----------------------------------------------*/ + +//The light bugs +void priestess_fire3( edict_t *self, float pitch_ofs, float yaw_ofs, float roll_ofs ) +{ + edict_t *proj; + vec3_t vf, vr, ang, startPos; + float len; + + // Spawn the projectile + + proj = G_Spawn(); + + create_priestess_proj(self,proj); + + proj->takedamage = DAMAGE_YES; + proj->die = priestess_proj2_die; + + proj->monsterinfo.attack_state = AS_BROODS_SACRIFICE; + proj->owner = self; + + AngleVectors(self->s.angles, vf, vr, NULL); + VectorNormalize(vf); + + VectorCopy(self->s.origin, proj->s.origin); + + VectorMA(self->s.origin, 30, vf, proj->s.origin); + VectorMA(proj->s.origin, 8, vr, proj->s.origin); + proj->s.origin[2] += 56; + VectorCopy(proj->s.origin, startPos); + + len = M_DistanceToTarget(self, self->enemy); + + len /= 200; + + proj->ideal_yaw = irand(500*len,750*len); + proj->missile_range = flrand(0.65, 0.75); + + VectorSubtract(self->enemy->s.origin, proj->s.origin, vf); + VectorNormalize(vf); + + vectoangles( vf, ang ); + + ang[PITCH] *= -1; + + ang[PITCH] += irand( -10, 5 ); + ang[YAW] += irand( -35, 35 ); + + AngleVectors( ang, vf, NULL, NULL ); + + VectorScale( vf, proj->ideal_yaw, proj->velocity ); + + proj->monsterinfo.attack_finished= level.time + 5; + + vectoangles(proj->velocity, proj->s.angles); + + proj->think=priestess_proj2_think; + + gi.sound (self, CHAN_AUTO, sounds[SND_BUGS], 1, ATTN_NORM, 0); + + gi.CreateEffect(&proj->s, + FX_HP_MISSILE, + CEF_OWNERS_ORIGIN, + startPos, + "vb", + proj->velocity, + HPMISSILE3); + + gi.linkentity(proj); +} + +/*----------------------------------------------- + priestess_fire4 +-----------------------------------------------*/ + +//Big special light show of doom and chaos and destruction... or something... +void priestess_fire4( edict_t *self, float pitch_ofs, float yaw_ofs, float roll_ofs ) +{ + trace_t trace; + vec3_t vf, vr, /*ang,*/ startPos, endPos; + vec3_t mins = { -1, -1, -1 }; + vec3_t maxs = { 1, 1, 1 }; + float len; + + if (self->monsterinfo.sound_finished < level.time) + { + gi.sound (self, CHAN_AUTO, sounds[SND_ZAP], 1, ATTN_NORM, 0); + self->monsterinfo.sound_finished = level.time + 5; + } + + AngleVectors(self->s.angles, vf, vr, NULL); + + VectorCopy(self->s.origin, startPos); + + VectorMA(self->s.origin, 30, vf, startPos); + VectorMA(startPos, 8, vr, startPos); + startPos[2] += 56; + + //The 5 to 8 effects are spawn on the other side, no reason to send each one + gi.CreateEffect(NULL, + FX_HP_MISSILE, + 0, + startPos, + "vb", + startPos, + HPMISSILE4); + + AngleVectors(self->s.angles, vf, vr, NULL); + + VectorCopy(self->s.origin, startPos); + + VectorMA(self->s.origin, 30, vf, startPos); + VectorMA(startPos, 8, vr, startPos); + startPos[2] += 56; + + if ( self->monsterinfo.misc_debounce_time < level.time ) + { + VectorSubtract(self->enemy->s.origin, startPos, vf); + len = VectorNormalize(vf); + + VectorMA( startPos, len, vf, endPos ); + + gi.trace( startPos, mins, maxs, endPos, self, MASK_SHOT ,&trace); + + if (trace.ent == self->enemy) + { + T_Damage(trace.ent, self, self, vf, trace.endpos, trace.plane.normal, + irand(HP_DMG_FIRE_MIN, HP_DMG_FIRE_MAX), 0, DAMAGE_DISMEMBER,MOD_DIED); + + gi.sound (self, CHAN_AUTO, sounds[SND_ZAPHIT], 1, ATTN_NORM, 0); + } + + gi.CreateEffect(NULL, + FX_HP_MISSILE, + 0, + startPos, + "vb", + trace.endpos, + HPMISSILE5); + + self->monsterinfo.misc_debounce_time = level.time + flrand(0.2, 0.4); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/* + + Priestess Helper Functions + +*/ + +/*----------------------------------------------- + priestess_attack1_pause +-----------------------------------------------*/ + +void priestess_attack1_pause( edict_t *self ) +{ + if (self->monsterinfo.search_time--) + { + } + else + { + priestess_pause(self); + } +} + +/*----------------------------------------------- + priestess_attack3_loop +-----------------------------------------------*/ + +void priestess_attack3_loop ( edict_t *self ) +{ + vec3_t spawnSpot, vf, vr; + + SetAnim(self, ANIM_ATTACK3_LOOP); + self->monsterinfo.attack_finished = level.time + 4; + + AngleVectors(self->s.angles, vf, vr, NULL); + + VectorCopy(self->s.origin, spawnSpot); + + VectorMA(self->s.origin, 30, vf, spawnSpot); + VectorMA(spawnSpot, 8, vr, spawnSpot); + spawnSpot[2] += 56; + + //RIGHT HERE! + self->monsterinfo.jump_time = level.time + 10; + self->monsterinfo.attack_state = irand(0,2); + + //Don't repeat an attack (people want to see them all!) + if (self->monsterinfo.lefty == self->monsterinfo.attack_state) + { + switch ( self->monsterinfo.attack_state ) + { + case AS_QUEENS_FURY: + + self->monsterinfo.attack_state += irand(1,2); + break; + + case AS_BROODS_SACRIFICE: + + if (irand(0,1)) + self->monsterinfo.attack_state = AS_QUEENS_FURY; + else + self->monsterinfo.attack_state = AS_HEAVENS_RAIN; + break; + + case AS_HEAVENS_RAIN: + + self->monsterinfo.attack_state -= irand(1,2); + break; + } + } + + self->monsterinfo.lefty = self->monsterinfo.attack_state; + + switch ( self->monsterinfo.attack_state ) + { + case AS_QUEENS_FURY: + gi.CreateEffect(NULL, + FX_HP_MISSILE, + 0, + spawnSpot, + "vb", + vec3_origin, + HPMISSILE1_LIGHT); + + break; + + case AS_BROODS_SACRIFICE: + self->monsterinfo.attack_finished = level.time + 2; + gi.CreateEffect(NULL, + FX_HP_MISSILE, + 0, + spawnSpot, + "vb", + vec3_origin, + HPMISSILE3_LIGHT); + break; + + case AS_HEAVENS_RAIN: + gi.CreateEffect(NULL, + FX_HP_MISSILE, + 0, + spawnSpot, + "vb", + vec3_origin, + HPMISSILE4_LIGHT); + + gi.CreateEffect(NULL, + FX_LENSFLARE, + CEF_FLAG8, + spawnSpot, + "ibbbf", + 4, + (byte) 128, + (byte) 128, + (byte) 128, + 0.9); + + break; + } +} + +/*----------------------------------------------- + priestess_attackc_loop_fire +-----------------------------------------------*/ + +void priestess_attack3_loop_fire ( edict_t *self ) +{ + if (self->monsterinfo.attack_finished < level.time) + { + SetAnim(self, ANIM_ATTACK3_END); + return; + } + + //NOTE: These effects are not necessarily called each frame (hence the irands) + switch ( self->monsterinfo.attack_state ) + { + case AS_QUEENS_FURY: + + if (self->monsterinfo.search_time < level.time) + { + priestess_fire2( self, 0, 0, 0 ); + self->monsterinfo.search_time = level.time + 0.25; + } + break; + + case AS_BROODS_SACRIFICE: + + if (self->monsterinfo.search_time < level.time) + { + priestess_fire3( self, 0, 0, 0 ); + self->monsterinfo.search_time = level.time + 0.15; + } + break; + + case AS_HEAVENS_RAIN: + + priestess_fire4( self, 0, 0, 0 ); + break; + } +} + +/*----------------------------------------------- + priestess_pounce_attack +-----------------------------------------------*/ + +void priestess_pounce_attack ( edict_t *self ) +{ + float len; + + if (M_ValidTarget(self, self->enemy)) + { + len = M_DistanceToTarget(self, self->enemy); + + if (len < 64) + { + SetAnim(self, ANIM_POUNCE_ATTACK); + } + else if (len < 128) + { + SetAnim(self, ANIM_ATTACK2); + } + else + { + priestess_pause(self); + } + } +} + +/*----------------------------------------------- + priestess_pounce +-----------------------------------------------*/ + +//Number of frames the priestess is in the air +#define PRIESTESS_JUMPFRAMES 10 +#define PRIESTESS_HOPDIST 0 + +void priestess_jump_attack ( edict_t *self ) +{ + vec3_t predPos, jumpVel; + float jumpDist, moveDist, hopDist; + + //Find out where the player will be when we would probably land + M_PredictTargetPosition( self->enemy, self->enemy->velocity, PRIESTESS_JUMPFRAMES+2, predPos); + + //Find the vector to that spot and the length + VectorSubtract(predPos, self->s.origin, jumpVel); + moveDist = VectorNormalize(jumpVel); + + //Velocity is applied per tenth of a frame, so take the distance, divide by the number of frames in the air, and FRAMETIME + jumpDist = ( moveDist * PRIESTESS_JUMPFRAMES ) * FRAMETIME; + + //Now get the height to keep her in the air long enough to complete this jump + hopDist = ( PRIESTESS_HOPDIST + ( ( sv_gravity->value * PRIESTESS_JUMPFRAMES ) / 4 ) ) * FRAMETIME; + + //Setup the vector for the jump + VectorScale( jumpVel, jumpDist, jumpVel ); + jumpVel[2] = hopDist; + + //Set the priestess in motion + VectorCopy( jumpVel, self->velocity ); +// self->groundentity = NULL; +} + +void priestess_pounce ( edict_t *self ) +{ + vec3_t predPos, jumpVel; + float jumpDist, moveDist, hopDist; + + if (!self->enemy) + return; + + //Find out where the player will be when we would probably land + M_PredictTargetPosition( self->enemy, self->enemy->velocity, PRIESTESS_JUMPFRAMES+2, predPos); + + //Find the vector to that spot and the length + VectorSubtract(predPos, self->s.origin, jumpVel); + moveDist = VectorNormalize(jumpVel); + + //Velocity is applied per tenth of a frame, so take the distance, divide by the number of frames in the air, and FRAMETIME + jumpDist = ( moveDist * PRIESTESS_JUMPFRAMES ) * FRAMETIME; + + //Now get the height to keep her in the air long enough to complete this jump + hopDist = ( PRIESTESS_HOPDIST + ( ( sv_gravity->value * PRIESTESS_JUMPFRAMES ) / 4 ) ) * FRAMETIME; + + //Setup the vector for the jump + VectorScale( jumpVel, jumpDist, jumpVel ); + jumpVel[2] = hopDist; + + //Set her in motion + VectorCopy( jumpVel, self->velocity ); +// self->groundentity = NULL; +} + +/*----------------------------------------------- + priestess_strike +-----------------------------------------------*/ + +void priestess_strike ( edict_t *self, float damage ) +{ + trace_t trace; + edict_t *victim; + vec3_t soff, eoff, mins, maxs, bloodDir, direction; + + //FIXME: Take out the mults here, done this way to speed up tweaking (sue me) + switch ( self->s.frame ) + { + case FRAME_attackB8: + VectorSet(soff, 16*4, -16*5, 16*3); + VectorSet(eoff, 16*3, 16*5, -8); + break; + + case FRAME_attackB14: + VectorSet(soff, 16*2, 16*5, 16*4); + VectorSet(eoff, 16*5, -16*5,-16*2); + break; + + case FRAME_jumpatt12: + VectorSet(soff, 16*2, 0, 16*5); + VectorSet(eoff, 16*5, 4, 4); + break; + } + + VectorSet(mins, -4, -4, -4); + VectorSet(maxs, 4, 4, 4); + + VectorSubtract(soff, eoff, bloodDir); + VectorNormalize(bloodDir); + + victim = M_CheckMeleeLineHit(self, soff, eoff, mins, maxs, &trace, direction); + + //Did something get hit? + if (victim) + { + if (victim == self) + { + //Create a spark effect + gi.CreateEffect(NULL, FX_SPARKS, CEF_FLAG6, trace.endpos, "d", direction); + gi.sound (self, CHAN_WEAPON, sounds[SND_SWIPEWALL], 1, ATTN_NORM, 0); + } + else + { + //Hurt whatever we were whacking away at + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, damage, damage*2, DAMAGE_DISMEMBER,MOD_DIED); + gi.sound (self, CHAN_WEAPON, sounds[SND_SWIPE], 1, ATTN_NORM, 0); + } + } + else + { + //Play swoosh sound + gi.sound (self, CHAN_AUTO, sounds[SND_SWIPEMISS], 1, ATTN_NORM, 0); + } +} + +/*----------------------------------------------- + priestess_move +-----------------------------------------------*/ + +void priestess_move( edict_t *self, float vf, float vr, float vu ) +{ +} + +/*----------------------------------------------- + priestess_jump_right +-----------------------------------------------*/ + +void priestess_jump_right( edict_t *self ) +{ + vec3_t vr; + + AngleVectors(self->s.angles, NULL, vr, NULL); + VectorScale( vr, 300, vr ); + vr[2] = 150; + + VectorCopy(vr, self->velocity); +// self->groundentity = NULL; +} + +/*----------------------------------------------- + priestess_jump_left +-----------------------------------------------*/ + +void priestess_jump_left( edict_t *self ) +{ + vec3_t vr; + + AngleVectors(self->s.angles, NULL, vr, NULL); + VectorScale( vr, -300, vr ); + vr[2] = 150; + + VectorCopy(vr, self->velocity); +// self->groundentity = NULL; +} + +/*----------------------------------------------- + priestess_jump_forward +-----------------------------------------------*/ + +void priestess_jump_forward( edict_t *self ) +{ + vec3_t vf; + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorScale( vf, 300, vf ); + vf[2] = 150; + + VectorCopy(vf, self->velocity); +// self->groundentity = NULL; +} + +/*----------------------------------------------- + priestess_jump_back +-----------------------------------------------*/ + +void priestess_jump_back( edict_t *self ) +{ + vec3_t vf; + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorScale( vf, -300, vf ); + vf[2] = 150; + + VectorCopy(vf, self->velocity); +// self->groundentity = NULL; +} + +/*----------------------------------------------- + priestess_pause +-----------------------------------------------*/ + +void priestess_pause( edict_t *self ) +{ + qboolean clear_LOS; + float len; + int chance; + + chance = irand(0,100); + + if (M_ValidTarget(self, self->enemy)) + { + len = M_DistanceToTarget(self, self->enemy); + + clear_LOS = visible(self, self->enemy); + + if (!clear_LOS && chance < 75) + { + SetAnim(self, ANIM_SHIELD_GO); + return; + } + + chance = irand(0,100); + + if (len < 64) + { + if (chance < 20) + SetAnim(self, ANIM_ATTACK2); + else if (chance < 40) + SetAnim(self, ANIM_BACKUP); + else + SetAnim(self, ANIM_JUMP_BACK); + } + else + { + if (chance < 40 && self->monsterinfo.jump_time < level.time) + { + SetAnim(self, ANIM_ATTACK3_GO); + } + else if (chance < 40 && self->monsterinfo.attack_state != AS_LIGHT_MISSILE) + { + self->monsterinfo.search_time = 2; + self->monsterinfo.attack_state = AS_LIGHT_MISSILE; + SetAnim(self, ANIM_ATTACK1_GO); + } + else if (chance < 80 && self->monsterinfo.attack_state != AS_POUNCE) + { + self->monsterinfo.attack_state = AS_POUNCE; + + if (len > 256) + SetAnim(self, ANIM_JUMP_POUNCE); + else + SetAnim(self, ANIM_JUMP_ATTACK); + } + else if (chance < 90 && self->monsterinfo.attack_finished < level.time) + { + SetAnim(self, ANIM_SHIELD_GO); + self->monsterinfo.attack_finished = level.time + 5; + } + else if (self->monsterinfo.attack_state != AS_JUMP_RIGHT) + { + self->monsterinfo.attack_state = AS_JUMP_RIGHT; + SetAnim(self, ANIM_JUMP_RIGHT); + } + else + { + self->monsterinfo.attack_state = AS_JUMP_LEFT; + SetAnim(self, ANIM_JUMP_LEFT); + } + } + + //SetAnim(self, ANIM_SHIELD_GO); + //self->monsterinfo.attack_state = AS_LIGHT_MISSILE; + //self->monsterinfo.search_time = 2; + //SetAnim(self, ANIM_STAND1); + //SetAnim(self, ANIM_ATTACK3_GO); + //SetAnim(self, ANIM_ATTACK1_GO); + //SetAnim(self, ANIM_JUMP_ATTACK); + //SetAnim(self, ANIM_JUMP_POUNCE); + + return; + } + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +/*----------------------------------------------- + priestess_idle +-----------------------------------------------*/ + +void priestess_idle(edict_t *self) +{ +} + +/*----------------------------------------------- + priestess_dead +-----------------------------------------------*/ + +void priestess_dead( edict_t *self ) +{ + /* CINEMATICS HERE */ + + self->mood_nextthink = -1;//never mood_think again + self->maxs[2] = self->mins[2] + 16; + + gi.RemovePersistantEffect(self->PersistantCFX); + self->PersistantCFX = 0; + gi.RemoveEffects(&self->s, 0); + + gi.linkentity (self); + + self->think = G_FreeEdict; + self->nextthink = level.time + 0.1; +} + +/* + + Priestess Message Functions + +*/ + +/*----------------------------------------------- + priestess_death +-----------------------------------------------*/ + +void priestess_death( edict_t *self, G_Message_t *msg ) +{ + self->msgHandler = DeadMsgHandler; + + if(self->deadflag == DEAD_DEAD) + return; + + self->deadflag = DEAD_DEAD; + self->takedamage = DAMAGE_NO; + + self->dmg = 0; + self->health = 0; + self->max_health = 0; + + M_ShowLifeMeter( self, 0, 0); + + SetAnim(self, ANIM_DEATH); +} + + +/*----------------------------------------------- + priestess_evade +-----------------------------------------------*/ + +void priestess_evade( edict_t *self, G_Message_t *msg ) +{ + if (irand(0,1)) + SetAnim(self, ANIM_DODGE_LEFT); + else + SetAnim(self, ANIM_DODGE_RIGHT); +} + +/*----------------------------------------------- + priestess_stand +-----------------------------------------------*/ + +void priestess_stand(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_STAND1); +} + +/*----------------------------------------------- + priestess_missile +-----------------------------------------------*/ + +void priestess_missile(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_ATTACK2); +} + +/*----------------------------------------------- + priestess_run +-----------------------------------------------*/ + +void priestess_run(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_WALK); +} + +/*----------------------------------------------- + priestess_pain +-----------------------------------------------*/ + +void priestess_pain(edict_t *self, G_Message_t *msg) +{ + int temp, damage; + int force_pain; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_pain, &damage, &temp); + + if (self->curAnimID == ANIM_ATTACK3_GO || self->curAnimID == ANIM_ATTACK3_LOOP || + self->curAnimID == ANIM_SHIELD_GO) + return; + + //Weighted random based on health compared to the maximum it was at + if (force_pain || ((irand(0, self->max_health+50) > self->health) && !irand(0,2))) + { + if (irand(0,1)) + gi.sound (self, CHAN_AUTO, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound (self, CHAN_AUTO, sounds[SND_PAIN2], 1, ATTN_NORM, 0); + + SetAnim(self, ANIM_PAIN); + } +} + +void priestess_postthink(edict_t *self) +{ + //Only display a lifemeter if we have an enemy + if (self->enemy) + { + if (self->dmg < self->max_health) + { + M_ShowLifeMeter( self, self->dmg, self->dmg); + self->dmg+=50; + } + else + { + M_ShowLifeMeter( self, self->health, self->max_health); + } + } + + self->next_post_think = level.time + 0.05; +} + + +/* + + Priestess Spawn Functions + +*/ + +void HighPriestessStaticsInit() +{ + classStatics[CID_HIGHPRIESTESS].msgReceivers[MSG_STAND] = priestess_stand; + classStatics[CID_HIGHPRIESTESS].msgReceivers[MSG_MISSILE] = priestess_missile; + classStatics[CID_HIGHPRIESTESS].msgReceivers[MSG_RUN] = priestess_run; + classStatics[CID_HIGHPRIESTESS].msgReceivers[MSG_EVADE] = priestess_evade; + classStatics[CID_HIGHPRIESTESS].msgReceivers[MSG_DEATH] = priestess_death; + classStatics[CID_HIGHPRIESTESS].msgReceivers[MSG_PAIN] = priestess_pain; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/highpriestess/tris.fm"); + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + sounds[SND_PAIN1]=gi.soundindex("monsters/highpriestess/pain1.wav"); + sounds[SND_PAIN2]=gi.soundindex("monsters/highpriestess/pain2.wav"); + sounds[SND_FALL]=gi.soundindex("monsters/highpriestess/fall.wav"); + sounds[SND_3BALLATK]=gi.soundindex("monsters/highpriestess/3ballatk.wav"); + sounds[SND_BALLHIT]=gi.soundindex("monsters/highpriestess/ballhit.wav"); + sounds[SND_WHIRL]=gi.soundindex("weapons/stafftwirl_2.wav"); + sounds[SND_BUGS]=gi.soundindex("monsters/highpriestess/bugs.wav"); + sounds[SND_BUGBUZZ]=gi.soundindex("monsters/highpriestess/bugbuzz.wav"); + sounds[SND_BUGHIT]=gi.soundindex("monsters/highpriestess/bughit.wav"); + sounds[SND_ZAP]=gi.soundindex("monsters/highpriestess/zap.wav"); + sounds[SND_ZAPHIT]=gi.soundindex("monsters/highpriestess/zaphit.wav"); + sounds[SND_HOMINGATK]=gi.soundindex("monsters/highpriestess/homatk.wav"); + sounds[SND_HOMINGHIT]=gi.soundindex("monsters/highpriestess/homhit.wav"); + sounds[SND_TPORT_IN]=gi.soundindex("monsters/highpriestess/tportin.wav"); + sounds[SND_TPORT_OUT]=gi.soundindex("monsters/highpriestess/tpotout.wav"); + sounds[SND_SWIPE]=gi.soundindex("weapons/staffswing_2.wav"); + sounds[SND_SWIPEHIT]=gi.soundindex("weapons/staffhit_2.wav"); + sounds[SND_SWIPEMISS]=gi.soundindex("monsters/seraph/guard/attack_miss.wav"); + sounds[SND_SWIPEWALL]=gi.soundindex("weapons/staffhitwall.wav"); + + classStatics[CID_HIGHPRIESTESS].resInfo = &resInfo; +} + +/*QUAKED monster_high_priestess (1 .5 0) (-24 -24 0) (24 24 72) + +The High Priestess (what more do you need to know?!?!) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +*/ +void SP_monster_high_priestess (edict_t *self) +{ + if (deathmatch->value) + { + return; + } + + if (!walkmonster_start(self)) // Failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_HIGHPRIESTESS; + + if (!self->health) + { + self->max_health = self->health = HP_HEALTH; + } + + //Apply to the end result (whether designer set or not) + self->health = MonsterHealth(self->health); + + self->mass = HP_MASS; + self->yaw_speed = 24; + + self->movetype = PHYSICSTYPE_STEP; + self->solid=SOLID_BBOX; + self->clipmask = MASK_MONSTERSOLID; + + self->s.origin[2] += 36; + VectorSet(self->mins, -24, -24, -36); + VectorSet(self->maxs, 24, 24, 36); + + self->materialtype = MAT_INSECT; + + self->s.modelindex = classStatics[CID_HIGHPRIESTESS].resInfo->modelIndex; + self->s.skinnum = 0; + + self->monsterinfo.jump_time = level.time + 15; + self->monsterinfo.otherenemyname = "monster_rat"; + + if (self->monsterinfo.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + MG_InitMoods( self ); + + //Setup her reference points + self->PersistantCFX = gi.CreatePersistantEffect(&self->s, + FX_HP_STAFF, + CEF_OWNERS_ORIGIN | CEF_BROADCAST, + vec3_origin, + "bs", + HP_STAFF_INIT, + self->s.number); + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + + self->post_think = priestess_postthink; + self->next_post_think = level.time + 0.1; + + self->svflags|=SVF_BOSS; +} diff --git a/Toolkit/Programming/GameCode/game/m_priestess.h b/Toolkit/Programming/GameCode/game/m_priestess.h new file mode 100644 index 0000000..22e275b --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_priestess.h @@ -0,0 +1,126 @@ +#include "g_local.h" + +typedef enum AnimID_e +{ + ANIM_STAND1, + ANIM_ATTACK1_GO, + ANIM_ATTACK1_LOOP, + ANIM_ATTACK1_END, + ANIM_ATTACK2, + ANIM_BACKUP, + ANIM_DEATH, + ANIM_IDLE, + ANIM_JUMP, + ANIM_PAIN, + ANIM_IDLE_POSE, + ANIM_POSE_TRANS, + ANIM_SHIELD_GO, + ANIM_SHIELD_END, + ANIM_DODGE_LEFT, + ANIM_DODGE_RIGHT, + ANIM_WALK, + ANIM_JUMP_FORWARD, + ANIM_JUMP_BACK, + ANIM_JUMP_RIGHT, + ANIM_JUMP_LEFT, + ANIM_JUMP_POUNCE, + ANIM_POUNCE_ATTACK, + ANIM_ATTACK3_GO, + ANIM_ATTACK3_LOOP, + ANIM_ATTACK3_END, + ANIM_JUMP_ATTACK, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ //shield being used at all? + //reuse staff swing, hit, and landing sounds +//she takes pain + SND_PAIN1, + SND_PAIN2, +//you win + SND_FALL, +//attack 1 - 3 balls spell + SND_3BALLATK, + SND_BALLHIT, +//attack 2 - whirling staff + SND_WHIRL, + SND_SWIPE, + SND_SWIPEHIT, + SND_SWIPEMISS, + SND_SWIPEWALL, +//bug minefield + SND_BUGS,//fire a bug out + SND_BUGBUZZ,//bug buzzes in place + SND_BUGHIT,//bug explodes +//ray of light + SND_ZAP,//earthquake, lightning, rays of light + SND_ZAPHIT,//earthquake, lightning, rays of light +//homing missiles + SND_HOMINGATK, + SND_HOMINGHIT, +//teleport in & out + SND_TPORT_IN, + SND_TPORT_OUT, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t priestess_move_stand1, + priestess_move_attack1_go, + priestess_move_attack1_loop, + priestess_move_attack1_end, + priestess_move_attack2, + priestess_move_backup, + priestess_move_death, + priestess_move_idle, + priestess_move_jump, + priestess_move_pain, + priestess_move_idle_pose, + priestess_move_pose_trans, + priestess_move_shield_go, + priestess_move_shield_end, + priestess_move_dodge_left, + priestess_move_dodge_right, + priestess_move_walk, + priestess_move_jump_forward, + priestess_move_jump_back, + priestess_move_jump_right, + priestess_move_jump_left, + priestess_move_jump_pounce, + priestess_move_pounce_attack, + priestess_move_attack3_go, + priestess_move_attack3_loop, + priestess_move_attack3_end, + priestess_move_jump_attack; + +void priestess_fire1( edict_t *self, float pitch_ofs, float yaw_ofs, float roll_ofs ); + +void priestess_jump_forward( edict_t *self ); +void priestess_jump_back( edict_t *self ); +void priestess_jump_right( edict_t *self ); +void priestess_jump_left( edict_t *self ); + +void priestess_strike( edict_t *self, float damage ); + +void priestess_pounce_attack( edict_t *self ); +void priestess_idle( edict_t *self ); +void priestess_pounce( edict_t *self ); +void priestess_move( edict_t *self, float vf, float vr, float vu ); +void priestess_pause( edict_t *self ); + +void priestess_attack3_loop( edict_t *self ); +void priestess_attack3_loop_fire( edict_t *self ); + +void priestess_jump_attack( edict_t *self ); + +void priestess_teleport_go( edict_t *self ); +void priestess_teleport_end( edict_t *self ); +void priestess_teleport_move( edict_t *self ); +void priestess_teleport_return( edict_t *self ); +void priestess_teleport_self_effects( edict_t *self ); + +void priestess_attack1_pause( edict_t *self ); +void priestess_dead( edict_t *self ); +void priestess_stop_alpha( edict_t *self ); + +void priestess_delta_alpha( edict_t *self, float amount ); \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/m_priestess_anim.c b/Toolkit/Programming/GameCode/game/m_priestess_anim.c new file mode 100644 index 0000000..c63ba22 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_priestess_anim.c @@ -0,0 +1,511 @@ +#include "g_local.h" +#include "m_priestess.h" +#include "m_priestess_anim.h" + +animframe_t priestess_frames_stand1[] = +{ + FRAME_idle1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t priestess_move_stand1 = {18,priestess_frames_stand1, priestess_idle}; + +animframe_t priestess_frames_attack1_go[] = +{ + FRAME_attackA7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackA8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackA9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackA10, priestess_fire1, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackA11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackA12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackA13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackA14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackA15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackA16, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_attack1_go = {10,priestess_frames_attack1_go, priestess_attack1_pause}; + +animframe_t priestess_frames_attack1_loop[] = +{ + FRAME_attackA7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attackA8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attackA9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attackA10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attackA11, priestess_fire1, 0, 0, 0, NULL, 0, NULL, + FRAME_attackA12, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_attack1_loop = {6,priestess_frames_attack1_loop, priestess_idle}; + +animframe_t priestess_frames_attack1_end[] = +{ + FRAME_attackA13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attackA14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attackA15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_attackA16, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_attack1_end = {4,priestess_frames_attack1_end, priestess_pause}; + +//Attack 2 + +animframe_t priestess_frames_attack2[] = +{ + FRAME_attackB1, NULL, 0, 0, 0, ai_charge, 2, NULL, + FRAME_attackB2, NULL, 0, 0, 0, ai_charge, 2, NULL, + FRAME_attackB3, NULL, 0, 0, 0, ai_charge, 2, NULL, + FRAME_attackB4, NULL, 0, 0, 0, ai_charge, 4, NULL, + FRAME_attackB5, NULL, 0, 0, 0, ai_charge, 4, NULL, + FRAME_attackB6, NULL, 0, 0, 0, ai_charge, 4, NULL, + FRAME_attackB7, NULL, 0, 0, 0, ai_charge, 2, NULL, + FRAME_attackB8, NULL, 0, 0, 0, priestess_strike, 16, NULL, + FRAME_attackB9, NULL, 0, 0, 0, ai_charge, 1, NULL, + FRAME_attackB10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB14, NULL, 0, 0, 0, priestess_strike, 8, NULL, + FRAME_attackB15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB17, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB18, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB19, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_attack2 = {19,priestess_frames_attack2, priestess_pause}; + +animframe_t priestess_frames_pounce_attack[] = +{ + FRAME_atttrans1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_atttrans2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB19, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB14, NULL, 0, 0, 0, priestess_strike, 8, NULL, + FRAME_attackB15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackB17, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_pounce_attack = {9,priestess_frames_pounce_attack, priestess_pounce_attack}; + +animframe_t priestess_frames_backup[] = +{ + FRAME_backup3, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup4, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup5, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup6, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup7, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup8, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup9, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup10, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup11, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup12, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup13, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup14, NULL, 0, 0, 0, ai_run, -8, NULL, +}; +animmove_t priestess_move_backup = {12,priestess_frames_backup, priestess_pause}; + +animframe_t priestess_frames_death[] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death32, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death33, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death34, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death35, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death36, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death37, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death38, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death39, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death40, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death41, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death42, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death43, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death44, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death45, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death46, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death47, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death48, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death49, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death50, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death51, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death52, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death53, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death54, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death55, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death56, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death57, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death58, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death59, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death60, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death61, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death62, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death63, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death64, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death65, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death66, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death67, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death68, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death69, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_death70, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_death = {70, priestess_frames_death, priestess_dead}; + +animframe_t priestess_frames_idle[] = +{ + FRAME_idle1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_idle = {18,priestess_frames_idle, priestess_idle}; + +animframe_t priestess_frames_jump[] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_jump = {14,priestess_frames_jump, priestess_pause}; + +animframe_t priestess_frames_jump_forward[] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_charge, 0, priestess_jump_forward, + FRAME_jump6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_jump_forward = {14,priestess_frames_jump_forward, priestess_pause}; + +animframe_t priestess_frames_jump_back[] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_charge, 0, priestess_jump_back, + FRAME_jump6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_jump_back = {14,priestess_frames_jump_back, priestess_pause}; + +animframe_t priestess_frames_jump_right[] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_charge, 0, priestess_jump_right, + FRAME_jump6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_jump_right = {14,priestess_frames_jump_right, priestess_pause}; + +animframe_t priestess_frames_jump_left[] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_charge, 0, priestess_jump_left, + FRAME_jump6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_jump_left= {14,priestess_frames_jump_left, priestess_pause}; + +animframe_t priestess_frames_jump_pounce[] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump5, NULL, 0, 0, 0, ai_charge, 0, priestess_pounce, + FRAME_jump6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_jump_pounce = {14,priestess_frames_jump_pounce, priestess_pounce_attack}; + +animframe_t priestess_frames_pain[] = +{ + FRAME_pain1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_pain = {6,priestess_frames_pain, priestess_pause}; + +animframe_t priestess_frames_idle_pose[] = +{ + FRAME_poseidle1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poseidle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poseidle3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poseidle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poseidle5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poseidle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poseidle7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poseidle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_poseidle9, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_idle_pose = {9,priestess_frames_idle_pose, priestess_idle}; + +animframe_t priestess_frames_pose_trans[] = +{ + FRAME_pose2ready1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pose2ready2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pose2ready3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pose2ready4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pose2ready5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pose2ready6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_pose_trans = {6,priestess_frames_pose_trans, priestess_idle}; + +animframe_t priestess_frames_shield_go[] = +{ + FRAME_shield1, NULL, 0, 0, 0, NULL, 0.0, NULL, + FRAME_shield2, NULL, 0, 0, 0, NULL, 0.0, priestess_teleport_go, + FRAME_shield3, NULL, 0, 0, 0, NULL, 0.0, NULL, + FRAME_shield4, NULL, 0, 0, 0, NULL, 0.0, NULL, + FRAME_shield5, NULL, 0, 0, 0, NULL, 0.0, NULL, + FRAME_shield6, NULL, 0, 0, 0, NULL, 0.0, NULL, + FRAME_shield7, NULL, 0, 0, 0, NULL, 0.0, priestess_teleport_self_effects, + FRAME_shield8, NULL, 0, 0, 0, priestess_delta_alpha, -32.0, NULL, + FRAME_shield8, NULL, 0, 0, 0, priestess_delta_alpha, -32.0, NULL, + FRAME_shield8, NULL, 0, 0, 0, priestess_delta_alpha, -32.0, NULL, + FRAME_shield8, NULL, 0, 0, 0, priestess_delta_alpha, -32.0, NULL, + FRAME_shield8, NULL, 0, 0, 0, priestess_delta_alpha, -32.0, NULL, + FRAME_shield8, NULL, 0, 0, 0, priestess_delta_alpha, -32.0, NULL, + FRAME_shield8, NULL, 0, 0, 0, priestess_delta_alpha, -32.0, priestess_teleport_move, + FRAME_shield8, NULL, 0, 0, 0, priestess_delta_alpha, -32.0, priestess_teleport_return, +}; +animmove_t priestess_move_shield_go = {15,priestess_frames_shield_go, NULL}; + +animframe_t priestess_frames_shield_end[] = +{ + FRAME_shield8, NULL, 0, 0, 0, priestess_delta_alpha, 32.0, priestess_teleport_end, + FRAME_shield7, NULL, 0, 0, 0, priestess_delta_alpha, 32.0, NULL, + FRAME_shield6, NULL, 0, 0, 0, priestess_delta_alpha, 32.0, NULL, + FRAME_shield5, NULL, 0, 0, 0, priestess_delta_alpha, 32.0, NULL, + FRAME_shield4, NULL, 0, 0, 0, priestess_delta_alpha, 32.0, NULL, + FRAME_shield3, NULL, 0, 0, 0, priestess_delta_alpha, 32.0, NULL, + FRAME_shield2, NULL, 0, 0, 0, priestess_delta_alpha, 32.0, NULL, + FRAME_shield1, NULL, 0, 0, 0, priestess_delta_alpha, 32.0, priestess_stop_alpha, + FRAME_shield1, NULL, 0, 0, 0, NULL, 0, priestess_stop_alpha, +}; +animmove_t priestess_move_shield_end = {9,priestess_frames_shield_end, priestess_pause}; + +animframe_t priestess_frames_dodge_left[] = +{ + FRAME_sidestplft1, priestess_move, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestplft2, priestess_move, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestplft3, priestess_move, 0, -4, 0, NULL, 0, NULL, + FRAME_sidestplft4, priestess_move, 0, -8, 0, NULL, 0, NULL, + FRAME_sidestplft5, priestess_move, 0, -16, 0, NULL, 0, NULL, + FRAME_sidestplft6, priestess_move, 0, -16, 0, NULL, 0, NULL, + FRAME_sidestplft7, priestess_move, 0, -16, 0, NULL, 0, NULL, + FRAME_sidestplft8, priestess_move, 0, -12, 0, NULL, 0, NULL, + FRAME_sidestplft9, priestess_move, 0, -8, 0, NULL, 0, NULL, + FRAME_sidestplft10, priestess_move, 0, -4, 0, NULL, 0, NULL, + FRAME_sidestplft11, priestess_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_dodge_left = {11,priestess_frames_dodge_left, priestess_pause}; + +animframe_t priestess_frames_dodge_right[] = +{ + FRAME_sidestprt1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_sidestprt11, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_dodge_right = {11,priestess_frames_dodge_right, priestess_pause}; + +animframe_t priestess_frames_walk[] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_run, 6, NULL, + FRAME_walk2, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_run, 6, NULL, + FRAME_walk7, NULL, 0, 0, 0, ai_run, 6, NULL, + FRAME_walk8, NULL, 0, 0, 0, ai_run, 4, NULL, + FRAME_walk9, NULL, 0, 0, 0, ai_run, 6, NULL, + FRAME_walk10, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk12, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk13, NULL, 0, 0, 0, ai_run, 8, NULL, + FRAME_walk14, NULL, 0, 0, 0, ai_run, 6, NULL, + FRAME_walk15, NULL, 0, 0, 0, ai_run, 6, NULL, + FRAME_walk16, NULL, 0, 0, 0, ai_run, 4, NULL, +}; +animmove_t priestess_move_walk = {16,priestess_frames_walk, priestess_pause}; + +animframe_t priestess_frames_attack3_go[] = +{ + FRAME_attackc1, NULL, 0, 0, 0, ai_charge, 6, NULL, + FRAME_attackc2, NULL, 0, 0, 0, ai_charge, 6, NULL, + FRAME_attackc3, NULL, 0, 0, 0, ai_charge, 6, NULL, + FRAME_attackc4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackc5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackc6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackc7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackc8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackc9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackc10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackc11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_attackc12, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_attack3_go = {12, priestess_frames_attack3_go, priestess_attack3_loop}; + +animframe_t priestess_frames_attack3_loop[] = +{ + FRAME_attackc13, NULL, 0, 0, 0, NULL, 0, priestess_attack3_loop_fire, +}; +animmove_t priestess_move_attack3_loop = {1,priestess_frames_attack3_loop, NULL}; + +animframe_t priestess_frames_attack3_end[] = +{ + FRAME_attackc14, NULL, 0, 0, 0, ai_charge, -8, NULL, + FRAME_attackc15, NULL, 0, 0, 0, ai_charge, -8, NULL, + FRAME_attackc16, NULL, 0, 0, 0, ai_charge, -2, NULL, +}; +animmove_t priestess_move_attack3_end = {3,priestess_frames_attack3_end, priestess_pause}; + +animframe_t priestess_frames_jump_attack[] = +{ + FRAME_jumpatt1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt6, NULL, 0, 0, 0, ai_charge, 0, priestess_jump_attack, + FRAME_jumpatt7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt12, NULL, 0, 0, 0, priestess_strike, 8, NULL, + FRAME_jumpatt13, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jumpatt14, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t priestess_move_jump_attack = {14,priestess_frames_jump_attack, priestess_pause}; + +/* +animframe_t priestess_frames_[] = +{ + FRAME_, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t priestess_move_ = {1,priestess_frames_, priestess_idle}; +*/ diff --git a/Toolkit/Programming/GameCode/game/m_priestess_anim.h b/Toolkit/Programming/GameCode/game/m_priestess_anim.h new file mode 100644 index 0000000..d1373bc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_priestess_anim.h @@ -0,0 +1,296 @@ +// R:\Art\models/monsters\highpriestess\work + +// This file generated by qdata - Do NOT Modify + +#define FRAME_attackA1 0 +#define FRAME_attackA2 1 +#define FRAME_attackA3 2 +#define FRAME_attackA4 3 +#define FRAME_attackA5 4 +#define FRAME_attackA6 5 +#define FRAME_attackA7 6 +#define FRAME_attackA8 7 +#define FRAME_attackA9 8 +#define FRAME_attackA10 9 +#define FRAME_attackA11 10 +#define FRAME_attackA12 11 +#define FRAME_attackA13 12 +#define FRAME_attackA14 13 +#define FRAME_attackA15 14 +#define FRAME_attackA16 15 +#define FRAME_attackB1 16 +#define FRAME_attackB2 17 +#define FRAME_attackB3 18 +#define FRAME_attackB4 19 +#define FRAME_attackB5 20 +#define FRAME_attackB6 21 +#define FRAME_attackB7 22 +#define FRAME_attackB8 23 +#define FRAME_attackB9 24 +#define FRAME_attackB10 25 +#define FRAME_attackB11 26 +#define FRAME_attackB12 27 +#define FRAME_attackB13 28 +#define FRAME_attackB14 29 +#define FRAME_attackB15 30 +#define FRAME_attackB16 31 +#define FRAME_attackB17 32 +#define FRAME_attackB18 33 +#define FRAME_attackB19 34 +#define FRAME_backup1 35 +#define FRAME_backup2 36 +#define FRAME_backup3 37 +#define FRAME_backup4 38 +#define FRAME_backup5 39 +#define FRAME_backup6 40 +#define FRAME_backup7 41 +#define FRAME_backup8 42 +#define FRAME_backup9 43 +#define FRAME_backup10 44 +#define FRAME_backup11 45 +#define FRAME_backup12 46 +#define FRAME_backup13 47 +#define FRAME_backup14 48 +#define FRAME_death1 49 +#define FRAME_death2 50 +#define FRAME_death3 51 +#define FRAME_death4 52 +#define FRAME_death5 53 +#define FRAME_death6 54 +#define FRAME_death7 55 +#define FRAME_death8 56 +#define FRAME_death9 57 +#define FRAME_death10 58 +#define FRAME_death11 59 +#define FRAME_death12 60 +#define FRAME_death13 61 +#define FRAME_death14 62 +#define FRAME_death15 63 +#define FRAME_death16 64 +#define FRAME_death17 65 +#define FRAME_death18 66 +#define FRAME_death19 67 +#define FRAME_death20 68 +#define FRAME_death21 69 +#define FRAME_death22 70 +#define FRAME_death23 71 +#define FRAME_death24 72 +#define FRAME_death25 73 +#define FRAME_death26 74 +#define FRAME_death27 75 +#define FRAME_death28 76 +#define FRAME_death29 77 +#define FRAME_death30 78 +#define FRAME_death31 79 +#define FRAME_death32 80 +#define FRAME_death33 81 +#define FRAME_death34 82 +#define FRAME_death35 83 +#define FRAME_death36 84 +#define FRAME_death37 85 +#define FRAME_death38 86 +#define FRAME_death39 87 +#define FRAME_death40 88 +#define FRAME_death41 89 +#define FRAME_death42 90 +#define FRAME_death43 91 +#define FRAME_death44 92 +#define FRAME_death45 93 +#define FRAME_death46 94 +#define FRAME_death47 95 +#define FRAME_death48 96 +#define FRAME_death49 97 +#define FRAME_death50 98 +#define FRAME_death51 99 +#define FRAME_death52 100 +#define FRAME_death53 101 +#define FRAME_death54 102 +#define FRAME_death55 103 +#define FRAME_death56 104 +#define FRAME_death57 105 +#define FRAME_death58 106 +#define FRAME_death59 107 +#define FRAME_death60 108 +#define FRAME_death61 109 +#define FRAME_death62 110 +#define FRAME_death63 111 +#define FRAME_death64 112 +#define FRAME_death65 113 +#define FRAME_death66 114 +#define FRAME_death67 115 +#define FRAME_death68 116 +#define FRAME_death69 117 +#define FRAME_death70 118 +#define FRAME_idle1 119 +#define FRAME_idle2 120 +#define FRAME_idle3 121 +#define FRAME_idle4 122 +#define FRAME_idle5 123 +#define FRAME_idle6 124 +#define FRAME_idle7 125 +#define FRAME_idle8 126 +#define FRAME_idle9 127 +#define FRAME_idle10 128 +#define FRAME_idle11 129 +#define FRAME_idle12 130 +#define FRAME_idle13 131 +#define FRAME_idle14 132 +#define FRAME_idle15 133 +#define FRAME_idle16 134 +#define FRAME_idle17 135 +#define FRAME_idle18 136 +#define FRAME_jump1 137 +#define FRAME_jump2 138 +#define FRAME_jump3 139 +#define FRAME_jump4 140 +#define FRAME_jump5 141 +#define FRAME_jump6 142 +#define FRAME_jump7 143 +#define FRAME_jump8 144 +#define FRAME_jump9 145 +#define FRAME_jump10 146 +#define FRAME_jump11 147 +#define FRAME_jump12 148 +#define FRAME_jump13 149 +#define FRAME_jump14 150 +#define FRAME_pain1 151 +#define FRAME_pain2 152 +#define FRAME_pain3 153 +#define FRAME_pain4 154 +#define FRAME_pain5 155 +#define FRAME_pain6 156 +#define FRAME_poseidle1 157 +#define FRAME_poseidle10 158 +#define FRAME_poseidle11 159 +#define FRAME_poseidle12 160 +#define FRAME_poseidle13 161 +#define FRAME_poseidle14 162 +#define FRAME_poseidle15 163 +#define FRAME_poseidle16 164 +#define FRAME_poseidle17 165 +#define FRAME_poseidle18 166 +#define FRAME_poseidle2 167 +#define FRAME_poseidle3 168 +#define FRAME_poseidle4 169 +#define FRAME_poseidle5 170 +#define FRAME_poseidle6 171 +#define FRAME_poseidle7 172 +#define FRAME_poseidle8 173 +#define FRAME_poseidle9 174 +#define FRAME_pose2ready1 175 +#define FRAME_pose2ready2 176 +#define FRAME_pose2ready3 177 +#define FRAME_pose2ready4 178 +#define FRAME_pose2ready5 179 +#define FRAME_pose2ready6 180 +#define FRAME_ready 181 +#define FRAME_shield1 182 +#define FRAME_shield2 183 +#define FRAME_shield3 184 +#define FRAME_shield4 185 +#define FRAME_shield5 186 +#define FRAME_shield6 187 +#define FRAME_shield7 188 +#define FRAME_shield8 189 +#define FRAME_sidestplft1 190 +#define FRAME_sidestplft2 191 +#define FRAME_sidestplft3 192 +#define FRAME_sidestplft4 193 +#define FRAME_sidestplft5 194 +#define FRAME_sidestplft6 195 +#define FRAME_sidestplft7 196 +#define FRAME_sidestplft8 197 +#define FRAME_sidestplft9 198 +#define FRAME_sidestplft10 199 +#define FRAME_sidestplft11 200 +#define FRAME_sidestprt1 201 +#define FRAME_sidestprt2 202 +#define FRAME_sidestprt3 203 +#define FRAME_sidestprt4 204 +#define FRAME_sidestprt5 205 +#define FRAME_sidestprt6 206 +#define FRAME_sidestprt7 207 +#define FRAME_sidestprt8 208 +#define FRAME_sidestprt9 209 +#define FRAME_sidestprt10 210 +#define FRAME_sidestprt11 211 +#define FRAME_walk1 212 +#define FRAME_walk2 213 +#define FRAME_walk3 214 +#define FRAME_walk4 215 +#define FRAME_walk5 216 +#define FRAME_walk6 217 +#define FRAME_walk7 218 +#define FRAME_walk8 219 +#define FRAME_walk9 220 +#define FRAME_walk10 221 +#define FRAME_walk11 222 +#define FRAME_walk12 223 +#define FRAME_walk13 224 +#define FRAME_walk14 225 +#define FRAME_walk15 226 +#define FRAME_walk16 227 +#define FRAME_walk2pose1 228 +#define FRAME_walk2pose2 229 +#define FRAME_walk2pose3 230 +#define FRAME_walk2pose4 231 +#define FRAME_walk2pose5 232 +#define FRAME_walk2pose6 233 +#define FRAME_walk2pose7 234 +#define FRAME_walk2pose8 235 +#define FRAME_walk2pose9 236 +#define FRAME_walk2pose10 237 +#define FRAME_walk2pose11 238 +#define FRAME_walk2pose12 239 +#define FRAME_walk2pose13 240 +#define FRAME_walk2pose14 241 +#define FRAME_walk2pose15 242 +#define FRAME_walk2pose16 243 +#define FRAME_walk2pose17 244 +#define FRAME_walk2pose18 245 +#define FRAME_walk2pose19 246 +#define FRAME_walk2pose20 247 +#define FRAME_walk2pose21 248 +#define FRAME_walk2pose22 249 +#define FRAME_walk2pose23 250 +#define FRAME_walk2pose24 251 +#define FRAME_atttrans1 252 +#define FRAME_atttrans2 253 +#define FRAME_jumpatt1 254 +#define FRAME_jumpatt2 255 +#define FRAME_jumpatt3 256 +#define FRAME_jumpatt4 257 +#define FRAME_jumpatt5 258 +#define FRAME_jumpatt6 259 +#define FRAME_jumpatt7 260 +#define FRAME_jumpatt8 261 +#define FRAME_jumpatt9 262 +#define FRAME_jumpatt10 263 +#define FRAME_jumpatt11 264 +#define FRAME_jumpatt12 265 +#define FRAME_jumpatt13 266 +#define FRAME_jumpatt14 267 +#define FRAME_attackc1 268 +#define FRAME_attackc2 269 +#define FRAME_attackc3 270 +#define FRAME_attackc4 271 +#define FRAME_attackc5 272 +#define FRAME_attackc6 273 +#define FRAME_attackc7 274 +#define FRAME_attackc8 275 +#define FRAME_attackc9 276 +#define FRAME_attackc10 277 +#define FRAME_attackc11 278 +#define FRAME_attackc12 279 +#define FRAME_attackc13 280 +#define FRAME_attackc14 281 +#define FRAME_attackc15 282 +#define FRAME_attackc16 283 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 3 + +#define MESH_BASEBIN 0 +#define MESH__STAFF 1 +#define MESH__QUEENBODY 2 diff --git a/Toolkit/Programming/GameCode/game/m_rat.c b/Toolkit/Programming/GameCode/game/m_rat.c new file mode 100644 index 0000000..9ff3b22 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_rat.c @@ -0,0 +1,842 @@ +//============================================================================== +// +// m_rat.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// +// AI : +// +// STAND1 : Looking straight ahead +// STAND2 : Rising up to sit on his haunches +// STAND3 : Sitting on his haunches looking straight ahead +// STAND4 : On haunches, looking left +// STAND5 : On haunches, looking right +// STAND6 : On haunches, scratching left +// STAND7 : On haunches, scratching right +// STAND8 : On haunches, dropping to a stand +// +// WATCH1 : Hiss while on all fours +// WATCH2 : Stand up and hiss then go back to all fours +// +// WALK1 : a normal straight line +// +// MELEE1 : Attack at feet +// MELEE2 : Attack in air +// +// RUN1 : chasing an enemy straight ahead +// RUN2 : chasing an enemy and turning left +// RUN3 : chasing an enemy and turning right +// +// EATING1 : Bite low +// EATING2 : Bite low and tear up +// EATING3 : Bite low and pull back a little +// +// PAIN1 : backup and runaway +// +// DIE1 : Big death, dbig flip over +// DIE2 : Little death flipping over +// +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "vector.h" + +#include "m_rat.h" +#include "m_rat_anim.h" +#include "g_misc.h" +#include "m_stats.h" + +#include "g_monster.h" + +void ai_runaway (edict_t *self, float dist); + +/*---------------------------------------------------------------------- + Rat Base Info +-----------------------------------------------------------------------*/ + +static animmove_t *animations[NUM_ANIMS] = +{ + &rat_move_eat1, + &rat_move_eat2, + &rat_move_eat3, + &rat_move_stand1, + &rat_move_stand2, + &rat_move_stand3, + &rat_move_stand4, + &rat_move_stand5, + &rat_move_stand6, + &rat_move_stand7, + &rat_move_stand8, + &rat_move_watch1, + &rat_move_watch2, + &rat_move_walk1, + &rat_move_run1, + &rat_move_run2, + &rat_move_run3, + &rat_move_melee1, + &rat_move_melee2, + &rat_move_melee3, + &rat_move_pain1, + &rat_move_death1, + &rat_move_death2, +}; + +static int sounds[NUM_SOUNDS]; + +static ClassResourceInfo_t resInfo; + +void rat_dead_pain (edict_t *self, G_Message_t *msg) +{ + if (self->health <= -80) + { + gi.sound (self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + BecomeDebris(self); + } + return; +} + +//---------------------------------------------------------------------- +// Rat Pain - choose a pain to use +//---------------------------------------------------------------------- +void rat_pain(edict_t *self, G_Message_t *msg) +{ + rat_pain_init(self); + + SetAnim(self, ANIM_PAIN1); + + return; +} + +//---------------------------------------------------------------------- +// Rat Death - choose deatha or deathb or gib. +//---------------------------------------------------------------------- +void rat_death(edict_t *self, G_Message_t *msg) +{ + if(self->monsterinfo.aiflags&AI_DONT_THINK) + { + // Big enough death to be thrown back + if (irand(0,10) < 5) + SetAnim(self, ANIM_DIE2); + else + SetAnim(self, ANIM_DIE1); + return; + } + + M_StartDeath(self, 0); + + if (self->health <= -40 + irand(0, 20)) + { + gi.sound (self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + BecomeDebris(self); + } + else + { + if(!strcmp(self->classname, "monster_rat_giant")) + self->s.skinnum = 1; + + // Big enough death to be thrown back + if (self->health <= -20) + { + SetAnim(self, ANIM_DIE1); + } + else + { + SetAnim(self, ANIM_DIE2); + } + } +} + +//---------------------------------------------------------------------- +// Rat Run - choose a run to use +//---------------------------------------------------------------------- +void rat_run(edict_t *self, G_Message_t *msg) +{ + float delta, len; + vec3_t vec; + + if (M_ValidTarget(self, self->enemy)) + { + VectorSubtract(self->enemy->s.origin, self->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + delta = anglemod(self->s.angles[YAW] - self->ideal_yaw); + + if(self->monsterinfo.attack_finished < level.time) + { + len = VectorLength(vec); + + if (len < 150 && len > 50) + { + if (delta < 10) + { + SetAnim(self, ANIM_MELEE2); + return; + } + } + } + + // Look right + if (delta > 25 && delta <= 180) + { + SetAnim(self, ANIM_RUN3); + return; + } + else if (delta > 180 && delta < 335) // Look left + { + SetAnim(self, ANIM_RUN2); + return; + } + else + { + SetAnim(self, ANIM_RUN1); + return; + } + + return; + } + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + + +//---------------------------------------------------------------------- +// Rat Walk - choose a walk to use +//---------------------------------------------------------------------- +void rat_walk(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_WALK1); +} + +//---------------------------------------------------------------------- +// Rat Melee - choose a melee to use +//---------------------------------------------------------------------- +void rat_melee(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + if (irand(0,1) < 1) + { + SetAnim(self, ANIM_MELEE1); + } + else + { + SetAnim(self, ANIM_MELEE3); + } + + return; + } + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +//---------------------------------------------------------------------- +// Rat Watch - which watch animation to use? +//---------------------------------------------------------------------- +void rat_watch(edict_t *self, G_Message_t *msg) +{ + if (irand(0, 1)) + { + SetAnim(self, ANIM_WATCH1); + } + else + { + SetAnim(self, ANIM_WATCH2); + } +} + +//---------------------------------------------------------------------- +// Rat Stand -decide which standing animations to use +//---------------------------------------------------------------------- +void rat_stand(edict_t *self, G_Message_t *msg) +{ + int chance; + + chance = irand(0, 100); + + // On the ground + switch(self->curAnimID) + { + case ANIM_STAND1: + if (chance < 95) + SetAnim(self, ANIM_STAND1); + else + SetAnim(self, ANIM_STAND2); + + break; + case ANIM_STAND2: + if(chance < 75) + SetAnim(self, ANIM_STAND3); + else + SetAnim(self, ANIM_STAND4 + irand(0, 4)); + break; + case ANIM_STAND4: + case ANIM_STAND5: + case ANIM_STAND6: + case ANIM_STAND7: + SetAnim(self, ANIM_STAND8); + break; + case ANIM_STAND8: + SetAnim(self, ANIM_STAND1); + break; + default: + if(chance < 75) + SetAnim(self, ANIM_STAND3); + else + SetAnim(self, ANIM_STAND4 + irand(0, 4)); + break; + } +} + +//---------------------------------------------------------------------- +// Rat Eat - decide which eating animations to use +//---------------------------------------------------------------------- +void rat_eat(edict_t *self, G_Message_t *msg) +{ + int chance; + + chance = irand(0, 10); + if (chance < 4) + { + SetAnim(self, ANIM_EATING1); + } + else if (chance < 8) + { + SetAnim(self, ANIM_EATING3); + } + else + { + SetAnim(self, ANIM_EATING2); + } +} + +/*---------------------------------------------------------------------- + + ACTION FUNCTIONS FOR THE MONSTER + +-----------------------------------------------------------------------*/ + +void ratchew (edict_t *self) +{ + int chance; + + chance = irand(0, 100); + + if (chance > 50 && chance < 65) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_CHEW1], 1, ATTN_IDLE, 0); + } + else if (chance < 85) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_CHEW2], 1, ATTN_IDLE, 0); + } + else + { + gi.sound (self, CHAN_WEAPON, sounds[SND_CHEW3], 1, ATTN_IDLE, 0); + } +} + +void ratchatter (edict_t *self) +{ + int chance; + + chance = irand(0, 20); + + if (chance < 1) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_CHATTER1], 1, ATTN_IDLE, 0); + } + else if (chance < 2) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_CHATTER2], 1, ATTN_IDLE, 0); + } + else if (chance < 3) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_CHATTER3], 1, ATTN_IDLE, 0); + } +} + +void ratswallow (edict_t *self) +{ + gi.sound (self, CHAN_WEAPON, sounds[SND_SWALLOW], 1, ATTN_IDLE, 0); +} + +void rathiss (edict_t *self) +{ + gi.sound (self, CHAN_WEAPON, sounds[SND_HISS], 1, ATTN_NORM, 0); +} + +void ratscratch (edict_t *self) +{ + gi.sound (self, CHAN_WEAPON, sounds[SND_SCRATCH], 1, ATTN_IDLE, 0); +} + +void ratdeathsqueal (edict_t *self) +{ + gi.sound (self, CHAN_WEAPON, sounds[SND_DIE], 1, ATTN_NORM, 0); +} + +void ratsqueal (edict_t *self) +{ + if (irand(0, 1)) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_PAIN1], 1, ATTN_NORM, 0); + } + else + { + gi.sound (self, CHAN_WEAPON, sounds[SND_PAIN2], 1, ATTN_NORM, 0); + } +} + + +void ratbite (edict_t *self) +{ + float len; + vec3_t dir, endpos, normal, forward, startpos; + trace_t trace; + + if(!self->enemy) + return; + + self->monsterinfo.attack_finished = level.time + 3 - skill->value + flrand(0.5, 1); + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorCopy(self->s.origin, startpos); + VectorMA(startpos, self->maxs[0] * 0.5, forward, startpos); + startpos[2] += self->viewheight; + + VectorCopy(self->enemy->s.origin, endpos); + + endpos[0]+=flrand(-4, 4); + endpos[1]+=flrand(-4, 4); + endpos[2]+=flrand(-4, 4); + + VectorSubtract(endpos, startpos, dir); + len = VectorNormalize(dir); + + if (len < (self->maxs[0] + self->enemy->maxs[0] + 45)) // A hit + { + gi.trace(startpos, vec3_origin, vec3_origin, endpos, self, MASK_MONSTERSOLID,&trace); + + if (trace.ent->takedamage) // A hit + { + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEHIT1], 1, ATTN_NORM, 0); + VectorMA(trace.endpos, flrand(0, 8), dir, endpos); + VectorScale(dir, -1, normal); + // do 1 point. + if(self->s.scale > 1.5) + T_Damage (trace.ent, self, self, dir, endpos, normal, RAT_DMG_BITE * irand(2, 4), 0, DAMAGE_AVOID_ARMOR,MOD_DIED); + else + T_Damage (trace.ent, self, self, dir, endpos, normal, RAT_DMG_BITE, 0, DAMAGE_AVOID_ARMOR,MOD_DIED); + return; + } + } +// A misssss + if (irand(0, 1)) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEMISS1], 1, ATTN_NORM, 0); + } + else + { + gi.sound (self, CHAN_WEAPON, sounds[SND_BITEMISS2], 1, ATTN_NORM, 0); + } +} + +void rat_pain_init(edict_t *self) +{ + if (self->s.scale < 2.0 && irand(0,100) < 50) + { + self->monsterinfo.aiflags |= AI_FLEE; // Run away + self->monsterinfo.flee_finished = level.time + flrand(3.0, 7.0); + } +} + +void rat_runorder(edict_t *self) +{ + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); +} + +void rat_standorder(edict_t *self) +{ + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void rat_pause (edict_t *self) +{ + float len; + + if (M_ValidTarget(self, self->enemy)) + { + len = M_DistanceToTarget(self, self->enemy); + + // Far enough to run after + if ((len > 60) || (self->monsterinfo.aiflags & AI_FLEE)) + { + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + } + else // Close enough to Attack + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + } + + return; + } + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void ratjump(edict_t *self) +{ + vec3_t vf; + + AngleVectors(self->s.angles, vf, NULL, NULL); + + VectorMA(self->velocity, 125, vf, self->velocity); + self->velocity[2] += 225; +} + +/*---------------------------------------------------------------------- + Rat WatchOrder - order the rat to watch +-----------------------------------------------------------------------*/ +void rat_watchorder(edict_t *self) +{ + QPostMessage(self, MSG_WATCH, PRI_DIRECTIVE, NULL); +} + +/*---------------------------------------------------------------------- + Rat EatOrder - order the rat to choose an eat animation +-----------------------------------------------------------------------*/ +void rat_eatorder(edict_t *self) +{ + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); +} + +void rat_use(edict_t *self, edict_t *other, edict_t *activator) +{ + self->enemy = activator; + FoundTarget(self, 1); +} + +void rat_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + //M_Touch is overridden because the player can just step over rats + + vec3_t pos1, pos2, dir; + float zdiff; + + if ((other->svflags & SVF_MONSTER) || other->client) + { + VectorCopy(other->s.origin, pos1); + pos1[2] += other->mins[2]; + + VectorCopy(ent->s.origin, pos2); + pos2[2] += ent->maxs[2]; + + zdiff = pos1[2] - pos2[2]; + + // On top + if (zdiff >= 0 ) + { + //Squish the rat a bit + T_Damage (ent, other, other, dir, pos2, vec3_origin, flrand(4,6), 0, DAMAGE_AVOID_ARMOR,MOD_DIED); + } + /* else //Kick um + { + //Squish the rat a bit + T_Damage (ent, other, other, dir, pos2, vec3_origin, flrand(0,1), 0, DAMAGE_AVOID_ARMOR); + + VectorSubtract(ent->s.origin, ent->enemy->s.origin, dir); + dir[2] = 0; + VectorNormalize(dir); + VectorScale(dir, 64, dir); + + dir[2] = 150; + VectorCopy(dir, ent->velocity); + }*/ + } +} + +#define MAX_RAT_ATTACK 2 +#define MAX_RAT_IGNORE_DIST 150 + +void rat_ai_stand(edict_t *self, float dist) +{ + float MG_FaceGoal (edict_t *self, qboolean doturn); + + if (M_ValidTarget(self, self->enemy)) + { + //Find the number of rats around us (-1 denotes it hasn't check previously) + if (self->monsterinfo.supporters == -1) + self->monsterinfo.supporters = M_FindSupport( self, RAT_GROUP_RANGE ); + + //We've got an enemy, now see if we have enough support to attack it + if (self->monsterinfo.supporters >= MAX_RAT_ATTACK) + { + FoundTarget(self, true); + } + else + { + //Is he close enough to scare us away? + if (M_DistanceToTarget(self, self->enemy) < MAX_RAT_IGNORE_DIST) + { + if (self->s.scale < 2.0 || irand(0,1)) + { + //Just attack him + FoundTarget(self, true); + } + else + { + //Run away + self->monsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + 10; + } + } + else + { + //Not close enough to bother us right now, but watch this enemy + MG_FaceGoal(self, true); + self->enemy = NULL; + } + } + } +} + +void rat_ai_eat(edict_t *self, float dist) +{ + if (M_ValidTarget(self, self->enemy)) + { + if (M_DistanceToTarget(self, self->enemy) < MAX_RAT_IGNORE_DIST) + { + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + } + else + { + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + } + } +} + +qboolean EqualAngle(float angle1, float angle2, float leniency); +void rat_ai_run (edict_t *self, float dist) +{ + vec3_t vec; + + if (!self->enemy) + return; + + if (self->monsterinfo.aiflags & AI_FLEE||self->monsterinfo.aiflags & AI_COWARD) + { + if(!self->count) + self->count = 180; + VectorSubtract (self->enemy->s.origin, self->s.origin, vec); + self->ideal_yaw = vectoyaw(vec); + self->ideal_yaw = anglemod(self->ideal_yaw + self->count); + M_ChangeYaw(self); + if(!M_walkmove(self, self->s.angles[YAW], dist) && EqualAngle(self->s.angles[YAW], self->ideal_yaw, 5)) + self->count = flrand(60, 300); + } + else + { + ai_run(self, dist); + } +} + +void RatStaticsInit() +{ + classStatics[CID_RAT].msgReceivers[MSG_STAND] = rat_stand; + classStatics[CID_RAT].msgReceivers[MSG_WALK] = rat_walk; + classStatics[CID_RAT].msgReceivers[MSG_RUN] = rat_run; + classStatics[CID_RAT].msgReceivers[MSG_EAT] = rat_eat; + classStatics[CID_RAT].msgReceivers[MSG_MELEE] = rat_melee; + classStatics[CID_RAT].msgReceivers[MSG_WATCH] = rat_watch; + classStatics[CID_RAT].msgReceivers[MSG_PAIN] = rat_pain; + classStatics[CID_RAT].msgReceivers[MSG_DEATH] = rat_death; + classStatics[CID_RAT].msgReceivers[MSG_JUMP] = M_jump; + classStatics[CID_RAT].msgReceivers[MSG_DEATH_PAIN] = rat_dead_pain; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/rat/tris.fm"); + + sounds[SND_BITEHIT1] = gi.soundindex ("monsters/rat/meleehit1.wav"); + sounds[SND_BITEMISS1] = gi.soundindex ("monsters/rat/meleemiss1.wav"); + sounds[SND_BITEMISS2] = gi.soundindex ("monsters/rat/meleemiss2.wav"); + sounds[SND_HISS] = gi.soundindex ("monsters/rat/hiss.wav"); + sounds[SND_SCRATCH] = gi.soundindex ("monsters/rat/scratch.wav"); + sounds[SND_PAIN1] = gi.soundindex ("monsters/rat/pain1.wav"); + sounds[SND_PAIN2] = gi.soundindex ("monsters/rat/pain2.wav"); + + sounds[SND_CHATTER1] = gi.soundindex ("monsters/rat/chatter1.wav"); + sounds[SND_CHATTER2] = gi.soundindex ("monsters/rat/chatter2.wav"); + sounds[SND_CHATTER3] = gi.soundindex ("monsters/rat/chatter3.wav"); + + sounds[SND_CHEW1] = gi.soundindex ("monsters/rat/chew1.wav"); + sounds[SND_CHEW2] = gi.soundindex ("monsters/rat/chew2.wav"); + sounds[SND_CHEW3] = gi.soundindex ("monsters/rat/chew3.wav"); + + sounds[SND_SWALLOW] = gi.soundindex ("monsters/rat/swallow.wav"); + + sounds[SND_DIE] = gi.soundindex ("monsters/rat/death1.wav"); + sounds[SND_GIB] = gi.soundindex ("monsters/rat/gib.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + classStatics[CID_RAT].resInfo = &resInfo; +} + +/*QUAKED monster_rat (1 .5 0) (-16 -16 -0) (16 16 32) AMBUSH ASLEEP EATING 8 16 32 64 FIXED(na) WANDER(na) MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +The rat + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +EATING - Chomp chomp... chewie chomp + +COWARD - Runs away + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +*/ + +void SP_monster_rat (edict_t *self) +{ + // Generic Monster Initialization + if (!monster_start(self)) // Failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_RAT; + self->think = walkmonster_start_go; + self->materialtype = MAT_FLESH; + + if (!self->health) + self->health = RAT_HEALTH; + + self->mass = RAT_MASS; + self->yaw_speed = 20; + + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + self->movetype=PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + //Init this to -1 because we can't check for supporters in this function + self->monsterinfo.supporters = -1; + + self->s.modelindex = classStatics[CID_RAT].resInfo->modelIndex; + + self->s.skinnum = 0; + + if (self->monsterinfo.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + self->viewheight = self->maxs[2] * 0.5 * self->s.scale; + + self->use = rat_use; + self->touch = rat_touch; + + if (self->spawnflags & MSF_EATING) + { + //self->monsterinfo.aiflags |= AI_EATING; + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + if(!self->wakeup_distance) + self->wakeup_distance = 300; + } + else + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } +} + + +/*QUAKED monster_rat_giant (1 .5 0) (-16 -16 0) (16 16 32) AMBUSH ASLEEP EATING 8 16 32 64 FIXED(na) WANDER(na) MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +A giant rat witha second skin and a bit tougher + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +EATING - Chomp chomp... chewie chomp (wakeup_distance will default to 100) + +COWARD - Runs away + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +*/ +void SP_monster_rat_giant (edict_t *self) +{ + // Generic Monster Initialization + if (!walkmonster_start(self)) // Failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_RAT; + self->materialtype = MAT_FLESH; + + if (!self->health) + self->health = RAT_HEALTH * 4; + + self->mass = RAT_MASS * 2; + self->yaw_speed = 20; + + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + self->movetype=PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + //this will be scaled up later + VectorSet(self->mins, -8, -8, 0); + VectorSet(self->maxs, 8, 8, 16); + + self->s.modelindex = gi.modelindex("models/monsters/rat/superduperat/tris.fm"); + + self->s.skinnum = 0; + + if (self->s.scale < 2.0) + { + self->s.scale = self->monsterinfo.scale = 2.0; + } + else + self->monsterinfo.scale = self->s.scale; + + //Init this to -1 because we can't check for supporters in this function + self->monsterinfo.supporters = -1; + + self->viewheight = self->maxs[2] * 0.5 * self->s.scale; + + self->use = rat_use; + self->touch = rat_touch; + + if (self->spawnflags & MSF_EATING) + { + self->monsterinfo.aiflags |= AI_EATING; + QPostMessage(self, MSG_EAT, PRI_DIRECTIVE, NULL); + if(!self->wakeup_distance) + self->wakeup_distance = 300; + } + else + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } +} diff --git a/Toolkit/Programming/GameCode/game/m_rat.h b/Toolkit/Programming/GameCode/game/m_rat.h new file mode 100644 index 0000000..02c522e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_rat.h @@ -0,0 +1,115 @@ +typedef enum AnimID_e +{ + ANIM_EATING1, + ANIM_EATING2, + ANIM_EATING3, + ANIM_STAND1, + ANIM_STAND2, + ANIM_STAND3, + ANIM_STAND4, + ANIM_STAND5, + ANIM_STAND6, + ANIM_STAND7, + ANIM_STAND8, + ANIM_WATCH1, + ANIM_WATCH2, + ANIM_WALK1, + ANIM_RUN1, + ANIM_RUN2, + ANIM_RUN3, + ANIM_MELEE1, + ANIM_MELEE2, + ANIM_MELEE3, + ANIM_PAIN1, + ANIM_DIE1, + ANIM_DIE2, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_BITEHIT1, + SND_BITEMISS1, + SND_BITEMISS2, + + SND_SCRATCH, + + SND_HISS, + + SND_PAIN1, + SND_PAIN2, + + SND_CHATTER1, + SND_CHATTER2, + SND_CHATTER3, + + SND_CHEW1, + SND_CHEW2, + SND_CHEW3, + + SND_SWALLOW, + + SND_DIE, + SND_GIB, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t rat_move_eat1; +extern animmove_t rat_move_eat2; +extern animmove_t rat_move_eat3; +extern animmove_t rat_move_stand1; +extern animmove_t rat_move_stand2; +extern animmove_t rat_move_stand3; +extern animmove_t rat_move_stand4; +extern animmove_t rat_move_stand5; +extern animmove_t rat_move_stand6; +extern animmove_t rat_move_stand7; +extern animmove_t rat_move_stand8; +extern animmove_t rat_move_watch1; +extern animmove_t rat_move_watch2; +extern animmove_t rat_move_walk1; +extern animmove_t rat_move_run1; +extern animmove_t rat_move_run2; +extern animmove_t rat_move_run3; +extern animmove_t rat_move_melee1; +extern animmove_t rat_move_melee2; +extern animmove_t rat_move_melee3; +extern animmove_t rat_move_pain1; +extern animmove_t rat_move_death1; +extern animmove_t rat_move_death2; + +void rat_use(edict_t *self, edict_t *other, edict_t *activator); +void rat_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf); + +void ratdeathsqueal (edict_t *self); +void ratsqueal (edict_t *self); +void ratbite (edict_t *self); +void rat_pain_init(edict_t *self); +void rat_runorder(edict_t *self); +void rat_standorder(edict_t *self); +void rat_pause (edict_t *self); + +int rat_standdecision (edict_t *self); +int rat_eatdecision (edict_t *self); +void rat_eatorder(edict_t *self); +void rat_runorder(edict_t *self); +void rathiss (edict_t *self); +void ratscratch (edict_t *self); +void ratchatter (edict_t *self); +void ratchew (edict_t *self); +void ratswallow (edict_t *self); +void ratjump(edict_t *self); + +void rat_init (void); + +void rat_pain(edict_t *self, G_Message_t *msg); +void rat_death(edict_t *self, G_Message_t *msg); +void rat_run(edict_t *self, G_Message_t *msg); +void rat_walk(edict_t *self, G_Message_t *msg); +void rat_melee(edict_t *self, G_Message_t *msg); +void rat_watch(edict_t *self, G_Message_t *msg); +void rat_stand(edict_t *self, G_Message_t *msg); +void rat_eat(edict_t *self, G_Message_t *msg); + +void rat_ai_eat(edict_t *self, float dist); +void rat_ai_stand(edict_t *self, float dist); \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/m_rat_anim.c b/Toolkit/Programming/GameCode/game/m_rat_anim.c new file mode 100644 index 0000000..b39c6c9 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_rat_anim.c @@ -0,0 +1,423 @@ +//============================================================================== +// +// m_rat_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_rat_anim.h" +#include "m_rat.h" + +#include "g_monster.h" + +void rat_ai_run (edict_t *self, float dist); + +/*---------------------------------------------------------------------- + Rat Death 2 - the little death, flipping over +-----------------------------------------------------------------------*/ +animframe_t rat_frames_death2 [] = +{ + FRAME_DeathB1, NULL, 0, 0, 0, NULL, 0, ratdeathsqueal, + FRAME_DeathB2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_DeathB3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_DeathB4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_DeathB5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_DeathB6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_DeathB7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_DeathB9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_DeathB9, NULL, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t rat_move_death2 = {9, rat_frames_death2, M_EndDeath}; + + +/*---------------------------------------------------------------------- + Rat Death 1 - the big death, flying backwards and flipping over +-----------------------------------------------------------------------*/ +animframe_t rat_frames_death1 [] = +{ + FRAME_deathA1, NULL, 0, 0, 0, ai_move, 0, ratdeathsqueal, + FRAME_deathA2, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA3, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA4, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA5, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA6, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA7, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA8, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA9, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA10, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA11, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA12, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA13, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathA14, NULL, 0, 0, 0, ai_move, 0, NULL, +}; + +animmove_t rat_move_death1 = {14, rat_frames_death1, M_EndDeath}; + + +/*---------------------------------------------------------------------- + Rat Pain - backup and run away +-----------------------------------------------------------------------*/ +animframe_t rat_frames_pain1 [] = +{ + FRAME_backup1, NULL, 0, 0, 0, ai_move, -4, ratsqueal, + FRAME_backup2, NULL, 0, 0, 0, ai_move, -4, NULL, + FRAME_backup3, NULL, 0, 0, 0, ai_move, -4, NULL, + FRAME_backup4, NULL, 0, 0, 0, ai_move, -4, NULL, + FRAME_backup5, NULL, 0, 0, 0, ai_move, -4, NULL, + FRAME_backup6, NULL, 0, 0, 0, ai_move, -4, NULL +}; + +animmove_t rat_move_pain1 = {6, rat_frames_pain1, rat_pause}; + +/*---------------------------------------------------------------------- + Rat Melee - rat attacking at feet +-----------------------------------------------------------------------*/ +animframe_t rat_frames_melee1 [] = +{ + FRAME_eat1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_eat2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_eat3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_eat4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_eat5, NULL, 0, 0, 0, ai_charge, 0, ratbite +}; + +animmove_t rat_move_melee1 = {5, rat_frames_melee1, rat_pause}; + + +/*---------------------------------------------------------------------- + Rat Melee - rat attacking jumping in the air +-----------------------------------------------------------------------*/ +animframe_t rat_frames_melee2 [] = +{ + FRAME_attack1, NULL, 0, 0, 0, ai_move, 0, ratjump, + FRAME_attack2, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_attack3, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_attack4, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_attack5, NULL, 0, 0, 0, ai_move, 0, ratbite, + FRAME_attack6, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_attack7, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_attack8, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_attack9, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_attack10, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_attack11, NULL, 0, 0, 0, ai_move, 0, NULL, +}; + +animmove_t rat_move_melee2 = {11, rat_frames_melee2, rat_pause}; + +/*---------------------------------------------------------------------- + Rat Melee - rat attacking 2 +-----------------------------------------------------------------------*/ +animframe_t rat_frames_melee3 [] = +{ + FRAME_eat12, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat13, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat14, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat15, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat16, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat17, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat18, NULL, 0, 0, 0, ai_move, 0, ratbite, + FRAME_eat19, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat20, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat21, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat22, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat23, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_eat24, NULL, 0, 0, 0, ai_move, 0, NULL +}; + +animmove_t rat_move_melee3 = {13, rat_frames_melee3, rat_pause}; + + +/*---------------------------------------------------------------------- + Rat Running - rat running to the right +-----------------------------------------------------------------------*/ +animframe_t rat_frames_run3 [] = +{ + FRAME_run_rt1, NULL, 0, 0, 0, rat_ai_run, 10, ratchatter, + FRAME_run_rt2, NULL, 0, 0, 0, rat_ai_run, 10, NULL, + FRAME_run_rt3, NULL, 0, 0, 0, rat_ai_run, 10, NULL, + FRAME_run_rt4, NULL, 0, 0, 0, rat_ai_run, 10, rat_runorder +}; + +animmove_t rat_move_run3 = {4, rat_frames_run3, NULL}; + +/*---------------------------------------------------------------------- + Rat Running - rat running to the left +-----------------------------------------------------------------------*/ +animframe_t rat_frames_run2 [] = +{ + FRAME_run_lft1, NULL, 0, 0, 0, rat_ai_run, 10, ratchatter, + FRAME_run_lft2, NULL, 0, 0, 0, rat_ai_run, 10, NULL, + FRAME_run_lft3, NULL, 0, 0, 0, rat_ai_run, 10, NULL, + FRAME_run_lft4, NULL, 0, 0, 0, rat_ai_run, 10, NULL +}; + +animmove_t rat_move_run2 = {4, rat_frames_run2, rat_runorder}; + +/*---------------------------------------------------------------------- + Rat Running - rat running +-----------------------------------------------------------------------*/ +animframe_t rat_frames_run1 [] = +{ + FRAME_run1, NULL, 0, 0, 0, rat_ai_run, 10, ratchatter, + FRAME_run2, NULL, 0, 0, 0, rat_ai_run, 20, NULL, + FRAME_run3, NULL, 0, 0, 0, rat_ai_run, 10, NULL, + FRAME_run4, NULL, 0, 0, 0, rat_ai_run, 10, NULL, + FRAME_run5, NULL, 0, 0, 0, rat_ai_run, 10, NULL +}; + +animmove_t rat_move_run1 = {5, rat_frames_run1, rat_runorder}; + +/*---------------------------------------------------------------------- + Rat Walking - rat walking +-----------------------------------------------------------------------*/ +animframe_t rat_frames_walk1 [] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_walk, 4, ratchatter, + FRAME_walk2, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_walk, 4, NULL +}; + +animmove_t rat_move_walk1 = {6, rat_frames_walk1, NULL}; + +/*---------------------------------------------------------------------- + Rat Stand8 - from haunches, dropping down to ground +-----------------------------------------------------------------------*/ + +animframe_t rat_frames_stand8 [] = +{ +// FRAME_haunch43, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_haunch44, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch45, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch46, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch47, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch48, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch49, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL +}; + +animmove_t rat_move_stand8 = {5, rat_frames_stand8, rat_standorder}; + +/*---------------------------------------------------------------------- + Rat Stand7 - sitting on haunches, scratch right +-----------------------------------------------------------------------*/ +animframe_t rat_frames_stand7 [] = +{ + FRAME_haunch38, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch39, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch40, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, ratscratch, + FRAME_haunch41, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch42, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL +}; + +animmove_t rat_move_stand7 = {5, rat_frames_stand7, rat_standorder}; + +/*---------------------------------------------------------------------- + Rat Stand6 - sitting on haunches, scratch left +-----------------------------------------------------------------------*/ +animframe_t rat_frames_stand6 [] = +{ +// FRAME_haunch31, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_haunch32, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch33, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch34, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, ratscratch, + FRAME_haunch35, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch36, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, +// FRAME_haunch37, NULL, 0, 0, 0, ai_stand, 0, NULL +}; + +animmove_t rat_move_stand6 = {5, rat_frames_stand6, rat_standorder}; + +/*---------------------------------------------------------------------- + Rat Stand5 - sitting on haunches, look right +-----------------------------------------------------------------------*/ +animframe_t rat_frames_stand5 [] = +{ + FRAME_haunch26, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch27, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch28, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch29, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch30, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL +}; + +animmove_t rat_move_stand5 = {5, rat_frames_stand5, rat_standorder}; + +/*---------------------------------------------------------------------- + Rat Stand4 - sitting on haunches, looking left +-----------------------------------------------------------------------*/ +animframe_t rat_frames_stand4 [] = +{ + FRAME_haunch20, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch21, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch22, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch23, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch24, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL +// FRAME_haunch25, NULL, 0, 0, 0, ai_stand, 0, NULL +}; + +animmove_t rat_move_stand4 = {5, rat_frames_stand4, rat_standorder}; + +/*---------------------------------------------------------------------- + Rat Stand3 - sitting on haunches +-----------------------------------------------------------------------*/ +animframe_t rat_frames_stand3 [] = +{ + FRAME_haunch12, NULL, 0, 0, 0, rat_ai_stand, 0, ratchatter, + FRAME_haunch13, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch14, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch15, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch16, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch17, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch18, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL +//RAME_haunch19, NULL, 0, 0, 0, ai_stand, 0, NULL +}; + +animmove_t rat_move_stand3 = {7, rat_frames_stand3, rat_standorder}; + +/*---------------------------------------------------------------------- + Rat Stand2 - rising up to sit on haunches +-----------------------------------------------------------------------*/ +animframe_t rat_frames_stand2 [] = +{ + FRAME_haunch1, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch2, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch3, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch4, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch5, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch6, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch7, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_haunch8, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch9, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_haunch10, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL +// FRAME_haunch11, NULL, 0, 0, 0, ai_stand, 0, NULL +}; + +animmove_t rat_move_stand2 = {10, rat_frames_stand2, rat_standorder}; + +/*---------------------------------------------------------------------- + Rat Standing - +-----------------------------------------------------------------------*/ +animframe_t rat_frames_stand1 [] = +{ + FRAME_idle1, NULL, 0, 0, 0, rat_ai_stand, 0, ratchatter, + FRAME_idle2, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, rat_ai_stand, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, NULL/*ai_stand*/, 0, NULL +}; + +animmove_t rat_move_stand1 = {8, rat_frames_stand1, rat_standorder}; + + +/*---------------------------------------------------------------------- + Rat Watch2 - Stand up and hiss then go back to all fours +-----------------------------------------------------------------------*/ +animframe_t rat_frames_watch2 [] = +{ + FRAME_hiss1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss13, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t rat_move_watch2 = {13, rat_frames_watch2, rat_eatorder}; + +/*---------------------------------------------------------------------- + Rat Hiss 1 - Hiss while on all fours +-----------------------------------------------------------------------*/ +animframe_t rat_frames_watch1 [] = +{ + FRAME_hiss14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss15, NULL, 0, 0, 0, NULL, 0, rathiss, + FRAME_hiss16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_hiss29, NULL, 0, 0, 0, NULL, 0, NULL +}; + +animmove_t rat_move_watch1 = {16, rat_frames_watch1, rat_eatorder}; + +/*---------------------------------------------------------------------- + Rat Eat3 - Bite and pull back a little +-----------------------------------------------------------------------*/ +animframe_t rat_frames_eat3 [] = +{ + FRAME_eat9, NULL, 0, 0, 0, rat_ai_eat, 0, NULL, + FRAME_eat10, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat11, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, ratchew, + FRAME_eat12, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL +}; + +animmove_t rat_move_eat3 = {4, rat_frames_eat3, rat_eatorder}; + +/*---------------------------------------------------------------------- + Rat Eat2 - Bite low and tear up +-----------------------------------------------------------------------*/ +animframe_t rat_frames_eat2 [] = +{ + FRAME_eat12, NULL, 0, 0, 0, rat_ai_eat, 0, NULL, + FRAME_eat13, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat14, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat15, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat16, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat17, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, ratchew, + FRAME_eat18, NULL, 0, 0, 0, rat_ai_eat, 0, NULL, + FRAME_eat19, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat20, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, ratswallow, + FRAME_eat21, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat22, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat23, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat24, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL +}; + +animmove_t rat_move_eat2 = {13, rat_frames_eat2, rat_eatorder}; + +/*---------------------------------------------------------------------- + Rat Eat1 - Bite down low +-----------------------------------------------------------------------*/ +animframe_t rat_frames_eat1 [] = +{ + FRAME_eat1, NULL, 0, 0, 0, rat_ai_eat, 0, NULL, + FRAME_eat2, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat3, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat4, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat5, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, ratchew, + FRAME_eat6, NULL, 0, 0, 0, rat_ai_eat, 0, NULL, + FRAME_eat7, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL, + FRAME_eat8, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, ratchew, + FRAME_eat9, NULL, 0, 0, 0, NULL/*rat_ai_eat*/, 0, NULL +}; + +animmove_t rat_move_eat1 = {9, rat_frames_eat1, rat_eatorder}; diff --git a/Toolkit/Programming/GameCode/game/m_rat_anim.h b/Toolkit/Programming/GameCode/game/m_rat_anim.h new file mode 100644 index 0000000..a700e34 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_rat_anim.h @@ -0,0 +1,198 @@ +// r:\base\models/monsters\rat\final + +// This file generated by qdata - Do NOT Modify + +#define FRAME_attack1 0 +#define FRAME_attack2 1 +#define FRAME_attack3 2 +#define FRAME_attack4 3 +#define FRAME_attack5 4 +#define FRAME_attack6 5 +#define FRAME_attack7 6 +#define FRAME_attack8 7 +#define FRAME_attack9 8 +#define FRAME_attack10 9 +#define FRAME_attack11 10 +#define FRAME_attack12 11 +#define FRAME_backup1 12 +#define FRAME_backup2 13 +#define FRAME_backup3 14 +#define FRAME_backup4 15 +#define FRAME_backup5 16 +#define FRAME_backup6 17 +#define FRAME_deathA1 18 +#define FRAME_deathA2 19 +#define FRAME_deathA3 20 +#define FRAME_deathA4 21 +#define FRAME_deathA5 22 +#define FRAME_deathA6 23 +#define FRAME_deathA7 24 +#define FRAME_deathA8 25 +#define FRAME_deathA9 26 +#define FRAME_deathA10 27 +#define FRAME_deathA11 28 +#define FRAME_deathA12 29 +#define FRAME_deathA13 30 +#define FRAME_deathA14 31 +#define FRAME_DeathB1 32 +#define FRAME_DeathB2 33 +#define FRAME_DeathB3 34 +#define FRAME_DeathB4 35 +#define FRAME_DeathB5 36 +#define FRAME_DeathB6 37 +#define FRAME_DeathB7 38 +#define FRAME_DeathB8 39 +#define FRAME_DeathB9 40 +#define FRAME_eat1 41 +#define FRAME_eat2 42 +#define FRAME_eat3 43 +#define FRAME_eat4 44 +#define FRAME_eat5 45 +#define FRAME_eat6 46 +#define FRAME_eat7 47 +#define FRAME_eat8 48 +#define FRAME_eat9 49 +#define FRAME_eat10 50 +#define FRAME_eat11 51 +#define FRAME_eat12 52 +#define FRAME_eat13 53 +#define FRAME_eat14 54 +#define FRAME_eat15 55 +#define FRAME_eat16 56 +#define FRAME_eat17 57 +#define FRAME_eat18 58 +#define FRAME_eat19 59 +#define FRAME_eat20 60 +#define FRAME_eat21 61 +#define FRAME_eat22 62 +#define FRAME_eat23 63 +#define FRAME_eat24 64 +#define FRAME_haunch1 65 +#define FRAME_haunch2 66 +#define FRAME_haunch3 67 +#define FRAME_haunch4 68 +#define FRAME_haunch5 69 +#define FRAME_haunch6 70 +#define FRAME_haunch7 71 +#define FRAME_haunch8 72 +#define FRAME_haunch9 73 +#define FRAME_haunch10 74 +#define FRAME_haunch11 75 +#define FRAME_haunch12 76 +#define FRAME_haunch13 77 +#define FRAME_haunch14 78 +#define FRAME_haunch15 79 +#define FRAME_haunch16 80 +#define FRAME_haunch17 81 +#define FRAME_haunch18 82 +#define FRAME_haunch19 83 +#define FRAME_haunch20 84 +#define FRAME_haunch21 85 +#define FRAME_haunch22 86 +#define FRAME_haunch23 87 +#define FRAME_haunch24 88 +#define FRAME_haunch25 89 +#define FRAME_haunch26 90 +#define FRAME_haunch27 91 +#define FRAME_haunch28 92 +#define FRAME_haunch29 93 +#define FRAME_haunch30 94 +#define FRAME_haunch31 95 +#define FRAME_haunch32 96 +#define FRAME_haunch33 97 +#define FRAME_haunch34 98 +#define FRAME_haunch35 99 +#define FRAME_haunch36 100 +#define FRAME_haunch37 101 +#define FRAME_haunch38 102 +#define FRAME_haunch39 103 +#define FRAME_haunch40 104 +#define FRAME_haunch41 105 +#define FRAME_haunch42 106 +#define FRAME_haunch43 107 +#define FRAME_haunch44 108 +#define FRAME_haunch45 109 +#define FRAME_haunch46 110 +#define FRAME_haunch47 111 +#define FRAME_haunch48 112 +#define FRAME_haunch49 113 +#define FRAME_hiss1 114 +#define FRAME_hiss2 115 +#define FRAME_hiss3 116 +#define FRAME_hiss4 117 +#define FRAME_hiss5 118 +#define FRAME_hiss6 119 +#define FRAME_hiss7 120 +#define FRAME_hiss8 121 +#define FRAME_hiss9 122 +#define FRAME_hiss10 123 +#define FRAME_hiss11 124 +#define FRAME_hiss12 125 +#define FRAME_hiss13 126 +#define FRAME_hiss14 127 +#define FRAME_hiss15 128 +#define FRAME_hiss16 129 +#define FRAME_hiss17 130 +#define FRAME_hiss18 131 +#define FRAME_hiss19 132 +#define FRAME_hiss20 133 +#define FRAME_hiss21 134 +#define FRAME_hiss22 135 +#define FRAME_hiss23 136 +#define FRAME_hiss24 137 +#define FRAME_hiss25 138 +#define FRAME_hiss26 139 +#define FRAME_hiss27 140 +#define FRAME_hiss28 141 +#define FRAME_hiss29 142 +#define FRAME_idle1 143 +#define FRAME_idle2 144 +#define FRAME_idle3 145 +#define FRAME_idle4 146 +#define FRAME_idle5 147 +#define FRAME_idle6 148 +#define FRAME_idle7 149 +#define FRAME_idle8 150 +#define FRAME_idle9 151 +#define FRAME_idle10 152 +#define FRAME_runstop1 153 +#define FRAME_runstop2 154 +#define FRAME_runstop3 155 +#define FRAME_runstop4 156 +#define FRAME_runstop5 157 +#define FRAME_runstop6 158 +#define FRAME_run_att1 159 +#define FRAME_run_att2 160 +#define FRAME_run_att3 161 +#define FRAME_run_att4 162 +#define FRAME_run_att5 163 +#define FRAME_run_lft1 164 +#define FRAME_run_lft2 165 +#define FRAME_run_lft3 166 +#define FRAME_run_lft4 167 +#define FRAME_run_lft5 168 +#define FRAME_run_rt1 169 +#define FRAME_run_rt2 170 +#define FRAME_run_rt3 171 +#define FRAME_run_rt4 172 +#define FRAME_run_rt5 173 +#define FRAME_run1 174 +#define FRAME_run2 175 +#define FRAME_run3 176 +#define FRAME_run4 177 +#define FRAME_run5 178 +#define FRAME_walk1 179 +#define FRAME_walk2 180 +#define FRAME_walk3 181 +#define FRAME_walk4 182 +#define FRAME_walk5 183 +#define FRAME_walk6 184 + + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 3 + +#define MESH_BASE 0 +#define MESH__BODY 1 +#define MESH__TAIL 2 diff --git a/Toolkit/Programming/GameCode/game/m_seraph.c b/Toolkit/Programming/GameCode/game/m_seraph.c new file mode 100644 index 0000000..e3cf8af --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_seraph.c @@ -0,0 +1,1107 @@ +//============================================================================== +// +// m_seraph.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// jweier +//============================================================================== + +#include "g_local.h" +#include "m_seraph.h" +#include "m_seraph_anim.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "fx.h" +#include "g_HitLocation.h" +#include "g_misc.h" + +#include "m_stats.h" + +void MG_InitMoods(edict_t *self); +//Seraphs need knowledge of the ogle's animations +//Any changes in m_ogle.h must be mirrored here +enum +{ + OGLE_ANIM_WALK1, + OGLE_ANIM_PUSH1, + OGLE_ANIM_PUSH2, + OGLE_ANIM_PUSH3, + OGLE_ANIM_STAND1, + OGLE_ANIM_WORK1, + OGLE_ANIM_WORK2, + OGLE_ANIM_WORK3, + OGLE_ANIM_WORK4, + OGLE_ANIM_WORK5, + OGLE_ANIM_PAIN1, + OGLE_ANIM_PAIN2, + OGLE_ANIM_PAIN3, + OGLE_ANIM_REST1_TRANS, + OGLE_ANIM_REST1_WIPE, + OGLE_ANIM_REST1, + OGLE_ANIM_REST2_WIPE, + OGLE_ANIM_REST3_WIPE, + OGLE_ANIM_REST4_TRANS, + OGLE_ANIM_REST4_TRANS2, + OGLE_ANIM_REST4, + OGLE_ANIM_CELEBRATE1, + OGLE_ANIM_CELEBRATE2, + OGLE_ANIM_CELEBRATE3_TRANS, + OGLE_ANIM_CELEBRATE3, + OGLE_ANIM_CELEBRATE4_TRANS, + OGLE_ANIM_CELEBRATE4, + OGLE_ANIM_CELEBRATE5_TRANS, + OGLE_ANIM_CELEBRATE5, + OGLE_ANIM_CHARGE1, + OGLE_ANIM_CHARGE2, + OGLE_ANIM_CHARGE3, + OGLE_ANIM_CHARGE4, + OGLE_ANIM_CHARGE5, + OGLE_ANIM_ATTACK1, + OGLE_ANIM_ATTACK2, + OGLE_ANIM_ATTACK3, + OGLE_ANIM_DEATH1, + OGLE_ANIM_DEATH2, + NUM_OGLE_ANIMS +}; + +static animmove_t *animations[NUM_ANIMS] = +{ + &seraph_move_walk1, + &seraph_move_walk2, + &seraph_move_whip1, + &seraph_move_whip1_loop, + &seraph_move_whip1_end, + &seraph_move_stand1, + &seraph_move_stand1_tr, + &seraph_move_stand1_r, + &seraph_move_stand1_trc, + &seraph_move_stand1_tl, + &seraph_move_stand1_l, + &seraph_move_stand1_tlc, + &seraph_move_point1, + &seraph_move_run1, + &seraph_move_fjump, + &seraph_move_run1_whip, + &seraph_move_pain, + &seraph_move_swipe, + &seraph_move_get2work, + &seraph_move_get2work2, + &seraph_move_startle, + &seraph_move_ready2idle, + &seraph_move_backup, + &seraph_move_death1, + &seraph_move_death2_go, + &seraph_move_death2_loop, + &seraph_move_death2_end, + &seraph_move_backup2, +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + +#define OVERLORD_RADIUS 1000 //FIXME: Tweak out + +/* +========================================================== + + Seraph Helper functions + +========================================================== +*/ + +void seraphApplyJump (edict_t *self) +{ + self->jump_time = level.time + 0.75; + VectorCopy(self->movedir, self->velocity); + VectorNormalize(self->movedir); +} + +void seraph_dead ( edict_t *self ) +{ + self->health = 0; + self->solid = SOLID_NOT; + + M_EndDeath ( self ); +} + +void seraph_death_loop ( edict_t *self ) +{ + SetAnim(self, ANIM_DEATH2_LOOP); +} + +void seraph_check_land ( edict_t *self ) +{ + vec3_t endpos; + trace_t trace; + + M_ChangeYaw(self); + + VectorCopy(self->s.origin, endpos); + endpos[2] -= 48; + + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&trace); + + if ( (trace.fraction < 1 || trace.allsolid || trace.startsolid ) && self->curAnimID != ANIM_DEATH2_END && self->curAnimID != ANIM_DEATH2_GO) + { + self->elasticity = 1.25; + self->friction = 0.5; + SetAnim(self, ANIM_DEATH2_END); + } +} + +void seraph_sound_startle(edict_t *self) +{ + gi.sound (self, CHAN_VOICE, sounds[SND_STARTLE], 1, ATTN_NORM, 0); +} + +void seraph_sound_slap(edict_t *self) +{ + gi.sound (self, CHAN_WEAPON, sounds[SND_SLAP], 1, ATTN_NORM, 0); +} + +void seraph_sound_scold(edict_t *self) +{//no talking! + gi.sound (self, CHAN_VOICE, sounds[SND_SCOLD3], 1, ATTN_NORM, 0); +} + +void seraph_sound_scold2(edict_t *self) +{ + if(irand(0, 1))//back to work! + gi.sound(self, CHAN_VOICE, sounds[SND_SCOLD1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_SCOLD2], 1, ATTN_NORM, 0); +} + +void seraph_sound_yell(edict_t *self) +{ + gi.sound (self, CHAN_VOICE, sounds[SND_SCARE], 1, ATTN_NORM, 0); +} + +void seraph_sound_whip(edict_t *self) +{ + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACK], 1, ATTN_NORM, 0); +} + +//Become startled and look around +void seraph_startle(edict_t *self) +{ + SetAnim(self, ANIM_STARTLE); +} + +//Seraph has finished his startle, either track down the enemy, or go back to normal +void seraph_done_startle(edict_t *self) +{ + if (!FindTarget(self)) + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +//Seraph has finished ANIM_GET2WORK, and must reset its enemy +void seraph_done_get2work(edict_t *self) +{ + if(self->enemy) + self->enemy->targeted = 0; + self->enemy = NULL; + self->ai_mood = AI_MOOD_STAND; + self->ai_mood_flags &= ~AI_MOOD_FLAG_IGNORE; + seraph_pause(self); +} + +//Special walk code for going to yell at an ogle +void seraph_ai_walk(edict_t *self, float dist) +{ + qboolean MG_MoveToGoal (edict_t *self, float dist); + + if (self->enemy && M_DistanceToTarget(self, self->enemy) < 72) + { + self->ai_mood = AI_MOOD_STAND; + if (irand(0,1)) + SetAnim(self, ANIM_GET2WORK); + else + SetAnim(self, ANIM_GET2WORK2); + } + else + { + MG_MoveToGoal(self, dist); + } +} + +void seraph2idle (edict_t *self) +{ + SetAnim(self, ANIM_STAND1); +} + +//Upper level AI interfacing +void seraph_pause(edict_t *self) +{ + self->mood_think(self); + + if(self->enemy) + if ((self->ai_mood_flags & AI_MOOD_FLAG_IGNORE)&& self->enemy->classID == CID_OGLE) + return; + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_PURSUE: + case AI_MOOD_NAVIGATE: + case AI_MOOD_WALK: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_STAND: + if (!self->enemy) + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break;//else what? + + case AI_MOOD_DELAY: + break; + + case AI_MOOD_WANDER: + SetAnim(self, ANIM_WALK1); + break; + + case AI_MOOD_POINT_NAVIGATE: + SetAnim(self, ANIM_WALK2); + break; + + case AI_MOOD_JUMP: + SetAnim(self, ANIM_FJUMP); + break; + + default : +#ifdef _DEVEL + gi.dprintf("seraph guard: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } +} + +void seraph_check_mood (edict_t *self, G_Message_t *msg) +{ + ParseMsgParms(msg, "i", &self->ai_mood); + + seraph_pause(self); +} + +//Targets a specific ogle and puts it back to work +void seraph_enforce_ogle(edict_t *self) +{ + if(!self->enemy) + return; + + self->enemy->use(self->enemy, self, self); + + if(irand(0, 1))//back to work! + gi.sound(self, CHAN_VOICE, sounds[SND_SCOLD1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, sounds[SND_SCOLD2], 1, ATTN_NORM, 0); +} + +//Targets all idle ogles and puts them back to work +void seraph_enforce(edict_t *self) +{ + edict_t *ogle; + + ogle = NULL; + + while((ogle = findradius(ogle, self->s.origin, OVERLORD_RADIUS)) != NULL) + { + if (ogle->classID != CID_OGLE) + continue; + + if (ogle->ai_mood != AI_MOOD_REST) + continue; + + if (ogle->targetEnt != self) + continue; + + //Setup within the ogle code + ogle->use(ogle, self, self); + } + +} + +//Check to see if you can make it to an idle ogle and scare them +qboolean seraph_checkscare(edict_t *self, edict_t *ogle) +{//FIX? refers to goalentity + trace_t trace; + vec3_t sf, of, mins; + float dot; + + AngleVectors(self->s.angles, sf, NULL, NULL); + AngleVectors(ogle->s.angles, of, NULL, NULL); + + dot = DotProduct(sf, of); + + //Only do it if you're in back of them, and they're facing away + if (dot) + { + VectorCopy(self->mins, mins); + mins[2] += 18; //Account for step ability + gi.trace(self->s.origin, mins, self->maxs, ogle->s.origin, self, MASK_MONSTERSOLID,&trace); + + if (trace.ent == ogle) + { + //Necessary info for the AI_MOOD_POINT_NAVIGATE stuff + VectorCopy(self->s.origin, self->monsterinfo.nav_goal); + self->old_yaw = self->s.angles[YAW]; + self->ai_mood = AI_MOOD_POINT_NAVIGATE; + self->movetarget = self->goalentity = self->enemy = ogle; + + //Tells the other Seraphs not to try and get this one too + ogle->targeted = 1; + + self->ai_mood_flags |= AI_MOOD_FLAG_IGNORE; + + return true; + } + } + return false; +} + +//Check the ogles and make sure their noses are to the grind stone +void seraph_oversee(edict_t *self) +{ + edict_t *ogle; + ogle=NULL; + + while((ogle = findradius(ogle, self->s.origin, OVERLORD_RADIUS)) != NULL) + { + if (ogle->ai_mood != AI_MOOD_REST) + continue; + + if (ogle->classID != CID_OGLE) + continue; + + if (ogle->targeted) + return; + + if (ogle->targetEnt != self) + return; + + //See if we can scare this one + if (!seraph_checkscare(self, ogle)) + { + self->ai_mood = AI_MOOD_ATTACK; + self->ai_mood_flags |= AI_MOOD_FLAG_WHIP; + } + else //If we can scare it, stop and do it + return; + } +} + +//Cycles through the various idle animations +void seraph_idle(edict_t *self) +{ + int chance = irand(0,100); + + seraph_oversee(self); + + //Check to see if we were supposed to point at an ogle + if ( (self->ai_mood == AI_MOOD_ATTACK) && (self->ai_mood_flags & AI_MOOD_FLAG_WHIP) && (self->curAnimID != ANIM_POINT1) ) + { + SetAnim(self, ANIM_POINT1); + self->ai_mood = AI_MOOD_STAND; + self->ai_mood_flags &= ~AI_MOOD_FLAG_WHIP; + return; + } + + //See if we're going to go scare an ogle + if ( (self->ai_mood == AI_MOOD_POINT_NAVIGATE) ) + { + SetAnim(self, ANIM_WALK2); + return; + } + + switch( self->curAnimID ) + { + case ANIM_STAND1: + if (chance < 20) + SetAnim(self, ANIM_STAND1_TR); + else if (chance < 40) + SetAnim(self, ANIM_STAND1_TL); + break; + + //Right + case ANIM_POINT1: + case ANIM_STAND1_TR: + SetAnim(self, ANIM_STAND1_R); + break; + + case ANIM_STAND1_R: + if (chance < 50) + SetAnim(self, ANIM_STAND1_TRC); + break; + + case ANIM_STAND1_TLC: + case ANIM_STAND1_TRC: + SetAnim(self, ANIM_STAND1); + break; + + //Left + case ANIM_STAND1_TL: + SetAnim(self, ANIM_STAND1_L); + break; + + case ANIM_STAND1_L: + if (chance < 50) + SetAnim(self, ANIM_STAND1_TLC); + break; + } +} + +//Check to do damage with a whip +void seraph_strike(edict_t *self, float damage, float a, float b) +{ + trace_t trace; + edict_t *victim; + vec3_t soff, eoff, mins, maxs, bloodDir, direction; + + VectorSet(soff, 16, 16, 32); + VectorSet(eoff, 80, 16, 8); + + VectorSet(mins, -2, -2, -2); + VectorSet(maxs, 2, 2, 2); + + VectorSubtract(soff, eoff, bloodDir); + VectorNormalize(bloodDir); + + victim = M_CheckMeleeLineHit(self, soff, eoff, mins, maxs, &trace, direction); + + if (victim) + { + if (victim == self) + { + //Create a puff effect + //gi.CreateEffect(NULL, FX_SPARKS, 0, hitPos, "db", vec3_origin, irand(1,3)); + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACK], 1, ATTN_NORM, 0); + } + else + { + //Hurt whatever we were whacking away at + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, + damage, damage, DAMAGE_EXTRA_BLOOD|DAMAGE_EXTRA_KNOCKBACK,MOD_DIED); + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACK], 1, ATTN_NORM, 0); + } + } + else + { + //Play swoosh sound? + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACK], 1, ATTN_NORM, 0); + } +} + +/* +========================================================== + + Seraph Message functions + +========================================================== +*/ + +//Seraph has died +void seraph_death_pain(edict_t *self, G_Message_t *msg) +{ + if (self->health < -80) + { + BecomeDebris(self); + return; + } + +} + +void seraph_dropweapon (edict_t *self); +void seraph_death(edict_t *self, G_Message_t *msg) +{ + edict_t *targ, *inflictor, *attacker; + vec3_t dVel, vf, yf; + float damage; + int soundID; + + ParseMsgParms(msg, "eeei", &targ, &inflictor, &attacker, &damage); + + M_StartDeath(self, ANIM_DEATH1); + + if (!stricmp(attacker->classname, "monster_ogle")) + { + self->health = 1; + self->takedamage = DAMAGE_NO; + self->solid = SOLID_BBOX; + + SetAnim(self, ANIM_DEATH1); + + soundID = irand(SND_DEATH1, SND_DEATH4); + gi.sound (self, CHAN_BODY, sounds[soundID], 1, ATTN_NORM, 0); + + return; + } + + if (self->health < -80) + { + return; + } + else if (self->health < -10) + { + seraph_dropweapon (self); + + SetAnim(self, ANIM_DEATH2_GO); + + VectorCopy(targ->velocity, vf); + VectorNormalize(vf); + + VectorScale(vf, -1, yf); + + self->ideal_yaw = vectoyaw( yf ); + self->yaw_speed = 24; + + self->elasticity = 1.2; + self->friction = 0.8; + + VectorScale(vf, 300, dVel); + dVel[2] = irand(150,200); + + VectorCopy(dVel, self->velocity); + } + else + { + SetAnim(self, ANIM_DEATH1); + } + + soundID = irand(SND_DEATH1, SND_DEATH4); + gi.sound (self, CHAN_BODY, sounds[soundID], 1, ATTN_NORM, 0); +} + +//Check to see if the Seraph is already standing, if not, transition into it +void seraph_stand(edict_t *self, G_Message_t *msg) +{ + if (self->curAnimID == ANIM_READY2IDLE) + SetAnim(self, ANIM_STAND1); + else + SetAnim(self, ANIM_READY2IDLE); +} + +//Classic run-attack function +void seraph_run(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + SetAnim(self, ANIM_RUN1); + return; + } + + //If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +//Classic melee attack function +void seraph_melee(edict_t *self, G_Message_t *msg) +{ + vec3_t attackVel, vf; + float dist; + int ret; + + //Don't interrupt a current animation with another melee call inside of it + if (self->curAnimID == ANIM_ATTACK1_LOOP) + return; + + if(self->enemy) + if ( (self->ai_mood_flags & AI_MOOD_FLAG_IGNORE) && (!stricmp(self->enemy->classname, "monster_ogle")) ) + return; + + if (M_ValidTarget(self, self->enemy)) + { + if(self->ai_mood == AI_MOOD_FLEE) + { + SetAnim(self, ANIM_BACKUP2); + return; + } + //Set this for any uses below + AngleVectors(self->s.angles, vf, NULL, NULL); + + dist = M_DistanceToTarget(self, self->enemy); + + if (dist < 100) + { + VectorMA(vf, 0, vf, attackVel); + ret = M_PredictTargetEvasion( self, self->enemy, attackVel, self->enemy->velocity, self->melee_range, 5 ); + + if (ret) + SetAnim(self, ANIM_ATTACK1_LOOP); + else + SetAnim(self, ANIM_RUN1_WHIP); + } + else + SetAnim(self, ANIM_RUN1); + + return; + } + + //If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +//Take pain +void seraph_pain(edict_t *self, G_Message_t *msg) +{ + edict_t *attacker; + int temp, damage, soundID; + int force_pain; + + ParseMsgParms(msg, "eeiii", &temp, &attacker, &force_pain, &damage, &temp); + + if(self->monsterinfo.awake) + self->ai_mood_flags &= ~AI_MOOD_FLAG_IGNORE; + + //Weighted random based on health compared to the maximum it was at + if (force_pain || ((irand(0, self->max_health+50) > self->health) && !irand(0,2))) + { + soundID = irand(SND_PAIN1, SND_PAIN4); + + gi.sound (self, CHAN_BODY, sounds[soundID], 1, ATTN_NORM, 0); + + SetAnim(self, ANIM_PAIN); + } + + if(attacker) + { + if(attacker!=self->enemy) + { + if(!self->enemy) + self->enemy = attacker; + else if(M_DistanceToTarget(self, self->enemy) > self->melee_range) + { + if(self->enemy->client) + self->oldenemy = self->enemy; + self->enemy = attacker; + } + } + } +} + + +qboolean seraphAlerted (edict_t *self, alertent_t *alerter, edict_t *enemy) +{ + if(self->alert_time < level.time) + {//not startled already + if(!(alerter->alert_svflags&SVF_ALERT_NO_SHADE) && skill->value < 3.0 && !(self->monsterinfo.aiflags & AI_NIGHTVISION)) + { + if(enemy->light_level < flrand(6, 77)) + {//too dark, can't see enemy + return false; + } + } + + if(!infront(self,enemy)) + { + if(alerter->lifetime < level.time + 2) + self->alert_time = level.time + 2;//be ready for 2 seconds to wake up if alerted again + else + self->alert_time = alerter->lifetime;//be alert as long as the alert sticks around + seraph_startle(self); + return false; + } + } + + if(enemy->svflags&SVF_MONSTER) + self->enemy = alerter->enemy; + else + self->enemy = enemy; + + FoundTarget(self, true); + + return true; +} + + + +int Bit_for_MeshNode_so [NUM_MESH_NODES] = +{ + BIT_BASEBIN, + BIT_PITHEAD,//overlord head + BIT_SHOULDPAD, + BIT_GUARDHEAD,//guard head + BIT_LHANDGRD,//left hand guard + BIT_LHANDBOSS,//left hand overlord + BIT_RHAND,//right hand + BIT_FRTORSO, + BIT_ARMSPIKES, + BIT_LFTUPARM, + BIT_RTLEG, + BIT_RTARM, + BIT_LFTLEG, + BIT_BKTORSO, + BIT_AXE,//axe + BIT_WHIP//whip +}; + +void seraph_back (edict_t *self, float dist) +{ + if(!MG_BoolWalkMove(self, self->s.angles[YAW] + 180, dist)) + { + if(!irand(0, 1000)) + { + self->monsterinfo.aiflags |= AI_COWARD; + SetAnim(self, ANIM_RUN1); + } + } +} + +qboolean canthrownode_so (edict_t *self, int BP, int *throw_nodes) +{//see if it's on, if so, add it to throw_nodes + //turn it off on thrower + if(!(self->s.fmnodeinfo[BP].flags & FMNI_NO_DRAW)) + { + *throw_nodes |= Bit_for_MeshNode_so[BP]; + self->s.fmnodeinfo[BP].flags |= FMNI_NO_DRAW; + return true; + } + return false; +} + +//THROWS weapon, turns off those nodes, sets that weapon as gone +void seraph_dropweapon (edict_t *self) +{ + vec3_t handspot, forward, right, up; + + if(!(self->s.fmnodeinfo[MESH__WHIP].flags & FMNI_NO_DRAW)) + { + VectorClear(handspot); + AngleVectors(self->s.angles,forward,right,up); + + VectorMA(handspot,8,forward,handspot); + VectorMA(handspot,5,right,handspot); + VectorMA(handspot,12,up,handspot); + ThrowWeapon(self, &handspot, BIT_WHIP, 0, FRAME_partfly); + self->s.fmnodeinfo[MESH__WHIP].flags |= FMNI_NO_DRAW; + return; + } +} + +void seraph_dismember(edict_t *self, int damage, int HitLocation) +{ + int throw_nodes = 0; + vec3_t gore_spot, right; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; + + + VectorClear(gore_spot); + switch(HitLocation) + { + case hl_Head: + if(self->s.fmnodeinfo[MESH__PITHEAD].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__PITHEAD].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,8,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { + self->s.fmnodeinfo[MESH__PITHEAD].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__PITHEAD].skin = self->s.skinnum+1; + } + break; + + case hl_TorsoFront://split in half? + if(self->s.fmnodeinfo[MESH__FRTORSO].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.fmnodeinfo[MESH__FRTORSO].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__FRTORSO].skin = self->s.skinnum+1; + } + break; + case hl_TorsoBack://split in half? + if(self->s.fmnodeinfo[MESH__BKTORSO].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health) < damage) + { + self->s.fmnodeinfo[MESH__BKTORSO].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__BKTORSO].skin = self->s.skinnum+1; + } + break; + + case hl_ArmUpperLeft: + if(flrand(0,self->health)s.fmnodeinfo[MESH__LFTUPARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LFTUPARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmLowerLeft://left arm + if(self->s.fmnodeinfo[MESH__LHANDBOSS].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__LHANDBOSS].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + } + } + else + { + self->s.fmnodeinfo[MESH__LHANDBOSS].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LHANDBOSS].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperRight: + if(flrand(0,self->health)s.fmnodeinfo[MESH__RTARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RTARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmLowerRight://right arm + if(self->s.fmnodeinfo[MESH__RHAND].flags & FMNI_NO_DRAW) + break; + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + seraph_dropweapon (self); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + } + } + else + { + self->s.fmnodeinfo[MESH__RHAND].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RHAND].skin = self->s.skinnum+1; + } + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft://left leg + if(self->s.fmnodeinfo[MESH__LFTLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__LFTLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LFTLEG].skin = self->s.skinnum+1; + break; + case hl_LegUpperRight: + case hl_LegLowerRight://right leg + if(self->s.fmnodeinfo[MESH__RTLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__RTLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RTLEG].skin = self->s.skinnum+1; + break; + } + + if(self->s.fmnodeinfo[MESH__RHAND].flags & FMNI_NO_DRAW) + self->monsterinfo.aiflags |= AI_NO_MELEE; + +//FIXME: when get missile anim +// if(self->s.fmnodeinfo[MESH__LHANDGRD].flags & FMNI_NO_DRAW) +// self->monsterinfo.aiflags |= AI_NO_MISSILE; + + if(self->monsterinfo.aiflags & AI_NO_MELEE)//&&self->monsterinfo.aiflags & AI_NO_MISSILE) + SetAnim(self, ANIM_BACKUP); +} + +void ser_ovl_SightSound(edict_t *self, G_Message_t *Msg) +{ + gi.sound(self, CHAN_VOICE, sounds[irand(SND_SIGHT1, SND_SIGHT3)], 1, ATTN_NORM, 0); +} + +/* +========================================================== + + Seraph Spawn functions + +========================================================== +*/ + +void SeraphOverlordStaticsInit() +{ + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_STAND] = seraph_stand; + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_RUN] = seraph_run; + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_MELEE] = seraph_melee; + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_PAIN] = seraph_pain; + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_DEATH] = seraph_death; + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_DEATH_PAIN] = seraph_death_pain; + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_CHECK_MOOD] = seraph_check_mood; + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_SERAPH_OVERLORD].msgReceivers[MSG_VOICE_SIGHT] = ser_ovl_SightSound; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/overlord/tris.fm"); + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + sounds[SND_ATTACK] = gi.soundindex("monsters/seraph/overlord/attack.wav"); + + sounds[SND_SCOLD1] = gi.soundindex("monsters/seraph/overlord/scold1.wav");// Back to work + sounds[SND_SCOLD2] = gi.soundindex("monsters/seraph/overlord/scold2.wav"); // Get to work + sounds[SND_SCOLD3] = gi.soundindex("monsters/seraph/overlord/scold3.wav"); // No talking + + sounds[SND_SCARE] = gi.soundindex("monsters/seraph/overlord/scare.wav");// Hey! + + sounds[SND_STARTLE] = gi.soundindex("monsters/seraph/overlord/startle.wav"); + sounds[SND_SLAP] = gi.soundindex("monsters/seraph/overlord/slap.wav"); + + sounds[SND_DEATH1] = gi.soundindex("monsters/seraph/death1.wav"); + sounds[SND_DEATH2] = gi.soundindex("monsters/seraph/death2.wav"); + sounds[SND_DEATH3] = gi.soundindex("monsters/seraph/wimpdeath1.wav"); + sounds[SND_DEATH4] = gi.soundindex("monsters/seraph/wimpdeath2.wav"); + + sounds[SND_PAIN1] = gi.soundindex("monsters/seraph/pain1.wav"); + sounds[SND_PAIN2] = gi.soundindex("monsters/seraph/pain2.wav"); + sounds[SND_PAIN3] = gi.soundindex("monsters/seraph/pain3.wav"); + sounds[SND_PAIN4] = gi.soundindex("monsters/seraph/pain4.wav"); + + sounds[SND_SIGHT1] = gi.soundindex("monsters/seraph/overlord/sight1.wav"); + sounds[SND_SIGHT2] = gi.soundindex("monsters/seraph/overlord/sight2.wav"); + sounds[SND_SIGHT3] = gi.soundindex("monsters/seraph/overlord/scare.wav"); + + classStatics[CID_SERAPH_OVERLORD].resInfo = &resInfo; +} + +/*QUAKED monster_seraph_overlord(1 .5 0) (-24 -24 -34) (24 24 34) AMBUSH ASLEEP 4 8 16 32 64 FIXED WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 +The big, nasty, tyranical Overlords.. + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING- Use WANDER instead + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 24 +melee_range = 100 +missile_range = 0 +min_missile_range = 0 +bypass_missile_chance = 0 +jump_chance = 30 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +void SP_monster_seraph_overlord(edict_t *self) +{ + self->classID = CID_SERAPH_OVERLORD; + + if (!monster_start(self)) // Failed initialization + return; + + self->msgHandler = DefaultMsgHandler; + self->monsterinfo.alert = seraphAlerted; + self->think = walkmonster_start_go; + self->monsterinfo.dismember = seraph_dismember; + + if (!self->health) + { + self->max_health = self->health = SERAPH_HEALTH; + } + + //Apply to the end result (whether designer set or not) + self->health = MonsterHealth(self->health); + + self->mass = SERAPH_MASS; + self->yaw_speed = 18; + + self->movetype = PHYSICSTYPE_STEP; + self->solid=SOLID_BBOX; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + self->materialtype = MAT_FLESH; + + self->s.modelindex = classStatics[CID_SERAPH_OVERLORD].resInfo->modelIndex; + self->s.skinnum=0; + + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + + self->monsterinfo.otherenemyname = "monster_rat"; + + if (!self->s.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + //Turn off the Guard pieces! + self->s.fmnodeinfo[MESH__AXE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GUARDHEAD].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__LHANDGRD].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__ARMSPIKES].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__SHOULDPAD].flags |= FMNI_NO_DRAW; + + MG_InitMoods(self); + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + + self->melee_range *= self->s.scale; +} diff --git a/Toolkit/Programming/GameCode/game/m_seraph.h b/Toolkit/Programming/GameCode/game/m_seraph.h new file mode 100644 index 0000000..ba38e1d --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_seraph.h @@ -0,0 +1,133 @@ +#include "g_local.h" + +typedef enum AnimID_e +{ + ANIM_WALK1, + ANIM_WALK2, + ANIM_ATTACK1, + ANIM_ATTACK1_LOOP, + ANIM_ATTACK1_END, + ANIM_STAND1, + ANIM_STAND1_TR, + ANIM_STAND1_R, + ANIM_STAND1_TRC, + ANIM_STAND1_TL, + ANIM_STAND1_L, + ANIM_STAND1_TLC, + ANIM_POINT1, + ANIM_RUN1, + ANIM_FJUMP, + ANIM_RUN1_WHIP, + ANIM_PAIN, + ANIM_SWIPE, + ANIM_GET2WORK, + ANIM_GET2WORK2, + ANIM_STARTLE, + ANIM_READY2IDLE, + ANIM_BACKUP, + ANIM_DEATH1, + ANIM_DEATH2_GO, + ANIM_DEATH2_LOOP, + ANIM_DEATH2_END, + ANIM_BACKUP2, + + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_ATTACK, + SND_SCOLD1, + SND_SCOLD2, + SND_SCOLD3, + SND_STARTLE, + SND_SLAP, + SND_DEATH1, + SND_DEATH2, + SND_DEATH3, + SND_DEATH4, + SND_PAIN1, + SND_PAIN2, + SND_PAIN3, + SND_PAIN4, + SND_SCARE, + SND_SIGHT1, + SND_SIGHT2, + SND_SIGHT3, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t seraph_move_walk1, + seraph_move_walk2, + seraph_move_whip1, + seraph_move_whip1_loop, + seraph_move_whip1_end, + seraph_move_stand1, + seraph_move_stand1_tr, + seraph_move_stand1_r, + seraph_move_stand1_trc, + seraph_move_stand1_tl, + seraph_move_stand1_l, + seraph_move_stand1_tlc, + seraph_move_point1, + seraph_move_run1, + seraph_move_fjump, + seraph_move_run1_whip, + seraph_move_pain, + seraph_move_swipe, + seraph_move_get2work, + seraph_move_get2work2, + seraph_move_startle, + seraph_move_ready2idle, + seraph_move_backup, + seraph_move_death1, + seraph_move_death2_go, + seraph_move_death2_loop, + seraph_move_death2_end, + seraph_move_backup2; + +void SP_monster_seraph_overlord(edict_t* self); + +void seraph_done_startle(edict_t *self); +void seraph_done_get2work(edict_t *self); +void seraph_enforce_ogle(edict_t *self); +void seraph_ai_walk(edict_t *self, float dist); +void seraph_idle(edict_t *self); +void seraph_pause(edict_t *self); +void seraph_enforce(edict_t *self); +void seraph_strike(edict_t *self, float damage, float a, float b); + +void seraph_dead ( edict_t *self ); + +void seraph_death_loop ( edict_t *self ); +void seraph_check_land ( edict_t *self ); + +void seraph_sound_startle(edict_t *self); +void seraph_sound_slap(edict_t *self); +void seraph_sound_scold(edict_t *self); +void seraph_sound_yell(edict_t *self); +void seraph_sound_whip(edict_t *self); +void seraphApplyJump (edict_t *self); + +void seraph_back (edict_t *self, float dist); +void seraph_sound_scold2(edict_t *self); +void seraph2idle (edict_t *self); + +qboolean MG_BoolWalkMove (edict_t *self, float yaw, float dist); + +#define BIT_BASEBIN 0 +#define BIT_PITHEAD 1 +#define BIT_SHOULDPAD 2 +#define BIT_GUARDHEAD 4 +#define BIT_LHANDGRD 8 +#define BIT_LHANDBOSS 16 +#define BIT_RHAND 32 +#define BIT_FRTORSO 64 +#define BIT_ARMSPIKES 128 +#define BIT_LFTUPARM 256 +#define BIT_RTLEG 512 +#define BIT_RTARM 1024 +#define BIT_LFTLEG 2048 +#define BIT_BKTORSO 4096 +#define BIT_AXE 8192 +#define BIT_WHIP 16384 \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/m_seraph_anim.c b/Toolkit/Programming/GameCode/game/m_seraph_anim.c new file mode 100644 index 0000000..91ff943 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_seraph_anim.c @@ -0,0 +1,683 @@ +#include "g_local.h" +#include "m_seraph.h" +#include "m_seraph_anim.h" +#include "g_monster.h" +#include "m_stats.h" + +/*---------------------------------------------------- + seraph idles + + stand1 - standing, looking straight ahead + stand1_tr - standing, transitioning to looking right + stand1_r - standing, looking right + stand1_trc - standing, transition to look back to center from looking right + stand1_tl - standing, transitioning to looking left + stand1_l - standing, looking left + stand1_trl - standing, transition to look back to center from looking left + +----------------------------------------------------*/ + +animframe_t seraph_frames_stand1[] = +{ + FRAME_idle1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle20, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t seraph_move_stand1 = {20,seraph_frames_stand1, seraph_idle}; + +//Look right + +animframe_t seraph_frames_stand1_tr[] = +{ + FRAME_idle_htr1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htr19, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t seraph_move_stand1_tr = {19,seraph_frames_stand1_tr, seraph_idle}; + +animframe_t seraph_frames_stand1_r[] = +{ + FRAME_idle_hrt1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrt19, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t seraph_move_stand1_r = {19,seraph_frames_stand1_r, seraph_idle}; + +animframe_t seraph_frames_stand1_trc[] = +{ + FRAME_idle_hrc1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hrc19, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t seraph_move_stand1_trc = {19,seraph_frames_stand1_trc, seraph_idle}; + +//Look left + +animframe_t seraph_frames_stand1_tl[] = +{ + FRAME_idle_htl1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htl2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htl6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htl10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htl14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_htl18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_htl19, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_stand1_tl = {19,seraph_frames_stand1_tl, seraph_idle}; + +animframe_t seraph_frames_stand1_l[] = +{ + FRAME_idle_hl1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hl2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hl6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hl10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hl14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hl18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hl19, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_stand1_l = {19,seraph_frames_stand1_l, seraph_idle}; + +animframe_t seraph_frames_stand1_tlc[] = +{ + FRAME_idle_hlc1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hlc5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hlc9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hlc13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle_hlc17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle_hlc19, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_stand1_tlc = {19,seraph_frames_stand1_tlc, seraph_idle}; + +/*---------------------------------------------------- + seraph walking +----------------------------------------------------*/ +animframe_t seraph_frames_walk1[] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk2, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk7, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk8, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk9, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk10, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk12, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk13, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk14, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk15, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk16, NULL, 0, 0, 0, ai_walk, 6, NULL, +}; +animmove_t seraph_move_walk1 = {16,seraph_frames_walk1, seraph_pause}; + +animframe_t seraph_frames_walk2[] = +{ + FRAME_walk1, NULL, 0, 0, 0, seraph_ai_walk, 6, NULL, + FRAME_walk2, NULL, 0, 0, 0, seraph_ai_walk, 6, NULL, + FRAME_walk3, NULL, 0, 0, 0, seraph_ai_walk, 6, NULL, + FRAME_walk4, NULL, 0, 0, 0, seraph_ai_walk, 5, NULL, + FRAME_walk5, NULL, 0, 0, 0, seraph_ai_walk, 4, NULL, + FRAME_walk6, NULL, 0, 0, 0, seraph_ai_walk, 4, NULL, + FRAME_walk7, NULL, 0, 0, 0, seraph_ai_walk, 5, NULL, + FRAME_walk8, NULL, 0, 0, 0, seraph_ai_walk, 6, NULL, + FRAME_walk9, NULL, 0, 0, 0, seraph_ai_walk, 6, NULL, + FRAME_walk10, NULL, 0, 0, 0, seraph_ai_walk, 6, NULL, + FRAME_walk11, NULL, 0, 0, 0, seraph_ai_walk, 6, NULL, + FRAME_walk12, NULL, 0, 0, 0, seraph_ai_walk, 5, NULL, + FRAME_walk13, NULL, 0, 0, 0, seraph_ai_walk, 4, NULL, + FRAME_walk14, NULL, 0, 0, 0, seraph_ai_walk, 4, NULL, + FRAME_walk15, NULL, 0, 0, 0, seraph_ai_walk, 5, NULL, + FRAME_walk16, NULL, 0, 0, 0, seraph_ai_walk, 6, NULL, +}; +animmove_t seraph_move_walk2 = {16,seraph_frames_walk2, seraph_pause}; + +/*---------------------------------------------------- + seraph whipping + + whip1 - full whip, beginning to end + whip1_loop - loopable whipping + whip1_end - end transition +----------------------------------------------------*/ + +animframe_t seraph_frames_whip1[] = +{ + FRAME_whip1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip6, seraph_strike, SERAPH_DMG_WHIP, 0, 0, NULL, 0, NULL, + FRAME_whip7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip13, seraph_strike, SERAPH_DMG_WHIP, 0, 0, NULL, 0, NULL, + FRAME_whip14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip17, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_whip1 = {16, seraph_frames_whip1, seraph_pause}; + +animframe_t seraph_frames_whip1_loop[] = +{ + FRAME_whip7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_whip8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_whip9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_whip10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_whip12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_whip13, seraph_strike, SERAPH_DMG_WHIP, 0, 0, ai_charge, 0, NULL, +}; +animmove_t seraph_move_whip1_loop = {6, seraph_frames_whip1_loop, seraph_pause}; + +animframe_t seraph_frames_whip1_end[] = +{ + FRAME_whip14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip16, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_whip1_end = {3, seraph_frames_whip1_end, seraph_pause}; + +/*---------------------------------------------------- + seraph pointing and yelling +----------------------------------------------------*/ + +animframe_t seraph_frames_point1[] = +{ + FRAME_point1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point3, NULL, 0, 0, 0, NULL, 0, seraph_sound_scold,//no talking + FRAME_point4, NULL, 0, 0, 0, NULL, 0, seraph_enforce, + FRAME_point5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_point21, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_point1 = {21,seraph_frames_point1, seraph_idle}; + +/*---------------------------------------------------- + seraph running + + the names are self explanitory +----------------------------------------------------*/ + +animframe_t seraph_frames_run1[] = +{ + FRAME_run1, NULL, 0, 0, 0, ai_run, 20, NULL, + FRAME_run2, NULL, 0, 0, 0, ai_run, 16, NULL, + FRAME_run3, NULL, 0, 0, 0, ai_run, 16, seraph_pause, + FRAME_run4, NULL, 0, 0, 0, ai_run, 16, NULL, + FRAME_run5, NULL, 0, 0, 0, ai_run, 20, NULL, + FRAME_run6, NULL, 0, 0, 0, ai_run, 16, seraph_pause, + FRAME_run7, NULL, 0, 0, 0, ai_run, 16, NULL, + FRAME_run8, NULL, 0, 0, 0, ai_run, 16, NULL, +}; +animmove_t seraph_move_run1 = {8,seraph_frames_run1, seraph_pause}; + +animframe_t seraph_frames_fjump[] = +{ + FRAME_run1, NULL, 0, 0, 0, NULL, 0, seraphApplyJump, + FRAME_run2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run8, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_fjump = {8,seraph_frames_fjump, seraph_pause}; + +animframe_t seraph_frames_run1_whip[] = +{ + FRAME_run_whip1, NULL, 0, 0, 0, ai_charge, 20, NULL, + FRAME_run_whip2, NULL, 0, 0, 0, ai_charge, 16, NULL, + FRAME_run_whip3, NULL, 0, 0, 0, ai_charge, 16, NULL, + FRAME_run_whip4, NULL, 0, 0, 0, ai_charge, 16, NULL, + FRAME_run_whip5, NULL, 0, 0, 0, ai_charge, 20, NULL, + FRAME_run_whip6, NULL, 0, 0, 0, ai_charge, 16, NULL, + FRAME_run_whip7, seraph_strike, SERAPH_DMG_WHIP_RUN, 0, 0, ai_charge, 16, NULL, + FRAME_run_whip8, NULL, 0, 0, 0, ai_charge, 16, NULL, +}; +animmove_t seraph_move_run1_whip = {8,seraph_frames_run1_whip, seraph_pause}; + +/*---------------------------------------------------- + seraph pain +----------------------------------------------------*/ + +animframe_t seraph_frames_pain[] = +{ + FRAME_pain1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain5, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_pain = {5,seraph_frames_pain, seraph_pause}; + +/*---------------------------------------------------- + seraph swipe +----------------------------------------------------*/ + +animframe_t seraph_frames_swipe[] = +{ + FRAME_swipe1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swipe2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swipe3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swipe4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swipe5, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_swipe = {4,seraph_frames_swipe, seraph_pause}; + +/*---------------------------------------------------- + seraph get2work + + yells at the ogle, slaps the ogle, then goes back to standing +----------------------------------------------------*/ + +animframe_t seraph_frames_get2work[] = +{ + FRAME_get_work1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work19, NULL, 0, 0, 0, NULL, 0, seraph_sound_yell,//hey! + FRAME_get_work20, NULL, 0, 0, 0, NULL, 0, seraph_enforce, + FRAME_get_work21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swipe1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swipe2, NULL, 0, 0, 0, NULL, 0, seraph_sound_slap, + FRAME_swipe3, NULL, 0, 0, 0, NULL, 0, seraph_enforce_ogle, + FRAME_swipe4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_swipe5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup1, NULL, 0, 0, 0, ai_run, -8, NULL,//can't this use ai_move or ai_walk? + FRAME_backup2, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup3, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup4, NULL, 0, 0, 0, ai_run, -7, NULL, + FRAME_backup5, NULL, 0, 0, 0, ai_run, -6, NULL, + FRAME_backup6, NULL, 0, 0, 0, ai_run, -7, NULL, + FRAME_backup7, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup8, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup9, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup10, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup11, NULL, 0, 0, 0, ai_run, -7, NULL, + FRAME_backup12, NULL, 0, 0, 0, ai_run, -6, NULL, + FRAME_backup13, NULL, 0, 0, 0, ai_run, -7, NULL, + FRAME_backup14, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup15, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup16, NULL, 0, 0, 0, ai_run, -8, NULL, +}; +animmove_t seraph_move_get2work = {47,seraph_frames_get2work, seraph_done_get2work}; + +/*---------------------------------------------------- + seraph get2work2 + + yells at the ogle, whips the ogle, then goes back to standing +----------------------------------------------------*/ + +animframe_t seraph_frames_get2work2[] = +{ + FRAME_get_work1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work19, NULL, 0, 0, 0, NULL, 0, seraph_sound_scold2, + FRAME_get_work20, NULL, 0, 0, 0, NULL, 0, seraph_enforce, + FRAME_get_work21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_get_work26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip6, NULL, 0, 0, 0, NULL, 0, seraph_sound_whip, + FRAME_whip7, NULL, 0, 0, 0, NULL, 0, seraph_enforce, + FRAME_whip8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip14, NULL, 0, 0, 0, NULL, 0, seraph_sound_whip, + FRAME_whip15, NULL, 0, 0, 0, NULL, 0, seraph_enforce, + FRAME_whip16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_whip17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup1, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup2, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup3, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup4, NULL, 0, 0, 0, ai_run, -7, NULL, + FRAME_backup5, NULL, 0, 0, 0, ai_run, -6, NULL, + FRAME_backup6, NULL, 0, 0, 0, ai_run, -7, NULL, + FRAME_backup7, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup8, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup9, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup10, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup11, NULL, 0, 0, 0, ai_run, -7, NULL, + FRAME_backup12, NULL, 0, 0, 0, ai_run, -6, NULL, + FRAME_backup13, NULL, 0, 0, 0, ai_run, -7, NULL, + FRAME_backup14, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup15, NULL, 0, 0, 0, ai_run, -8, NULL, + FRAME_backup16, NULL, 0, 0, 0, ai_run, -8, NULL, +}; +animmove_t seraph_move_get2work2 = {57,seraph_frames_get2work2, seraph_done_get2work}; + +/*---------------------------------------------------- + seraph startle +----------------------------------------------------*/ + +animframe_t seraph_frames_startle[] = +{ + FRAME_startle1, NULL, 0, 0, 0, NULL, 0, seraph_sound_startle, + FRAME_startle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle10,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle11,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle12,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle13,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle14,NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_startle15,NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_startle = {15,seraph_frames_startle, seraph_done_startle}; + +/*---------------------------------------------------- + seraph ready2idle + + transition frame various frames to standing with arms folded +----------------------------------------------------*/ + +animframe_t seraph_frames_ready2idle[] = +{ + FRAME_rdy_idle1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_rdy_idle11, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_ready2idle = {11,seraph_frames_ready2idle, seraph2idle}; + +/*---------------------------------------------------- + seraph backup + + backing up... +----------------------------------------------------*/ + +animframe_t seraph_frames_backup[] = +{ + FRAME_backup1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_backup16, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_backup = {16,seraph_frames_backup, seraph_pause}; + +/*---------------------------------------------------- + seraph death + + death1 - dying due to massive ogle overload +----------------------------------------------------*/ + +animframe_t seraph_frames_death1[] = +{ + FRAME_odeath1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath24, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath25, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath26, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath27, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath28, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath29, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath30, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath31, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath32, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath34, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_odeath34, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_move_death1 = {34,seraph_frames_death1, seraph_dead}; + +animframe_t seraph_frames_death2_go[] = +{ + FRAME_deathb1, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb2, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb3, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb4, NULL, 0, 0, 0, NULL, 0, seraph_death_loop, +}; +animmove_t seraph_move_death2_go = {4, seraph_frames_death2_go, NULL}; + +animframe_t seraph_frames_death2_loop[] = +{ + FRAME_deathb5, NULL, 0, 0, 0, NULL, 0, seraph_check_land, +}; +animmove_t seraph_move_death2_loop = {1, seraph_frames_death2_loop, NULL}; + +animframe_t seraph_frames_death2_end[] = +{ + FRAME_deathb6, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb7, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb8, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb9, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb10, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb11, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb12, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb13, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb14, NULL, 0, 0, 0, NULL, 0, seraph_check_land, + FRAME_deathb15, NULL, 0, 0, 0, NULL, 0, M_EndDeath, +}; +animmove_t seraph_move_death2_end = {10, seraph_frames_death2_end, NULL}; + +animframe_t seraph_frames_backup2[] = +{ + FRAME_backup1, NULL, 0, 0, 0, seraph_back, 24, NULL, + FRAME_backup2, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup3, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup4, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup5, NULL, 0, 0, 0, seraph_back, 24, NULL, + FRAME_backup6, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup7, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup8, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup9, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup10, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup11, NULL, 0, 0, 0, seraph_back, 24, NULL, + FRAME_backup12, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup13, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup14, NULL, 0, 0, 0, seraph_back, 20, NULL, + FRAME_backup15, NULL, 0, 0, 0, seraph_back, 24, NULL, + FRAME_backup16, NULL, 0, 0, 0, seraph_back, 20, NULL, +}; +animmove_t seraph_move_backup2 = {16, seraph_frames_backup2, seraph_pause}; diff --git a/Toolkit/Programming/GameCode/game/m_seraph_anim.h b/Toolkit/Programming/GameCode/game/m_seraph_anim.h new file mode 100644 index 0000000..77f6d89 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_seraph_anim.h @@ -0,0 +1,359 @@ +// R:\Art\models/monsters\overlord + +// This file generated by qdata - Do NOT Modify + +#define FRAME_partfly 0 +#define FRAME_idle_htr1 1 +#define FRAME_idle_htr2 2 +#define FRAME_idle_htr3 3 +#define FRAME_idle_htr4 4 +#define FRAME_idle_htr5 5 +#define FRAME_idle_htr6 6 +#define FRAME_idle_htr7 7 +#define FRAME_idle_htr8 8 +#define FRAME_idle_htr9 9 +#define FRAME_idle_htr10 10 +#define FRAME_idle_htr11 11 +#define FRAME_idle_htr12 12 +#define FRAME_idle_htr13 13 +#define FRAME_idle_htr14 14 +#define FRAME_idle_htr15 15 +#define FRAME_idle_htr16 16 +#define FRAME_idle_htr17 17 +#define FRAME_idle_htr18 18 +#define FRAME_idle_htr19 19 +#define FRAME_idle_hrt1 20 +#define FRAME_idle_hrt2 21 +#define FRAME_idle_hrt3 22 +#define FRAME_idle_hrt4 23 +#define FRAME_idle_hrt5 24 +#define FRAME_idle_hrt6 25 +#define FRAME_idle_hrt7 26 +#define FRAME_idle_hrt8 27 +#define FRAME_idle_hrt9 28 +#define FRAME_idle_hrt10 29 +#define FRAME_idle_hrt11 30 +#define FRAME_idle_hrt12 31 +#define FRAME_idle_hrt13 32 +#define FRAME_idle_hrt14 33 +#define FRAME_idle_hrt15 34 +#define FRAME_idle_hrt16 35 +#define FRAME_idle_hrt17 36 +#define FRAME_idle_hrt18 37 +#define FRAME_idle_hrt19 38 +#define FRAME_idle_hrc1 39 +#define FRAME_idle_hrc2 40 +#define FRAME_idle_hrc3 41 +#define FRAME_idle_hrc4 42 +#define FRAME_idle_hrc5 43 +#define FRAME_idle_hrc6 44 +#define FRAME_idle_hrc7 45 +#define FRAME_idle_hrc8 46 +#define FRAME_idle_hrc9 47 +#define FRAME_idle_hrc10 48 +#define FRAME_idle_hrc11 49 +#define FRAME_idle_hrc12 50 +#define FRAME_idle_hrc13 51 +#define FRAME_idle_hrc14 52 +#define FRAME_idle_hrc15 53 +#define FRAME_idle_hrc16 54 +#define FRAME_idle_hrc17 55 +#define FRAME_idle_hrc18 56 +#define FRAME_idle_hrc19 57 +#define FRAME_idle_htl1 58 +#define FRAME_idle_htl2 59 +#define FRAME_idle_htl3 60 +#define FRAME_idle_htl4 61 +#define FRAME_idle_htl5 62 +#define FRAME_idle_htl6 63 +#define FRAME_idle_htl7 64 +#define FRAME_idle_htl8 65 +#define FRAME_idle_htl9 66 +#define FRAME_idle_htl10 67 +#define FRAME_idle_htl11 68 +#define FRAME_idle_htl12 69 +#define FRAME_idle_htl13 70 +#define FRAME_idle_htl14 71 +#define FRAME_idle_htl15 72 +#define FRAME_idle_htl16 73 +#define FRAME_idle_htl17 74 +#define FRAME_idle_htl18 75 +#define FRAME_idle_htl19 76 +#define FRAME_idle_hl1 77 +#define FRAME_idle_hl2 78 +#define FRAME_idle_hl3 79 +#define FRAME_idle_hl4 80 +#define FRAME_idle_hl5 81 +#define FRAME_idle_hl6 82 +#define FRAME_idle_hl7 83 +#define FRAME_idle_hl8 84 +#define FRAME_idle_hl9 85 +#define FRAME_idle_hl10 86 +#define FRAME_idle_hl11 87 +#define FRAME_idle_hl12 88 +#define FRAME_idle_hl13 89 +#define FRAME_idle_hl14 90 +#define FRAME_idle_hl15 91 +#define FRAME_idle_hl16 92 +#define FRAME_idle_hl17 93 +#define FRAME_idle_hl18 94 +#define FRAME_idle_hl19 95 +#define FRAME_idle_hlc1 96 +#define FRAME_idle_hlc2 97 +#define FRAME_idle_hlc3 98 +#define FRAME_idle_hlc4 99 +#define FRAME_idle_hlc5 100 +#define FRAME_idle_hlc6 101 +#define FRAME_idle_hlc7 102 +#define FRAME_idle_hlc8 103 +#define FRAME_idle_hlc9 104 +#define FRAME_idle_hlc10 105 +#define FRAME_idle_hlc11 106 +#define FRAME_idle_hlc12 107 +#define FRAME_idle_hlc13 108 +#define FRAME_idle_hlc14 109 +#define FRAME_idle_hlc15 110 +#define FRAME_idle_hlc16 111 +#define FRAME_idle_hlc17 112 +#define FRAME_idle_hlc18 113 +#define FRAME_idle_hlc19 114 +#define FRAME_idle1 115 +#define FRAME_idle2 116 +#define FRAME_idle3 117 +#define FRAME_idle4 118 +#define FRAME_idle5 119 +#define FRAME_idle6 120 +#define FRAME_idle7 121 +#define FRAME_idle8 122 +#define FRAME_idle9 123 +#define FRAME_idle10 124 +#define FRAME_idle11 125 +#define FRAME_idle12 126 +#define FRAME_idle13 127 +#define FRAME_idle14 128 +#define FRAME_idle15 129 +#define FRAME_idle16 130 +#define FRAME_idle17 131 +#define FRAME_idle18 132 +#define FRAME_idle19 133 +#define FRAME_idle20 134 +#define FRAME_point1 135 +#define FRAME_point2 136 +#define FRAME_point3 137 +#define FRAME_point4 138 +#define FRAME_point5 139 +#define FRAME_point6 140 +#define FRAME_point7 141 +#define FRAME_point8 142 +#define FRAME_point9 143 +#define FRAME_point10 144 +#define FRAME_point11 145 +#define FRAME_point12 146 +#define FRAME_point13 147 +#define FRAME_point14 148 +#define FRAME_point15 149 +#define FRAME_point16 150 +#define FRAME_point17 151 +#define FRAME_point18 152 +#define FRAME_point19 153 +#define FRAME_point20 154 +#define FRAME_point21 155 +#define FRAME_rdy_idle1 156 +#define FRAME_rdy_idle2 157 +#define FRAME_rdy_idle3 158 +#define FRAME_rdy_idle4 159 +#define FRAME_rdy_idle5 160 +#define FRAME_rdy_idle6 161 +#define FRAME_rdy_idle7 162 +#define FRAME_rdy_idle8 163 +#define FRAME_rdy_idle9 164 +#define FRAME_rdy_idle10 165 +#define FRAME_rdy_idle11 166 +#define FRAME_startle1 167 +#define FRAME_startle2 168 +#define FRAME_startle3 169 +#define FRAME_startle4 170 +#define FRAME_startle5 171 +#define FRAME_startle6 172 +#define FRAME_startle7 173 +#define FRAME_startle8 174 +#define FRAME_startle9 175 +#define FRAME_startle10 176 +#define FRAME_startle11 177 +#define FRAME_startle12 178 +#define FRAME_startle13 179 +#define FRAME_startle14 180 +#define FRAME_startle15 181 +#define FRAME_walk1 182 +#define FRAME_walk2 183 +#define FRAME_walk3 184 +#define FRAME_walk4 185 +#define FRAME_walk5 186 +#define FRAME_walk6 187 +#define FRAME_walk7 188 +#define FRAME_walk8 189 +#define FRAME_walk9 190 +#define FRAME_walk10 191 +#define FRAME_walk11 192 +#define FRAME_walk12 193 +#define FRAME_walk13 194 +#define FRAME_walk14 195 +#define FRAME_walk15 196 +#define FRAME_walk16 197 +#define FRAME_whip1 198 +#define FRAME_whip2 199 +#define FRAME_whip3 200 +#define FRAME_whip4 201 +#define FRAME_whip5 202 +#define FRAME_whip6 203 +#define FRAME_whip7 204 +#define FRAME_whip8 205 +#define FRAME_whip9 206 +#define FRAME_whip10 207 +#define FRAME_whip11 208 +#define FRAME_whip12 209 +#define FRAME_whip13 210 +#define FRAME_whip14 211 +#define FRAME_whip15 212 +#define FRAME_whip16 213 +#define FRAME_whip17 214 +#define FRAME_run1 215 +#define FRAME_run2 216 +#define FRAME_run3 217 +#define FRAME_run4 218 +#define FRAME_run5 219 +#define FRAME_run6 220 +#define FRAME_run7 221 +#define FRAME_run8 222 +#define FRAME_run_whip1 223 +#define FRAME_run_whip2 224 +#define FRAME_run_whip3 225 +#define FRAME_run_whip4 226 +#define FRAME_run_whip5 227 +#define FRAME_run_whip6 228 +#define FRAME_run_whip7 229 +#define FRAME_run_whip8 230 +#define FRAME_pain1 231 +#define FRAME_pain2 232 +#define FRAME_pain3 233 +#define FRAME_pain4 234 +#define FRAME_pain5 235 +#define FRAME_swipe1 236 +#define FRAME_swipe2 237 +#define FRAME_swipe3 238 +#define FRAME_swipe4 239 +#define FRAME_swipe5 240 +#define FRAME_swipe6 241 +#define FRAME_swipe7 242 +#define FRAME_get_work1 243 +#define FRAME_get_work2 244 +#define FRAME_get_work3 245 +#define FRAME_get_work4 246 +#define FRAME_get_work5 247 +#define FRAME_get_work6 248 +#define FRAME_get_work7 249 +#define FRAME_get_work8 250 +#define FRAME_get_work9 251 +#define FRAME_get_work10 252 +#define FRAME_get_work11 253 +#define FRAME_get_work12 254 +#define FRAME_get_work13 255 +#define FRAME_get_work14 256 +#define FRAME_get_work15 257 +#define FRAME_get_work16 258 +#define FRAME_get_work17 259 +#define FRAME_get_work18 260 +#define FRAME_get_work19 261 +#define FRAME_get_work20 262 +#define FRAME_get_work21 263 +#define FRAME_get_work22 264 +#define FRAME_get_work23 265 +#define FRAME_get_work24 266 +#define FRAME_get_work25 267 +#define FRAME_get_work26 268 +#define FRAME_backup1 269 +#define FRAME_backup2 270 +#define FRAME_backup3 271 +#define FRAME_backup4 272 +#define FRAME_backup5 273 +#define FRAME_backup6 274 +#define FRAME_backup7 275 +#define FRAME_backup8 276 +#define FRAME_backup9 277 +#define FRAME_backup10 278 +#define FRAME_backup11 279 +#define FRAME_backup12 280 +#define FRAME_backup13 281 +#define FRAME_backup14 282 +#define FRAME_backup15 283 +#define FRAME_backup16 284 +#define FRAME_odeath1 285 +#define FRAME_odeath2 286 +#define FRAME_odeath3 287 +#define FRAME_odeath4 288 +#define FRAME_odeath5 289 +#define FRAME_odeath6 290 +#define FRAME_odeath7 291 +#define FRAME_odeath8 292 +#define FRAME_odeath9 293 +#define FRAME_odeath10 294 +#define FRAME_odeath11 295 +#define FRAME_odeath12 296 +#define FRAME_odeath13 297 +#define FRAME_odeath14 298 +#define FRAME_odeath15 299 +#define FRAME_odeath16 300 +#define FRAME_odeath17 301 +#define FRAME_odeath18 302 +#define FRAME_odeath19 303 +#define FRAME_odeath20 304 +#define FRAME_odeath21 305 +#define FRAME_odeath22 306 +#define FRAME_odeath23 307 +#define FRAME_odeath24 308 +#define FRAME_odeath25 309 +#define FRAME_odeath26 310 +#define FRAME_odeath27 311 +#define FRAME_odeath28 312 +#define FRAME_odeath29 313 +#define FRAME_odeath30 314 +#define FRAME_odeath31 315 +#define FRAME_odeath32 316 +#define FRAME_odeath33 317 +#define FRAME_odeath34 318 +#define FRAME_deathb1 319 +#define FRAME_deathb2 320 +#define FRAME_deathb3 321 +#define FRAME_deathb4 322 +#define FRAME_deathb5 323 +#define FRAME_deathb6 324 +#define FRAME_deathb7 325 +#define FRAME_deathb8 326 +#define FRAME_deathb9 327 +#define FRAME_deathb10 328 +#define FRAME_deathb11 329 +#define FRAME_deathb12 330 +#define FRAME_deathb13 331 +#define FRAME_deathb14 332 +#define FRAME_deathb15 333 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASEBIN 0 +#define MESH__PITHEAD 1 +#define MESH__SHOULDPAD 2 +#define MESH__GUARDHEAD 3 +#define MESH__LHANDGRD 4 +#define MESH__LHANDBOSS 5 +#define MESH__RHAND 6 +#define MESH__FRTORSO 7 +#define MESH__ARMSPIKES 8 +#define MESH__LFTUPARM 9 +#define MESH__RTLEG 10 +#define MESH__RTARM 11 +#define MESH__LFTLEG 12 +#define MESH__BKTORSO 13 +#define MESH__AXE 14 +#define MESH__WHIP 15 diff --git a/Toolkit/Programming/GameCode/game/m_seraph_guard.c b/Toolkit/Programming/GameCode/game/m_seraph_guard.c new file mode 100644 index 0000000..657929e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_seraph_guard.c @@ -0,0 +1,1304 @@ +//============================================================================== +// +// m_seraph_guard.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// jweier +//============================================================================== + +#include "g_local.h" +#include "m_seraph_guard.h" +#include "m_seraph_guard_anim.h" +#include "g_DefaultMessageHandler.h" +#include "Utilities.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "g_misc.h" +#include "fx.h" + +#include "g_HitLocation.h" +#include "m_stats.h" +#include "g_playstats.h" +#include "p_anim_branch2.h" +#include "p_anims2.h" + +void MG_InitMoods(edict_t *self); +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); + +static animmove_t *animations[NUM_ANIMS] = +{ + &seraph_guard_move_stand, + &seraph_guard_move_run, + &seraph_guard_move_fjump, + &seraph_guard_move_runmelee, + &seraph_guard_move_walk, + &seraph_guard_move_pain, + &seraph_guard_move_melee, + &seraph_guard_move_melee2, + &seraph_guard_move_melee3, + &seraph_guard_move_death1, + &seraph_guard_move_death2_go, + &seraph_guard_move_death2_loop, + &seraph_guard_move_death2_end, + &seraph_guard_move_backup, + &seraph_guard_move_missile, + &seraph_guard_move_delay, +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + +#define NUM_PREDFRAMES 5 + +#define SERAPH_FLAG_GOLEM 4 + +/* +========================================================== + + Seraph Guard Helper functions + +========================================================== +*/ + +/*----------------------------------------------- + create_guard_proj +-----------------------------------------------*/ + +// create the guts of morcalavin's projectile +void create_guard_proj(edict_t *self,edict_t *proj) +{ + void guard_beam_blocked( edict_t *self, trace_t *trace ); + + proj->svflags |= SVF_ALWAYS_SEND; + proj->movetype = PHYSICSTYPE_FLY; + proj->gravity = 0; + proj->solid = SOLID_BBOX; + proj->classname = "Guard_Missile"; + proj->dmg = flrand(SGUARD_DMG_SPELL_MIN, SGUARD_DMG_SPELL_MAX); + proj->s.scale = 1.0; + proj->clipmask = MASK_SHOT; + proj->nextthink = level.time + 0.1; + + proj->isBlocked = proj->isBlocking = proj->bounced = guard_beam_blocked; + + proj->s.effects=EF_MARCUS_FLAG1|EF_CAMERA_NO_CLIP; + proj->enemy = self->enemy; + + VectorSet(proj->mins, -4.0, -4.0, -4.0); + VectorSet(proj->maxs, 4.0, 4.0, 4.0); + VectorCopy(self->s.origin, proj->s.origin); +} + +/*----------------------------------------------- + guard_beam_blocked +-----------------------------------------------*/ + +void guard_beam_blocked( edict_t *self, trace_t *trace ) +{ + //edict_t *proj; + + /* + if(EntReflecting(trace->ent, true, true) && self->reflect_debounce_time) + { + proj = G_Spawn(); + + create_guard_proj(self,proj); + proj->isBlocked = guard_beam_blocked; + proj->classname = "M_ref_HMissile"; + proj->owner = self->owner; + proj->ideal_yaw = self->ideal_yaw; + proj->classID = self->classID; + + Create_rand_relect_vect(self->velocity, proj->velocity); + Vec3ScaleAssign(proj->ideal_yaw,proj->velocity); + vectoangles(proj->velocity, proj->s.angles); + + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + proj->classID, + proj->velocity); + + proj->reflect_debounce_time = self->reflect_debounce_time -1; + gi.linkentity(proj); + + G_SetToFree(self); + + return; + } + */ + + if (trace->ent->takedamage ) + { + vec3_t hitDir; + + VectorCopy( self->velocity, hitDir ); + VectorNormalize( hitDir ); + + T_Damage(trace->ent, self, self->owner, hitDir, self->s.origin, trace->plane.normal, self->dmg, 0, DAMAGE_SPELL | DAMAGE_NO_KNOCKBACK,MOD_DIED); + } + + gi.sound(self, CHAN_WEAPON, gi.soundindex("monsters/seraph/guard/spellhit.wav"), 1, ATTN_NORM, 0); + + gi.CreateEffect(&self->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + self->s.origin, + "bv", + FX_M_MISC_EXPLODE, + vec3_origin); + + G_SetToFree(self); +} + +void guard_beam_think (edict_t *self) +{ + self->think = NULL; + self->nextthink = -1; +} + +void guard_beam( edict_t *self) +{ + edict_t *proj; + vec3_t Forward, vf, vr; + + // Spawn the projectile + + proj = G_Spawn(); + + create_guard_proj(self,proj); + + proj->reflect_debounce_time = MAX_REFLECT; + proj->classname = "M_Beam"; + + proj->isBlocked = guard_beam_blocked; + + proj->owner = self; + + AngleVectors(self->s.angles, vf, vr, NULL); + VectorMA(proj->s.origin, 24, vf, proj->s.origin); + VectorMA(proj->s.origin, 16, vr, proj->s.origin); + proj->s.origin[2] += 10; + + if(!ahead(self, self->enemy)) + VectorCopy(vf, Forward); + else + { + VectorSubtract(self->enemy->s.origin, self->s.origin, Forward); + VectorNormalize(Forward); + } + + VectorScale(Forward, 500, proj->velocity); + + vectoangles(proj->velocity, proj->s.angles); + + proj->think = guard_beam_think; + proj->nextthink = level.time + 1; + + gi.sound(self, CHAN_WEAPON, gi.soundindex("monsters/seraph/guard/spell.wav"), 1, ATTN_NORM, 0); + + gi.CreateEffect(&proj->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_M_BEAM, + proj->s.angles); + + + gi.linkentity(proj); +} + +/*-------------------------------------- + seraph_guard_checkpoke +----------------------------------------*/ + +void seraph_guard_checkpoke ( edict_t *self ) +{ + vec3_t attackVel, vf; + float dist; + int ret, chance; + + //Really, this is a given, but it could fail... + if (M_ValidTarget(self, self->enemy)) + { + //Set this for any uses below + AngleVectors(self->s.angles, vf, NULL, NULL); + + dist = M_DistanceToTarget(self, self->enemy); + + if (dist < 120) + { + VectorMA(vf, 1, vf, attackVel); + ret = M_PredictTargetEvasion( self, self->enemy, attackVel, self->enemy->velocity, 150, NUM_PREDFRAMES ); + + if (ret) + { + chance = irand(0,100); + + if (chance < 40) + SetAnim(self, ANIM_MELEE3); + else if (chance < 60) + SetAnim(self, ANIM_MELEE2); + } + else + { + if (irand(0,1)) + SetAnim(self, ANIM_RUN_MELEE); + else + SetAnim(self, ANIM_MELEE2); + } + } + + return; + } + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +/*-------------------------------------- + seraph_guard_death_loop +----------------------------------------*/ + +void seraph_guard_death_loop ( edict_t *self ) +{ + SetAnim(self, ANIM_DEATH2_LOOP); +} + +/*-------------------------------------- + seraph_guard_check_land +----------------------------------------*/ + +void seraph_guard_check_land ( edict_t *self ) +{ + vec3_t endpos; + trace_t trace; + + M_ChangeYaw(self); + + VectorCopy(self->s.origin, endpos); + endpos[2] -= 48; + + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&trace); + + if ( ( trace.fraction < 1 || trace.startsolid || trace.allsolid) && + self->curAnimID != ANIM_DEATH2_END && + self->curAnimID != ANIM_DEATH2_GO) + { + self->elasticity = 1.25; + self->friction = 0.5; + SetAnim(self, ANIM_DEATH2_END); + } +} + +/*-------------------------------------- + seraph_guard_dead +----------------------------------------*/ + +void seraph_guard_dead ( edict_t *self ) +{ + M_EndDeath(self); +} + +/*-------------------------------------- + seraph_guard_strike +----------------------------------------*/ + +void seraph_guard_strike( edict_t *self, float damage, float var2, float var3 ) +{ + trace_t trace; + edict_t *victim; + vec3_t soff, eoff, mins, maxs, bloodDir, direction; + qboolean knockback = true; +// vec3_t dir, fwd, right, up; + + if(self->monsterinfo.aiflags & AI_NO_MELEE) + return; + + damage *= self->s.scale; + + self->monsterinfo.attack_finished = level.time + (3 - skill->value) * 2 + flrand(0, 1); + + switch (self->curAnimID) + { + case ANIM_MELEE2: + VectorSet(soff, 16, -16, 24); + VectorSet(eoff, 124,-16, 16); + break; + + case ANIM_MELEE3: + VectorSet(soff, 32, -48, 34); + VectorSet(eoff, 64, 64, -8); + break; + + default: + knockback = false; + VectorSet(soff, 32, -16, 64); + VectorSet(eoff, 72, 16, -8); + break; + } + + Vec3ScaleAssign(self->s.scale, soff); + Vec3ScaleAssign(self->s.scale, eoff); + + VectorSet(mins, -4, -4, -4); + VectorSet(maxs, 4, 4, 4); + + VectorSubtract(eoff, soff, bloodDir); + VectorNormalize(bloodDir); + + victim = M_CheckMeleeLineHit(self, soff, eoff, mins, maxs, &trace, direction); + + //Did something get hit? + if (victim) + { + if (victim == self) + { + //Create a spark effect + gi.CreateEffect(NULL, FX_SPARKS, CEF_FLAG6, trace.endpos, "d", direction); + gi.sound (self, CHAN_WEAPON, sounds[SND_HIT_WALL], 1, ATTN_NORM, 0); + } + else + { + // Get a proper angle for this attack from the absolute vector provided. +/* AngleVectors(self->s.angles, fwd, right, up); + VectorScale(fwd, hitDir[0], dir); + VectorMA(dir, -hitDir[1], right, dir); + VectorMA(dir, hitDir[2], up, dir);*/ + + if(self->curAnimID == ANIM_MELEE3) + { + gi.CreateEffect(NULL, + FX_WEAPON_STAFF_STRIKE, + 0, + trace.endpos, + "db", + trace.plane.normal, + 2); + + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/staffhit_2.wav"),1,ATTN_NORM,0); + } + else + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACK], 1, ATTN_NORM, 0); + //Hurt whatever we were whacking away at + damage *= ((skill->value + 1)/3) //skill 0 = 1/3, skill 3 = 1 1/3 + * flrand(0.85, 1.15); // Add some variance to the hit, since it passes a constant. + if(knockback) + { + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, + damage, damage*20, DAMAGE_DISMEMBER|DAMAGE_DOUBLE_DISMEMBER|DAMAGE_EXTRA_BLOOD|DAMAGE_EXTRA_KNOCKBACK,MOD_DIED); + } + else + { + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, + damage, 0, DAMAGE_NO_KNOCKBACK|DAMAGE_DISMEMBER|DAMAGE_DOUBLE_DISMEMBER|DAMAGE_EXTRA_BLOOD,MOD_DIED); + } + if(self->curAnimID == ANIM_MELEE3) + { + if(victim->client) + { + if(victim->health > 0) + { + if(victim->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN && infront(self, victim)) + { + KnockDownPlayer(&victim->client->playerinfo); + } + } + } + } + } + } + else + { + //Play swoosh sound + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACK_MISS], 1, ATTN_NORM, 0); + } +} + +/*-------------------------------------- + seraph_guard_pause +----------------------------------------*/ + +void seraphGuardApplyJump (edict_t *self) +{ + self->jump_time = level.time + 0.75; + VectorCopy(self->movedir, self->velocity); + VectorNormalize(self->movedir); +} + +void seraph_guard_pause( edict_t *self ) +{ + if(self->spawnflags & MSF_FIXED && self->curAnimID == ANIM_DELAY && self->enemy) + { + self->monsterinfo.searchType = SEARCH_COMMON; + MG_FaceGoal(self, true); + } + + self->mood_think(self); + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + if(self->ai_mood_flags & AI_MOOD_FLAG_MISSILE) + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_PURSUE: + case AI_MOOD_NAVIGATE: + case AI_MOOD_WALK: + case AI_MOOD_FLEE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + case AI_MOOD_STAND: + if (!self->enemy) + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_DELAY: + SetAnim(self, ANIM_DELAY); + break; + + case AI_MOOD_WANDER: + SetAnim(self, ANIM_WALK); + break; + + case AI_MOOD_JUMP: + SetAnim(self, ANIM_FJUMP); + break; + + default : +#ifdef _DEVEL + gi.dprintf("seraph guard: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } +} + +void seraph_guard_check_mood (edict_t *self, G_Message_t *msg) +{ + ParseMsgParms(msg, "i", &self->ai_mood); + + seraph_guard_pause(self); +} + +/* +========================================================== + + Seraph Guard Message functions + +========================================================== +*/ + +/*-------------------------------------- + void seraph_guard_pain +----------------------------------------*/ + +void seraph_guard_pain(edict_t *self, G_Message_t *msg) +{ + int temp, damage; + int force_damage, soundID; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_damage, &damage, &temp); + //Weighted random based on health compared to the maximum it was at + if (force_damage || ((irand(0, self->max_health+50) > self->health) && irand(0,2))) + { + soundID = irand(SND_PAIN1, SND_PAIN4); + gi.sound (self, CHAN_WEAPON, sounds[soundID], 1, ATTN_NORM, 0); + + SetAnim(self, ANIM_PAIN); + } +} + +/*-------------------------------------- + void seraph_guard_stand +----------------------------------------*/ + +void seraph_guard_stand(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_STAND); +} + +/*-------------------------------------- + void seraph_guard_melee +----------------------------------------*/ + +void seraph_guard_melee(edict_t *self, G_Message_t *msg) +{ + vec3_t attackVel, vf; + float dist; + int ret; + + //Don't interrupt a current animation with another melee call inside of it + if (self->curAnimID == ANIM_MELEE1 || self->curAnimID == ANIM_MELEE2) + return; + + if (M_ValidTarget(self, self->enemy)) + { + if(self->ai_mood == AI_MOOD_FLEE) + { + SetAnim(self, ANIM_BACKUP); + return; + } + //Set this for any uses below + AngleVectors(self->s.angles, vf, NULL, NULL); + + dist = M_DistanceToTarget(self, self->enemy); + + if (dist < 120) + { + if(self->s.fmnodeinfo[MESH__AXE].flags & FMNI_NO_DRAW) + { + SetAnim(self, ANIM_MISSILE); + return; + } + + VectorMA(vf, 0, vf, attackVel); + ret = M_PredictTargetEvasion( self, self->enemy, attackVel, self->enemy->velocity, self->melee_range, NUM_PREDFRAMES ); + + + if (ret) + { + if(dist < 88 && !irand(0, 3)) + SetAnim(self, ANIM_MISSILE);//punch + else if(irand(0, 4)) + { + if(irand(0, 10)) + SetAnim(self, ANIM_MELEE1); + else + SetAnim(self, ANIM_MISSILE); + } + else + SetAnim(self, ANIM_MELEE2); + } + else + SetAnim(self, ANIM_RUN_MELEE); + } + else + SetAnim(self, ANIM_RUN); + + return; + } + + //If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void morcalavin_beam( edict_t *self); +void seraph_guard_fire (edict_t *self) +{ + if(!self->enemy) + return; + + if(M_DistanceToTarget(self, self->enemy) < self->min_missile_range) + {//punch + trace_t trace; + edict_t *victim; + vec3_t soff, eoff, mins, maxs, bloodDir, direction; + float damage; + + damage = 15 * self->s.scale; + + VectorSet(soff, 12, -18, 24); + VectorSet(eoff, 88, -4, -16); + + Vec3ScaleAssign(self->s.scale, soff); + Vec3ScaleAssign(self->s.scale, eoff); + + VectorSet(mins, -4, -4, -4); + VectorSet(maxs, 4, 4, 4); + + VectorSubtract(eoff, soff, bloodDir); + VectorNormalize(bloodDir); + + victim = M_CheckMeleeLineHit(self, soff, eoff, mins, maxs, &trace, direction); + + //Did something get hit? + if (victim) + { + if (victim == self) + { + gi.sound (self, CHAN_WEAPON, sounds[SND_FIST_HIT_WALL], 1, ATTN_NORM, 0); + } + else + { + //Hurt whatever we were whacking away at + damage *= (skill->value + 1)/3;//skill 0 = 1/3, skill 3 = 1 1/3 + T_Damage(victim, self, self, direction, trace.endpos, bloodDir, + damage, damage*20, DAMAGE_EXTRA_KNOCKBACK, MOD_DIED); + gi.sound (self, CHAN_WEAPON, sounds[SND_HIT_WALL], 1, ATTN_NORM, 0); + if(victim->client) + { + if(victim->health > 0) + { + if(victim->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN && infront(self, victim)) + { + KnockDownPlayer(&victim->client->playerinfo); + } + } + } + } + } + else + { + //Play swoosh sound + gi.sound (self, CHAN_WEAPON, sounds[SND_ATTACK_MISS], 1, ATTN_NORM, 0); + } + } + else + guard_beam (self); +} + +void seraph_guard_missile(edict_t *self, G_Message_t *msg) +{ + vec3_t attackVel, vf; + float dist; + int ret; + + if (M_ValidTarget(self, self->enemy)) + { + if(self->ai_mood == AI_MOOD_FLEE) + { + SetAnim(self, ANIM_BACKUP); + return; + } + //Set this for any uses below + AngleVectors(self->s.angles, vf, NULL, NULL); + + dist = M_DistanceToTarget(self, self->enemy); + + if (dist < self->min_missile_range) + { + VectorMA(vf, 0, vf, attackVel); + ret = M_PredictTargetEvasion( self, self->enemy, attackVel, self->enemy->velocity, self->melee_range, NUM_PREDFRAMES ); + + if(irand(0, 4)) + { + if(irand(0, 10)) + SetAnim(self, ANIM_MELEE1); + else + SetAnim(self, ANIM_MISSILE); + } + else + SetAnim(self, ANIM_MELEE2); + } + else if(ahead(self, self->enemy)) + SetAnim(self, ANIM_MISSILE); + + return; + } + + //If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +/*-------------------------------------- + void seraph_guard_death +----------------------------------------*/ + +void seraph_guard_death_pain(edict_t *self, G_Message_t *msg) +{ + if (self->health < -80) + { + BecomeDebris(self); + return; + } +} + +void seraph_guard_dropweapon (edict_t *self); +void seraph_guard_death(edict_t *self, G_Message_t *msg) +{ + edict_t *targ, *inflictor, *attacker; + vec3_t dVel, vf, yf; + float damage; + int soundID; + + ParseMsgParms(msg, "eeei", &targ, &inflictor, &attacker, &damage); + + M_StartDeath(self, ANIM_DEATH1); + + if (self->health < -80) + { + return; + } + else if (self->health < -10) + { + seraph_guard_dropweapon(self); + + SetAnim(self, ANIM_DEATH2_GO); + + VectorCopy(targ->velocity, vf); + VectorNormalize(vf); + + VectorScale(vf, -1, yf); + + self->ideal_yaw = vectoyaw( yf ); + self->yaw_speed = 24; + + VectorScale(vf, 300, dVel); + dVel[2] = irand(150,200); + + VectorCopy(dVel, self->velocity); +// self->groundentity = NULL; + } + else + { + SetAnim(self, ANIM_DEATH1); + } + + soundID = irand(SND_DEATH1, SND_DEATH4); + gi.sound (self, CHAN_BODY, sounds[soundID], 1, ATTN_NORM, 0); +} + +/*-------------------------------------- + void seraph_guard_run +----------------------------------------*/ + +void seraph_guard_run(edict_t *self, G_Message_t *msg) +{ + trace_t trace; + vec3_t attackVel, vf; + float dist; + int ret; + + if (M_ValidTarget(self, self->enemy)) + { + if(self->ai_mood == AI_MOOD_FLEE) + { + SetAnim(self, ANIM_RUN); + return; + } + + if(self->monsterinfo.attack_finished > level.time || self->monsterinfo.aiflags & AI_NO_MELEE) + { + SetAnim(self, ANIM_RUN); + return; + } + + //Set this for any uses below + AngleVectors(self->s.angles, vf, NULL, NULL); + + dist = M_DistanceToTarget(self, self->enemy); + + if (dist < 100) + { + VectorMA(vf, 0, vf, attackVel); + ret = M_PredictTargetEvasion( self, self->enemy, attackVel, self->enemy->velocity, self->melee_range, NUM_PREDFRAMES ); + + //See what the predicted outcome is + if (ret && (M_CheckMeleeHit( self, self->melee_range, &trace) == self->enemy)) + SetAnim(self, ANIM_MELEE1); + else + SetAnim(self, ANIM_RUN_MELEE); + } + else if (dist < 200) + { + VectorMA(vf, 150, vf, attackVel); + ret = M_PredictTargetEvasion( self, self->enemy, attackVel, self->enemy->velocity, 150, NUM_PREDFRAMES ); + + //See what the predicted outcome is + if (ret && (M_CheckMeleeHit( self, 150, &trace) == self->enemy)) + SetAnim(self, ANIM_RUN_MELEE); + else + SetAnim(self, ANIM_RUN); + } + else + { + SetAnim(self, ANIM_RUN); + } + + return; + } + + //If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + + +int Bit_for_MeshNode_sg [NUM_MESH_NODES] = +{ + BIT_BASEBIN, + BIT_PITHEAD,//overlord head + BIT_SHOULDPAD, + BIT_GUARDHEAD,//guard head + BIT_LHANDGRD,//left hand guard + BIT_LHANDBOSS,//left hand overlord + BIT_RHAND,//right hand + BIT_FRTORSO, + BIT_ARMSPIKES, + BIT_LFTUPARM, + BIT_RTLEG, + BIT_RTARM, + BIT_LFTLEG, + BIT_BKTORSO, + BIT_AXE,//axe + BIT_WHIP//whip +}; + +void seraph_guard_back (edict_t *self, float dist) +{ + if(!MG_BoolWalkMove(self, self->s.angles[YAW] + 180, dist)) + { + if(!irand(0, 1000)) + { + self->monsterinfo.aiflags |= AI_COWARD; + SetAnim(self, ANIM_RUN); + } + } +} + +qboolean canthrownode_sg (edict_t *self, int BP, int *throw_nodes) +{//see if it's on, if so, add it to throw_nodes + //turn it off on thrower + if(!(self->s.fmnodeinfo[BP].flags & FMNI_NO_DRAW)) + { + *throw_nodes |= Bit_for_MeshNode_sg[BP]; + self->s.fmnodeinfo[BP].flags |= FMNI_NO_DRAW; + return true; + } + return false; +} + +//THROWS weapon, turns off those nodes, sets that weapon as gone +void seraph_guard_dropweapon (edict_t *self) +{//NO PART FLY FRAME! + vec3_t handspot, forward, right, up; + + if(!(self->s.fmnodeinfo[MESH__AXE].flags & FMNI_NO_DRAW)) + { + VectorClear(handspot); + AngleVectors(self->s.angles,forward,right,up); + + VectorMA(handspot,8,forward,handspot); + VectorMA(handspot,5,right,handspot); + VectorMA(handspot,12,up,handspot); + ThrowWeapon(self, &handspot, BIT_AXE, 0, FRAME_partfly); + self->s.fmnodeinfo[MESH__AXE].flags |= FMNI_NO_DRAW; + return; + } +} + +void seraph_guard_dismember(edict_t *self, int damage, int HitLocation) +{ + int throw_nodes = 0; + vec3_t gore_spot, right; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; + + + if(HitLocation == hl_TorsoFront && dismember_ok) + {//melee swing at chest during my melee swing + if(self->curAnimID == ANIM_MELEE1 || + self->curAnimID == ANIM_MELEE2 || + self->curAnimID == ANIM_MELEE3|| + self->curAnimID == ANIM_RUN_MELEE) + { + if(!irand(0, 2)) + HitLocation = hl_ArmLowerLeft; + else + HitLocation = hl_ArmLowerRight; + } + } + + VectorClear(gore_spot); + switch(HitLocation) + { + case hl_Head: + if(self->s.fmnodeinfo[MESH__GUARDHEAD].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__GUARDHEAD].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,8,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { + self->s.fmnodeinfo[MESH__GUARDHEAD].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__GUARDHEAD].skin = self->s.skinnum+1; + } + break; + + case hl_TorsoFront://split in half? + if(self->s.fmnodeinfo[MESH__FRTORSO].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.fmnodeinfo[MESH__FRTORSO].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__FRTORSO].skin = self->s.skinnum+1; + } + break; + case hl_TorsoBack://split in half? + if(self->s.fmnodeinfo[MESH__BKTORSO].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health) < damage) + { + self->s.fmnodeinfo[MESH__BKTORSO].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__BKTORSO].skin = self->s.skinnum+1; + } + break; + + case hl_ArmUpperLeft: + if(flrand(0,self->health)s.fmnodeinfo[MESH__LFTUPARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LFTUPARM].skin = self->s.skinnum+1; + } + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + seraph_guard_dropweapon (self); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + } + } + break; + case hl_ArmLowerLeft://left arm + if(self->s.fmnodeinfo[MESH__LHANDGRD].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__LHANDGRD].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + seraph_guard_dropweapon (self); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + } + } + else + { + self->s.fmnodeinfo[MESH__LHANDGRD].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LHANDGRD].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperRight: + if(flrand(0,self->health)s.fmnodeinfo[MESH__RTARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RTARM].skin = self->s.skinnum+1; + } + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + seraph_guard_dropweapon (self); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + } + } + break; + case hl_ArmLowerRight://right arm + if(self->s.fmnodeinfo[MESH__RHAND].flags & FMNI_NO_DRAW) + break; + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + seraph_guard_dropweapon (self); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + } + } + else + { + self->s.fmnodeinfo[MESH__RHAND].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RHAND].skin = self->s.skinnum+1; + } + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft://left leg + if(self->s.fmnodeinfo[MESH__LFTLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__LFTLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LFTLEG].skin = self->s.skinnum+1; + break; + case hl_LegUpperRight: + case hl_LegLowerRight://right leg + if(self->s.fmnodeinfo[MESH__RTLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__RTLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RTLEG].skin = self->s.skinnum+1; + break; + } + +//FIXME: when get missile anim + if(self->s.fmnodeinfo[MESH__RHAND].flags & FMNI_NO_DRAW) + { + self->monsterinfo.aiflags |= AI_NO_MISSILE; + + if(self->s.fmnodeinfo[MESH__AXE].flags & FMNI_NO_DRAW) + self->monsterinfo.aiflags |= AI_NO_MELEE; + } + + if(self->monsterinfo.aiflags & AI_NO_MELEE && self->monsterinfo.aiflags & AI_NO_MISSILE) + { + self->monsterinfo.aiflags |= AI_COWARD; + SetAnim(self, ANIM_BACKUP); + } +} + +void ser_grd_SightSound(edict_t *self, G_Message_t *Msg) +{ + gi.sound(self, CHAN_VOICE, sounds[irand(SND_SIGHT1, SND_SIGHT4)], 1, ATTN_NORM, 0); +} + +/* +========================================================== + + Seraph Guard Spawn functions + +========================================================== +*/ + +void SeraphGuardStaticsInit() +{ + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_STAND] = seraph_guard_stand; + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_RUN] = seraph_guard_run; + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_MELEE] = seraph_guard_melee; + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_MISSILE] = seraph_guard_missile; + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_PAIN] = seraph_guard_pain; + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_DEATH] = seraph_guard_death; + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_DEATH_PAIN] = seraph_guard_death_pain; + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_CHECK_MOOD] = seraph_guard_check_mood; + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_SERAPH_GUARD].msgReceivers[MSG_VOICE_SIGHT] = ser_grd_SightSound; + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/guard/tris.fm"); + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = sounds; + + sounds[SND_ATTACK] = gi.soundindex("monsters/seraph/guard/attack.wav"); + sounds[SND_ATTACK_MISS] = gi.soundindex("monsters/seraph/guard/attack_miss.wav"); + sounds[SND_HIT_WALL] = gi.soundindex("weapons/staffhitwall.wav"); + sounds[SND_MISSILE] = gi.soundindex("monsters/seraph/guard/spell.wav"); + sounds[SND_MISSHIT] = gi.soundindex("monsters/seraph/guard/spellhit.wav"); + sounds[SND_FIST_HIT_WALL] = gi.soundindex("objects/bam1.wav"); + + sounds[SND_DEATH1] = gi.soundindex("monsters/seraph/death1.wav"); + sounds[SND_DEATH2] = gi.soundindex("monsters/seraph/death2.wav"); + sounds[SND_DEATH3] = gi.soundindex("monsters/seraph/wimpdeath1.wav"); + sounds[SND_DEATH4] = gi.soundindex("monsters/seraph/wimpdeath2.wav"); + + sounds[SND_PAIN1] = gi.soundindex("monsters/seraph/pain1.wav"); + sounds[SND_PAIN2] = gi.soundindex("monsters/seraph/pain2.wav"); + sounds[SND_PAIN3] = gi.soundindex("monsters/seraph/pain3.wav"); + sounds[SND_PAIN4] = gi.soundindex("monsters/seraph/pain4.wav"); + + sounds[SND_SIGHT1] = gi.soundindex("monsters/seraph/guard/sight1.wav"); + sounds[SND_SIGHT2] = gi.soundindex("monsters/seraph/guard/sight2.wav"); + sounds[SND_SIGHT3] = gi.soundindex("monsters/seraph/guard/sight3.wav"); + sounds[SND_SIGHT4] = gi.soundindex("monsters/seraph/guard/sight4.wav"); + + classStatics[CID_SERAPH_GUARD].resInfo = &resInfo; +} + +void golem_awaken (edict_t *self, edict_t *other, edict_t *activator) +{ + if (!monster_start(self)) // Initialization failed + return; + + self->think = walkmonster_start_go; + self->msgHandler = DefaultMsgHandler; + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + self->monsterinfo.dismember = seraph_guard_dismember; + MG_InitMoods(self); + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + self->melee_range *= self->s.scale; + + self->enemy = activator; + FoundTarget(self, false); +} + + +/*QUAKED monster_seraph_guard(1 .5 0) (-24 -24 -34) (24 24 34) AMBUSH ASLEEP GOLEM 8 16 32 64 FIXED WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 +The big, ugly, brutal Guard.. + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING- Use WANDER instead + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 20 +melee_range = 100 +missile_range = 1024 +min_missile_range = 64 +bypass_missile_chance = 30 +jump_chance = 20 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +void SP_monster_seraph_guard(edict_t *self) +{ + if (self->spawnflags & SERAPH_FLAG_GOLEM) + { + self->classID = CID_SERAPH_GUARD; + + self->clipmask = MASK_MONSTERSOLID; + + if (!self->health) + self->health = SGUARD_HEALTH * 2; + + self->mass = SGUARD_MASS * 10; + self->yaw_speed = 12; + + self->movetype = PHYSICSTYPE_STEP; + self->solid=SOLID_BBOX; + + if (!self->s.scale) + { + self->s.scale = self->monsterinfo.scale = 2.5; + } + + self->s.skinnum = 3; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + self->materialtype = MAT_STONE; + + self->s.modelindex = classStatics[CID_SERAPH_GUARD].resInfo->modelIndex; + self->s.skinnum = 0; + + self->monsterinfo.otherenemyname = "monster_rat"; + + //Turn off the Overlord pieces + self->s.fmnodeinfo[MESH__WHIP].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__LHANDBOSS].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__PITHEAD].flags |= FMNI_NO_DRAW; + + self->s.frame = FRAME_idle; + + //enable this and use guards to make them wake up on command + //self->use = golem_awaken; + } + else + { + self->classID = CID_SERAPH_GUARD; + + if (!monster_start(self)) + return; // Failed initialization + + self->think = walkmonster_start_go; + self->msgHandler = DefaultMsgHandler; + + if (!self->health) + { + self->max_health = self->health = SGUARD_HEALTH; + } + + //Apply to the end result (whether designer set or not) + self->health = MonsterHealth(self->health); + + self->mass = SGUARD_MASS; + self->yaw_speed = 24; + + if(irand(0, 2)) + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + self->movetype = PHYSICSTYPE_STEP; + self->solid=SOLID_BBOX; + self->monsterinfo.dismember = seraph_guard_dismember; + + if (!self->s.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + + self->materialtype = MAT_FLESH; + + self->s.modelindex = classStatics[CID_SERAPH_GUARD].resInfo->modelIndex; + self->s.skinnum = 0; + + self->monsterinfo.otherenemyname = "monster_rat"; + + //Turn off the Overlord pieces + self->s.fmnodeinfo[MESH__WHIP].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__LHANDBOSS].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__PITHEAD].flags |= FMNI_NO_DRAW; + + MG_InitMoods(self); + + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + + self->melee_range *= self->s.scale; + } +} diff --git a/Toolkit/Programming/GameCode/game/m_seraph_guard.h b/Toolkit/Programming/GameCode/game/m_seraph_guard.h new file mode 100644 index 0000000..82ec1c7 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_seraph_guard.h @@ -0,0 +1,95 @@ +#include "g_local.h" + +typedef enum AnimID_e +{ + ANIM_STAND, + ANIM_RUN, + ANIM_FJUMP, + ANIM_RUN_MELEE, + ANIM_WALK, + ANIM_PAIN, + ANIM_MELEE1, + ANIM_MELEE2, + ANIM_MELEE3, + ANIM_DEATH1, + ANIM_DEATH2_GO, + ANIM_DEATH2_LOOP, + ANIM_DEATH2_END, + ANIM_BACKUP, + ANIM_MISSILE, + ANIM_DELAY, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_ATTACK, + SND_ATTACK_MISS, + SND_PAIN1, + SND_PAIN2, + SND_PAIN3, + SND_PAIN4, + SND_DEATH1, + SND_DEATH2, + SND_DEATH3, + SND_DEATH4, + SND_HIT_WALL, + SND_MISSILE, + SND_MISSHIT, + SND_FIST_HIT_WALL, + SND_SIGHT1, + SND_SIGHT2, + SND_SIGHT3, + SND_SIGHT4, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t seraph_guard_move_stand, + seraph_guard_move_run, + seraph_guard_move_fjump, + seraph_guard_move_runmelee, + seraph_guard_move_walk, + seraph_guard_move_pain, + seraph_guard_move_melee, + seraph_guard_move_melee2, + seraph_guard_move_melee3, + seraph_guard_move_death1, + seraph_guard_move_death2_go, + seraph_guard_move_death2_loop, + seraph_guard_move_death2_end, + seraph_guard_move_backup, + seraph_guard_move_missile, + seraph_guard_move_delay; + +void SP_monster_seraph_guard( edict_t* self ); + +void seraph_guard_death_loop ( edict_t *self ); +void seraph_guard_check_land ( edict_t *self ); +void seraph_guard_dead ( edict_t *self ); +void seraph_guard_checkpoke ( edict_t *self ); + +void seraph_guard_pause( edict_t *self ); +void seraph_guard_strike( edict_t *self, float damage, float forward, float up ); +void seraphGuardApplyJump (edict_t *self); +void seraph_guard_back (edict_t *self, float dist); +void seraph_guard_fire (edict_t *self); + +qboolean MG_BoolWalkMove (edict_t *self, float yaw, float dist); + + +#define BIT_BASEBIN 0 +#define BIT_PITHEAD 1 +#define BIT_SHOULDPAD 2 +#define BIT_GUARDHEAD 4 +#define BIT_LHANDGRD 8 +#define BIT_LHANDBOSS 16 +#define BIT_RHAND 32 +#define BIT_FRTORSO 64 +#define BIT_ARMSPIKES 128 +#define BIT_LFTUPARM 256 +#define BIT_RTLEG 512 +#define BIT_RTARM 1024 +#define BIT_LFTLEG 2048 +#define BIT_BKTORSO 4096 +#define BIT_AXE 8192 +#define BIT_WHIP 16384 diff --git a/Toolkit/Programming/GameCode/game/m_seraph_guard_anim.c b/Toolkit/Programming/GameCode/game/m_seraph_guard_anim.c new file mode 100644 index 0000000..e08c9a2 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_seraph_guard_anim.c @@ -0,0 +1,303 @@ +#include "g_local.h" +#include "m_seraph_guard.h" +#include "m_seraph_guard_anim.h" +#include "m_stats.h" + +animframe_t seraph_guard_frames_stand[] = +{ + FRAME_idle1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle20, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle21, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle22, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle23, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle24, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle25, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle26, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle27, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle28, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle29, NULL, 0, 0, 0, ai_stand, 0, NULL, +}; +animmove_t seraph_guard_move_stand = {29, seraph_guard_frames_stand, seraph_guard_pause}; + +animframe_t seraph_guard_frames_melee[] = +{ + FRAME_axea1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea5, seraph_guard_strike, SGUARD_DMG_AXE, 0, 0, ai_charge, 0, NULL, + FRAME_axea5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea6, NULL, 0, 0, 0, ai_charge, 0, seraph_guard_checkpoke, + FRAME_axea7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea9, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea11, seraph_guard_strike, SGUARD_DMG_AXE, 0, 0, ai_charge, 0, NULL, + FRAME_axea11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_axea13, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t seraph_guard_move_melee = {22,seraph_guard_frames_melee, seraph_guard_pause}; + +animframe_t seraph_guard_frames_pain[] = +{ + FRAME_pain1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_pain5, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_guard_move_pain = {5,seraph_guard_frames_pain, seraph_guard_pause}; + +animframe_t seraph_guard_frames_runmelee[] = +{ + FRAME_runaxe4, NULL, 0, 0, 0, ai_charge, 20, NULL, + FRAME_runaxe5, NULL, 0, 0, 0, ai_charge, 24, NULL, + FRAME_runaxe6, NULL, 0, 0, 0, ai_charge, 20, NULL, + FRAME_runaxe7, seraph_guard_strike, SGUARD_DMG_AXE, 0, 0, ai_charge, 20, NULL, + FRAME_runaxe8, NULL, 0, 0, 0, ai_charge, 20, NULL, + FRAME_runaxe1, NULL, 0, 0, 0, ai_charge, 24, NULL, + FRAME_runaxe2, NULL, 0, 0, 0, ai_charge, 20, NULL, + FRAME_runaxe3, NULL, 0, 0, 0, ai_charge, 20, NULL, +}; +animmove_t seraph_guard_move_runmelee = {8,seraph_guard_frames_runmelee, seraph_guard_pause}; + +animframe_t seraph_guard_frames_run[] = +{ + FRAME_run1, NULL, 0, 0, 0, ai_run, 24, seraph_guard_pause, + FRAME_run2, NULL, 0, 0, 0, ai_run, 20, seraph_guard_pause, + FRAME_run3, NULL, 0, 0, 0, ai_run, 20, seraph_guard_pause, + FRAME_run4, NULL, 0, 0, 0, ai_run, 20, seraph_guard_pause, + FRAME_run5, NULL, 0, 0, 0, ai_run, 24, seraph_guard_pause, + FRAME_run6, NULL, 0, 0, 0, ai_run, 20, seraph_guard_pause, + FRAME_run7, NULL, 0, 0, 0, ai_run, 20, seraph_guard_pause, + FRAME_run8, NULL, 0, 0, 0, ai_run, 20, seraph_guard_pause, +}; +animmove_t seraph_guard_move_run = {8,seraph_guard_frames_run, seraph_guard_pause}; + +animframe_t seraph_guard_frames_fjump[] = +{ + FRAME_run1, NULL, 0, 0, 0, NULL, 0, seraphGuardApplyJump, + FRAME_run2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_run8, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_guard_move_fjump = {8,seraph_guard_frames_fjump, seraph_guard_pause}; + +animframe_t seraph_guard_frames_walk[] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk2, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk7, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk8, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk9, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk10, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_walk12, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk13, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk14, NULL, 0, 0, 0, ai_walk, 4, NULL, + FRAME_walk15, NULL, 0, 0, 0, ai_walk, 5, NULL, + FRAME_walk16, NULL, 0, 0, 0, ai_walk, 6, NULL, +}; +animmove_t seraph_guard_move_walk = {16,seraph_guard_frames_walk, seraph_guard_pause}; + +animframe_t seraph_guard_frames_melee2[] = +{ + FRAME_axeb1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb4, seraph_guard_strike, SGUARD_DMG_AXE_SPIN, 0, 0, NULL, 0, NULL, + FRAME_axeb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axeb6, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_guard_move_melee2 = {12, seraph_guard_frames_melee2, seraph_guard_pause}; + +animframe_t seraph_guard_frames_melee3[] = +{ + FRAME_axec1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec7, seraph_guard_strike, SGUARD_DMG_AXE, 0, 0, NULL, 0, NULL, + FRAME_axec7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_axec10, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_guard_move_melee3 = {16, seraph_guard_frames_melee3, seraph_guard_pause}; + +animframe_t seraph_guard_frames_death1[] = +{ + FRAME_deatha1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha20, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha23, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deatha24, NULL, 0, 0, 0, NULL, 0, seraph_guard_dead, +}; +animmove_t seraph_guard_move_death1 = {24, seraph_guard_frames_death1, NULL}; + +animframe_t seraph_guard_frames_death2_go[] = +{ + FRAME_deathb1, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb2, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb3, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb4, NULL, 0, 0, 0, NULL, 0, seraph_guard_death_loop, +}; +animmove_t seraph_guard_move_death2_go = {4, seraph_guard_frames_death2_go, NULL}; + +animframe_t seraph_guard_frames_death2_loop[] = +{ + FRAME_deathb5, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, +}; +animmove_t seraph_guard_move_death2_loop = {1, seraph_guard_frames_death2_loop, NULL}; + +animframe_t seraph_guard_frames_death2_end[] = +{ + FRAME_deathb6, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb7, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb8, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb9, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb10, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb11, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb12, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb13, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb14, NULL, 0, 0, 0, NULL, 0, seraph_guard_check_land, + FRAME_deathb15, NULL, 0, 0, 0, NULL, 0, seraph_guard_dead, +}; +animmove_t seraph_guard_move_death2_end = {10, seraph_guard_frames_death2_end, NULL}; + +animframe_t seraph_guard_frames_backup[] = +{ + FRAME_backup1, NULL, 0, 0, 0, seraph_guard_back, 24, NULL, + FRAME_backup2, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup3, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup4, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup5, NULL, 0, 0, 0, seraph_guard_back, 24, NULL, + FRAME_backup6, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup7, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup8, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup9, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup10, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup11, NULL, 0, 0, 0, seraph_guard_back, 24, NULL, + FRAME_backup12, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup13, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup14, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, + FRAME_backup15, NULL, 0, 0, 0, seraph_guard_back, 24, NULL, + FRAME_backup16, NULL, 0, 0, 0, seraph_guard_back, 20, NULL, +}; +animmove_t seraph_guard_move_backup = {16, seraph_guard_frames_backup, seraph_guard_pause}; + +animframe_t seraph_guard_frames_missile[] = +{ + FRAME_newshot1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newshot2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newshot3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newshot4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newshot5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newshot6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newshot7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newshot8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newshot9, NULL, 0, 0, 0, NULL, 0, seraph_guard_fire, + FRAME_newshot10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_newshot11, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t seraph_guard_move_missile = {11, seraph_guard_frames_missile, seraph_guard_pause}; + +animframe_t seraph_guard_frames_delay[] = +{ + FRAME_idle1, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle2, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle3, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle4, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle5, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle6, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle7, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle8, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle9, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle10, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle11, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle12, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle13, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle14, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle15, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle16, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle17, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle18, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle19, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle20, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle21, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle22, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle23, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle24, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle25, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle26, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle27, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle28, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, + FRAME_idle29, NULL, 0, 0, 0, NULL, 0, seraph_guard_pause, +}; +animmove_t seraph_guard_move_delay = {29, seraph_guard_frames_delay, seraph_guard_pause}; diff --git a/Toolkit/Programming/GameCode/game/m_seraph_guard_anim.h b/Toolkit/Programming/GameCode/game/m_seraph_guard_anim.h new file mode 100644 index 0000000..e51d18a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_seraph_guard_anim.h @@ -0,0 +1,188 @@ +// R:\Art\models/monsters\guard + +// This file generated by qdata - Do NOT Modify + +#define FRAME_partfly 0 +#define FRAME_newshot1 1 +#define FRAME_newshot2 2 +#define FRAME_newshot3 3 +#define FRAME_newshot4 4 +#define FRAME_newshot5 5 +#define FRAME_newshot6 6 +#define FRAME_newshot7 7 +#define FRAME_newshot8 8 +#define FRAME_newshot9 9 +#define FRAME_newshot10 10 +#define FRAME_newshot11 11 +#define FRAME_backup1 12 +#define FRAME_backup2 13 +#define FRAME_backup3 14 +#define FRAME_backup4 15 +#define FRAME_backup5 16 +#define FRAME_backup6 17 +#define FRAME_backup7 18 +#define FRAME_backup8 19 +#define FRAME_backup9 20 +#define FRAME_backup10 21 +#define FRAME_backup11 22 +#define FRAME_backup12 23 +#define FRAME_backup13 24 +#define FRAME_backup14 25 +#define FRAME_backup15 26 +#define FRAME_backup16 27 +#define FRAME_axea1 28 +#define FRAME_axea2 29 +#define FRAME_axea3 30 +#define FRAME_axea4 31 +#define FRAME_axea5 32 +#define FRAME_axea6 33 +#define FRAME_axea7 34 +#define FRAME_axea8 35 +#define FRAME_axea9 36 +#define FRAME_axea10 37 +#define FRAME_axea11 38 +#define FRAME_axea12 39 +#define FRAME_axea13 40 +#define FRAME_axeb1 41 +#define FRAME_axeb2 42 +#define FRAME_axeb3 43 +#define FRAME_axeb4 44 +#define FRAME_axeb5 45 +#define FRAME_axeb6 46 +#define FRAME_axec1 47 +#define FRAME_axec2 48 +#define FRAME_axec3 49 +#define FRAME_axec4 50 +#define FRAME_axec5 51 +#define FRAME_axec6 52 +#define FRAME_axec7 53 +#define FRAME_axec8 54 +#define FRAME_axec9 55 +#define FRAME_axec10 56 +#define FRAME_deatha1 57 +#define FRAME_deatha2 58 +#define FRAME_deatha3 59 +#define FRAME_deatha4 60 +#define FRAME_deatha5 61 +#define FRAME_deatha6 62 +#define FRAME_deatha7 63 +#define FRAME_deatha8 64 +#define FRAME_deatha9 65 +#define FRAME_deatha10 66 +#define FRAME_deatha11 67 +#define FRAME_deatha12 68 +#define FRAME_deatha13 69 +#define FRAME_deatha14 70 +#define FRAME_deatha15 71 +#define FRAME_deatha16 72 +#define FRAME_deatha17 73 +#define FRAME_deatha18 74 +#define FRAME_deatha19 75 +#define FRAME_deatha20 76 +#define FRAME_deatha21 77 +#define FRAME_deatha22 78 +#define FRAME_deatha23 79 +#define FRAME_deatha24 80 +#define FRAME_deathb1 81 +#define FRAME_deathb2 82 +#define FRAME_deathb3 83 +#define FRAME_deathb4 84 +#define FRAME_deathb5 85 +#define FRAME_deathb6 86 +#define FRAME_deathb7 87 +#define FRAME_deathb8 88 +#define FRAME_deathb9 89 +#define FRAME_deathb10 90 +#define FRAME_deathb11 91 +#define FRAME_deathb12 92 +#define FRAME_deathb13 93 +#define FRAME_deathb14 94 +#define FRAME_deathb15 95 +#define FRAME_idle 96 +#define FRAME_idle1 97 +#define FRAME_idle2 98 +#define FRAME_idle3 99 +#define FRAME_idle4 100 +#define FRAME_idle5 101 +#define FRAME_idle6 102 +#define FRAME_idle7 103 +#define FRAME_idle8 104 +#define FRAME_idle9 105 +#define FRAME_idle10 106 +#define FRAME_idle11 107 +#define FRAME_idle12 108 +#define FRAME_idle13 109 +#define FRAME_idle14 110 +#define FRAME_idle15 111 +#define FRAME_idle16 112 +#define FRAME_idle17 113 +#define FRAME_idle18 114 +#define FRAME_idle19 115 +#define FRAME_idle20 116 +#define FRAME_idle21 117 +#define FRAME_idle22 118 +#define FRAME_idle23 119 +#define FRAME_idle24 120 +#define FRAME_idle25 121 +#define FRAME_idle26 122 +#define FRAME_idle27 123 +#define FRAME_idle28 124 +#define FRAME_idle29 125 +#define FRAME_pain1 126 +#define FRAME_pain2 127 +#define FRAME_pain3 128 +#define FRAME_pain4 129 +#define FRAME_pain5 130 +#define FRAME_runaxe1 131 +#define FRAME_runaxe2 132 +#define FRAME_runaxe3 133 +#define FRAME_runaxe4 134 +#define FRAME_runaxe5 135 +#define FRAME_runaxe6 136 +#define FRAME_runaxe7 137 +#define FRAME_runaxe8 138 +#define FRAME_run1 139 +#define FRAME_run2 140 +#define FRAME_run3 141 +#define FRAME_run4 142 +#define FRAME_run5 143 +#define FRAME_run6 144 +#define FRAME_run7 145 +#define FRAME_run8 146 +#define FRAME_walk1 147 +#define FRAME_walk2 148 +#define FRAME_walk3 149 +#define FRAME_walk4 150 +#define FRAME_walk5 151 +#define FRAME_walk6 152 +#define FRAME_walk7 153 +#define FRAME_walk8 154 +#define FRAME_walk9 155 +#define FRAME_walk10 156 +#define FRAME_walk11 157 +#define FRAME_walk12 158 +#define FRAME_walk13 159 +#define FRAME_walk14 160 +#define FRAME_walk15 161 +#define FRAME_walk16 162 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_BASEBIN 0 +#define MESH__PITHEAD 1 +#define MESH__SHOULDPAD 2 +#define MESH__GUARDHEAD 3 +#define MESH__LHANDGRD 4 +#define MESH__LHANDBOSS 5 +#define MESH__RHAND 6 +#define MESH__FRTORSO 7 +#define MESH__ARMSPIKES 8 +#define MESH__LFTUPARM 9 +#define MESH__RTLEG 10 +#define MESH__RTARM 11 +#define MESH__LFTLEG 12 +#define MESH__BKTORSO 13 +#define MESH__AXE 14 +#define MESH__WHIP 15 diff --git a/Toolkit/Programming/GameCode/game/m_spreader.c b/Toolkit/Programming/GameCode/game/m_spreader.c new file mode 100644 index 0000000..37e00cc --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_spreader.c @@ -0,0 +1,1413 @@ + +//============================================================================== +// +// m_spreader.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "g_Physics.h" + +#include "m_spreader.h" +#include "m_spreader_anim.h" +#include "m_spreadermist.h" +#include "matrix.h" +#include "Angles.h" +#include "g_misc.h" +#include "g_HitLocation.h" +#include "m_stats.h" +#include "p_anim_branch2.h" +#include "p_anims2.h" + +// Stats +/*#define SPREADER_HEALTH (200.0) +#define SPREADER_MASS (300.0)*/ + +//FIXME I basically pulled these numbers out of the air +#define SPREADER_TOO_CLOSE 70 +#define SPREADER_CLOSE 120 +#define SPREADER_FAR 300 +#define SPREADER_TOO_FAR 600 + +#ifndef TRYSTEP_OK +#define TRYSTEP_OK 0 +#define TRYSTEP_ALLSOLID 1 +#define TRYSTEP_STARTSOLID 2 +#define TRYSTEP_OFFEDGE 3 +#define TRYSTEP_NOSUPPORT 4 +#define TRYSTEP_INWATER 5 +#endif + +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); + +/*--------------------------------------------------------------- + spreader Base Info +---------------------------------------------------------------*/ +static animmove_t *animations[NUM_ANIMS] = +{ + &spreader_move_attack1, + &spreader_move_attack2, + &spreader_move_backup1, + &spreader_move_backattack1, + &spreader_move_death1_go, + &spreader_move_death1_loop, + &spreader_move_death1_end, + &spreader_move_duck1, + &spreader_move_dkatck1, + &spreader_move_duckdown, + &spreader_move_duckstill, + &spreader_move_duckup, + &spreader_move_idle1, + &spreader_move_pain1, + &spreader_move_pvtlt1, + &spreader_move_pvtrt1, + &spreader_move_rnatck1, + &spreader_move_run1, + &spreader_move_land, + &spreader_move_inair, + &spreader_move_fjump, + &spreader_move_walk1, + &spreader_move_walk2, + &spreader_move_death2, + &spreader_move_fly, + &spreader_move_flyloop, + &spreader_move_fdie, + &spreader_move_dead, + &spreader_move_delay +}; + +static int sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + +void SprayDebris(edict_t *self, vec3_t spot, byte NoOfChunks, float damage); + +/*========================================================================== + + NEW SPREADER IMPLEMENTATION + +==========================================================================*/ + +/*========================================================================== + + SPREADER HELPER FUNCTIONS + +==========================================================================*/ + +void spreader_showgrenade(edict_t *self) +{ + if(self->monsterinfo.aiflags & AI_NO_MISSILE) + return;//fixme: actually prevent these anims + + self->s.fmnodeinfo[MESH__BOMB].flags &= ~FMNI_NO_DRAW; +} + +void spreader_pain_sound(edict_t *self) +{ + gi.sound(self, CHAN_WEAPON, sounds[SND_PAIN], 1, ATTN_NORM, 0); +} + +void spreader_miststartsound(edict_t *self) +{ + if(self->monsterinfo.aiflags & AI_NO_MELEE) + return;//fixme: actually prevent these anims + + gi.sound(self, CHAN_WEAPON, sounds[SND_SPRAYSTART], 1, ATTN_IDLE, 0); +} + +/*------------------------------------------------------------------------- + spreader_miststopsound +-------------------------------------------------------------------------*/ +void spreader_miststopsound(edict_t *self) +{ +// gi.sound(self, CHAN_WEAPON, self->moveinfo.sound_end, 1, ATTN_NORM, 0); +// self->s.sound = 0; +} + +void spreader_idlenoise(edict_t *self) +{ + static int i = 0; + + int chance = irand(0, 9); + if(i >= 50) i=0; + + if(chance < 7 && i) + return; + ++i; + chance = irand(0, 9); + + if(chance < 5 ) + gi.sound(self, CHAN_AUTO, sounds[SND_VOICE1], 1, ATTN_IDLE, 0); + else + gi.sound(self, CHAN_AUTO, sounds[SND_VOICE2], 1, ATTN_IDLE, 0); +} + +void spreader_hidegrenade(edict_t *self) +{ + self->s.fmnodeinfo[MESH__BOMB].flags |= FMNI_NO_DRAW; + gi.sound(self, CHAN_AUTO, sounds[SND_THROW], 1, ATTN_IDLE, 0); +} + +void spreader_flyback_loop(edict_t *self) +{ + SetAnim(self, ANIM_DEATH1_LOOP); +} + +void spreader_flyback_move(edict_t *self) +{ + vec3_t endpos; + trace_t trace; + int flags = 0; + + M_ChangeYaw(self); + + VectorCopy(self->s.origin, endpos); + endpos[2] -= 48; + + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&trace); + + if(trace.fraction < 1 || trace.startsolid || trace.allsolid) + { + if(trace.fraction < 1) + { + vec3_t bottom; + + if(irand(0, 1)) + flags |= CEF_FLAG6; + + VectorSet(bottom, trace.endpos[0]+flrand(-4, 4), trace.endpos[1]+flrand(-4, 4), trace.endpos[2] + self->mins[2]); + + gi.CreateEffect(NULL, + FX_BLOOD_TRAIL, + flags, + bottom, + "d", + trace.plane.normal); + } + + if (self->curAnimID != ANIM_DEATH1_END && + self->curAnimID != ANIM_DEATH1_GO) + { + self->elasticity = 1.1; + self->friction = 0.5; + SetAnim(self, ANIM_DEATH1_END); + } + } +} + +void spreader_dead(edict_t *self) +{ + vec3_t spraydir, sprayorg, offset; + + if (irand(0,1) && self->curAnimID == ANIM_DEATH1_END) + { + edict_t *gas; + + spraydir[0] = flrand(-10, 10); + spraydir[1] = flrand(-10, 10); + spraydir[2] = flrand( 10, 100); + + VectorSet(offset, 0, 0, -24); + VectorAdd(self->s.origin, offset, sprayorg); + + // create the volume effect for the damage + gas = RadiusDamageEnt(self,//owner + self,//damage-owner + 1,//damage + 0,//d_damage + 30,//radius + 1.0,//d_radius + DAMAGE_NO_BLOOD|DAMAGE_ALIVE_ONLY,//dflags + 4.5,//lifetime + 0.2,//thinkincr + NULL,//origin + offset,//velocity or offset + true);//offset from owner? + + gas->svflags |= SVF_ALWAYS_SEND; + gas->s.effects=EF_MARCUS_FLAG1; + + gi.CreateEffect(&gas->s, FX_PLAGUEMIST, CEF_OWNERS_ORIGIN, offset, "vb", spraydir, 100);//sprayorg, not offset? + } + + M_EndDeath(self); +} + +void spreader_crouch(edict_t *self) +{ + VectorSet(self->maxs, 16, 16, 0); + self->viewheight = 0; + SetAnim(self, ANIM_DUCKDOWN); +} + +qboolean spreader_check_uncrouch(edict_t *self) +{//FIXME: Need to ultimately make sure this is ok! + vec3_t mins, maxs, endpos; + trace_t trace; + float desired_height; + + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + + mins[2] = 0; + maxs[2] = 1; + + desired_height = STDMaxsForClass[CID_SPREADER][2] * self->s.scale; + + VectorCopy(self->s.origin, endpos); + endpos[2] += desired_height; + + gi.trace(self->s.origin, mins, maxs, endpos, self, MASK_MONSTERSOLID,&trace); + if(trace.fraction < 1.0) + return false; +/* + VectorCopy(self->mins,self->intentMins); + VectorCopy(self->maxs,self->intentMaxs); + self->intentMaxs[2] = 40; +*/ + self->maxs[2] = desired_height; + self->viewheight = self->maxs[2] - 8 * self->s.scale; + +// self->physicsFlags |= PF_RESIZE; + return true; +// SetAnim(self, ANIM_DUCKUP); +} + +void spreader_duckpause(edict_t *self) +{ + float dist; + qboolean stay_duck = false; + + if(self->evade_debounce_time > level.time) + stay_duck = true; + + if (M_ValidTarget(self, self->enemy)) + { + dist = M_DistanceToTarget(self, self->enemy); + + if ( dist < 128 ) + SetAnim(self, ANIM_DUCKATTACK); + else if ( !irand(0,10) || stay_duck) + SetAnim(self, ANIM_DUCKSTILL); + else if(spreader_check_uncrouch(self)) + SetAnim(self, ANIM_DUCKUP); + else + SetAnim(self, ANIM_DUCKSTILL); + + return; + } + + if(spreader_check_uncrouch(self)) + SetAnim(self, ANIM_DUCKUP); + else + SetAnim(self, ANIM_DUCKSTILL); +} + +void spreader_pause(edict_t *self) +{ + if(self->spawnflags & MSF_FIXED && self->curAnimID == ANIM_DELAY && self->enemy) + { + self->monsterinfo.searchType = SEARCH_COMMON; + MG_FaceGoal(self, true); + } + + self->mood_think(self); + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_NAVIGATE: + case AI_MOOD_PURSUE: + case AI_MOOD_FLEE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_STAND: + if (!self->enemy) + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_DELAY: + SetAnim(self, ANIM_DELAY); + break; + + case AI_MOOD_WANDER: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_WALK: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_JUMP: + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_FJUMP); + break; + + case AI_MOOD_BACKUP: + QPostMessage(self, MSG_FALLBACK, PRI_DIRECTIVE, NULL); + break; + + default : +#ifdef _DEVEL + gi.dprintf("spreader: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } +} + +void spreader_check_mood (edict_t *self, G_Message_t *msg) +{ + ParseMsgParms(msg, "i", &self->ai_mood); + + spreader_pause(self); +} + +/*========================================================================== + + SPREADER MESSAGE FUNCTIONS + +==========================================================================*/ + +void spreader_pain(edict_t *self, G_Message_t *msg) +{ + int temp, damage; + qboolean force_pain; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_pain, &damage, &temp); + + //Weighted random based on health compared to the maximum it was at + if (force_pain||((flrand(0, self->max_health+50) > self->health) && irand(0,2))) + { + gi.sound (self, CHAN_BODY, sounds[SND_PAIN], 1, ATTN_NORM, 0); + SetAnim(self, ANIM_PAIN1); + } +} + +void spreader_stand(edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_IDLE1); +} + +void spreader_run(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + if(self->spawnflags&MSF_FIXED) + { + SetAnim(self, ANIM_DELAY); + return; + } + else + { + SetAnim(self, ANIM_RUN1); + } + + return; + } + + //If our enemy is dead, we need to stand + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void spreader_walk(edict_t *self, G_Message_t *msg) +{ + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_WALK1); +} + +void spreader_melee(edict_t *self, G_Message_t *msg) +{ + int chance; + float dist; + + chance = irand(0, 100); + + if (M_ValidTarget(self, self->enemy)) + { + if(self->spawnflags&MSF_FIXED) + { + if(chance<50) + SetAnim(self, ANIM_DUCKDOWN); + else + SetAnim(self, ANIM_DELAY); + return; + } + + dist = M_DistanceToTarget(self, self->enemy); + + if (dist < 64) + { + if(self->curAnimID == ANIM_RUNATTACK) + {//bumped into player, knock him down + if(self->enemy->health>0) + { + if(self->enemy->client) + { + if(!irand(0, 2)) + { + if(self->enemy->client->playerinfo.lowerseq != ASEQ_KNOCKDOWN) + { + if(infront(self->enemy, self)) + { + KnockDownPlayer(&self->enemy->client->playerinfo); + } + } + } + } + } + } + + if(self->curAnimID == ANIM_RUNATTACK || (self->curAnimID == ANIM_RUN1 && self->s.frame > FRAME_run1)) + { + if (chance < 40) + SetAnim(self, ANIM_DUCKDOWN); + else + SetAnim(self, ANIM_ATTACK2); + return; + } + + if (irand(0,1) && !(self->monsterinfo.aiflags & AI_NO_MELEE)) + { + SetAnim(self, ANIM_BACKATTACK); + } + else + SetAnim(self, ANIM_BACKUP); + } + else + { + if (chance < 20) + SetAnim(self, ANIM_BACKUP); + else if (chance < 40) + SetAnim(self, ANIM_DUCKDOWN); + else if (chance < 60 || (self->monsterinfo.aiflags & AI_NO_MELEE)) + SetAnim(self, ANIM_RUN1); + else + SetAnim(self, ANIM_ATTACK2); + } + + return; + } + + SetAnim(self, ANIM_IDLE1); +} + +void spreader_missile(edict_t *self, G_Message_t *msg) +{ + float dist; + int chance; + qboolean ret; + trace_t trace; + + chance = irand(0, 100); + + if (M_ValidTarget(self, self->enemy)) + { + dist = M_DistanceToTarget(self, self->enemy); + + if (dist < 64) + { + if(!(self->monsterinfo.aiflags & AI_NO_MELEE) && irand(0, 5)) + SetAnim(self, ANIM_BACKATTACK); + else + SetAnim(self, ANIM_BACKUP); + } + else if (dist < 128) + { + if (chance < 20) + SetAnim(self, ANIM_BACKUP); + else if (chance < 40) + SetAnim(self, ANIM_DUCKDOWN); + else if (chance < 60 || self->monsterinfo.aiflags & AI_NO_MELEE) + SetAnim(self, ANIM_RUN1); + else + SetAnim(self, ANIM_ATTACK2); + } + else + { + vec3_t vf, attackVel; + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorScale(vf, 200, attackVel); + ret = M_PredictTargetEvasion( self, self->enemy, attackVel, self->enemy->velocity, 150, 5 ); + + //See what the predicted outcome is + if (!(self->monsterinfo.aiflags & AI_NO_MELEE) && ret && (M_CheckMeleeHit( self, 200, &trace) == self->enemy) && (chance < 25)) + SetAnim(self, ANIM_RUNATTACK); + else if(self->monsterinfo.aiflags & AI_NO_MISSILE) + SetAnim(self, ANIM_RUN1); + else + SetAnim(self, ANIM_ATTACK1); + } + + return; + } + + SetAnim(self, ANIM_IDLE1); +} + +void spreader_fallback(edict_t *self, G_Message_t *msg) +{ + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else if(!(self->monsterinfo.aiflags & AI_NO_MELEE)) + SetAnim(self, ANIM_BACKATTACK); + else + SetAnim(self, ANIM_BACKUP); +} + +void spreader_evade(edict_t *self, G_Message_t *msg) +{ + edict_t *projectile; + HitLocation_t HitLocation; + int duck_chance, chance; + float eta; + + ParseMsgParms(msg, "eif", &projectile, &HitLocation, &eta); + + switch (self->curAnimID) + { + case ANIM_DUCKDOWN: + case ANIM_DUCKUP: + case ANIM_DUCKSTILL: + return; + break; + + default: + break; + } + + if (irand(0,1)) + { + switch(HitLocation) + { + case hl_Head: + duck_chance = 100; + break; + + case hl_TorsoFront: + case hl_TorsoBack: + duck_chance = 75; + break; + + case hl_ArmUpperLeft: + case hl_ArmUpperRight: + duck_chance = 75; + break; + + case hl_ArmLowerLeft: + case hl_ArmLowerRight: + duck_chance = 35; + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft: + case hl_LegUpperRight: + case hl_LegLowerRight: + duck_chance = 0; + break; + + default: + duck_chance = 10; + + break; + } + + chance = irand(0, 100); + if(chance < duck_chance) + { + self->evade_debounce_time = level.time + eta; + spreader_crouch(self); + return; + } + } +} + +void spreader_death(edict_t *self, G_Message_t *msg) +{ + edict_t *targ, *inflictor, *attacker; + float damage; + vec3_t dVel, vf, yf; + + if(msg) + ParseMsgParms(msg, "eeei", &targ, &inflictor, &attacker, &damage); + + spreader_hidegrenade(self); + + M_StartDeath(self, ANIM_DEATH1_GO); + + if (self->health < -80) + { + return; + } + else if (self->health < -10) + { + SetAnim(self, ANIM_DEATH1_GO); + + VectorSet(self->knockbackvel, 0, 0, 0); + + VectorCopy(targ->velocity, vf); + VectorNormalize(vf); + + VectorScale(vf, -1, yf); + + self->ideal_yaw = vectoyaw( yf ); + self->yaw_speed = 16; + + VectorScale(vf, 300, dVel); + dVel[2] = irand(150,250); + + VectorCopy(dVel, self->velocity); +// self->groundentity = NULL; + } + else + { + SetAnim(self, ANIM_DEATH2); + } + + gi.sound (self, CHAN_BODY, sounds[SND_DEATH], 1, ATTN_NORM, 0); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/*--------------------------------------------------------------- + + MG STUFF + +---------------------------------------------------------------*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +qboolean canthrownode_ps (edict_t *self, int BP, int *throw_nodes) +{//see if it's on, if so, add it to throw_nodes + //turn it off on thrower + if(!(self->s.fmnodeinfo[BP].flags & FMNI_NO_DRAW)) + { + *throw_nodes |= Bit_for_MeshNode_ps[BP]; + self->s.fmnodeinfo[BP].flags |= FMNI_NO_DRAW; + return true; + } + return false; +} + +void spreader_dropweapon (edict_t *self) +{//NO PART FLY FRAME! + vec3_t handspot, right; + + AngleVectors(self->s.angles,NULL,right,NULL); + + if(self->s.fmnodeinfo[BIT_BOMB].flags & FMNI_NO_DRAW) + return; + + VectorClear(handspot); + VectorMA(handspot, -12, right, handspot); + ThrowWeapon(self, &handspot, BIT_BOMB, 0, 0); + self->s.fmnodeinfo[MESH__BOMB].flags |= FMNI_NO_DRAW; +} + +void spreader_dead_pain (edict_t *self, G_Message_t *msg) +{ + if(msg) + if(!(self->svflags & SVF_PARTS_GIBBED)) + MG_parse_dismember_msg(self, msg); +} + +void spreader_dismember(edict_t *self, int damage, int HitLocation) +{//fixme: throw current weapon +//fixme - make part fly dir the vector from hit loc to sever loc +//remember- turn on caps! + + int throw_nodes = 0; + vec3_t gore_spot, right; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; + + VectorCopy(vec3_origin,gore_spot); + switch(HitLocation) + { + case hl_Head: + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.origin, gore_spot, gore_spot); + SprayDebris(self, gore_spot,(byte)(8),damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { + self->s.fmnodeinfo[MESH__HEAD].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__HEAD].skin = self->s.skinnum+1; + } + break; + + case hl_TorsoFront://split in half? + if(self->s.fmnodeinfo[MESH__BODY].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0, self->health) < damage*0.3 && !irand(0,9)) // One in 10 chance of the takeoff even if reqs met. + {//fly straight up, hit cieling, head squish, otherwise go though sky + gore_spot[2]+=12; + + canthrownode_ps(self, MESH__TANK3,&throw_nodes); + canthrownode_ps(self, MESH__TANK2,&throw_nodes); + canthrownode_ps(self, MESH__TANK1,&throw_nodes); + canthrownode_ps(self, MESH__HOSE,&throw_nodes); + + ThrowWeapon(self, &gore_spot, throw_nodes, 0, FRAME_death17); + + if(self->health>0) + spreaderTakeOff(self); + return; + } + else + { + self->s.fmnodeinfo[MESH__BODY].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__BODY].skin = self->s.skinnum+1; + } + break; + case hl_TorsoBack://split in half? + if(self->s.fmnodeinfo[MESH__BODY].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0, self->health) < damage*0.7 && !irand(0,3)) // 25% chance of the takeoff even if reqs met.. + {//fly straight up, hit cieling, head squish, otherwise go though sky + gore_spot[2]+=12; + + canthrownode_ps(self, MESH__TANK3,&throw_nodes); + canthrownode_ps(self, MESH__TANK2,&throw_nodes); + canthrownode_ps(self, MESH__TANK1,&throw_nodes); + canthrownode_ps(self, MESH__HOSE,&throw_nodes); + + ThrowWeapon(self, &gore_spot, throw_nodes, 0, FRAME_death17); + + if(self->health>0) + spreaderTakeOff(self); + return; + } + else + { + self->s.fmnodeinfo[MESH__BODY].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__BODY].skin = self->s.skinnum+1; + } + break; + + case hl_ArmUpperLeft: + case hl_ArmLowerLeft://left arm + //what about hose? + if(self->s.fmnodeinfo[MESH__LFTARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__LFTARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + } + else + { + self->s.fmnodeinfo[MESH__LFTARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LFTARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperRight: + case hl_ArmLowerRight://right arm + //what about grenade? + if(self->s.fmnodeinfo[MESH__RITARM].flags & FMNI_NO_DRAW) + break; + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + spreader_dropweapon (self); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + } + else + { + self->s.fmnodeinfo[MESH__RITARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RITARM].skin = self->s.skinnum+1; + } + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft://left leg + if(self->s.fmnodeinfo[MESH__LFTLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__LFTLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LFTLEG].skin = self->s.skinnum+1; + break; + case hl_LegUpperRight: + case hl_LegLowerRight://right leg + if(self->s.fmnodeinfo[MESH__RITLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__RITLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RITLEG].skin = self->s.skinnum+1; + break; + + default: + if(flrand(0,self->health)s.fmnodeinfo[MESH__LFTARM].flags&FMNI_NO_DRAW&& + self->s.fmnodeinfo[MESH__RITARM].flags&FMNI_NO_DRAW) + { + self->monsterinfo.aiflags |= AI_COWARD; + } + else + { + if(self->s.fmnodeinfo[MESH__LFTARM].flags&FMNI_NO_DRAW) + self->monsterinfo.aiflags |= AI_NO_MELEE; + + if(self->s.fmnodeinfo[MESH__RITARM].flags&FMNI_NO_DRAW) + self->monsterinfo.aiflags |= AI_NO_MISSILE; + } + +// gi.dprintf(" done\n"); +} + +void spreader_stop (edict_t *self, trace_t *trace) +{//aparently being on ground no longer causes you to lose avelocity so I do it manually + VectorClear(self->avelocity); + self->svflags &= ~SVF_TAKE_NO_IMPACT_DMG; + self->isBlocked = NULL; + self->bounced = NULL; +} + +void spreader_isblocked (edict_t *self, trace_t *trace) +{ + edict_t *other; + vec3_t gore_spot; + + if(trace->surface) + { + if(trace->surface->flags & SURF_SKY) + { + self->movetype = PHYSICSTYPE_NOCLIP; + self->solid = SOLID_NOT; + self->isBlocked = NULL; + self->bounced = NULL; + return; + } + } + + other = trace->ent; + + if((other->movetype != PHYSICSTYPE_NONE) && (other->movetype != PHYSICSTYPE_PUSH)) + { + if(other == self->enemy && self->touch_debounce_time > level.time) + return; + + self->enemy = other; + + VectorAdd(other->velocity, self->velocity, other->velocity); + + if(other->takedamage) + T_Damage (other, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + + self->touch_debounce_time = level.time + 0.3; + return; + } + + + self->s.fmnodeinfo[MESH__HEAD].flags |= FMNI_NO_DRAW; + VectorCopy(self->s.origin, gore_spot); + gore_spot[2]+=self->maxs[2] - 8; + SprayDebris(self, gore_spot, 8, 100); + + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + self->isBlocked = spreader_stop; + self->bounced = spreader_stop; + spreader_death(self, NULL); + self->avelocity[YAW] = 0; + + self->elasticity = 1.3; + self->friction = 0.8; + return; +} + +void spreaderTakeOff (edict_t *self) +{ + vec3_t forward; + edict_t *gas; + + self->msgHandler=DeadMsgHandler; + self->isBlocked = spreader_isblocked; + self->bounced = spreader_isblocked; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->s.origin, -12, forward, self->pos1); + self->pos1[2] += self->maxs[2] * 0.8; + + // create the volume effect for the damage + gas = RadiusDamageEnt(self,//owner + self,//damage-owner + 1,//damage + 0,//d_damage + 150,//radius + 0.0,//d_radius + DAMAGE_NO_BLOOD|DAMAGE_ALIVE_ONLY,//dflags + 4.5,//lifetime + 0.1,//thinkincr + NULL,//origin + self->pos1,//velocity or offset + true);//offset from owner? + + gas->svflags |= SVF_ALWAYS_SEND; + gas->s.effects=EF_MARCUS_FLAG1; + + gi.CreateEffect(&gas->s, FX_PLAGUEMISTEXPLODE, CEF_OWNERS_ORIGIN, self->pos1, "b", 70); + + gi.sound(self, CHAN_VOICE, sounds[SND_PAIN], 1, ATTN_NORM, 0); + gi.sound(self, CHAN_WEAPON, sounds[SND_SPRAYSTART], 1, ATTN_NORM, 0); + gi.sound(self, CHAN_AUTO, sounds[SND_BOMB], 1, ATTN_NORM, 0); + + self->pain_debounce_time = level.time + flrand(0.4, 0.8);//for sound loop + + self->velocity[0] = self->velocity[1] = 0;//not realistic, but funnier + self->velocity[2]+=150; + self->avelocity[YAW] = flrand(-200, -600); + if(irand(0,10)<5) + self->avelocity[YAW]*=-1; + + self->movetype = PHYSICSTYPE_FLY; + self->svflags |= SVF_ALWAYS_SEND; + + spreader_dropweapon (self); + + self->svflags |= SVF_TAKE_NO_IMPACT_DMG; + + SetAnim(self, ANIM_FLY); +} + +void spreaderSplat (edict_t *self, trace_t *trace)//, edict_s *other, cplane_s *plane, csurface_s *surf)/*(edict_t *self, trace_t *trace)*/ +{ + vec3_t dir; + float speed; + + if(trace->ent) + { + if(trace->ent->takedamage) + { + if(Vec3IsZero(self->velocity)) + VectorSet(dir, 0, 0, 1); + else + { + VectorCopy(self->velocity, dir); + speed = VectorNormalize(dir); + } + + if(speed<50) + speed = irand(50, 200); + + T_Damage(trace->ent, self, self, dir, trace->endpos, dir, speed, 0, 0,MOD_DIED); + + if(trace->ent->health>0)//else don't gib? + if(!stricmp(trace->ent->classname, "player")) + KnockDownPlayer(&trace->ent->client->playerinfo); + } + } + + self->deadflag = DEAD_DEAD; + self->health = -1000; + self->mass = 0.01; + self->think = BecomeDebris; + self->nextthink = level.time + 0.01; +} + +void spreader_go_deadloop (edict_t *self) +{ + SetAnim(self, ANIM_DEAD); +} + +void spreaderSolidAgain (edict_t *self) +{ + vec3_t org; + + VectorCopy(self->s.origin, org); + org[2]+=self->maxs[2]; + + self->nextthink = level.time + 0.1; + + if(!gi.pointcontents(org)) + { + if(self->movetype == PHYSICSTYPE_STEP) + return; + + self->svflags &= ~SVF_ALWAYS_SEND; + self->movetype = PHYSICSTYPE_STEP; + self->solid = SOLID_BBOX; + self->isBlocked = spreaderSplat; + self->bounced = spreaderSplat; + self->svflags &= ~SVF_TAKE_NO_IMPACT_DMG; + } + else + { + if(self->velocity[2]>-600) + { + if(VectorLength(self->movedir)>500) + VectorCopy(self->movedir, self->velocity); + else + self->velocity[2] -= 50; + } + else + VectorCopy(self->velocity, self->movedir); + } +} + +void spreaderDropDown (edict_t *self) +{ + self->movetype = PHYSICSTYPE_NOCLIP; + self->solid=SOLID_NOT; + self->velocity[2] = -200; + self->avelocity[0] = irand(-300, 300); + self->avelocity[1] = irand(-300, 300); + self->avelocity[2] = irand(-300, 300); + + SetAnim(self, ANIM_FDIE); + self->think = monster_think; + self->nextthink = level.time + 0.1; +} + +void spreaderFly (edict_t *self) +{ + vec3_t spraydir, forward; + + if(self->pain_debounce_time <= level.time) + { + gi.sound(self, CHAN_BODY, sounds[SND_SPRAYLOOP], 1, ATTN_NORM, 0); + self->pain_debounce_time = level.time + flrand(0.4, 0.8); + } + + if(self->velocity[2]<800) + self->velocity[2] += 100; + + if(self->velocity[2] > 800) + self->velocity[2] = 800; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->s.origin, -12, forward, self->pos1); + self->pos1[2] += self->maxs[2] * 0.8; + + spraydir[0] = flrand(-100, 100); + spraydir[1] = flrand(-100, 100); + spraydir[2] = -self->velocity[2]; + gi.CreateEffect(NULL, FX_PLAGUEMIST, 0, self->pos1, "vb", spraydir, 41); + + if(self->s.origin[2]>3900) + { + self->movetype = PHYSICSTYPE_NONE; + VectorClear(self->velocity); + self->think = spreaderDropDown; + self->nextthink = level.time + flrand(1.5, 3); + } + else if(self->health<=0) + { + VectorClear(self->avelocity); + //spreader_death(self); + } +} + +void spreaderFlyLoop (edict_t *self) +{ + SetAnim(self, ANIM_FLYLOOP); +} + +void spreader_land(edict_t *self) +{ + gi.sound(self, CHAN_BODY, gi.soundindex("misc/land.wav"), 1, ATTN_NORM, 0); + gi.CreateEffect(&self->s, + FX_DUST_PUFF, + CEF_OWNERS_ORIGIN, + self->s.origin, + NULL); +} + +void spreaderApplyJump (edict_t *self) +{ + self->jump_time = level.time + 0.5; + VectorCopy(self->movedir, self->velocity); + VectorNormalize(self->movedir); +} + +void spreader_jump (edict_t *self, G_Message_t *msg) +{ + SetAnim(self, ANIM_FJUMP); +} + +void spreader_go_inair (edict_t *self) +{ + SetAnim(self, ANIM_INAIR); +} + +/*------------------------------------------------------------------------ + startup stuff -- initialization for the spreader class and individual + spreaders +/*------------------------------------------------------------------------- + SpreaderStaticsInit +-------------------------------------------------------------------------*/ +void SpreaderStaticsInit() +{ + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + resInfo.modelIndex = gi.modelindex("models/monsters/spreader/tris.fm"); + + classStatics[CID_SPREADER].msgReceivers[MSG_STAND] = spreader_stand; + classStatics[CID_SPREADER].msgReceivers[MSG_RUN] = spreader_run; + classStatics[CID_SPREADER].msgReceivers[MSG_WALK] = spreader_walk; + classStatics[CID_SPREADER].msgReceivers[MSG_MELEE] = spreader_melee; + classStatics[CID_SPREADER].msgReceivers[MSG_MISSILE] = spreader_missile; + classStatics[CID_SPREADER].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_SPREADER].msgReceivers[MSG_JUMP] = spreader_jump; + classStatics[CID_SPREADER].msgReceivers[MSG_EVADE] = spreader_evade; + classStatics[CID_SPREADER].msgReceivers[MSG_FALLBACK] = spreader_fallback; + classStatics[CID_SPREADER].msgReceivers[MSG_DEATH] = spreader_death; + classStatics[CID_SPREADER].msgReceivers[MSG_PAIN] = spreader_pain; + classStatics[CID_SPREADER].msgReceivers[MSG_DEATH_PAIN] = spreader_dead_pain; + classStatics[CID_SPREADER].msgReceivers[MSG_CHECK_MOOD] = spreader_check_mood; + + sounds[SND_SPRAYSTART] = gi.soundindex("monsters/spreader/spraystart.wav"); + sounds[SND_SPRAYLOOP] = gi.soundindex("monsters/spreader/sprayloop.wav"); + sounds[SND_PAIN] = gi.soundindex("monsters/spreader/pain1.wav"); + sounds[SND_VOICE1] = gi.soundindex("monsters/spreader/voice1.wav"); + sounds[SND_VOICE2] = gi.soundindex("monsters/spreader/voice2.wav"); + sounds[SND_THROW] = gi.soundindex("monsters/spreader/throw.wav"); + sounds[SND_DEATH] = gi.soundindex("monsters/spreader/death.wav"); + sounds[SND_BOMB] = gi.soundindex("monsters/spreader/gasbomb.wav"); + sounds[SND_SPRAYLOOP] = gi.soundindex("monsters/spreader/sprayloop.wav"); + resInfo.numSounds = NUM_SOUNDS; + + resInfo.sounds = sounds; + + classStatics[CID_SPREADER].resInfo = &resInfo; +} + +/*QUAKED monster_spreader (1 .5 0) (-16 -16 -0) (16 16 32) AMBUSH ASLEEP WALKING 8 16 32 64 FIXED WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +The spreader + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING - use WANDER instead + +WANDER - Monster will wander around aimlessly (but follows buoys) + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 24 +melee_range = 100 +missile_range = 512 +min_missile_range = 200 +bypass_missile_chance = 50 +jump_chance = 30 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +/*------------------------------------------------------------------------- + SP_monster_spreader +-------------------------------------------------------------------------*/ +void SP_monster_spreader (edict_t *self) +{ + if(self->spawnflags & MSF_WALKING) + { + self->spawnflags |= MSF_WANDER; + self->spawnflags &= ~MSF_WALKING; + } + + self->classID = CID_SPREADER; + + if (!monster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->think = walkmonster_start_go; + self->monsterinfo.dismember = spreader_dismember; + + if (!self->health) + self->health = SPREADER_HEALTH; + + self->health = MonsterHealth(self->health); + + self->mass = SPREADER_MASS; + self->materialtype = MAT_FLESH; + self->yaw_speed = 20; + + self->s.origin[2] += 40; + self->movetype = PHYSICSTYPE_STEP; + + self->solid=SOLID_BBOX; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + self->viewheight = 36; + + self->s.modelindex = classStatics[CID_SPREADER].resInfo->modelIndex; + self->s.fmnodeinfo[MESH__BOMB].flags |= FMNI_NO_DRAW; //hide the bomb + + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + + self->s.skinnum = 0; + self->monsterinfo.scale = MODEL_SCALE; + + self->moveinfo.sound_start = gi.soundindex("monsters/spreader/spraystart.wav"); + self->moveinfo.sound_middle = gi.soundindex("monsters/spreader/sprayloop.wav"); + self->moveinfo.sound_end = gi.soundindex("monsters/spreader/sprayloop.wav"); + + self->touch = M_Touch; + + self->monsterinfo.otherenemyname = "monster_box"; + self->monsterinfo.aiflags = 0; + self->monsterinfo.flee_finished = 0; + + MG_InitMoods(self); + self->min_melee_range = 24; + + //FIXME what else should he spawn doing? + if(self->spawnflags & MSF_WANDER) + { + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + } + else + { + QPostMessage(self,MSG_STAND,PRI_DIRECTIVE, NULL); + } +} diff --git a/Toolkit/Programming/GameCode/game/m_spreader.h b/Toolkit/Programming/GameCode/game/m_spreader.h new file mode 100644 index 0000000..a5853d4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_spreader.h @@ -0,0 +1,156 @@ +/*------------------------------------------------------------------------- +m_spreader.h + +Copyright 1998 Raven Software +All rights reserved +-------------------------------------------------------------------------*/ + +#ifndef M_SPREADER_H +#define M_SPREADER_H + +typedef enum AnimID_e +{ + ANIM_ATTACK1, + ANIM_ATTACK2, + ANIM_BACKUP, + ANIM_BACKATTACK, + ANIM_DEATH1_GO, + ANIM_DEATH1_LOOP, + ANIM_DEATH1_END, + ANIM_DUCK, + ANIM_DUCKATTACK, + ANIM_DUCKDOWN, + ANIM_DUCKSTILL, + ANIM_DUCKUP, + ANIM_IDLE1, + ANIM_PAIN1, + ANIM_PIVOT_LEFT, + ANIM_PIVOT_RIGHT, + ANIM_RUNATTACK, + ANIM_RUN1, + ANIM_LAND, + ANIM_INAIR, + ANIM_FJUMP, + ANIM_WALK1, + ANIM_WALK2, + ANIM_DEATH2, + ANIM_FLY, + ANIM_FLYLOOP, + ANIM_FDIE, + ANIM_DEAD, + ANIM_DELAY, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_SPRAYSTART, + SND_SPRAYLOOP, + SND_PAIN, + SND_VOICE1, + SND_VOICE2, + SND_THROW, + SND_DEATH, + SND_BOMB, + NUM_SOUNDS +} SoundID_t; + +#define BIT_PARENT 0 +#define BIT_CHILD 1 +#define BIT_BODY 2 +#define BIT_BOMB 4 +#define BIT_RITLEG 8 +#define BIT_LFTARM 16 +#define BIT_LFTLEG 32 +#define BIT_HEAD 64 +#define BIT_RITARM 128 +#define BIT_TANK3 256 +#define BIT_TANK2 512 +#define BIT_TANK1 1024 +#define BIT_HOSE 2048 + +static int Bit_for_MeshNode_ps [13] = +{ + BIT_PARENT, + BIT_CHILD, + BIT_BODY, + BIT_BOMB, + BIT_RITLEG, + BIT_LFTARM, + BIT_LFTLEG, + BIT_HEAD, + BIT_RITARM, + BIT_TANK3, + BIT_TANK2, + BIT_TANK1, + BIT_HOSE +}; + +extern animmove_t spreader_move_attack1; +extern animmove_t spreader_move_attack2; +extern animmove_t spreader_move_backup1; +extern animmove_t spreader_move_backattack1; +extern animmove_t spreader_move_death1_go; +extern animmove_t spreader_move_death1_loop; +extern animmove_t spreader_move_death1_end; +extern animmove_t spreader_move_duck1; +extern animmove_t spreader_move_dkatck1; +extern animmove_t spreader_move_duckdown; +extern animmove_t spreader_move_duckstill; +extern animmove_t spreader_move_duckup; +extern animmove_t spreader_move_idle1; +extern animmove_t spreader_move_pain1; +extern animmove_t spreader_move_pvtlt1; +extern animmove_t spreader_move_pvtrt1; +extern animmove_t spreader_move_rnatck1; +extern animmove_t spreader_move_run1; +extern animmove_t spreader_move_land; +extern animmove_t spreader_move_inair; +extern animmove_t spreader_move_fjump; +extern animmove_t spreader_move_walk1; +extern animmove_t spreader_move_walk2; +extern animmove_t spreader_move_death2; +extern animmove_t spreader_move_flyloop; +extern animmove_t spreader_move_fly; +extern animmove_t spreader_move_fdie; +extern animmove_t spreader_move_dead; +extern animmove_t spreader_move_delay; + +void spreader_mist(edict_t *self, float x, float y, float z); + +void SpreaderStaticsInit(); +void spreaderFly (edict_t *self); +void spreaderTakeOff (edict_t *self); +void spreaderFlyLoop (edict_t *self); +void spreader_dropweapon (edict_t *self); +void spreader_go_deadloop (edict_t *self); +void spreaderSolidAgain (edict_t *self); +void M_MoveFrame (edict_t *self); + +void spreader_dismember(edict_t *self, int damage, int HitLocation); + +void spreader_pause(edict_t *self); +void spreader_crouch(edict_t *self); +void spreader_uncrouch(edict_t *self); +void spreader_duckpause(edict_t *self); +void spreader_death(edict_t *self, G_Message_t *msg); +void spreader_dead(edict_t *self); + +void spreader_flyback_move(edict_t *self); +void spreader_flyback_loop(edict_t *self); + +void spreader_showgrenade(edict_t *self); +void spreader_pain_sound(edict_t *self); +void spreader_miststartsound(edict_t *self); +void spreader_miststopsound(edict_t *self); +void spreader_idlenoise(edict_t *self); +void spreader_hidegrenade(edict_t *self); +void spreaderApplyJump (edict_t *self); +void spreader_land(edict_t *self); +void spreader_jump (edict_t *self, G_Message_t *msg); +void spreader_go_inair (edict_t *self); +void MG_CheckLanded (edict_t *self, float next_anim); + +edict_t *RadiusDamageEnt(edict_t *posowner, edict_t *dmgowner, int damage, float d_damage, float radius, float d_radius, int dflags, float lifetime, float thinkIncrement, vec3_t origin, vec3_t offset, float attach); + +#endif //M_SPREADER_H diff --git a/Toolkit/Programming/GameCode/game/m_spreader_anim.c b/Toolkit/Programming/GameCode/game/m_spreader_anim.c new file mode 100644 index 0000000..e9692b3 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_spreader_anim.c @@ -0,0 +1,492 @@ +//============================================================================== +// +// m_spreader_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_spreader_anim.h" +#include "m_spreadermist.h" +#include "m_spreader.h" + +void ai_charge2 (edict_t *self, float dist); + +/*------------------------------------------------------------------ + spreader attack 1 -- the throw +-------------------------------------------------------------------*/ +animframe_t spreader_frames_attack1 [] = +{ + FRAME_atacka1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka6, NULL, 0, 0, 0, ai_charge2, 0, spreader_showgrenade, + FRAME_atacka7, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka8, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka9, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka10, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka11, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka12, NULL, 0, 0, 0, ai_charge2, 0, spreader_hidegrenade, + FRAME_atacka13, NULL, 0, 0, 0, ai_charge2, 0, spreader_toss_grenade, + FRAME_atacka14, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka15, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atacka16, NULL, 0, 0, 0, ai_charge2, 0, NULL +}; +animmove_t spreader_move_attack1 = { 16, spreader_frames_attack1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader attack 2 -- the plague effect attack + + Using the move func for the spreader mist instead of the action + func because the action func is already being used as a move + func... +-------------------------------------------------------------------*/ +animframe_t spreader_frames_attack2 [] = +{ + FRAME_atackb1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atackb2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atackb3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atackb4, spreader_mist, 14.59, -0.96, 16, ai_charge2, 0, spreader_miststartsound, + FRAME_atackb5, spreader_mist, 12.49, -5.98, 16, ai_charge2, 0, NULL, + FRAME_atackb6, spreader_mist, 10.35, -13.15, 16, ai_charge2, 0, NULL, + FRAME_atackb7, spreader_mist, 6.14, -17.95, 16, ai_charge2, 0, NULL, + FRAME_atackb8, spreader_mist, 2.4, -18.06, 16, ai_charge2, 0, NULL, + FRAME_atackb9, spreader_mist, 6.23, -14.4, 16, ai_charge2, 0, NULL, + FRAME_atackb10, spreader_mist, 12.85, -4.18, 16, ai_charge2, 0, NULL, + FRAME_atackb11, spreader_mist, 13.88, 10.8, 16.36, ai_charge2, 0, NULL, + FRAME_atackb12, spreader_mist, 7.11, 23.19, 16.81, ai_charge2, 0, spreader_miststopsound, + FRAME_atackb13, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_atackb14, NULL, 0, 0, 0, ai_charge2, 0, NULL +}; +animmove_t spreader_move_attack2 = { 14, spreader_frames_attack2, spreader_pause }; + +/*------------------------------------------------------------------ + spreader backattack 1 -- the spreader backpedals while shooting +-------------------------------------------------------------------*/ +animframe_t spreader_frames_backattack1 [] = +{ + FRAME_bkatck1, spreader_mist, 14.4, 10.24, 16, ai_run, -5, spreader_miststartsound, + FRAME_bkatck2, spreader_mist, 14.22, 10.03, 16, ai_run, -5, NULL, + FRAME_bkatck3, spreader_mist, 13.79, 9.79, 16, ai_run, -5, NULL, + FRAME_bkatck4, spreader_mist, 13.62, 9.63, 16, ai_run, -5, NULL, + FRAME_bkatck5, spreader_mist, 13.84, 9.64, 16, ai_run, -5, NULL, + FRAME_bkatck6, spreader_mist, 14.23, 9.75, 16, ai_run, -5, NULL, + FRAME_bkatck7, spreader_mist, 14.59, 9.85, 16, ai_run, -5, NULL, + FRAME_bkatck8, spreader_mist, 14.15, 9.75, 16, ai_run, -5, NULL, + FRAME_bkatck9, spreader_mist, 13.83, 9.66, 16, ai_run, -5, NULL, + FRAME_bkatck10, spreader_mist, 13.58, 9.65, 16, ai_run, -5, NULL, + FRAME_bkatck11, spreader_mist, 13.82, 9.82, 16, ai_run, -5, NULL, + FRAME_bkatck12, spreader_mist, 14.2, 10.06, 16, ai_run, -5, NULL, + FRAME_bkatck13, spreader_mist, 14.47, 10.38, 16, ai_run, -5, spreader_miststopsound +}; +animmove_t spreader_move_backattack1 = { 13, spreader_frames_backattack1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader backup 1 -- the spreader backpedals +-------------------------------------------------------------------*/ +animframe_t spreader_frames_backup1 [] = +{ + FRAME_backup1, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup2, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup3, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup4, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup5, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup6, NULL, 0, 0, 0, ai_run, -5, spreader_pause, + FRAME_backup7, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup8, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup9, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup10, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup11, NULL, 0, 0, 0, ai_run, -5, spreader_pause, + FRAME_backup12, NULL, 0, 0, 0, ai_run, -5, NULL, + FRAME_backup13, NULL, 0, 0, 0, ai_run, -5, NULL +}; +animmove_t spreader_move_backup1 = { 13, spreader_frames_backup1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader death -- the spreader spreads no more (big death) +-------------------------------------------------------------------*/ +animframe_t spreader_frames_death1_go [] = +{ + FRAME_death1, NULL, 0, 0, 0, NULL, 0, spreader_flyback_move, +}; +animmove_t spreader_move_death1_go = { 1, spreader_frames_death1_go, spreader_flyback_loop }; + +animframe_t spreader_frames_death1_loop [] = +{ + FRAME_death2, NULL, 0, 0, 0, NULL, 0, spreader_flyback_move, +}; +animmove_t spreader_move_death1_loop = { 1, spreader_frames_death1_loop, NULL }; + +animframe_t spreader_frames_death1_end [] = +{ + FRAME_death3, NULL, 0, 0, 0, ai_move, -4, spreader_flyback_move, + FRAME_death4, NULL, 0, 0, 0, ai_move, -4, spreader_flyback_move, + FRAME_death5, NULL, 0, 0, 0, ai_move, -4, spreader_flyback_move, + FRAME_death6, NULL, 0, 0, 0, ai_move, -3, spreader_flyback_move, + FRAME_death7, NULL, 0, 0, 0, ai_move, -3, spreader_flyback_move, + FRAME_death8, NULL, 0, 0, 0, ai_move, -3, spreader_flyback_move, + FRAME_death9, NULL, 0, 0, 0, ai_move, -2, spreader_flyback_move, + FRAME_death10, NULL, 0, 0, 0, ai_move, -2, spreader_flyback_move, + FRAME_death11, NULL, 0, 0, 0, ai_move, -2, spreader_flyback_move, + FRAME_death12, NULL, 0, 0, 0, ai_move, -1, spreader_flyback_move, + FRAME_death13, NULL, 0, 0, 0, ai_move, -1, spreader_flyback_move, + FRAME_death14, NULL, 0, 0, 0, ai_move, 0, spreader_flyback_move, + FRAME_death15, NULL, 0, 0, 0, ai_move, 0, spreader_flyback_move, + FRAME_death16, NULL, 0, 0, 0, ai_move, 0, spreader_flyback_move, + FRAME_death17, NULL, 0, 0, 0, ai_move, 0, spreader_dead +}; +animmove_t spreader_move_death1_end = { 15, spreader_frames_death1_end, NULL }; + +/*------------------------------------------------------------------ + spreader death -- the spreader spreads no more (little death) +-------------------------------------------------------------------*/ +animframe_t spreader_frames_death2 [] = +{ + FRAME_deathb1, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb2, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb3, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb4, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb6, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb7, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb9, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb10, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb11, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb12, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb13, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb14, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb16, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_deathb17, NULL, 0, 0, 0, ai_move, 0, spreader_dead +}; +animmove_t spreader_move_death2 = { 14, spreader_frames_death2, NULL }; + + +/*------------------------------------------------------------------ + spreader duck attack 1 -- spreader ducking, shoots, rises +-------------------------------------------------------------------*/ +animframe_t spreader_frames_dkatck1 [] = +{ + FRAME_dkatck_1, spreader_mist, 21.39, 11.26, -16, ai_move, 0, spreader_miststartsound, + FRAME_dkatck_2, spreader_mist, 12.08, 24.16, -16, ai_move, 0, NULL, + FRAME_dkatck_3, spreader_mist, 26.14, 1.26, -16, ai_move, 0, NULL, + FRAME_dkatck_4, spreader_mist, 26.65, -0.43, -16, ai_move, 0, spreader_miststopsound, + FRAME_dkatck_5, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_dkatck_6, NULL, 0, 0, 0, ai_move, 0, NULL +}; +animmove_t spreader_move_dkatck1 = { 6, spreader_frames_dkatck1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader duck -- spreader ducks and rises +-------------------------------------------------------------------*/ +animframe_t spreader_frames_duck1 [] = +{ + FRAME_duck1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duck2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duck3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duck4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duck5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duck6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duck7, NULL, 0, 0, 0, ai_charge2, 0, NULL +}; +animmove_t spreader_move_duck1 = { 7, spreader_frames_duck1, spreader_pause }; + +/*------------------------------------------------------------------------- + spreader ducks +-------------------------------------------------------------------------*/ +animframe_t spreader_frames_duckdown [] = +{ + FRAME_duck1, NULL, 0,0,0, ai_charge2, 0, NULL, + FRAME_duck2, NULL, 0,0,0, ai_charge2, 0, NULL, + FRAME_duck3, NULL, 0,0,0, ai_charge2, 0, NULL, + FRAME_duck4, NULL, 0,0,0, ai_charge2, 0, NULL +}; +animmove_t spreader_move_duckdown = { 4, spreader_frames_duckdown, spreader_duckpause }; + +/*------------------------------------------------------------------ + spreader duck still 1 -- the spreader ducking, still +-------------------------------------------------------------------*/ +animframe_t spreader_frames_duckstill [] = +{ + FRAME_dkidle1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_dkidle12, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t spreader_move_duckstill = { 12, spreader_frames_duckstill, spreader_duckpause }; + + +/*------------------------------------------------------------------------- + spreader rises from a ducking pos +-------------------------------------------------------------------------*/ +animframe_t spreader_frames_duckup [] = +{ + FRAME_duck4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duck5, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duck6, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_duck7, NULL, 0, 0, 0, ai_charge2, 0, NULL +}; +animmove_t spreader_move_duckup = { 4, spreader_frames_duckup, spreader_pause }; + +/*------------------------------------------------------------------ + spreader idle 1 -- the spreader stands around +-------------------------------------------------------------------*/ +animframe_t spreader_frames_idle1 [] = +{ + FRAME_idle1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, ai_stand, 0, spreader_idlenoise, + FRAME_idle4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, ai_stand, 0, NULL +}; +animmove_t spreader_move_idle1 = { 11, spreader_frames_idle1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader pain -- spreader recoils from hit +-------------------------------------------------------------------*/ +animframe_t spreader_frames_pain1 [] = +{ + FRAME_pain1, NULL, 0, 0, 0, ai_move, 0, spreader_pain_sound, + FRAME_pain2, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_pain3, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_pain4, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_pain5, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_pain6, NULL, 0, 0, 0, ai_move, 0, NULL, + FRAME_pain7, NULL, 0, 0, 0, ai_move, 0, NULL +}; +animmove_t spreader_move_pain1 = { 7, spreader_frames_pain1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader pivot left -- spreader turns left +-------------------------------------------------------------------*/ +animframe_t spreader_frames_pvtlt1 [] = +{ + FRAME_pvtlt1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_pvtlt2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_pvtlt3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_pvtlt4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_pvtlt5, NULL, 0, 0, 0, ai_charge2, 0, NULL +}; +animmove_t spreader_move_pvtlt1 = { 5, spreader_frames_pvtlt1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader pivot right -- spreader turns right +-------------------------------------------------------------------*/ +animframe_t spreader_frames_pvtrt1 [] = +{ + FRAME_pvtrt1, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_pvtrt2, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_pvtrt3, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_pvtrt4, NULL, 0, 0, 0, ai_charge2, 0, NULL, + FRAME_pvtrt5, NULL, 0, 0, 0, ai_charge2, 0, NULL +}; +animmove_t spreader_move_pvtrt1 = { 5, spreader_frames_pvtrt1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader run 1 -- the spreader runs +-------------------------------------------------------------------*/ +animframe_t spreader_frames_run1 [] = +{ + FRAME_run1, NULL, 0, 0, 0, ai_run, 20, spreader_pause, + FRAME_run2, NULL, 0, 0, 0, ai_run, 18, NULL, + FRAME_run3, NULL, 0, 0, 0, ai_run, 16, NULL, + FRAME_run4, NULL, 0, 0, 0, ai_run, 18, spreader_pause, //foot down + FRAME_run5, NULL, 0, 0, 0, ai_run, 20, NULL, + FRAME_run6, NULL, 0, 0, 0, ai_run, 18, NULL, + FRAME_run7, NULL, 0, 0, 0, ai_run, 16, NULL, + FRAME_run8, NULL, 0, 0, 0, ai_run, 18, NULL //foot down +}; +animmove_t spreader_move_run1 = { 8, spreader_frames_run1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader land +-------------------------------------------------------------------*/ +animframe_t spreader_frames_land [] = +{ + FRAME_jump17, NULL, 0, 0, 0, NULL, 0, spreader_land, + FRAME_jump18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump20, NULL, 0, 0, 0, NULL, 0, NULL, //foot down + FRAME_jump21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump22, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump23, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t spreader_move_land = {7, spreader_frames_land, spreader_pause}; + +/*------------------------------------------------------------------ + spreader jump from buoy +-------------------------------------------------------------------*/ +animframe_t spreader_frames_inair [] = +{ + FRAME_jump16, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, +}; +animmove_t spreader_move_inair = {1, spreader_frames_inair, NULL}; + +/*------------------------------------------------------------------ + spreader jump from buoy +-------------------------------------------------------------------*/ +animframe_t spreader_frames_fjump [] = +{ + FRAME_jump1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, NULL, 0, NULL, //foot down + FRAME_jump5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, NULL, 0, spreaderApplyJump, + FRAME_jump8, NULL, 0, 0, 0, NULL, 0, NULL, //foot down + FRAME_jump9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump11, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump12, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, //foot down + FRAME_jump13, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump14, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump15, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, +}; +animmove_t spreader_move_fjump = {15, spreader_frames_fjump, spreader_go_inair}; + +/*------------------------------------------------------------------ + spreader run attack -- the spreader runs and shoots +-------------------------------------------------------------------*/ +animframe_t spreader_frames_rnatck1 [] = +{ + FRAME_rnatck1, spreader_mist_fast, 38.0*2, 5, 16, ai_run, 20, spreader_miststartsound, + FRAME_rnatck2, spreader_mist_fast, 39.27*2, 5, 16, ai_run, 18, NULL, + FRAME_rnatck3, spreader_mist_fast, 37.43*2, 5, 16, ai_run, 16, NULL, + FRAME_rnatck4, spreader_mist_fast, 36.68*2, 5, 16, ai_run, 18, spreader_pause, + FRAME_rnatck5, spreader_mist_fast, 37.02*2, 5, 16, ai_run, 20, NULL, + FRAME_rnatck6, spreader_mist_fast, 36.41*2, 5, 16, ai_run, 18, NULL, + FRAME_rnatck7, spreader_mist_fast, 35.69*2, 5, 16, ai_run, 16, spreader_pause, + FRAME_rnatck8, spreader_mist_fast, 35.68*2, 5, 16, ai_run, 18, spreader_pause,//spreader_mist_faststopsound +}; +animmove_t spreader_move_rnatck1 = { 8, spreader_frames_rnatck1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader walk 1 -- the spreader walks +-------------------------------------------------------------------*/ +animframe_t spreader_frames_walk1 [] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_walk, 8, spreader_idlenoise, + FRAME_walk2, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk3, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk4, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk5, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk6, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk7, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk8, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk9, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk10, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk11, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk12, NULL, 0, 0, 0, ai_walk, 8, NULL, + FRAME_walk13, NULL, 0, 0, 0, ai_walk, 8, NULL, +}; +animmove_t spreader_move_walk1 = { 13, spreader_frames_walk1, spreader_pause }; + +/*------------------------------------------------------------------ + spreader walk 2 -- the spreader walks +-------------------------------------------------------------------*/ +animframe_t spreader_frames_walk2 [] = +{ + FRAME_walk1, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk2, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk3, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk4, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk5, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk6, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk7, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk8, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk9, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk10, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk11, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk12, NULL, 0, 0, 0, ai_run, 6, spreader_pause, + FRAME_walk13, NULL, 0, 0, 0, ai_run, 6, spreader_pause +}; +animmove_t spreader_move_walk2 = { 13, spreader_frames_walk2, spreader_pause }; + +/*------------------------------------------------------------------ + spreader fly into air- ouch! +-------------------------------------------------------------------*/ +animframe_t spreader_frames_flyloop [] = +{ + FRAME_pain5, NULL, 0, 0, 0, NULL, 0, spreaderFly, +}; +animmove_t spreader_move_flyloop = { 1, spreader_frames_flyloop, NULL}; + +/*------------------------------------------------------------------ + spreader fly into air- ouch! +-------------------------------------------------------------------*/ +animframe_t spreader_frames_fly [] = +{ + FRAME_pain1, NULL, 0, 0, 0, NULL, 0, spreaderFly, + FRAME_pain2, NULL, 0, 0, 0, NULL, 0, spreaderFly, + FRAME_pain3, NULL, 0, 0, 0, NULL, 0, spreaderFly, + FRAME_pain4, NULL, 0, 0, 0, NULL, 0, spreaderFly, +}; +animmove_t spreader_move_fly = { 4, spreader_frames_fly, spreaderFlyLoop}; + + +animframe_t spreader_frames_dead [] = +{ + FRAME_deathb17, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain +}; +animmove_t spreader_move_dead = { 1, spreader_frames_dead, NULL}; + +animframe_t spreader_frames_fdie [] = +{ + FRAME_deathb1, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb2, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb3, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb4, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb6, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb7, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb9, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb10, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb11, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb12, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb13, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb14, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb16, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain, + FRAME_deathb17, NULL, 0, 0, 0, NULL, 0, spreaderSolidAgain +}; +animmove_t spreader_move_fdie = { 14, spreader_frames_fdie, spreader_go_deadloop}; + +/*------------------------------------------------------------------ + spreader delay +-------------------------------------------------------------------*/ +animframe_t spreader_frames_delay [] = +{ + FRAME_idle1, NULL, 0, 0, 0, NULL, 0, spreader_pause, + FRAME_idle2, NULL, 0, 0, 0, NULL, 0, spreader_pause, + FRAME_idle3, NULL, 0, 0, 0, NULL, 0, spreader_idlenoise, + FRAME_idle4, NULL, 0, 0, 0, NULL, 0, spreader_pause, + FRAME_idle5, NULL, 0, 0, 0, NULL, 0, spreader_pause, + FRAME_idle6, NULL, 0, 0, 0, NULL, 0, spreader_pause, + FRAME_idle7, NULL, 0, 0, 0, NULL, 0, spreader_pause, + FRAME_idle8, NULL, 0, 0, 0, NULL, 0, spreader_pause, + FRAME_idle9, NULL, 0, 0, 0, NULL, 0, spreader_pause, + FRAME_idle10, NULL, 0, 0, 0, NULL, 0, spreader_pause, + FRAME_idle11, NULL, 0, 0, 0, NULL, 0, spreader_pause +}; +animmove_t spreader_move_delay = { 11, spreader_frames_delay, spreader_pause }; diff --git a/Toolkit/Programming/GameCode/game/m_spreader_anim.h b/Toolkit/Programming/GameCode/game/m_spreader_anim.h new file mode 100644 index 0000000..5ba72c1 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_spreader_anim.h @@ -0,0 +1,218 @@ +// R:\Art\models/monsters\spreader + +// This file generated by qdata - Do NOT Modify + +#define FRAME_atacka1 0 +#define FRAME_atacka2 1 +#define FRAME_atacka3 2 +#define FRAME_atacka4 3 +#define FRAME_atacka5 4 +#define FRAME_atacka6 5 +#define FRAME_atacka7 6 +#define FRAME_atacka8 7 +#define FRAME_atacka9 8 +#define FRAME_atacka10 9 +#define FRAME_atacka11 10 +#define FRAME_atacka12 11 +#define FRAME_atacka13 12 +#define FRAME_atacka14 13 +#define FRAME_atacka15 14 +#define FRAME_atacka16 15 +#define FRAME_atackb1 16 +#define FRAME_atackb2 17 +#define FRAME_atackb3 18 +#define FRAME_atackb4 19 +#define FRAME_atackb5 20 +#define FRAME_atackb6 21 +#define FRAME_atackb7 22 +#define FRAME_atackb8 23 +#define FRAME_atackb9 24 +#define FRAME_atackb10 25 +#define FRAME_atackb11 26 +#define FRAME_atackb12 27 +#define FRAME_atackb13 28 +#define FRAME_atackb14 29 +#define FRAME_backup1 30 +#define FRAME_backup2 31 +#define FRAME_backup3 32 +#define FRAME_backup4 33 +#define FRAME_backup5 34 +#define FRAME_backup6 35 +#define FRAME_backup7 36 +#define FRAME_backup8 37 +#define FRAME_backup9 38 +#define FRAME_backup10 39 +#define FRAME_backup11 40 +#define FRAME_backup12 41 +#define FRAME_backup13 42 +#define FRAME_bkatck1 43 +#define FRAME_bkatck2 44 +#define FRAME_bkatck3 45 +#define FRAME_bkatck4 46 +#define FRAME_bkatck5 47 +#define FRAME_bkatck6 48 +#define FRAME_bkatck7 49 +#define FRAME_bkatck8 50 +#define FRAME_bkatck9 51 +#define FRAME_bkatck10 52 +#define FRAME_bkatck11 53 +#define FRAME_bkatck12 54 +#define FRAME_bkatck13 55 +#define FRAME_death1 56 +#define FRAME_death2 57 +#define FRAME_death3 58 +#define FRAME_death4 59 +#define FRAME_death5 60 +#define FRAME_death6 61 +#define FRAME_death7 62 +#define FRAME_death8 63 +#define FRAME_death9 64 +#define FRAME_death10 65 +#define FRAME_death11 66 +#define FRAME_death12 67 +#define FRAME_death13 68 +#define FRAME_death14 69 +#define FRAME_death15 70 +#define FRAME_death16 71 +#define FRAME_death17 72 +#define FRAME_dkatck 73 +#define FRAME_dkatck_1 74 +#define FRAME_dkatck_2 75 +#define FRAME_dkatck_3 76 +#define FRAME_dkatck_4 77 +#define FRAME_dkatck_5 78 +#define FRAME_dkatck_6 79 +#define FRAME_duck1 80 +#define FRAME_duck2 81 +#define FRAME_duck3 82 +#define FRAME_duck4 83 +#define FRAME_duck5 84 +#define FRAME_duck6 85 +#define FRAME_duck7 86 +#define FRAME_idle1 87 +#define FRAME_idle2 88 +#define FRAME_idle3 89 +#define FRAME_idle4 90 +#define FRAME_idle5 91 +#define FRAME_idle6 92 +#define FRAME_idle7 93 +#define FRAME_idle8 94 +#define FRAME_idle9 95 +#define FRAME_idle10 96 +#define FRAME_idle11 97 +#define FRAME_pain1 98 +#define FRAME_pain2 99 +#define FRAME_pain3 100 +#define FRAME_pain4 101 +#define FRAME_pain5 102 +#define FRAME_pain6 103 +#define FRAME_pain7 104 +#define FRAME_pvtlt1 105 +#define FRAME_pvtlt2 106 +#define FRAME_pvtlt3 107 +#define FRAME_pvtlt4 108 +#define FRAME_pvtlt5 109 +#define FRAME_pvtrt1 110 +#define FRAME_pvtrt2 111 +#define FRAME_pvtrt3 112 +#define FRAME_pvtrt4 113 +#define FRAME_pvtrt5 114 +#define FRAME_rnatck1 115 +#define FRAME_rnatck2 116 +#define FRAME_rnatck3 117 +#define FRAME_rnatck4 118 +#define FRAME_rnatck5 119 +#define FRAME_rnatck6 120 +#define FRAME_rnatck7 121 +#define FRAME_rnatck8 122 +#define FRAME_run1 123 +#define FRAME_run2 124 +#define FRAME_run3 125 +#define FRAME_run4 126 +#define FRAME_run5 127 +#define FRAME_run6 128 +#define FRAME_run7 129 +#define FRAME_run8 130 +#define FRAME_walk1 131 +#define FRAME_walk2 132 +#define FRAME_walk3 133 +#define FRAME_walk4 134 +#define FRAME_walk5 135 +#define FRAME_walk6 136 +#define FRAME_walk7 137 +#define FRAME_walk8 138 +#define FRAME_walk9 139 +#define FRAME_walk10 140 +#define FRAME_walk11 141 +#define FRAME_walk12 142 +#define FRAME_walk13 143 +#define FRAME_dkidle1 144 +#define FRAME_dkidle2 145 +#define FRAME_dkidle3 146 +#define FRAME_dkidle4 147 +#define FRAME_dkidle5 148 +#define FRAME_dkidle6 149 +#define FRAME_dkidle7 150 +#define FRAME_dkidle8 151 +#define FRAME_dkidle9 152 +#define FRAME_dkidle10 153 +#define FRAME_dkidle11 154 +#define FRAME_dkidle12 155 +#define FRAME_deathb1 156 +#define FRAME_deathb2 157 +#define FRAME_deathb3 158 +#define FRAME_deathb4 159 +#define FRAME_deathb5 160 +#define FRAME_deathb6 161 +#define FRAME_deathb7 162 +#define FRAME_deathb8 163 +#define FRAME_deathb9 164 +#define FRAME_deathb10 165 +#define FRAME_deathb11 166 +#define FRAME_deathb12 167 +#define FRAME_deathb13 168 +#define FRAME_deathb14 169 +#define FRAME_deathb15 170 +#define FRAME_deathb16 171 +#define FRAME_deathb17 172 +#define FRAME_jump1 173 +#define FRAME_jump2 174 +#define FRAME_jump3 175 +#define FRAME_jump4 176 +#define FRAME_jump5 177 +#define FRAME_jump6 178 +#define FRAME_jump7 179 +#define FRAME_jump8 180 +#define FRAME_jump9 181 +#define FRAME_jump10 182 +#define FRAME_jump11 183 +#define FRAME_jump12 184 +#define FRAME_jump13 185 +#define FRAME_jump14 186 +#define FRAME_jump15 187 +#define FRAME_jump16 188 +#define FRAME_jump17 189 +#define FRAME_jump18 190 +#define FRAME_jump19 191 +#define FRAME_jump20 192 +#define FRAME_jump21 193 +#define FRAME_jump22 194 +#define FRAME_jump23 195 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 13 + +#define MESH__PARENT 0 +#define MESH__CHILD 1 +#define MESH__BODY 2 +#define MESH__BOMB 3 +#define MESH__RITLEG 4 +#define MESH__LFTARM 5 +#define MESH__LFTLEG 6 +#define MESH__HEAD 7 +#define MESH__RITARM 8 +#define MESH__TANK3 9 +#define MESH__TANK2 10 +#define MESH__TANK1 11 +#define MESH__HOSE 12 diff --git a/Toolkit/Programming/GameCode/game/m_spreaderbomb_anim.h b/Toolkit/Programming/GameCode/game/m_spreaderbomb_anim.h new file mode 100644 index 0000000..7460677 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_spreaderbomb_anim.h @@ -0,0 +1,11 @@ +// r:\base\models/monsters\spreader\bomb + +// This file generated by qdata - Do NOT Modify + +#define FRAME_bomb 0 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 1 + +#define MESH_BOMBASE 0 diff --git a/Toolkit/Programming/GameCode/game/m_spreadermist.c b/Toolkit/Programming/GameCode/game/m_spreadermist.c new file mode 100644 index 0000000..17e4767 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_spreadermist.c @@ -0,0 +1,472 @@ +#include "fx.h" +#include "q_typedef.h" +#include "m_spreadermist.h" +#include "m_spreaderbomb_anim.h" +#include "g_local.h" +#include "vector.h" +#include "angles.h" +#include "random.h" +#include "matrix.h" +#include "g_volume_effect.h" +#include "g_ClassStatics.h" +#include "g_monster.h" + +#define SPREADER_GRENADE_DAMAGE (40.0) +#define SPREADER_GRENADE_RADIUS (100.0) +#define SPREADER_GRENADE_TIME (2.9F) + + +//NOTE:.this would be wrong if the sounds array in +//spreader.h changes +#define SND_BOMB 7 + +/*------------------------------------------------------------------------- + VolumeEffectThink +-------------------------------------------------------------------------*/ +void GenericRadiusDamageEntThink(edict_t *self) +{ + if(self->air_finishedyaw_speed) + {//apply my offset + if(self->activator) + { + if(Vec3NotZero(self->activator->s.origin)) + { + vec3_t forward, right, up; + + AngleVectors(self->activator->s.angles, forward, right, up); + + VectorMA(self->activator->s.origin, self->v_angle_ofs[0], forward, self->s.origin); + VectorMA(self->s.origin, self->v_angle_ofs[1], right, self->s.origin); + VectorMA(self->s.origin, self->v_angle_ofs[2], up, self->s.origin); + } + } + } + + T_DamageRadius(self, self->owner, self->owner, self->dmg_radius, self->dmg, 1, self->bloodType,MOD_DIED); + + self->dmg_radius -= self->speed; + if(self->dmg_radius<=0) + { + G_SetToFree(self); + return; + } + + self->dmg -= self->damage_debounce_time; + if(self->dmg<=0) + { + G_SetToFree(self); + return; + } + + self->nextthink = level.time + self->wait; +} + +edict_t *RadiusDamageEnt( edict_t *posowner,//for position + edict_t *dmgowner,//for damage credit + int damage,//damage + float d_damage,//d_damage + float radius,//radius + float d_radius,//d_radius + int dflags,//dflags + float lifetime,//lifetime + float thinkIncrement,//thinktime + vec3_t origin,//start origin + vec3_t offset,//velocity it not attached + float attach)//attach to posowner as offset? +{ + edict_t *self; + + assert(dmgowner); + + self = G_Spawn(); + + self->owner = dmgowner;//for damage + self->dmg = damage;//starting damage - (int) + self->damage_debounce_time = d_damage;//damage amount to decrease by each think + self->dmg_radius = radius;//radius of damage + self->speed = d_radius;//amount to change radius each think + self->bloodType = dflags;//damage flags + self->classname = "plague_mist"; + + self->air_finished = level.time + lifetime;//when to die out + + if(thinkIncrement<=0) + self->wait = 0.1;//default to 10 fps + else + self->wait = thinkIncrement;//how oftern to think + + self->think = GenericRadiusDamageEntThink;//what to do + self->nextthink = level.time + self->wait;//next think + + self->activator = posowner;//for offsetting + if(attach) + { + vec3_t forward, right, up; + + AngleVectors(self->activator->s.angles, forward, right, up); + + VectorCopy(offset, self->v_angle_ofs);// where to keep me- offset in {f, r, u} + + VectorMA(self->activator->s.origin, self->v_angle_ofs[0], forward, self->s.origin); + VectorMA(self->s.origin, self->v_angle_ofs[1], right, self->s.origin); + VectorMA(self->s.origin, self->v_angle_ofs[2], up, self->s.origin); + self->yaw_speed = attach;//whether to keep that offset from the owner or just sit here + } + else + { + self->movetype = PHYSICSTYPE_FLY; + self->gravity = 0; + + VectorCopy(offset, self->velocity); + VectorCopy(origin, self->s.origin); + } + + return self; +} + +/*------------------------------------------------------------------------- + spreader_grenade_explode +-------------------------------------------------------------------------*/ + +static void spreader_grenade_explode (edict_t *self) +{ + vec3_t origin; +// self->s.fmnodeinfo[MESH_BOMBASE].flags |= FMNI_NO_DRAW; + self->s.modelindex = 0; + + self->dmg = 1; + VectorMA (self->s.origin, -0.02, self->velocity, origin); + gi.CreateEffect(NULL, FX_PLAGUEMISTEXPLODE, 0, origin, "b", 3500 / 50); + self->nextthink = level.time + 0.2; + self->monsterinfo.thinkinc = 0.2; + self->think = spreader_grenade_think; + gi.sound(self, CHAN_AUTO, classStatics[CID_SPREADER].resInfo->sounds[SND_BOMB], + 1, ATTN_IDLE, 0); + PauseTime(self, SPREADER_GRENADE_TIME); + + self->bounced = NULL; + self->isBlocked = NULL; +// self->think = G_FreeEdict; +// self->nextthink = level.time + self->delay; +} + +/*------------------------------------------------------------------------- + spreader_grenade_die +-------------------------------------------------------------------------*/ +void spreader_grenade_die(edict_t *self) +{ + G_FreeEdict(self); +} + +/*------------------------------------------------------------------------- + spreader_grenade_think +-------------------------------------------------------------------------*/ +static void spreader_grenade_think(edict_t *self) +{ + edict_t *ent; + vec3_t temp; + + self->movetype = PHYSICSTYPE_NONE; + self->solid = SOLID_NOT; + + if(self->monsterinfo.pausetime < level.time) + { + self->think = spreader_grenade_die; + } + else + { + ent = NULL; + while ((ent = findradius(ent, self->s.origin, self->dmg_radius)) != NULL) + { + VectorCopy(ent->s.origin, temp); + temp[2] += 5; + if(!Q_stricmp(ent->classname, "monster_spreader")) + continue; + + if(!gi.inPVS(self->s.origin, ent->s.origin)) + continue; + + T_Damage(ent,self, self->owner, temp, self->s.origin, vec3_origin,self->dmg, + (int)0, DAMAGE_NO_BLOOD|DAMAGE_NO_KNOCKBACK|DAMAGE_ALIVE_ONLY|DAMAGE_AVOID_ARMOR,MOD_DIED); + } + } + + self->nextthink = level.time + FRAMETIME; +} + +static void spreader_grenade_bounce ( edict_t *self, struct trace_s *trace ) +{ + vec3_t vel; + + if (trace->plane.normal[2] > 0.1) + { + VectorCopy(self->velocity, vel); + VectorNormalize(vel); + VectorScale(vel, 100, vel); + + vel[0] += flrand(-100, 100); + vel[1] += flrand(-100, 100); + vel[2] = flrand(10, 100); + + // create the volume effect for the damage +/* + gas = RadiusDamageEnt(self,//position + self->owner,//damage credit + 5,//damage + 0,//d_damage + 60,//radius + 1.0,//d_radius + DAMAGE_NO_BLOOD|DAMAGE_NO_KNOCKBACK|DAMAGE_ALIVE_ONLY|DAMAGE_AVOID_ARMOR,//dflags + self->delay,//lifetime + 0.2,//thinktime + self->s.origin,//startpoint + vel,//velocity + false);//attach to owner until gone + + gas->svflags |= SVF_ALWAYS_SEND; + gas->s.effects=EF_MARCUS_FLAG1; +*/ + gi.CreateEffect(&self->s, FX_PLAGUEMIST, CEF_OWNERS_ORIGIN, self->s.origin, "vb", vel, 50); + + spreader_grenade_explode (self); + } +} + +/*------------------------------------------------------------------------- + spreader_grenade_touch +-------------------------------------------------------------------------*/ +static void spreader_grenade_touch (edict_t *self, edict_t *other, cplane_t *plane, + csurface_t *surf) +{ + vec3_t vel; + + if (other == self->owner) + return; + + if (surf && (surf->flags & SURF_SKY)) + { + G_FreeEdict (self); + return; + } + + VectorCopy(self->velocity, vel); + VectorNormalize(vel); + VectorScale(vel, 100, vel); + + vel[0] += flrand(-100, 100); + vel[1] += flrand(-100, 100); + vel[2] = flrand(10, 100); + + // create the volume effect for the damage +/* gas = RadiusDamageEnt(self,//position + self->owner,//damage credit + 5,//damage + 0,//d_damage + 60,//radius + 1.0,//d_radius + DAMAGE_NO_BLOOD|DAMAGE_NO_KNOCKBACK|DAMAGE_ALIVE_ONLY|DAMAGE_AVOID_ARMOR,//dflags + self->delay,//lifetime + 0.2,//thinktime + self->s.origin,//startpoint + vel,//velocity + false);//attach to owner until gone + + gas->svflags |= SVF_ALWAYS_SEND; + gas->s.effects=EF_MARCUS_FLAG1; +*/ + gi.CreateEffect(&self->s, FX_PLAGUEMIST, CEF_OWNERS_ORIGIN, self->s.origin, "vb", vel, 50); + + spreader_grenade_explode (self); + + self->touch = NULL; + self->bounced = NULL; + self->isBlocked = NULL; +} + + +/*------------------------------------------------------------------------- + spreader_mist +-------------------------------------------------------------------------*/ +void spreader_mist(edict_t *self, float x, float y, float z) +{ + vec3_t offset; + vec3_t rotoffset; + vec3_t normalized; + vec3_t velocity; + float yaw; + matrix3_t mat; + + if(self->monsterinfo.aiflags & AI_NO_MELEE) + return;//fixme: actually prevent these anims + + // Converts degrees to radians for use with trig and matrix functions + yaw = self->s.angles[YAW] * ANGLE_TO_RAD; + + // Sets offset presuming yaw of zero + VectorSet(offset, x, y, z); + + // Creates a rotation matrix to rotate the point about the z axis + CreateYawMatrix(mat, yaw); + + // Rotates point about local z axis + Matrix3MultByVec3(mat, offset, rotoffset); + + // Get normalized offset + VectorCopy(rotoffset, normalized); + normalized[2] = 0.0F; + VectorNormalize(normalized); + + // Add offset to owners origin + Vec3AddAssign(self->s.origin, rotoffset); + + // Get direction vector scaled by speed + VectorSet(velocity, cos(yaw) * 200.0F, sin(yaw) * 200.0F, 0); + + gi.CreateEffect(NULL, FX_PLAGUEMIST, 0, rotoffset, "vb", velocity, 2050 / 50); + + // create the volume effect for the damage + RadiusDamageEnt(self,//owner + self,//damage-owner + 1,//damage + 0,//d_damage + 60,//radius + 1.0,//d_radius + DAMAGE_NO_BLOOD|DAMAGE_NO_KNOCKBACK|DAMAGE_ALIVE_ONLY|DAMAGE_AVOID_ARMOR,//dflags + 2.0,//lifetime + 0.25,//thinkincr + rotoffset,//origin + velocity,//velocity or offset + false);//offset from owner? + + self->monsterinfo.attack_finished = level.time + (3 - skill->value) + flrand(0.5, 1); +} + + +void spreader_mist_fast(edict_t *self, float x, float y, float z) +{ + vec3_t offset; + vec3_t rotoffset; + vec3_t normalized; + vec3_t velocity; + float yaw; + matrix3_t mat; + + // Converts degrees to radians for use with trig and matrix functions + yaw = self->s.angles[YAW] * ANGLE_TO_RAD; + + // Sets offset presuming yaw of zero + VectorSet(offset, x, y, z); + + // Creates a rotation matrix to rotate the point about the z axis + CreateYawMatrix(mat, yaw); + + // Rotates point about local z axis + Matrix3MultByVec3(mat, offset, rotoffset); + + // Get normalized offset + VectorCopy(rotoffset, normalized); + normalized[2] = 0.0F; + VectorNormalize(normalized); + + // Add offset to owners origin + Vec3AddAssign(self->s.origin, rotoffset); + + // Get direction vector scaled by speed + VectorSet(velocity, cos(yaw) * 300.0F, sin(yaw) * 300.0F, 0); + + gi.CreateEffect(NULL, FX_PLAGUEMIST, 0, rotoffset, "vb", velocity, 2050 / 50); + + // create the volume effect for the damage + + //FIXME: Skill modifier here + RadiusDamageEnt(self,//owner + self,//damage-owner + 1,//damage + 0,//d_damage + 60,//radius + 1.0,//d_radius + DAMAGE_NO_BLOOD|DAMAGE_NO_KNOCKBACK|DAMAGE_ALIVE_ONLY|DAMAGE_AVOID_ARMOR,//dflags + 2.0,//lifetime + 0.25,//thinkincr + rotoffset,//origin + velocity,//velocity or offset + false);//offset from owner? +} + +/*------------------------------------------------------------------------- + spreader_toss_grenade -- this is where the grenade actually gets to + come to life and become; sorry about the confusion between this and + spreader_throw(). This is a "think func" for the + spreader_move_attack1 animmove_t +-------------------------------------------------------------------------*/ +void spreader_toss_grenade(edict_t *self) //self is the tosser +{ + edict_t *grenade; + vec3_t start; + vec3_t forward, right, up; + vec3_t aim; + vec3_t offset = {12, 10, 68}; + vec3_t dir; + vec3_t v; + vec3_t predPos; + float distance; + + if(self->monsterinfo.aiflags & AI_NO_MISSILE) + return;//fixme: actually prevent these anims + + AngleVectors (self->s.angles, forward, right, NULL); + G_ProjectSource (self->s.origin, offset, forward, right, start); + + grenade = G_Spawn(); + VectorCopy (start, grenade->s.origin); + + M_PredictTargetPosition( self->enemy, self->enemy->velocity, 15, predPos); + + VectorSubtract(self->s.origin, predPos, v); + distance = VectorLength (v); + distance *= 1.25; + + VectorCopy (forward, aim); + vectoangles (aim, dir); + AngleVectors (dir, forward, right, up); + + VectorScale (aim, distance, grenade->velocity); + VectorMA (grenade->velocity, flrand(100.0F, 125.0F), up, grenade->velocity); + + //FIXME: Difficulty modifier here + VectorMA (grenade->velocity, flrand(-10.0F, 10.0F), right, grenade->velocity); + + VectorSet (grenade->avelocity, flrand(300,600), flrand(300,600), flrand(300,600)); + + grenade->movetype = PHYSICSTYPE_STEP; + grenade->elasticity = 1; + grenade->friction = 1; + grenade->clipmask = MASK_SHOT; + grenade->solid = SOLID_BBOX; + VectorSet (grenade->mins, -1, -1, -1); + VectorSet (grenade->maxs, 1, 1, 1); + + grenade->s.modelindex = gi.modelindex ("models/monsters/spreader/bomb/tris.fm"); + grenade->owner = self; + //grenade->touch = spreader_grenade_touch; + grenade->bounced = spreader_grenade_bounce; + grenade->isBlocked = spreader_grenade_bounce; + self->delay = 5.0; + //grenade->isBlocked = spreader_grenade_blocked; + //grenade->think = spreader_grenade_explode; + grenade->dmg = SPREADER_GRENADE_DAMAGE; + + //FIXME: difficulty modifier here + grenade->dmg_radius = SPREADER_GRENADE_RADIUS; + grenade->classname = "spreader_grenade"; + + grenade->s.effects |= EF_CAMERA_NO_CLIP; + gi.linkentity (grenade); +} + diff --git a/Toolkit/Programming/GameCode/game/m_spreadermist.h b/Toolkit/Programming/GameCode/game/m_spreadermist.h new file mode 100644 index 0000000..75aa4e3 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_spreadermist.h @@ -0,0 +1,20 @@ +#ifndef _M_SPREADERMIST_H_ +#define _M_SPREADERMIST_H_ + +#include "q_typedef.h" +#include "q_shared.h" +#include "g_local.h" +#include "g_volume_effect.h" + +void spreader_grenade_die(edict_t *self); +static void spreader_grenade_explode (edict_t *self); +static void spreader_grenade_think(edict_t *self); +static void spreader_grenade_touch (edict_t *ent, edict_t *other, cplane_t *plane, + csurface_t *surf); + +void spreader_mist_fast(edict_t *self, float x, float y, float z); +void spreader_mist(edict_t *self, float x, float y, float z); +void spreader_toss_grenade(edict_t *self); +void mist_damage_think(edict_t *victim, volume_effect_t *vol); + +#endif diff --git a/Toolkit/Programming/GameCode/game/m_stats.c b/Toolkit/Programming/GameCode/game/m_stats.c new file mode 100644 index 0000000..2b5baa5 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_stats.c @@ -0,0 +1,392 @@ +#include "m_stats.h" + +/* +int AttackRangesForClass [NUM_ATTACKRANGES] = + +melee_range = How close an enemy must be to use melee attack. + If negative, how much distance the monster tries to keep + between itself and an enemy. +missile_range = Maximum distance a monster will try to attack + from using it's ranged attack. +min_missile_range = min range at which a monster will not use + it's missile attack (too close) +bypass_missile_chance = 0 - 100 chance of a monster not taking + a shot even when it can, otherwise it will close in. +*/ + +int AttackRangesForClass [NUM_ATTACKRANGES] = +{ +//melee_rng,missile_rng,min_msl_rng,bypass_missile_chance + 0, 0, 0, 0,// CID_NONE, -- NA - 0 + 0, 0, 0, 0,// CID_RAT, -- JW + 72, 150, 50, 20,// CID_GORGON, -- MG + 50, 0, 0, 0,// CID_PLAGUEELF, -- MG + 0, 256, 48, 0,// CID_GKROKON, -- JW + 0, 0, 0, 0,// CID_FISH, -- ? - 5 + 0, 0, 0, 0,// CID_OBJECT, -- NA + 0, 0, 0, 0,// CID_LIGHT, -- NA + 0, 0, 0, 0,// CID_TRIGGER, -- NA + 0, 0, 0, 0,// CID_HARPY, -- JW + 100, 512, 200, 50,// CID_SPREADER, -- JW - 10 + 0, 0, 0, 0,// CID_ELFLORD, -- JW + 0, 0, 0, 0,// CID_BBRUSH, -- NA + 0, 0, 0, 0,// CID_FUNC_ROTATE, -- NA + 0, 0, 0, 0,// CID_FUNC_DOOR, -- NA + 0, 0, 0, 0,// CID_CHICKEN, + 64, 512, 64, 50,// CID_SSITHRA, -- MG + 0, 0, 0, 0,// CID_SPELL, -- NA - 15 + 100, 800, 100, 25,// CID_MSSITHRA, -- MG + 48, 0, 0, 0,// CID_OGLE, -- JW + 100, 0, 0, 0,// CID_SERAPH_OVERLORD, -- JW + 100, 1024, 64, 85,// CID_SERAPH_GUARD, -- JW + 48, 1024, 64, 10,// CID_ASSASSIN, -- MG - 20 + 0, 0, 0, 0,// CID_TELEPORTER, -- NA + 0, 0, 0, 0,// CID_HIGHPRIESTESS, + -72, 512, 48, 0,// CID_TCHECKRIK, -- MG + 0, 0, 0, 0,// CID_BUTTON, -- NA + 0, 0, 0, 0,// CID_BEE, -- ? - 25 + 0, 0, 0, 0,// CID_CORVUS, + 64, 1024, 64, 25,// CID_MORK, + 400, 1500, 100, 77,// CID_TBEAST,//30 + -64, 1024, 32, 20,// CID_IMP, + + 0, 0, 0, 0,// CID_SSITHRA_VICTIM, //32 + 0, 0, 0, 0,// CID_SSITHRA_SCOUT, //33 + 0, 0, 0, 0,// CID_DRANOR, //34 + + 0, 0, 0, 0,// CID_TRIG_DAMAGE, //35 + 0, 0, 0, 0,// CID_TRIG_PUSH, //36 + 0, 0, 0, 0,// CID_C_ELFLORD, //37 + 0, 0, 0, 0,// CID_C_SIERNAN1, //38 + 0, 0, 0, 0,// CID_C_SIERNAN2, //39 + 0, 0, 0, 0,// CID_C_HIGHPRIESTESS,//40 + 0, 0, 0, 0,// CID_C_HIGHPRIESTESS2,//41 + 0, 0, 0, 0,// CID_C_TOME, //42 + 0, 0, 0, 0,// CID_C_MORCALAVIN, //43 + 0, 0, 0, 0,// CID_CORVUS2, //44 + 0, 0, 0, 0,// CID_CORVUS3, //45 + 0, 0, 0, 0,// CID_CORVUS4, //46 + 0, 0, 0, 0,// CID_CORVUS5, //47 + 0, 0, 0, 0,// CID_CORVUS6, //48 + 0, 0, 0, 0,// CID_CORVUS7, //49 + 0, 0, 0, 0,// CID_CORVUS8, //50 + 0, 0, 0, 0,// CID_CORVUS9, //51 +}; + +/* +byte *MaxBuoysForClass[NUM_CLASSIDS] + + MG + + This table determines how many buoys a monster will search + through in a line before it goes back and tries a different + buoy path. Helps cut down the hit of searching through + buoys and helps find the shorter path if there is one. +*/ +byte MaxBuoysForClass[NUM_CLASSIDS] = +{ + 0,// CID_NONE, + 8,// CID_RAT, + 20,// CID_GORGON, + 16,// CID_PLAGUEELF, + 12,// CID_GKROKON, + 6,// CID_FISH, + 0,// CID_OBJECT, + 0,// CID_LIGHT, + 0,// CID_TRIGGER, + 14,// CID_HARPY, + 24,// CID_SPREADER, + 0,// CID_ELFLORD, + 0,// CID_BBRUSH, + 0,// CID_FUNC_ROTATE, -- NA + 0,// CID_FUNC_DOOR, -- NA + 12,// CID_CHICKEN, + 28,// CID_SSITHRA, + 0,// CID_SPELL, + 16,// CID_MSSITHRA, + 8,// CID_OGLE, + 24,// CID_SERAPH_OVERLORD, + 20,// CID_SERAPH_GUARD, + 64,// CID_ASSASSIN, + 0,// CID_TELEPORTER, + 16,// CID_HIGHPRIESTESS, + 32,// CID_TCHECKRIK, + 0,// CID_BUTTON, + 6,// CID_BEE, + 0,// CID_CORVUS, + 40,// CID_MORK, + 100,// CID_BEAST, + 14,// CID_IMP, + + 0,// CID_SSITHRA_VICTIM, //32 + 0,// CID_SSITHRA_SCOUT, //33 + 0,// CID_DRANOR, //34 + + 0,// CID_TRIG_DAMAGE, //35 + 0,// CID_TRIG_PUSH, //36 + 0,// CID_C_ELFLORD, //37 + 0,// CID_C_SIERNAN1, //38 + 0,// CID_C_SIERNAN2, //39 + 0,// CID_C_HIGHPRIESTESS,//40 + 0,// CID_C_HIGHPRIESTESS2,//41 + 0,// CID_C_TOME, //42 + 0,// CID_C_MORCALAVIN, //43 + 0,// CID_CORVUS2, //44 + 0,// CID_CORVUS3, //45 + 0,// CID_CORVUS4, //46 + 0,// CID_CORVUS5, //47 + 0,// CID_CORVUS6, //48 + 0,// CID_CORVUS7, //49 + 0,// CID_CORVUS8, //50 + 0,// CID_CORVUS9, //51 +}; + +/* +int JumpChanceForClass[NUM_CLASSIDS] = + + MG + + 0 - 100 chance that a monster will + check and see if it can jump when it + hits a ledge +*/ +int JumpChanceForClass[NUM_CLASSIDS] = +{ + 0,// CID_NONE, + 100,// CID_RAT, + 80,// CID_GORGON, + 50,// CID_PLAGUEELF, + 100,// CID_GKROKON, + 0,// CID_FISH, + 0,// CID_OBJECT, + 0,// CID_LIGHT, + 0,// CID_TRIGGER, + 0,// CID_HARPY, + 30,// CID_SPREADER, + 0,// CID_ELFLORD, + 0,// CID_BBRUSH, + 0,// CID_FUNC_ROTATE, -- NA + 0,// CID_FUNC_DOOR, -- NA + 100,// CID_CHICKEN, + 100,// CID_SSITHRA, + 0,// CID_SPELL, + 25,// CID_MSSITHRA, + 10,// CID_OGLE, + 30,// CID_SERAPH_OVERLORD, + 20,// CID_SERAPH_GUARD, + 100,// CID_ASSASSIN, + 0,// CID_TELEPORTER, + 0,// CID_HIGHPRIESTESS, + 40,// CID_TCHECKRIK, + 0,// CID_BUTTON, + 0,// CID_BEE, + 0,// CID_CORVUS, + 0,// CID_MORK, + 100,// CID_TBEAST, + 0,// CID_IMP, + + 0,// CID_SSITHRA_VICTIM, //32 + 0,// CID_SSITHRA_SCOUT, //33 + 0,// CID_DRANOR, //34 + + 0,// CID_TRIG_DAMAGE, //35 + 0,// CID_TRIG_PUSH, //36 + 0,// CID_C_ELFLORD, //37 + 0,// CID_C_SIERNAN1, //38 + 0,// CID_C_SIERNAN2, //39 + 0,// CID_C_HIGHPRIESTESS,//40 + 0,// CID_C_HIGHPRIESTESS2,//41 + 0,// CID_C_TOME, //42 + 0,// CID_C_MORCALAVIN, //43 + 0,// CID_CORVUS2, //44 + 0,// CID_CORVUS3, //45 + 0,// CID_CORVUS4, //46 + 0,// CID_CORVUS5, //47 + 0,// CID_CORVUS6, //48 + 0,// CID_CORVUS7, //49 + 0,// CID_CORVUS8, //50 + 0,// CID_CORVUS9, //51 +}; + +struct MonsterShadow_s G_MonsterShadow[NUM_CLASSIDS] = +{ +//useShadow //scale + 0, 0, // CID_NONE + 1, 0.75, // CID_RAT + 1, 1.0, // CID_GORGON + 1, 1.5, // CID_PLAGUEELF + 1, 1.0, // CID_GKROKON + 0, 0.0, // CID_FISH + 0, 0.0, // CID_OBJECT + 0, 0.0, // CID_LIGHT + 0, 0.0, // CID_TRIGGER + 0, 0.0, // CID_HARPY + 1, 1.0, // CID_SPREADER + 0, 0.0, // CID_ELFLORD + 0, 0.0, // CID_BBRUSH + 0, 0.0, // CID_FUNC_ROTATE, -- NA + 0, 0.0, // CID_FUNC_DOOR, -- NA + 1, 1.0, // CID_CHICKEN + 1, 1.0, // CID_SSITHRA + 0, 0.0, // CID_SPELL + 1, 1.0, // CID_MSSITHRA + 1, 1.0, // CID_OGLE + 1, 1.0, // CID_SERAPH_OVERLORD + 1, 1.0, // CID_SERAPH_GUARD + 1, 1.0, // CID_ASSASSIN + 0, 0.0, // CID_TELEPORTER + 1, 1.0, // CID_HIGHPRIESTESS + 1, 1.0, // CID_TCHECKRIK + 0, 0.0, // CID_BUTTON + 0, 0.0, // CID_BEE, + 0, 0.0, // CID_CORVUS, + 1, 1.0, // CID_MORK, + 1, 1.0, // CID_TBEAST, + 0, 0.0, // CID_IMP + + 0, 0.0, // CID_SSITHRA_VICTIM, //32 + 0, 0.0, // CID_SSITHRA_SCOUT, //33 + 0, 0.0, // CID_DRANOR, //34 + + 0, 0.0, // CID_TRIG_DAMAGE, //35 + 0, 0.0, // CID_TRIG_PUSH, //36 + 0, 0.0, // CID_C_ELFLORD, //37 + 0, 0.0, // CID_C_SIERNAN1, //38 + 0, 0.0, // CID_C_SIERNAN2, //39 + 0, 0.0, // CID_C_HIGHPRIESTESS,//40 + 0, 0.0, // CID_C_HIGHPRIESTESS2,//41 + 0, 0.0, // CID_C_TOME, //42 + 0, 0.0, // CID_C_MORCALAVIN, //43 + 0, 0.0, // CID_CORVUS2, //44 + 0, 0.0, // CID_CORVUS3, //45 + 0, 0.0, // CID_CORVUS4, //46 + 0, 0.0, // CID_CORVUS5, //47 + 0, 0.0, // CID_CORVUS6, //48 + 0, 0.0, // CID_CORVUS7, //49 + 0, 0.0, // CID_CORVUS8, //50 + 0, 0.0, // CID_CORVUS9, //51 +}; + + +vec3_t STDMinsForClass [NUM_CLASSIDS] = +{ +//melee_rng,missile_rng,min_msl_rng,bypass_missile_chance + 0, 0, 0,// CID_NONE, -- NA - 0 + -8, -8, 0,// CID_RAT, -- JW + -16, -16, -16,// CID_GORGON, -- MG + -16, -16, -32,// CID_PLAGUEELF, -- MG + -20.0, -20.0, 0.0,// CID_GKROKON, -- JW + 0, 0, 0,// CID_FISH, -- ? - 5 + 0, 0, 0,// CID_OBJECT, -- NA + 0, 0, 0,// CID_LIGHT, -- NA + 0, 0, 0,// CID_TRIGGER, -- NA + -16, -16, -12,// CID_HARPY, -- JW + -16, -16, -40,// CID_SPREADER, -- JW - 10 + 0, 0, 0,// CID_ELFLORD, -- JW + 0, 0, 0,// CID_BBRUSH, -- NA + 0, 0, 0,// CID_FUNC_ROTATE, -- NA + 0, 0, 0,// CID_FUNC_DOOR, -- NA + 0, 0, 0,// CID_CHICKEN, + -16, -16, -26,// CID_SSITHRA, -- MG + 0, 0, 0,// CID_SPELL, -- NA - 15 + -36, -36, 0,// CID_MSSITHRA, -- MG + -16, -16, -24,// CID_OGLE, -- JW + -24, -24, -34,// CID_SERAPH_OVERLORD, -- JW + -24, -24, -34,// CID_SERAPH_GUARD, -- JW + -16, -16, -32,// CID_ASSASSIN, -- MG - 20 + 0, 0, 0,// CID_TELEPORTER, -- NA + 0, 0, 0,// CID_HIGHPRIESTESS, + -16, -16, -32,// CID_TCHECKRIK, -- MG + 0, 0, 0,// CID_BUTTON, -- NA + 0, 0, 0,// CID_BEE, -- ? - 25 + 0, 0, 0,// CID_CORVUS, + 0, 0, 0,// CID_MORK, + 0, 0, 0,// CID_TBEAST,//30 + -16, -16, 0,// CID_IMP, + + 0, 0, 0,// CID_SSITHRA_VICTIM, //32 + 0, 0, 0,// CID_SSITHRA_SCOUT, //33 + 0, 0, 0,// CID_DRANOR, //34 + + 0, 0, 0, // CID_TRIG_DAMAGE, //35 + 0, 0, 0, // CID_TRIG_PUSH, //36 + 0, 0, 0, // CID_C_ELFLORD, //37 + 0, 0, 0, // CID_C_SIERNAN1, //38 + 0, 0, 0, // CID_C_SIERNAN2, //39 + 0, 0, 0, // CID_C_HIGHPRIESTESS,//40 + 0, 0, 0, // CID_C_HIGHPRIESTESS2,//41 + 0, 0, 0, // CID_C_TOME, //42 + 0, 0, 0, // CID_C_MORCALAVIN, //43 + 0, 0, 0, // CID_CORVUS2, //44 + 0, 0, 0, // CID_CORVUS3, //45 + 0, 0, 0, // CID_CORVUS4, //46 + 0, 0, 0, // CID_CORVUS5, //47 + 0, 0, 0, // CID_CORVUS6, //48 + 0, 0, 0, // CID_CORVUS7, //49 + 0, 0, 0, // CID_CORVUS8, //50 + 0, 0, 0, // CID_CORVUS9, //51 +}; + +vec3_t STDMaxsForClass [NUM_CLASSIDS] = +{ +//melee_rng,missile_rng,min_msl_rng,bypass_missile_chance + 0, 0, 0,// CID_NONE, -- NA - 0 + 8, 8, 16,// CID_RAT, -- JW + 16, 16, 16,// CID_GORGON, -- MG + 16, 16, 27,// CID_PLAGUEELF, -- MG + 20, 20, 32,// CID_GKROKON, -- JW + 0, 0, 0,// CID_FISH, -- ? - 5 + 0, 0, 0,// CID_OBJECT, -- NA + 0, 0, 0,// CID_LIGHT, -- NA + 0, 0, 0,// CID_TRIGGER, -- NA + 16, 16, 12,// CID_HARPY, -- JW + 16, 16, 24,// CID_SPREADER, -- JW - 10 + 0, 0, 0,// CID_ELFLORD, -- JW + 0, 0, 0,// CID_BBRUSH, -- NA + 0, 0, 0,// CID_FUNC_ROTATE, -- NA + 0, 0, 0,// CID_FUNC_DOOR, -- NA + 0, 0, 0,// CID_CHICKEN, + 16, 16, 26,// CID_SSITHRA, -- MG + 0, 0, 0,// CID_SPELL, -- NA - 15 + 36, 36, 96,// CID_MSSITHRA, -- MG + 16, 16, 16,// CID_OGLE, -- JW + 24, 24, 34,// CID_SERAPH_OVERLORD, -- JW + 24, 24, 34,// CID_SERAPH_GUARD, -- JW + 16, 16, 48,// CID_ASSASSIN, -- MG - 20 + 0, 0, 0,// CID_TELEPORTER, -- NA + 0, 0, 0,// CID_HIGHPRIESTESS, + 16, 16, 32,// CID_TCHECKRIK, -- MG + 0, 0, 0,// CID_BUTTON, -- NA + 0, 0, 0,// CID_BEE, -- ? - 25 + 0, 0, 0,// CID_CORVUS, + 0, 0, 0,// CID_MORK, + 0, 0, 0,// CID_TBEAST,//30 + 16, 16, 32,// CID_IMP, + + 0, 0, 0,// CID_SSITHRA_VICTIM, //32 + 0, 0, 0,// CID_SSITHRA_SCOUT, //33 + 0, 0, 0,// CID_DRANOR, //34 + + 0, 0, 0, // CID_TRIG_DAMAGE, //35 + 0, 0, 0, // CID_TRIG_PUSH, //36 + 0, 0, 0, // CID_C_ELFLORD, //37 + 0, 0, 0, // CID_C_SIERNAN1, //38 + 0, 0, 0, // CID_C_SIERNAN2, //39 + 0, 0, 0, // CID_C_HIGHPRIESTESS,//40 + 0, 0, 0, // CID_C_HIGHPRIESTESS2,//41 + 0, 0, 0, // CID_C_TOME, //42 + 0, 0, 0, // CID_C_MORCALAVIN, //43 + 0, 0, 0, // CID_CORVUS2, //44 + 0, 0, 0, // CID_CORVUS3, //45 + 0, 0, 0, // CID_CORVUS4, //46 + 0, 0, 0, // CID_CORVUS5, //47 + 0, 0, 0, // CID_CORVUS6, //48 + 0, 0, 0, // CID_CORVUS7, //49 + 0, 0, 0, // CID_CORVUS8, //50 + 0, 0, 0, // CID_CORVUS9, //51 +}; + +//MISC GLOBALS + +edict_t *give_head_to_harpy = NULL; +edict_t *take_head_from = NULL; diff --git a/Toolkit/Programming/GameCode/game/m_stats.h b/Toolkit/Programming/GameCode/game/m_stats.h new file mode 100644 index 0000000..ae4e206 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_stats.h @@ -0,0 +1,434 @@ +#ifndef G_STATS_H +#define G_STATS_H +#include "g_ClassStatics.h" + +extern int AttackRangesForClass [NUM_ATTACKRANGES]; +extern byte MaxBuoysForClass [NUM_CLASSIDS]; +extern int JumpChanceForClass [NUM_CLASSIDS]; +extern vec3_t STDMinsForClass [NUM_CLASSIDS]; +extern vec3_t STDMaxsForClass [NUM_CLASSIDS]; + +typedef struct MonsterShadow_s +{ + qboolean useShadow; + float scale; +} MonsterShadow_t; + +extern struct MonsterShadow_s G_MonsterShadow[NUM_CLASSIDS]; + +#define ITEM_REWARD_CHANCE 2 + +#define MAX_SIGHT_PLAYER_DIST 1000 + +// *************************************** +// ** MONSTER SPAWNFLAGS +// *************************************** +#define MSF_NONE 0x000000//0-no spawn flags +#define MSF_AMBUSH 0x000001//1-monster spawn flag AMBUSH +#define MSF_ASLEEP 0x000002//2-monster spawn flag ASLEEP- will not so anything until used + +//next three are mutually exclusive, sorry- that's how it was made, would be a pain to change now- should make walking a seperate one from other two... +#define MSF_WALKING 0x000004//4-monster is walking a beat +#define MSF_EATING 0x000004//4-monster is eating +#define MSF_PERCHING 0x000004//4-monster is perched- only harpies and imps + +// spawnflags 8 - 64 are individual to the monster +#define MSF_SPECIAL1 0x000008//8 +#define MSF_SPECIAL2 0x000010//16 +#define MSF_SPECIAL3 0x000020//32 +#define MSF_SPECIAL4 0x000040//64 + +#define MSF_FIXED 0x000080//128 - monster will not move, only attack + +//spawnflags 256 - 4096 used for selective spawning +//selective spawning control spawnflags for all entities, don't mess with them +#define MSF_NOT_EASY 0x000100//256 +#define MSF_NOT_MEDIUM 0x000200//512 +#define MSF_NOT_HARD 0x000400//1024 +#define MSF_NOT_COOP 0x000800//2048 +#define MSF_NOT_DEATHMATCH 0x001000//4096 + +//Extra Spawnflags since our creatures are so Freakin awesome! +//these 4 are for all creatures, annot be per-creature specific +#define MSF_WANDER 0x002000//8192 +#define MSF_MELEE_LEAD 0x004000//16384 +#define MSF_STALK 0x008000//32768 +#define MSF_COWARD 0x010000//65536 + +//extra spawnflags 128K - 1024K are individual to the monster +#define MSF_EXTRA1 0x020000//128K +#define MSF_EXTRA2 0x040000//256K +#define MSF_EXTRA3 0x080000//512K +#define MSF_EXTRA4 0x100000//1024K + +//=================================== +//SPECIAL MONSTER-SPECIFIC SPAWNFLAGS +//=================================== +//SSITHRA +#define MSF_SSITHRA_NAMOR 8 //Ssithra will jump out of water when woken up or used +#define MSF_SSITHRA_SPIN 16 //Ssithra will spin around when woken up or used +#define MSF_SSITHRA_ALPHA 32 //Tougher ssithra +#define MSF_SSITHRA_CLOTHED 64 //Clothed, shoot explosive tip proj's + +//ASSASSIN +#define MSF_ASS_JUMPAMBUSH 8 //Will jump when awoken +#define MSF_ASS_NOSHADOW 16 //cannot cloak +#define MSF_ASS_NOTELEPORT 32 //cannot teleprt +#define MSF_ASS_CINEMATIC 64 //A cinematic monster +#define MSF_ASS_TPORTAMBUSH 0x020000//Will spawn in teleport when triggered +#define MSF_ASS_STARTSHADOW 0x040000 //Assasin starts shadowed and decloaks when woken +#define MSF_ASS_SIDEJUMPAMBUSH 0x080000//assassin will jump out sideways +#define MSF_ASS_TELEPORTDODGE 0x100000//assassin will use teleports to dodge + +//Gorgon +#define MSF_GORGON_SPEEDY 8 +#define MSF_GORGON_COWARD 64 + +//Plague Elves +#define MSF_PELF_CINEMATIC 8 //cinematic plague elf +#define MSF_PELF_MISSILE 16 //Missile-bearing plague elf +#define MSF_PELF_ONFIRE 32 //Starts on fire, as per request of sick-ass Raffel! + +//Insects +#define MSF_INSECT_CINEMATIC 8 //Cinematic insect +#define MSF_INSECT_BEAST_FODDER 16 //Looks for beasts +#define MSF_INSECT_YELLOWJACKET 32 //Diff skin and projectile- male +#define MSF_INSECT_ALTERNATE 32 //Diff tint and projectile- female + +//Ogles - special cases- have their own spawnflags +#define OF_PUSHING 1 +#define OF_PICK_UP 4 +#define OF_PICK_DOWN 8 +#define OF_CHISEL_UP 16 +#define OF_CHISEL_DOWN 32 +#define OF_HAMMER_UP 64 +#define OF_HAMMER_DOWN 128 +#define OF_SONG_LEADER 256 + +// *************************************** +// ** MONSTER STATS +// *************************************** + +#define MAX_BLOCKING_THING_HEALTH 100//highest health some blocking ent can be and let a monster still hack away at it to clear it's path +//********** +//**ASSASSIN +//********** + +#define ASSASSIN_HEALTH 250 +#define ASSASSIN_MASS 180 +#define ASSASSIN_MIN_DAMAGE 7 +#define ASSASSIN_MAX_DAMAGE 13 +#define ASSASSIN_MIN_CLOAK_RANGE 100 +#define ASSASSIN_DAGGER_SPEED 500.0 +#define ASS_TP_OFF 1 +#define ASS_TP_ANY 2 +#define ASS_TP_DEF 3 + +//********** +//**TRIAL BEAST +//********** + +#define TB_HEALTH 7000 +#define TB_MASS 10000 +#define TB_DMG_BITE_MIN 30 +#define TB_DMG_BITE_MAX 50 +#define TB_DMG_IMPACT_MIN 10 +#define TB_DMG_IMPACT_MAX 100 +#define TB_DMG_IMPACT_KB 150 + + +//********** +//**BEE +//********** + +#define BEE_HEALTH 50 +#define BEE_MASS 10 + + +//********** +//**CHICKEN +//********** + +#define CHICKEN_HEALTH 10 +#define CHICKEN_MASS 30 + + +//********** +//**ELF LORD +//********** + +#define ELFLORD_HEALTH 2250 +#define ELFLORD_MASS 2500 +#define ELFLORD_STAR_MIN_DAMAGE 8 +#define ELFLORD_STAR_MAX_DAMAGE 12 +#define ELFLORD_BEAM_MIN_DAMAGE 4 +#define ELFLORD_BEAM_MAX_DAMAGE 8 + + +//********** +//**FISH +//********** + +#define FISH_HEALTH 50 +#define FISH_MASS 120 +#define FISH_DMG_BITE_MIN 5 +#define FISH_DMG_BITE_MAX 10 + + +//********** +//**GKROKON +//********** + +#define GKROKON_HEALTH 75 +#define GKROKON_MASS 60 +#define GKROKON_DMG_SPOO_MIN 4 +#define GKROKON_DMG_SPOO_MAX 8 +#define GKROKON_DMG_BITE_MIN 5 +#define GKROKON_DMG_BITE_MAX 10 + + + +//********** +//**GORGON +//********** + +#define GORGON_HEALTH 100 +#define GORGON_MASS 80 +#define GORGON_SCALE_MIN 0.9 +#define GORGON_SCALE_MAX 1.2 +#define GORGON_DMG_MIN 5 // Note: This is multiplied by the scale of the creature +#define GORGON_DMG_MAX 10 // Note: This is multiplied by the scale of the creature +#define GORGON_LEADER_HEALTH 200 +#define GORGON_LEADER_MASS 300 +#define GORGON_ALERT_DIST 500 +#define GORGON_SKIN 0 +#define GORGON_PAIN_SKIN 1 + +//********** +//**HARPY +//********** + +#define HARPY_HEALTH 60 +#define HARPY_MASS 100 +#define HARPY_DMG_MIN 10 +#define HARPY_DMG_MAX 20 + + + +//********** +//**IMP +//********** + +#define IMP_HEALTH 200 +#define IMP_MASS 75 +#define IMP_DMG_MIN 10 +#define IMP_DMG_MAX 20 + + +//********** +//**MORCALAVIN +//********** + +#define MORK_HEALTH1 100 +#define MORK_HEALTH 2500 +#define MORK_MASS 2500 +#define MORK_DMG_BEAM_MIN 10 +#define MORK_DMG_BEAM_MAX 20 +#define MORK_DMG_PROJ1_MIN 2 +#define MORK_DMG_PROJ1_MAX 5 +#define MORK_DMG_PUFF_RADIUS 32 +#define MORK_DMG_PUFF_MAX 128 +#define MORK_DMG_PUFF_MIN 8 +#define MORK_DMG_EYES_MULT 200 +#define MORK_DMG_EYES_MIN 10 + + +//********** +//**MUTANT SSITHRA +//********** + +#define MSSITHRA_HEALTH 2250 +#define MSSITHRA_MASS 2000 +#define MSSITHRA_DMG_MIN 8 +#define MSSITHRA_DMG_MAX 16 +#define MSSITHRA_DMG_SWIPE 40 +#define MSSITHRA_DMG_ARROW_RADIUS 50 +#define MSSITHRA_ARROW_SPEED 600 + +//********** +//**OGLE +//********** + +#define OGLE_HEALTH 100 +#define OGLE_MASS 100 +#define OGLE_DMG_MIN 5 +#define OGLE_DMG_MAX 8 + + +//********** +//**PLAGUE ELF +//********** + +#define PLAGUEELF_HEALTH 50 +#define PLAGUEELF_MASS 150 +#define PLAGUEELF_DMG_MIN 2 +#define PLAGUEELF_DMG_MAX 4 +#define PLAGUEELF_DMG_HOE 1 // Modifiers to the min/max damage +#define PLAGUEELF_DMG_GAFF 2 // Modifiers to the min/max damage +#define PLAGUEELF_DMG_HAMMER -1 // Modifiers to the min/max damage +#define PLAGUEELF_DMG_SPELL_MIN 4 +#define PLAGUEELF_DMG_SPELL_MAX 8 +#define PLAGUEELF_GUARD_DMG_SPELL_MIN 5 +#define PLAGUEELF_GUARD_DMG_SPELL_MAX 10 +#define PALACE_ELF_SKIN 4 //for guards +#define DYING_ELF_PAIN_VOICE 0 +#define DYING_ELF_IDLE_VOICE 1 +#define DYING_ELF_TOUCH_VOICE 2 + + +//********** +//**PLAGUE SSITHRA +//********** + +#define SSITHRA_HEALTH 125 +#define SSITHRA_MASS 200 +#define SSITHRA_DMG_MIN 6 +#define SSITHRA_DMG_MAX 8 +#define SSITHRA_DMG_ARROW_RADIUS 50 +#define SSITHRA_JUMP_VELOCITY 300.0 +#define SSITHRA_HOP_VELOCITY 128.0 +#define SSITHRA_SPOO_SPEED 450 +#define SSITHRA_BIGARROW_DMG_MIN 16 +#define SSITHRA_BIGARROW_DMG_MAX 24 + +//********** +//**HIGH PRIESTESS +//********** + +#define HP_HEALTH 2500 +#define HP_MASS 2000 +#define HP_DMG_FURY_MIN 3 +#define HP_DMG_FURY_MAX 5 +#define HP_DMG_BROOD_MIN 8 +#define HP_DMG_BROOD_MAX 16 +#define HP_DMG_RAIN 2 +#define HP_DMG_MISSILE_MIN 2 +#define HP_DMG_MISSILE_MAX 4 +#define HP_DMG_FIRE_MIN 2 +#define HP_DMG_FIRE_MAX 4 + + +//********** +//**RAT +//********** + +#define RAT_HEALTH 10 +#define RAT_MASS 10 +#define RAT_DMG_BITE 1 +#define RAT_GROUP_RANGE 150 + +//********** +//**SERAPH OVERLORD +//********** + +#define SERAPH_HEALTH 250 +#define SERAPH_MASS 350 +#define SERAPH_DMG_WHIP 5 +#define SERAPH_DMG_WHIP_RUN 8 + + +//********** +//**SERAPH GUARD +//********** + +#define SGUARD_HEALTH 300 +#define SGUARD_MASS 1000 +#define SGUARD_DMG_AXE 15 +#define SGUARD_DMG_AXE_SPIN 30 +#define SGUARD_DMG_SPELL_MIN 10 +#define SGUARD_DMG_SPELL_MAX 15 + + +//********** +//**PLAGUE SPREADER +//********** + +#define SPREADER_HEALTH 200 +#define SPREADER_MASS 275 +#define SPREADER_DMG_DEATH 1 +#define SPREADER_DMG_DEATH_RAD 30 +#define SPREADER_DMG_RAM 10 +#define SPREADER_DMG_RAM_KB 20 +#define SPREADER_DMG_TAKEOFF 1 +#define SPREADER_DMG_TAKEOFF_RAD 100 + +#define SPREADER_GRENADE_DAMAGE 20 +#define SPREADER_GRENADE_RADIUS (100.0) +#define SPREADER_GRENADE_TIME (2.9F) +#define SPREADER_MIST_DAMAGE 1 +#define SPREADER_MIST_RADIUS 40 +#define SPREADER_MIST_GRADIUS 30 + + +//********** +//**TCHEKRIK +//********** + +#define TC_HEALTH_MALE 200 +#define TC_HEALTH_FEMALE 200 +#define MASS_TC_MALE 300 +#define MASS_TC_FEMALE 250 +#define TC_DMG_STAB_MIN 5 +#define TC_DMG_STAB_MAX 15 +#define TC_MALE_DMG_HACK_MIN 15 +#define TC_MALE_DMG_HACK_MAX 25 +#define TC_FEMALE_DMG_HACK_MIN 3 +#define TC_FEMALE_DMG_HACK_MAX 8 +#define TC_DMG_FIREBALL_MIN 3 +#define TC_DMG_FIREBALL_MAX 5 +#define TC_DMG_SPEAR_MIN 1 +#define TC_DMG_SPEAR_MAX 3 +#define TC_DMG_YSPEAR_MIN 6 +#define TC_DMG_YSPEAR_MAX 12 +#define GLOBE_DAMAGE_MIN 10 +#define GLOBE_DAMAGE_RANGE 35 +#define GLOBE_EXPLOSION_RADIUS_MIN 89.0 +#define GLOBE_EXPLOSION_RADIUS_MAX 160.0 +#define INSECT_STAFF_SPEED 100.0 +#define INSECT_STAFF_AIMED_SPEED 750.0 + +//MORCALAVIN EFFECTS + +enum { +//offensive + FX_M_BEAM, +//impacts + FX_M_MISC_EXPLODE, +//other + FX_IMP_FIRE, + FX_IMP_FBEXPL, + FX_CW_STARS, + FX_BUOY, + FX_BUOY_PATH, + FX_M_MOBLUR, + FX_ASS_DAGGER, + FX_UNDER_WATER_WAKE, + +//jweier + FX_QUAKE_RING, + FX_GROUND_ATTACK, + FX_MORK_BEAM, + FX_MORK_MISSILE, + FX_MORK_MISSILE_HIT, + FX_MORK_TRACKING_MISSILE, + + FX_MSSITHRA_EXPLODE, + FX_MSSITHRA_ARROW, + FX_MSSITHRA_ARROW_CHARGE, +}; + +//MISC globals + +extern edict_t *give_head_to_harpy; +extern edict_t *take_head_from; +#endif // G_STATS_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/m_tcheckrik.c b/Toolkit/Programming/GameCode/game/m_tcheckrik.c new file mode 100644 index 0000000..c57d4a9 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_tcheckrik.c @@ -0,0 +1,1894 @@ +//============================================================================== +// +// m_tcheckrik.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// +// AI : +// +// STAND1 : Looking straight ahead +// +// WALK1 : a normal straight line +// WALK2 : another normal straight line +// +// MELEE1 : Attack +// MELEE2 : Attack +// +// RUNATTACK : Running and swinging +// RUN1 : chasing an enemy straight ahead +// SHAKE : stand and spaz +// DIE1 : Fall back dead +// LEAN1 : lean agains the wall +// FIST1 : Beat against the wall in rage and desperation +// +// +//============================================================================== + +#include "g_local.h" +#include "Utilities.h" +#include "g_DefaultMessageHandler.h" +#include "g_monster.h" +#include "fx.h" +#include "random.h" +#include "buoy.h" +#include "vector.h" + +#include "m_tcheckrik.h" +#include "m_tcheckrik_anim.h" +#include "g_HitLocation.h" +#include "g_misc.h" +#include "angles.h" +#include "g_HitLocation.h" +#include "c_ai.h" + +#include "m_stats.h" + +void insect_dismember(edict_t *self, int damage, int HitLocation); + +/*---------------------------------------------------------------------- + insect Base Info +-----------------------------------------------------------------------*/ +static animmove_t *animations[ NUM_ANIMS] = +{ + &insect_move_back,// = {10, insect_frames_back, insect_pause}, + &insect_move_deathfr,// = {23, insect_frames_deathfr, insect_dead}, + &insect_move_idle,// = { 50, insect_frames_idle, NULL}, + &insect_move_land,// = {6, insect_frames_land, insect_pause}, + &insect_move_inair,// = {1, insect_frames_inair, NULL}, + &insect_move_forcedjump,// = {9, insect_frames_forcedjump, insect_go_inair}, + &insect_move_finair,// = {1, insect_frames_inair, NULL}, + &insect_move_fjump,// = {9, insect_frames_forcedjump, insect_go_inair}, + &insect_move_paina,// = {7, insect_frames_paina, insect_pause}, + &insect_move_painc,// = {6, insect_frames_painc, insect_pause}, + &insect_move_run,// = {10, insect_frames_run, insect_pause}, + &insect_move_spear,// = {11, insect_frames_spear, insect_pause}, + &insect_move_sword,// = {9, insect_frames_sword, insect_pause}, + &insect_move_spell,// = {8, insect_frames_spell, insect_pause}, + &insect_move_spell2,// = {8, insect_frames_spell, insect_pause}, + &insect_move_walk,// = {20, insect_frames_walk, insect_pause}, + &insect_delay,// = {50 , insect_frames_delay, insect_pause}, + &insect_move_knock1_go, + &insect_move_knock1_loop, + &insect_move_knock1_end, + &insect_move_twitch, + + // Cinematic + &insect_move_c_action1, + &insect_move_c_action2, + &insect_move_c_action3, + &insect_move_c_action4, + &insect_move_c_attack1, + &insect_move_c_attack2, + &insect_move_c_attack3, + &insect_move_c_backpedal, + &insect_move_c_death1, + &insect_move_c_idle1, + &insect_move_c_idle2, + &insect_move_c_idle3, + &insect_move_c_pain1, + &insect_move_c_run, + &insect_move_c_walk, +}; + +static int Sounds[NUM_SOUNDS]; +static ClassResourceInfo_t resInfo; + +/*---------------------------------------------------------------------- + Cinematic Functions for the monster +-----------------------------------------------------------------------*/ + + +/*------------------------------------------------------------------------- + plagueElf_c_anims +-------------------------------------------------------------------------*/ +void insect_c_anims(edict_t *self, G_Message_t *msg) +{ + int int_msg; + int curr_anim; + + ai_c_readmessage(self, msg); + int_msg = (int) msg->ID; + + self->monsterinfo.c_anim_flag = 0; + + switch(int_msg) + { + case MSG_C_ACTION1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION1; + break; + case MSG_C_ACTION2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION2; + break; + case MSG_C_ACTION3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION3; + break; + case MSG_C_ACTION4: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ACTION4; + break; + case MSG_C_ATTACK1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK1; + break; + case MSG_C_ATTACK2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK2; + break; + case MSG_C_ATTACK3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_ATTACK3; + break; + case MSG_C_BACKPEDAL1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_BACKPEDAL; + break; + case MSG_C_DEATH1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_DEATH1; + break; + case MSG_C_IDLE1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT | C_ANIM_IDLE; + curr_anim = ANIM_C_IDLE1; + break; + case MSG_C_IDLE2: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE2; + break; + case MSG_C_IDLE3: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_IDLE3; + break; + case MSG_C_PAIN1: + self->monsterinfo.c_anim_flag |= C_ANIM_REPEAT; + curr_anim = ANIM_C_PAIN1; + break; + case MSG_C_RUN1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_RUN1; + break; + case MSG_C_WALK1: + self->monsterinfo.c_anim_flag |= C_ANIM_MOVE; + curr_anim = ANIM_C_WALK1; + break; + default: + self = self; + break; + } + + SetAnim(self, curr_anim); +} + + + +/*------------------------------------------------------------------------- + insect_c_pause +-------------------------------------------------------------------------*/ +void insect_c_reallydead (edict_t *self) +{ + self->nextthink = level.time; + self->think = NULL; +} + + + + + + +/*---------------------------------------------------------------------- + Action Functions for the monster +-----------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------- + insectCut +-------------------------------------------------------------------------*/ +vec3_t TC_WPN_MINS = {-2.0, -2.0, -1.0}; +vec3_t TC_WPN_MAXS = {2.0, 2.0, 1.0}; +void insectCut (edict_t *self, float attacktype) +{ + trace_t trace; + vec3_t pos1, pos2, dir, forward, right, hitangles; + float damage; + + AngleVectors(self->s.angles, forward, right, NULL); + VectorCopy(self->s.origin, pos1); + VectorMA (pos1, 72, forward, pos2); + switch((int)attacktype) + { + case TC_ATK_STAB: + if(self->s.fmnodeinfo[MESH__SPEAR].flags & FMNI_NO_DRAW) + return; + VectorMA(pos2, -16, right, pos2); + damage = irand(TC_DMG_STAB_MIN, TC_DMG_STAB_MAX); + break; + case TC_ATK_HACK: +// if(self->s.fmnodeinfo[MESH__SWORD].flags & FMNI_NO_DRAW) + if(self->s.fmnodeinfo[MESH__MALEHAND].flags & FMNI_NO_DRAW) + { + VectorMA (pos1, 12, forward, pos1); + pos1[2]+= 28; + VectorMA(pos2, 24, right, pos2); + damage = irand(TC_MALE_DMG_HACK_MIN, TC_MALE_DMG_HACK_MAX); + } + else + { + VectorMA (pos1, 12, forward, pos1); + pos1[2]+= 18; + VectorMA(pos2, 12, right, pos2); + damage = irand(TC_FEMALE_DMG_HACK_MIN, TC_FEMALE_DMG_HACK_MAX); + } + break; + default: + return; + break; + } + + gi.trace(pos1, TC_WPN_MINS, TC_WPN_MAXS, pos2, self, MASK_MONSTERSOLID|MASK_SHOT,&trace); + + //sfs--do this check before the allsolid check, because trace is screwy--fraction should be valid in all cases, so shouldn't be a problem + if(trace.fraction == 1.0) + {//missed totally + return; + } + + if(trace.allsolid || trace.startsolid || !trace.ent->takedamage) + {//ping! + vectoangles(trace.plane.normal, hitangles); + gi.CreateEffect(NULL, FX_SPARKS, 0, trace.endpos, "d", hitangles); + gi.sound (self, CHAN_AUTO, Sounds[SND_SWIPEHITW], 1, ATTN_NORM, 0); +// gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/staffhitwall.wav"), 1, ATTN_NORM, 0); + return; + } + + //hit someone, cut em! + + VectorSubtract(pos2, pos1, dir); + gi.sound (self, CHAN_AUTO, Sounds[SND_SWIPEHITF], 1, ATTN_NORM, 0); +// gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/staffhit.wav"), 1, ATTN_NORM, 0); + + T_Damage (trace.ent, self, self, dir, trace.endpos, vec3_origin, damage, damage*2, DAMAGE_DISMEMBER,MOD_DIED); + +/* gi.CreateEffect(&self->s, + FX_I_EFFECTS, + 0, + vec3_origin, + "bv", + FX_I_SWORD, + vec3_origin);*/ +} + + +/*------------------------------------------------------------------------- + insect_dead +-------------------------------------------------------------------------*/ +void insect_dead(edict_t *self) +{ + self->s.effects |= EF_DISABLE_EXTRA_FX; + self->msgHandler = DeadMsgHandler; + self->deadState = DEAD_DEAD; + M_EndDeath(self); +} + +/*------------------------------------------------------------------------- + insect_death +-------------------------------------------------------------------------*/ +void insect_random_death_sound (edict_t *self) +{ + if(self->mass==MASS_TC_MALE)//irand(0,1)) + gi.sound(self, CHAN_VOICE, Sounds[SND_DIEM], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, Sounds[SND_DIEF], 1, ATTN_NORM, 0); +} + +void insect_random_idle_sound (edict_t *self) +{ + if(self->mass==MASS_TC_MALE)// + { + if(irand(0,1)) + gi.sound(self, CHAN_VOICE, Sounds[SND_GROWLM1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, Sounds[SND_GROWLM2], 1, ATTN_NORM, 0); + } + else + { + if(irand(0,1)) + gi.sound(self, CHAN_VOICE, Sounds[SND_GROWLF1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, Sounds[SND_GROWLF2], 1, ATTN_NORM, 0); + } +} + +void M_MoveFrame (edict_t *self); +void insect_dead_pain (edict_t *self, G_Message_t *msg) +{ + if(msg) + if(!(self->svflags & SVF_PARTS_GIBBED)) + MG_parse_dismember_msg(self, msg); + + if(self->curAnimID!=ANIM_TWITCH&&self->deadState!=DEAD_DEAD) + return;//still dying + + if(self->s.frame==FRAME_knock15) + { + self->think = M_MoveFrame; + SetAnim(self, ANIM_TWITCH); + self->nextthink = level.time + 0.1; + } +} + +void insect_wait_twitch (edict_t *self) +{ + if(self->curAnimID!=ANIM_TWITCH&&!irand(0,1)) + { + SetAnim(self, ANIM_TWITCH); + self->nextthink = level.time + 0.1; + } + else if(irand(0, 5)) + { + SetAnim(self, ANIM_TWITCH); + self->nextthink = level.time + flrand(0.2, 10); + } + else + { + self->s.effects |= EF_DISABLE_EXTRA_FX; + self->msgHandler = DeadMsgHandler; + self->deadState = DEAD_DEAD; + M_EndDeath(self); + self->think = NULL; + } +} + +void insect_flyback_loop(edict_t *self) +{ + SetAnim(self, ANIM_KNOCK1_LOOP); +} + +void insect_flyback_move(edict_t *self) +{ + vec3_t endpos; + trace_t trace; + + M_ChangeYaw(self); + + VectorCopy(self->s.origin, endpos); + endpos[2] -= 48; + + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&trace); + + if ( ( trace.fraction < 1 || trace.startsolid || trace.allsolid ) && + self->curAnimID != ANIM_KNOCK1_END && + self->curAnimID != ANIM_KNOCK1_GO) + { + self->elasticity = 1.1; + self->friction = 0.5; + SetAnim(self, ANIM_KNOCK1_END); + } +} + +void insect_death(edict_t *self, G_Message_t *msg) +{ + if(self->monsterinfo.aiflags&AI_DONT_THINK) + { + SetAnim(self, ANIM_DEATHFR); + return; + } + + self->msgHandler = DeadMsgHandler; + + if(self->deadflag == DEAD_DEAD) //Dead but still being hit + return; + + gi.RemoveEffects(&self->s, FX_I_EFFECTS); + self->s.effects |= EF_DISABLE_EXTRA_FX; + + self->deadflag = DEAD_DEAD; + + insect_dropweapon (self, BIT_SPEAR); + insect_dropweapon (self, BIT_STAFF); +// insect_dropweapon (self, BIT_SWORD); + + if(self->health <= -80) //gib death + { + gi.sound(self, CHAN_BODY, Sounds[SND_GIB], 1, ATTN_NORM, 0); + self->think = BecomeDebris; + self->nextthink = level.time + 0.1; + return; + } + else + { + insect_random_death_sound(self); + if(self->health<-20) + { + vec3_t vf, yf, dVel; + + SetAnim(self, ANIM_KNOCK1_GO); + + VectorSet(self->knockbackvel, 0, 0, 0); + + VectorCopy(self->velocity, vf); + VectorNormalize(vf); + + VectorScale(vf, -1, yf); + + self->ideal_yaw = vectoyaw( yf ); + self->yaw_speed = 16; + + VectorScale(vf, 300, dVel); + dVel[2] = irand(150,250); + + VectorCopy(dVel, self->velocity); + return; + } + + SetAnim(self, ANIM_DEATHFR); + return; + } +} + + +/*------------------------------------------------------------------------- + insectdeathsqueal +-------------------------------------------------------------------------*/ +void insectdeathsqueal (edict_t *self) +{ +// gi.sound(self, CHAN_WEAPON, Sounds[SND_DIE1], 1, ATTN_IDLE, 0); + return; +} + +/*------------------------------------------------------------------------- + insectgrowl +-------------------------------------------------------------------------*/ +void insectgrowl (edict_t *self) +{ + int chance; + + chance = irand(0, 10); + + if (chance <= 2 ) + { + if(irand(0, 1)) + { + if(self->mass == MASS_TC_MALE) + gi.sound (self, CHAN_WEAPON, Sounds[SND_GROWLM1], 1, ATTN_IDLE, 0); + else + gi.sound (self, CHAN_WEAPON, Sounds[SND_GROWLF1], 1, ATTN_IDLE, 0); + } + else + { + if(self->mass == MASS_TC_MALE) + gi.sound (self, CHAN_WEAPON, Sounds[SND_GROWLM2], 1, ATTN_IDLE, 0); + else + gi.sound (self, CHAN_WEAPON, Sounds[SND_GROWLF2], 1, ATTN_IDLE, 0); + } + } +} + +/*------------------------------------------------------------------------- + insect_melee +-------------------------------------------------------------------------*/ +/* +void insect_melee(edict_t *self, G_Message_t *msg) +{ + if (!self->enemy) + return; + + if (self->enemy->health <= 0) + { + if (!FindTarget(self)) + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + return; + } + } + + if (anglemod(self->s.angles[YAW] - self->ideal_yaw) > self->yaw_speed) + { + M_ChangeYaw(self); + SetAnim(self, ANIM_RUN); + return; + } + + if(self->mass == MASS_TC_MALE) + {//male + if(irand(0, 1)&&self->s.fmnodeinfo[MESH__SPEAR].flags & FMNI_NO_DRAW) + SetAnim(self, ANIM_SPEAR); + else// if(self->s.fmnodeinfo[MESH__SWORD].flags & FMNI_NO_DRAW) + SetAnim(self, ANIM_SWORD); + } + else//if no staff, diff spell? + SetAnim(self, ANIM_SPELL); +} +*/ + +void insect_backpedal(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_BACK);//not male? + } + else + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void insect_sound(edict_t *self, float channel, float soundnum, float attn) +{ + gi.sound (self, (int)(channel), Sounds[(int)(soundnum)], 1, (int)(attn), 0); +} + +void insect_melee(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + if(self->mass == MASS_TC_MALE) + {//male + if(self->enemy->classID == CID_TBEAST && self->enemy->enemy == self) + { + if(M_DistanceToTarget(self, self->enemy) < 250) + { + self->monsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + 3; + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + return; + } + } + SetAnim(self, ANIM_SWORD); + } + else//too close for female, back away(maybe attack anyway?) + { + if(!irand(0,5)&&!(self->monsterinfo.aiflags&AI_NO_MELEE)||(self->spawnflags&MSF_FIXED)) + SetAnim(self, ANIM_SPELL); + else + SetAnim(self, ANIM_BACK); + } + } + else + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +void insect_missile(edict_t *self, G_Message_t *msg) +{ + if (M_ValidTarget(self, self->enemy)) + { + if(self->mass == MASS_TC_MALE) + {//male + if(self->enemy->classID == CID_TBEAST && self->enemy->enemy == self) + { + if(M_DistanceToTarget(self, self->enemy) < 250) + { + if(self->enemy->enemy != self) + { + self->enemy->oldenemy = self->enemy->enemy; + self->enemy->enemy = self; + } + self->monsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + 3; + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + return; + } + } + SetAnim(self, ANIM_SPEAR); + } + else + { + if(self->spawnflags & MSF_INSECT_ALTERNATE) + SetAnim(self, ANIM_SPELL2); + else + SetAnim(self, ANIM_SPELL); + } + } + else + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); +} + +extern void SpellCastInsectSpear(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,int offset); +//extern void SpellCastFlyingFist(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value); +void insectStaff(edict_t *self) +{ + vec3_t org, forward, right; + + AngleVectors(self->s.angles, forward, right, NULL); + VectorCopy(self->s.origin, org); + VectorMA(org, 12, forward, org); + VectorMA(org, 4, right, org); + if(self->spawnflags & MSF_INSECT_YELLOWJACKET) + { + if(self->s.frame == FRAME_SpearB4) + { + if(!skill->value) + SpellCastInsectSpear(self, org, self->s.angles, irand(1, 3)); + else if(skill->value == 1) + { + SpellCastInsectSpear(self, org, self->s.angles, 1); + SpellCastInsectSpear(self, org, self->s.angles, 2); + } + else + { + SpellCastInsectSpear(self, org, self->s.angles, 1); + SpellCastInsectSpear(self, org, self->s.angles, 2); + SpellCastInsectSpear(self, org, self->s.angles, 3); + } + gi.sound (self, CHAN_WEAPON, Sounds[SND_SPELLM2], 1, ATTN_NORM, 0); + } + } + else + { + SpellCastInsectSpear(self, org, self->s.angles, false); + gi.sound (self, CHAN_WEAPON, Sounds[SND_SPELLM], 1, ATTN_NORM, 0); + } +} + +void imp_fireball (edict_t *self); +void insectSpell(edict_t *self, float whichspell) +{ + vec3_t org, forward, right; + + if (!(self->spawnflags & MSF_INSECT_CINEMATIC)) + ai_charge(self, 0); + + AngleVectors(self->s.angles, forward, right, NULL); + switch((int)whichspell) + { + case TC_SPL_GLOW: + if(self->s.fmnodeinfo[MESH__STAFF].flags & FMNI_NO_DRAW) + {//no staff, weaker spell + VectorCopy(self->s.origin, org); + VectorMA(org, 8, forward, org); + VectorMA(org, 2, right, org); + org[2] += 6; + SpellCastInsectStaff(self, org, self->s.angles, forward, 0); + gi.sound (self, CHAN_WEAPON, Sounds[SND_SPELLF], 1, ATTN_NORM, 0); + //SpellCastFlyingFist(self, org, self->s.angles, forward, 0); + } + else + {//staff, bigger spell + VectorCopy(self->s.origin, org); + VectorMA(org, 16, forward, org); + VectorMA(org, 4, right, org); + org[2] += 8; + + self->s.effects &= ~(EF_DISABLE_EXTRA_FX | EF_MARCUS_FLAG1); + self->damage_debounce_time = false; + SpellCastGlobeOfOuchiness(self, org, self->s.angles, forward); + gi.sound (self, CHAN_ITEM, Sounds[SND_SPLPWRUPF], 1, ATTN_NORM, 0); + } + break; + case TC_SPL_FIRE: + if(self->s.fmnodeinfo[MESH__STAFF].flags & FMNI_NO_DRAW) + {//no staff + VectorCopy(self->s.origin, org); // We need to initialize org, don't we? + VectorMA(org, 16, forward, org); + org[2] += 12; + SpellCastInsectStaff(self, org, self->s.angles, forward, 0); + gi.sound (self, CHAN_AUTO, Sounds[SND_SPELLF], 1, ATTN_NORM, 0); + return; + } + else + { + VectorCopy(self->s.origin, org); + VectorMA(org, 16, forward, org); + org[2] += 12; + SpellCastInsectStaff(self, org, self->s.angles, forward, 0); + gi.sound (self, CHAN_AUTO, Sounds[SND_SPELLF], 1, ATTN_NORM, 0); + } + break; + case TC_SPL_FIRE2: + if(!(self->s.fmnodeinfo[MESH__STAFF].flags & FMNI_NO_DRAW)) + {//no staff + VectorCopy(self->s.origin, org); + VectorMA(org, 16, forward, org); + org[2] += 12; + SpellCastInsectStaff(self, org, self->s.angles, forward, 1); + gi.sound(self, CHAN_AUTO, gi.soundindex("monsters/imp/fireball.wav"), 1, ATTN_NORM, 0); + } + else + { + VectorCopy(self->s.origin, org); + VectorMA(org, 16, forward, org); + org[2] += 12; + SpellCastInsectStaff(self, org, self->s.angles, forward, 0); + gi.sound (self, CHAN_AUTO, Sounds[SND_SPELLF], 1, ATTN_NORM, 0); + } + break; + } + +} + +void insectReleaseSpell (edict_t *self) +{ + gi.RemoveEffects(&self->s, FX_I_EFFECTS); + self->s.effects |= EF_DISABLE_EXTRA_FX | EF_MARCUS_FLAG1; + self->damage_debounce_time = true; +} + +/*------------------------------------------------------------------------- + insect_pain +-------------------------------------------------------------------------*/ +int Bit_for_MeshNode_tc [16] = +{ + BIT_MASTER, + BIT_LLEG, + BIT_HEAD, + BIT_LMANDIBLE, + BIT_RMANDIBLE, + BIT_CROWN, + BIT_L2NDARM, + BIT_SPEAR, + BIT_FEMHAND, + BIT_SWORD, + BIT_STAFF, + BIT_GEM, + BIT_R2NDARM, + BIT_RWINGS, + BIT_LWINGS, + BIT_RLEG +}; + +qboolean canthrownode_tc (edict_t *self, int BP, int *throw_nodes) +{//see if it's on, if so, add it to throw_nodes + //turn it off on thrower + if(!(self->s.fmnodeinfo[BP].flags & FMNI_NO_DRAW)) + { + *throw_nodes |= Bit_for_MeshNode_tc[BP]; + self->s.fmnodeinfo[BP].flags |= FMNI_NO_DRAW; + return true; + } + return false; +} + +void insect_chicken (edict_t *self, int coward, int flee, float fleetime) +{ + float chance; + + chance = flrand(0,10); + if(chancemonsterinfo.aiflags |= AI_COWARD; + return; + } + + if(chancemonsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + fleetime; + } +} + +//THROWS weapon, turns off those nodes, sets that weapon as gone +void insect_dropweapon (edict_t *self, int weapon) +{//NO PART FLY FRAME! + vec3_t handspot, forward, right, up; +// float chance; + + VectorClear(handspot); + AngleVectors(self->s.angles,forward,right,up); + +// if(self->deadflag == DEAD_DEAD||(self->s.fmnodeinfo[MESH__R_ARM].flags & FMNI_NO_DRAW)) +// chance = 0; +// else +// chance = 3; + if((!weapon || weapon&BIT_STAFF) && + !(self->s.fmnodeinfo[MESH__STAFF].flags & FMNI_NO_DRAW)) + { + VectorMA(handspot,8,forward,handspot); + VectorMA(handspot,5,right,handspot); + VectorMA(handspot,12,up,handspot); + ThrowWeapon(self, &handspot, BIT_STAFF, 0, FRAME_partfly); + self->s.fmnodeinfo[MESH__STAFF].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GEM].flags |= FMNI_NO_DRAW; +// insect_chicken(self,2,4,flrand(3,8)); + return; + } + if((!weapon || weapon&BIT_SPEAR)&& + !(self->s.fmnodeinfo[MESH__SPEAR].flags & FMNI_NO_DRAW)) + { + VectorMA(handspot,6,forward,handspot); + VectorMA(handspot,4,right,handspot); + ThrowWeapon(self, &handspot, BIT_SPEAR, 0, FRAME_partfly); + self->s.fmnodeinfo[MESH__SPEAR].flags |= FMNI_NO_DRAW; +// insect_chicken(self,2,4,flrand(3,8)); + return; + } + if((!weapon || weapon&BIT_SWORD)&& + !(self->s.fmnodeinfo[MESH__MALEHAND].flags & FMNI_NO_DRAW)) +// !(self->s.fmnodeinfo[MESH__SWORD].flags & FMNI_NO_DRAW)) + { + VectorMA(handspot,6,forward,handspot); + VectorMA(handspot,-6,right,handspot); + VectorMA(handspot,-6,up,handspot); + ThrowWeapon(self, &handspot, BIT_SWORD, 0, FRAME_partfly); + self->s.fmnodeinfo[MESH__MALEHAND].flags |= FMNI_NO_DRAW; +// self->s.fmnodeinfo[MESH__SWORD].flags |= FMNI_NO_DRAW; +// insect_chicken(self,2,4,flrand(3,8)); + return; + } +} + +void insect_dismember(edict_t *self, int damage, int HitLocation) +{//fixme: throw current weapon +//fixme - make part fly dir the vector from hit loc to sever loc +//remember- turn on caps! + int throw_nodes = 0; + vec3_t gore_spot, right; + qboolean dismember_ok = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; +// gi.dprintf("HL: %d",HitLocation); + +/* if(self->curAnimID==ANIM_MELEE1||self->curAnimID==ANIM_MELEE1) + {//Hit chest during melee, may have hit arms + if(HitLocation == hl_TorsoFront&&irand(0,10)<4) + { + if(irand(0,10)<7) + HitLocation = hl_ArmLowerRight; + else + HitLocation = hl_ArmLowerLeft; + } + } + + if( + (HitLocation == hl_ArmUpperLeft&& self->s.fmnodeinfo[MESH__L_ARM].flags & FMNI_NO_DRAW) || + (HitLocation == hl_ArmUpperRight&& self->s.fmnodeinfo[MESH__R_ARM].flags & FMNI_NO_DRAW)|| + ( + (HitLocation == hl_TorsoFront|| HitLocation == hl_TorsoBack) && + self->s.fmnodeinfo[MESH__R_ARM].flags & FMNI_NO_DRAW && + self->s.fmnodeinfo[MESH__L_ARM].flags & FMNI_NO_DRAW && + irand(0,10)<4) + ) + HitLocation = hl_Head;//Decap +*/ + self->monsterinfo.aiflags &= ~AI_OVERRIDE_GUIDE; + VectorClear(gore_spot); + switch(HitLocation) + { + case hl_Head: + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)health)s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,8,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, self, self, vec3_origin, vec3_origin, vec3_origin, 10, 20,0,MOD_DIED); + } + return; + } + else + { + if(irand(0,1)||self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_USE_SKIN) + { + if(self->mass == MASS_TC_MALE) + { + if(irand(0,1)||self->s.fmnodeinfo[MESH__RMANDIBLE].flags & FMNI_USE_SKIN) + { + self->s.fmnodeinfo[MESH__LMANDIBLE].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LMANDIBLE].skin = self->s.skinnum+1; + } + else + { + self->s.fmnodeinfo[MESH__RMANDIBLE].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RMANDIBLE].skin = self->s.skinnum+1; + } + } + else + { + self->s.fmnodeinfo[MESH__CROWN].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__CROWN].skin = self->s.skinnum+1; + } + } + else + { + self->s.fmnodeinfo[MESH__HEAD].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__HEAD].skin = self->s.skinnum+1; + } + } + break; + case hl_TorsoFront://split in half? + case hl_TorsoBack://split in half? + if(self->s.fmnodeinfo[MESH_MASTER].flags & FMNI_USE_SKIN) + break; + if(flrand(0,self->health)s.fmnodeinfo[MESH_MASTER].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH_MASTER].skin = self->s.skinnum+1; + break; + case hl_ArmUpperLeft: + if(self->mass == MASS_TC_FEMALE) + {//female + if(self->s.fmnodeinfo[MESH_MASTER].flags & FMNI_USE_SKIN) + return; + self->s.fmnodeinfo[MESH_MASTER].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH_MASTER].skin = self->s.skinnum+1; + return; + } + else + {//male - sword arm + if(self->s.fmnodeinfo[MESH__L2NDARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.fmnodeinfo[MESH__L2NDARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__L2NDARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmLowerLeft://left arm + if(self->mass == MASS_TC_FEMALE) + {//female + if(self->s.fmnodeinfo[MESH_MASTER].flags & FMNI_USE_SKIN) + return; + self->s.fmnodeinfo[MESH_MASTER].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH_MASTER].skin = self->s.skinnum+1; + return; + } + else + {//male - left spear arm + if(self->s.fmnodeinfo[MESH__L2NDARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__L2NDARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); +// insect_chicken(self,6,8,flrand(7,15)); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + if(self->s.fmnodeinfo[MESH__R2NDARM].flags & FMNI_NO_DRAW&& + !(self->s.fmnodeinfo[MESH__SPEAR].flags & FMNI_NO_DRAW)) + insect_dropweapon (self, BIT_SPEAR); + } + } + else + { + if(flrand(0,self->health)s.fmnodeinfo[MESH__L2NDARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__L2NDARM].skin = self->s.skinnum+1; + } + } + break; + case hl_ArmUpperRight: + if(self->mass == MASS_TC_FEMALE) + {//female + if(self->s.fmnodeinfo[MESH_MASTER].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + else + { + self->s.fmnodeinfo[MESH_MASTER].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH_MASTER].skin = self->s.skinnum+1; + } + if(flrand(0,self->health)s.fmnodeinfo[MESH_MASTER].flags & FMNI_USE_SKIN) + return; + self->s.fmnodeinfo[MESH_MASTER].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH_MASTER].skin = self->s.skinnum+1; + return; + } + //male - right upper arm- nothing in it + break; + case hl_ArmLowerRight://right arm + if(self->mass == MASS_TC_FEMALE) + {//female + if(self->s.fmnodeinfo[MESH_MASTER].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + else + { + self->s.fmnodeinfo[MESH_MASTER].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH_MASTER].skin = self->s.skinnum+1; + } + if(flrand(0,self->health)s.fmnodeinfo[MESH__R2NDARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__R2NDARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); +// insect_chicken(self,6,8,flrand(7,15)); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + if(self->s.fmnodeinfo[MESH__L2NDARM].flags & FMNI_NO_DRAW&& + !(self->s.fmnodeinfo[MESH__SPEAR].flags & FMNI_NO_DRAW)) + insect_dropweapon (self, BIT_SPEAR); + } + } + else + { + if(flrand(0,self->health)s.fmnodeinfo[MESH__R2NDARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__R2NDARM].skin = self->s.skinnum+1; + } + } + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft://left leg + if(self->health>0) + {//still alive + if(self->s.fmnodeinfo[MESH__LLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__LLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LLEG].skin = self->s.skinnum+1; + break; + } + else + { + if(self->s.fmnodeinfo[MESH__LLEG].flags & FMNI_NO_DRAW) + break; + if(canthrownode_tc(self, MESH__LLEG, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + } + } + break; + case hl_LegUpperRight: + case hl_LegLowerRight://right leg + if(self->health>0) + {//still alive + if(self->s.fmnodeinfo[MESH__RLEG].flags & FMNI_USE_SKIN) + break; + self->s.fmnodeinfo[MESH__RLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RLEG].skin = self->s.skinnum+1; + break; + } + else + { + if(self->s.fmnodeinfo[MESH__RLEG].flags & FMNI_NO_DRAW) + break; + if(canthrownode_tc(self, MESH__RLEG, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, FRAME_partfly); + } + } + break; + + default: + if(flrand(0,self->health)pain_debounce_time = 0; + + /*if(self->mass == MASS_TC_FEMALE) + { + if(self->s.fmnodeinfo[MESH__STAFF].flags & FMNI_NO_DRAW) + self->monsterinfo.aiflags |= AI_NO_MISSILE; + } + else*/ + if(self->mass == MASS_TC_MALE) + { +// if(self->s.fmnodeinfo[MESH__SWORD].flags & FMNI_NO_DRAW) + if(self->s.fmnodeinfo[MESH__MALEHAND].flags & FMNI_NO_DRAW) + self->monsterinfo.aiflags |= AI_NO_MELEE; + + if(self->s.fmnodeinfo[MESH__SPEAR].flags & FMNI_NO_DRAW) + self->monsterinfo.aiflags |= AI_NO_MISSILE; + } +} + +void insect_random_pain_sound (edict_t *self) +{ + if(self->mass==MASS_TC_MALE)//irand(0,1)) + gi.sound(self, CHAN_VOICE, Sounds[SND_PAINM], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_VOICE, Sounds[SND_PAINF], 1, ATTN_NORM, 0); +} + +void insect_pain(edict_t *self, G_Message_t *msg) +{ + int temp, damage; + int force_damage; + + ParseMsgParms(msg, "eeiii", &temp, &temp, &force_damage, &damage, &temp); + + if(!force_damage&&flrand(0,self->health)>damage) + return; + + gi.RemoveEffects(&self->s, FX_I_EFFECTS); + self->s.effects |= EF_DISABLE_EXTRA_FX; + //sound + insect_random_pain_sound(self); + //remove spell effects + self->monsterinfo.aiflags &= ~AI_OVERRIDE_GUIDE; + if (force_damage || self->pain_debounce_time < level.time) + { + self->pain_debounce_time = level.time + 1; + if(irand(0,1)) + SetAnim(self, ANIM_PAINA); + else + SetAnim(self, ANIM_PAINC); + } +} + +/*------------------------------------------------------------------------- + insect_pause +-------------------------------------------------------------------------*/ +void insect_pause (edict_t *self) +{ + vec3_t v; + float len; + + if(self->spawnflags & MSF_INSECT_BEAST_FODDER) + { + edict_t *found = NULL; + + if(found = G_Find(found, FOFS(classname), "monster_trial_beast")) + { + if(found->health > 0) + { + self->enemy = found; + found->oldenemy = found->enemy; + found->enemy = self; + + self->spawnflags &= ~MSF_INSECT_BEAST_FODDER; + self->monsterinfo.aiflags &= ~AI_NO_MISSILE; + self->missile_range = 3000; + self->min_missile_range = 250; + + //self->monsterinfo.aiflags |= AI_NO_MELEE; + //self->melee_range = -250; + self->monsterinfo.aiflags &= ~AI_NO_MELEE; + self->melee_range = 48; + + self->bypass_missile_chance = 0; + self->s.fmnodeinfo[MESH__MALEHAND].flags &= ~FMNI_NO_DRAW; + } + } + } + + if(self->monsterinfo.aiflags&AI_OVERRIDE_GUIDE) + { + if(self->groundentity) + self->monsterinfo.aiflags &= ~AI_OVERRIDE_GUIDE; + else + return; + } + + if(self->spawnflags & MSF_FIXED && self->curAnimID == ANIM_DELAY && self->enemy) + { + self->monsterinfo.searchType = SEARCH_COMMON; + MG_FaceGoal(self, true); + } + + self->mood_think(self); + + if (self->ai_mood == AI_MOOD_NORMAL) + { + FindTarget(self); + + if(self->enemy) + { + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + + if ((len > 80) || (self->monsterinfo.aiflags & AI_FLEE)) // Far enough to run after + { + QPostMessage(self, MSG_RUN,PRI_DIRECTIVE, NULL); + } + else // Close enough to Attack + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + } + } + } + else + { + //gi.dprintf("plageElf_pause: Using High Level Functionality\n"); + + + if(self->enemy) + { + if(self->enemy->classID == CID_TBEAST) + { + if(visible(self, self->enemy)) + { + if(M_DistanceToTarget(self, self->enemy) > 250) + { + if(infront(self, self->enemy)) + { + self->ai_mood = AI_MOOD_ATTACK; + self->monsterinfo.flee_finished = -1; + self->ai_mood_flags |= AI_MOOD_FLAG_MISSILE; + } + else + { + self->ai_mood = AI_MOOD_PURSUE; + self->ai_mood_flags &= ~AI_MOOD_FLAG_DUMB_FLEE; + self->monsterinfo.aiflags &= ~AI_FLEE; + self->monsterinfo.flee_finished = -1; + } + } + } + } + } + + switch (self->ai_mood) + { + case AI_MOOD_ATTACK: + if(self->ai_mood_flags & AI_MOOD_FLAG_MISSILE) + QPostMessage(self, MSG_MISSILE, PRI_DIRECTIVE, NULL); + else + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_PURSUE: + case AI_MOOD_NAVIGATE: + case AI_MOOD_FLEE: + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_STAND: + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_DELAY: + SetAnim(self, ANIM_DELAY); + break; + + + case AI_MOOD_WANDER: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_WALK: + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_BACKUP: + QPostMessage(self, MSG_FALLBACK, PRI_DIRECTIVE, NULL); + break; + + case AI_MOOD_JUMP: + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_FJUMP); + break; + + default : +#ifdef _DEVEL + gi.dprintf("insect: Unusable mood %d!\n", self->ai_mood); +#endif + break; + } + } +} + +void insect_check_mood (edict_t *self, G_Message_t *msg) +{ + ParseMsgParms(msg, "i", &self->ai_mood); + + insect_pause(self); +} + +/*------------------------------------------------------------------------- + insect_run +-------------------------------------------------------------------------*/ +void insect_run(edict_t *self, G_Message_t *msg) +{ + //turn on lerpflags + + if (M_ValidTarget(self, self->enemy)) + { + if(self->enemy->classID == CID_TBEAST && self->enemy->enemy != self) + { + if(M_DistanceToTarget(self, self->enemy) < 250) + { + self->monsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + 3; + } + } + + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_RUN); + } + else + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + } +} + + + +/*---------------------------------------------------------------------- + insect runorder - order the insect to choose an run animation +-----------------------------------------------------------------------*/ +void insect_runorder(edict_t *self) +{ + QPostMessage(self, MSG_RUN, PRI_DIRECTIVE, NULL); +} + + +/*------------------------------------------------------------------------- + insectsqueal +-------------------------------------------------------------------------*/ +void insectsqueal (edict_t *self) +{ +/* if(irand(0, 1)) + gi.sound(self, CHAN_WEAPON, Sounds[SND_PAIN1], 1, ATTN_NORM, 0); + else + gi.sound(self, CHAN_WEAPON, Sounds[SND_PAIN2], 1, ATTN_NORM, 0);*/ +} + +/*------------------------------------------------------------------------- + insect_stand +-------------------------------------------------------------------------*/ +void insect_stand(edict_t *self, G_Message_t *msg) +{ + if (self->ai_mood == AI_MOOD_DELAY) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_IDLE); + + return; +} + +/*------------------------------------------------------------------------- + insect_walk +-------------------------------------------------------------------------*/ +void insect_walk(edict_t *self, G_Message_t *msg) +{ + if(self->spawnflags&MSF_FIXED) + SetAnim(self, ANIM_DELAY); + else + SetAnim(self, ANIM_WALK); +} + + +/*void Monster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + vec3_t pos1, pos2; + float zdiff; + + if ((other->svflags & SVF_MONSTER) || (!stricmp(other->classname, "player"))) + { + VectorCopy(other->s.origin, pos1); + pos1[2] += other->mins[2]; + + VectorCopy(self->s.origin, pos2); + pos2[2] += self->maxs[2]; + + zdiff = pos1[2] - pos2[2]; + + if (zdiff >= 0 ) // On top + { + other->velocity[0] = flrand(75.0, 100.0); + other->velocity[1] = flrand(75.0, 100.0); + other->velocity[2] += 101; + + if (irand(0,1)) + other->velocity[0] *= -1; + + if (irand(0,1)) + other->velocity[1] *= -1; + + self->velocity[0] = -(other->velocity[0]); + self->velocity[1] = -(other->velocity[1]); + self->velocity[2] += 100; + + other->groundentity = NULL; + self->groundentity = NULL; + } + } +}*/ + +void insect_go_inair(edict_t *self) +{ + SetAnim(self, ANIM_INAIR); +} + +void insect_go_finair(edict_t *self) +{ + SetAnim(self, ANIM_FINAIR); +} + +void insectCheckLoop (edict_t *self, float frame) +{//see if should fire again + vec3_t v; + float len, melee_range, min_seperation, missile_range; + + if(!self->enemy) + return; + + if(self->enemy->health <= 0) + return; + + if(!visible(self, self->enemy)) + return; + + if(!infront(self, self->enemy)) + return; + + ai_charge2(self, 0); + + if(irand(0,100)bypass_missile_chance) + return; + + if(self->monsterinfo.attack_finished > level.time) + return; + + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + len = VectorLength (v); + melee_range = 64; + missile_range = 384; + min_seperation = self->maxs[0] + self->enemy->maxs[0]; + + if (infront(self, self->enemy)) + {//don't loop if enemy close enough + if (len < min_seperation + melee_range) + return; + else if (len < min_seperation + missile_range && irand(0,10)<3) + return; + } + + self->monsterinfo.currframeindex = (int)frame; +} + +void insect_jump (edict_t *self, G_Message_t *msg) +{ + if(self->spawnflags&MSF_FIXED) + { + SetAnim(self, ANIM_DELAY); + return; + } + SetAnim(self, ANIM_FORCED_JUMP); + self->monsterinfo.aiflags |= AI_OVERRIDE_GUIDE; +} + +/*------------------------------------------------------------------------- + insectStaticsInit +-------------------------------------------------------------------------*/ +void TcheckrikStaticsInit() +{ + classStatics[CID_TCHECKRIK].msgReceivers[MSG_STAND] = insect_stand; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_WALK] = insect_walk; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_RUN] = insect_run; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_MELEE] = insect_melee; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_MISSILE] = insect_missile; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_PAIN] = insect_pain; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_DEATH] = insect_death; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_FALLBACK] = insect_backpedal; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_DISMEMBER] = MG_parse_dismember_msg; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_JUMP] = insect_jump; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_DEATH_PAIN] = insect_dead_pain; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_CHECK_MOOD] = insect_check_mood; + + // Cinematics + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_ACTION1] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_ACTION2] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_ACTION3] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_ACTION4] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_ATTACK1] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_ATTACK2] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_ATTACK3] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_BACKPEDAL1] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_DEATH1] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_IDLE1] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_IDLE2] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_IDLE3] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_PAIN1] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_RUN1] = insect_c_anims; + classStatics[CID_TCHECKRIK].msgReceivers[MSG_C_WALK1] = insect_c_anims; + + + resInfo.numAnims = NUM_ANIMS; + resInfo.animations = animations; + + //note that the name is different in the path + resInfo.modelIndex = gi.modelindex("models/monsters/tcheckrik/male/tris.fm"); + + Sounds[SND_PAINM]=gi.soundindex("monsters/insect/painm.wav"); + Sounds[SND_PAINF]=gi.soundindex("monsters/insect/painf.wav"); + Sounds[SND_DIEM]=gi.soundindex("monsters/insect/deathm.wav"); + Sounds[SND_DIEF]=gi.soundindex("monsters/insect/deathf.wav"); + Sounds[SND_GIB]=gi.soundindex("monsters/insect/gib.wav"); + Sounds[SND_SWIPE]=gi.soundindex("monsters/insect/swipe.wav"); + Sounds[SND_SWIPEHITF]=gi.soundindex("monsters/plagueelf/hookhit.wav"); + Sounds[SND_SWIPEHITW]=gi.soundindex("monsters/insect/swipehitw.wav"); + Sounds[SND_SPELLM]=gi.soundindex("monsters/insect/spellm.wav"); + Sounds[SND_SPELLM2]=gi.soundindex("monsters/insect/spellm2.wav"); + Sounds[SND_SPLPWRUPF]=gi.soundindex("monsters/insect/splpwrupf.wav"); + Sounds[SND_SPELLF]=gi.soundindex("monsters/insect/spellf.wav"); + Sounds[SND_GROWLM1]=gi.soundindex("monsters/insect/growlm1.wav"); + Sounds[SND_GROWLM2] = gi.soundindex ("monsters/insect/growlm2.wav"); + Sounds[SND_GROWLF1]=gi.soundindex("monsters/insect/growlf1.wav"); + Sounds[SND_GROWLF2] = gi.soundindex ("monsters/insect/growlf2.wav"); + Sounds[SND_THUD] = gi.soundindex ("monsters/insect/thud.wav"); + + resInfo.numSounds = NUM_SOUNDS; + resInfo.sounds = Sounds; + + classStatics[CID_TCHECKRIK].resInfo = &resInfo; +} + +/*QUAKED monster_tcheckrik_male (1 .5 0) (-16 -16 -32) (16 16 32) AMBUSH ASLEEP WALKING CINEMATIC BEAST_FODDER YELLOWJACKET 64 FIXED WANDER LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +The insect + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING - use WANDER instead + +BEAST_FODDER - Will run away if a Trial Beast is present + +YELLOWJACKET - uses black and yellow skin, shoots a spread of three yellow stinger projectiles + +WANDER - Monster will wander around aimlessly (but follows buoys) + +LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -10self->classID == CID_MOTHER0 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 32 +melee_range = 30 +missile_range = 512 +min_missile_range = 48 +bypass_missile_chance = 30 +jump_chance = 40 +wakeup_distance = 1024 +*/ +/*------------------------------------------------------------------------- + SP_monster_insect +-------------------------------------------------------------------------*/ +void SP_monster_tcheckrik_male (edict_t *self) +{ + if(irand(0, 1))//made random again + self->spawnflags |= MSF_INSECT_YELLOWJACKET; + + if(self->spawnflags & MSF_WALKING) + { + self->spawnflags |= MSF_WANDER; + self->spawnflags &= ~MSF_WALKING; + } + + if (!monster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_TCHECKRIK; + self->think = walkmonster_start_go; + self->monsterinfo.dismember = insect_dismember; + + if (!self->health) + { + self->health = TC_HEALTH_MALE; + } + + self->mass = MASS_TC_MALE; + self->yaw_speed = 20; + + self->movetype = PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); +// VectorSet (self->mins, -16, -16, -32); +// VectorSet (self->maxs, 16, 16, 32); + self->viewheight = self->maxs[2]*0.8; + + self->touch = M_Touch; + + self->s.modelindex = gi.modelindex("models/monsters/tcheckrik/male/tris.fm"); + + // All skins are even numbers, pain skins are skin+1. + if(self->spawnflags & MSF_INSECT_YELLOWJACKET) + self->s.skinnum = 2; + else + self->s.skinnum = 0; + + if (!self->s.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + self->materialtype = MAT_INSECT; + + //turn on/off the weapons that aren't used + self->s.fmnodeinfo[MESH__CROWN].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__RWINGS].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__LWINGS].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__STAFF].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__GEM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__FEMHAND].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__CROWN].flags |= FMNI_NO_DRAW; + + if(self->spawnflags & MSF_INSECT_BEAST_FODDER) + self->s.fmnodeinfo[MESH__MALEHAND].flags |= FMNI_NO_DRAW;//? + + //FIXME (somewhere: otherenemy should be more than just *one* kind + self->monsterinfo.otherenemyname = "monster_rat"; + + + //override female's settings in m_stats.c + if(!self->bypass_missile_chance) + self->bypass_missile_chance = 30; + + if(!self->melee_range) + self->melee_range = 48; + //set up my mood function + MG_InitMoods(self); + if(!irand(0,2)) + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + + if(self->spawnflags & MSF_WANDER) + { + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + } + else if(self->spawnflags & MSF_INSECT_CINEMATIC) + { + self->monsterinfo.c_mode = 1; + QPostMessage(self, MSG_C_IDLE1, PRI_DIRECTIVE, "iiige",0,0,0,NULL,NULL); + } + else + { + QPostMessage(self,MSG_STAND,PRI_DIRECTIVE, NULL); + } + + gi.CreateEffect(&self->s, + FX_I_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_I_RREFS, + vec3_origin); +} + +/*QUAKED monster_tcheckrik_female (1 .5 0) (-16 -16 -32) (16 16 32) AMBUSH ASLEEP WALKING CINEMATIC 16 ALTERNATE 64 FIXED WANDER MELEE_LEAD STALK COWARD EXTRA1 EXTRA2 EXTRA3 EXTRA4 + +The insect + +AMBUSH - Will not be woken up by other monsters or shots from player + +ASLEEP - will not appear until triggered + +WALKING - use WANDER instead + +WANDER - Monster will wander around aimlessly (but follows buoys) + +ALTERNATE - fires alternate projectile, more damage, not multiple though + +MELEE_LEAD - Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not + +STALK - Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally + +COWARD - Monster starts off in flee mode- runs away from you when woken up + +"homebuoy" - monsters will head to this buoy if they don't have an enemy ("homebuoy" should be targetname of the buoy you want them to go to) + +"wakeup_target" - monsters will fire this target the first time it wakes up (only once) + +"pain_target" - monsters will fire this target the first time it gets hurt (only once) + +mintel - monster intelligence- this basically tells a monster how many buoys away an enemy has to be for it to give up. + +melee_range - How close the player has to be, maximum, for the monster to go into melee. If this is zero, the monster will never melee. If it is negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance. + Examples: + melee_range = 60 - monster will start swinging it player is closer than 60 + melee_range = 0 - monster will never do a mele attack + melee_range = -100 - monster will never do a melee attack and will back away (if it has that ability) when player gets too close + +missile_range - Maximum distance the player can be from the monster to be allowed to use it's ranged attack. + +min_missile_range - Minimum distance the player can be from the monster to be allowed to use it's ranged attack. + +bypass_missile_chance - Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire. A percentage (0 = always fire/never close in, 100 = never fire/always close in).- must be whole number + +jump_chance - every time the monster has the opportunity to jump, what is the chance (out of 100) that he will... (100 = jump every time)- must be whole number + +wakeup_distance - How far (max) the player can be away from the monster before it wakes up. This just means that if the monster can see the player, at what distance should the monster actually notice him and go for him. + +DEFAULTS: +mintel = 32 +melee_range = -72 +missile_range = 512 +min_missile_range = 48 +bypass_missile_chance = 0 +jump_chance = 40 +wakeup_distance = 1024 + +NOTE: A value of zero will result in defaults, if you actually want zero as the value, use -1 +*/ +/*------------------------------------------------------------------------- + SP_monster_insect +-------------------------------------------------------------------------*/ +void SP_monster_tcheckrik_female (edict_t *self) +{ + if(self->spawnflags & MSF_WALKING) + { + self->spawnflags |= MSF_WANDER; + self->spawnflags &= ~MSF_WALKING; + } + + if (!monster_start(self)) + return; // Failed initialization + + self->msgHandler = DefaultMsgHandler; + self->classID = CID_TCHECKRIK; + self->think = walkmonster_start_go; + self->monsterinfo.dismember = insect_dismember; + + if (!self->health) + { + self->health = TC_HEALTH_FEMALE; + } + + self->mass = MASS_TC_FEMALE; + self->yaw_speed = 20; + + self->movetype = PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + self->solid=SOLID_BBOX; + + VectorCopy(STDMinsForClass[self->classID], self->mins); + VectorCopy(STDMaxsForClass[self->classID], self->maxs); + self->viewheight = self->maxs[2]*0.4; + + self->touch = M_Touch; + + self->s.modelindex = gi.modelindex("models/monsters/tcheckrik/female/tris.fm"); + + // All skins are even numbers, pain skins are skin+1. + self->s.skinnum = 0; +// self->s.skinnum = 2; + + if (!self->s.scale) + { + self->s.scale = self->monsterinfo.scale = MODEL_SCALE; + } + + self->materialtype = MAT_INSECT; + + //turn on/off the weapons that aren't used + self->s.fmnodeinfo[MESH__LMANDIBLE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__RMANDIBLE].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__L2NDARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__R2NDARM].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__MALEHAND].flags |= FMNI_NO_DRAW;//? +// self->s.fmnodeinfo[MESH__SWORD].flags |= FMNI_NO_DRAW;//? + self->s.fmnodeinfo[MESH__SPEAR].flags |= FMNI_NO_DRAW;//? + +// self->s.fmnodeinfo[MESH__GEM].flags |= FMNI_NO_DRAW; + + //FIXME (somewhere: otherenemy should be more than just *one* kind + self->monsterinfo.otherenemyname = "monster_rat"; + + //set up my mood function + MG_InitMoods(self); + if(!irand(0,2)) + self->ai_mood_flags |= AI_MOOD_FLAG_PREDICT; + + if(self->spawnflags & MSF_WANDER) + { + QPostMessage(self, MSG_WALK, PRI_DIRECTIVE, NULL); + } + else + { + QPostMessage(self,MSG_STAND,PRI_DIRECTIVE, NULL); + } + + self->monsterinfo.aiflags |= AI_NO_MELEE; + + gi.CreateEffect(&self->s, + FX_I_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_I_RREFS, + vec3_origin); + + self->svflags |= SVF_WAIT_NOTSOLID; + + if(self->spawnflags & MSF_INSECT_ALTERNATE) + { + self->s.color.a = 255; + self->s.color.r = 250; + self->s.color.g = 150; + self->s.color.b = 100; + } +} diff --git a/Toolkit/Programming/GameCode/game/m_tcheckrik.h b/Toolkit/Programming/GameCode/game/m_tcheckrik.h new file mode 100644 index 0000000..6a866b7 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_tcheckrik.h @@ -0,0 +1,206 @@ +typedef enum AnimID_e +{ + ANIM_BACK, + ANIM_DEATHFR, + ANIM_IDLE, + ANIM_LAND, + ANIM_INAIR, + ANIM_FORCED_JUMP, + ANIM_FINAIR, + ANIM_FJUMP, + ANIM_PAINA, + ANIM_PAINC, + ANIM_RUN, + ANIM_SPEAR, + ANIM_SWORD, + ANIM_SPELL, + ANIM_SPELL2, + ANIM_WALK, + ANIM_DELAY, + ANIM_KNOCK1_GO, + ANIM_KNOCK1_LOOP, + ANIM_KNOCK1_END, + ANIM_TWITCH, + + + ANIM_C_ACTION1, + ANIM_C_ACTION2, + ANIM_C_ACTION3, + ANIM_C_ACTION4, + ANIM_C_ATTACK1, + ANIM_C_ATTACK2, + ANIM_C_ATTACK3, + ANIM_C_BACKPEDAL, + ANIM_C_DEATH1, + ANIM_C_IDLE1, + ANIM_C_IDLE2, + ANIM_C_IDLE3, + ANIM_C_PAIN1, + ANIM_C_RUN1, + ANIM_C_WALK1, + NUM_ANIMS +} AnimID_t; + +typedef enum SoundID_e +{ + SND_PAINM, + SND_PAINF, + SND_DIEM, + SND_DIEF, + SND_GIB, + SND_SWIPE, + SND_SWIPEHITF, + SND_SWIPEHITW, + SND_SPELLM, + SND_SPELLM2, + SND_SPLPWRUPF, + SND_SPELLF, + SND_GROWLM1, + SND_GROWLM2, + SND_GROWLF1, + SND_GROWLF2, + SND_THUD, + NUM_SOUNDS +} SoundID_t; + +extern animmove_t insect_move_back;// = {10, insect_frames_back, insect_pause}; +extern animmove_t insect_move_deathfr;// = {23, insect_frames_deathfr, insect_dead}; +extern animmove_t insect_move_idle;// = { 50, insect_frames_idle, NULL}; +extern animmove_t insect_move_land;// = {6, insect_frames_land, insect_pause}; +extern animmove_t insect_move_inair;// = {1, insect_frames_inair, NULL}; +extern animmove_t insect_move_forcedjump;// = {9, insect_frames_forcedjump, insect_go_inair}; +extern animmove_t insect_move_finair;// = {1, insect_frames_inair, NULL}; +extern animmove_t insect_move_fjump;// = {9, insect_frames_forcedjump, insect_go_inair}; +extern animmove_t insect_move_paina;// = {7, insect_frames_paina, insect_pause}; +extern animmove_t insect_move_painc;// = {6, insect_frames_painc, insect_pause}; +extern animmove_t insect_move_run;// = {10, insect_frames_run, insect_pause}; +extern animmove_t insect_move_spear;// = {11, insect_frames_spear, insect_pause}; +extern animmove_t insect_move_sword;// = {9, insect_frames_sword, insect_pause}; +extern animmove_t insect_move_spell;// = {8, insect_frames_spell, insect_pause}; +extern animmove_t insect_move_spell2;// = {8, insect_frames_spell, insect_pause}; +extern animmove_t insect_move_walk;// = {20, insect_frames_walk, insect_pause}; +extern animmove_t insect_delay;// = {50 , insect_frames_delay, insect_pause}; + +extern animmove_t insect_move_c_action1; +extern animmove_t insect_move_c_action2; +extern animmove_t insect_move_c_action3; +extern animmove_t insect_move_c_action4; +extern animmove_t insect_move_c_idle1; +extern animmove_t insect_move_c_idle2; +extern animmove_t insect_move_c_idle3; +extern animmove_t insect_move_c_walk; +extern animmove_t insect_move_c_run; +extern animmove_t insect_move_c_backpedal; +extern animmove_t insect_move_c_attack1; +extern animmove_t insect_move_c_attack2; +extern animmove_t insect_move_c_attack3; +extern animmove_t insect_move_c_death1; +extern animmove_t insect_move_c_pain1; +extern animmove_t insect_move_c_pain2; +extern animmove_t insect_move_c_jump; +extern animmove_t insect_move_c_inair; +extern animmove_t insect_move_knock1_go; +extern animmove_t insect_move_knock1_loop; +extern animmove_t insect_move_knock1_end; +extern animmove_t insect_move_twitch; + +extern void insect_c_walk(edict_t *self, G_Message_t *msg); +extern void insect_c_backpedal(edict_t *self, G_Message_t *msg); +extern void insect_c_action1(edict_t *self, G_Message_t *msg); +extern void insect_c_action2(edict_t *self, G_Message_t *msg); +extern void insect_c_action3(edict_t *self, G_Message_t *msg); +extern void insect_c_action4(edict_t *self, G_Message_t *msg); +extern void insect_c_idle1(edict_t *self, G_Message_t *msg); +extern void insect_c_idle2(edict_t *self, G_Message_t *msg); +extern void insect_c_idle3(edict_t *self, G_Message_t *msg); +extern void insect_c_attack1(edict_t *self, G_Message_t *msg); +extern void insect_c_attack2(edict_t *self, G_Message_t *msg); +extern void insect_c_attack3(edict_t *self, G_Message_t *msg); +extern void insect_c_death1(edict_t *self, G_Message_t *msg); +extern void insect_c_pain1(edict_t *self, G_Message_t *msg); +extern void insect_c_jump(edict_t *self, G_Message_t *msg); +extern void insect_c_pause (edict_t *self, G_Message_t *msg); +extern void insect_c_reallydead (edict_t *self); +extern void insect_c_go_inair (edict_t *self); + +void MG_CheckLanded (edict_t *self, float next_anim); +void MG_InAirMove (edict_t *self, float fwdspd,float upspd,float rtspd); +void MG_ApplyJump (edict_t *self); + +void SpellCastInsectStaff(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,qboolean power); +void SpellCastGlobeOfOuchiness(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir); +void insectReleaseSpell (edict_t *self); +void insectReadySpell (edict_t *self); +void insectDoneSpell (edict_t *self); + +void insectCut (edict_t *self, float attacktype); +void insectSpell(edict_t *self, float whichspell); +void insectStaff(edict_t *self); +void insectCheckLoop (edict_t *self, float frame); + +void insect_blocked(edict_t *self, G_Message_t *msg); +void insect_death(edict_t *self, G_Message_t *msg); +void insect_run(edict_t *self, G_Message_t *msg); +void insect_walk(edict_t *self, G_Message_t *msg); +void insect_melee(edict_t *self, G_Message_t *msg); +void insect_stand(edict_t *self, G_Message_t *msg); +void insect_pain(edict_t *self, G_Message_t *msg); + +void insect_dead(edict_t *self); +void insectdeathsqueal(edict_t *self); +void insectsqueal(edict_t *self); +void insectgrowl(edict_t *self); +void insectbite(edict_t *self); +void insect_think_pain(edict_t *self); +void insect_pause (edict_t *self); +void insect_dropweapon (edict_t *self, int weapon); +void insect_go_inair(edict_t *self); +void ai_charge2 (edict_t *self, float dist); +void insect_sound(edict_t *self, float channel, float soundnum, float attn); +void insect_wait_twitch (edict_t *self); +void insect_flyback_loop(edict_t *self); +void insect_flyback_move(edict_t *self); +void insect_random_idle_sound (edict_t *self); +void insect_go_finair(edict_t *self); + +void SP_monster_insect (edict_t *self); +void MG_InitMoods(edict_t *self); + + +#define BIT_MASTER 0 +#define BIT_LLEG 1 +#define BIT_HEAD 2 +#define BIT_LMANDIBLE 4 +#define BIT_RMANDIBLE 8 +#define BIT_CROWN 16 +#define BIT_L2NDARM 32 +#define BIT_SPEAR 64 +#define BIT_FEMHAND 128 +#define BIT_SWORD 256 +#define BIT_STAFF 512 +#define BIT_GEM 1024 +#define BIT_R2NDARM 2048 +#define BIT_RWINGS 4096 +#define BIT_LWINGS 8192 +#define BIT_RLEG 16384 + +#define TC_ATK_STAB 1 +#define TC_ATK_HACK 2 + +#define TC_SPL_FIRE 1 +#define TC_SPL_GLOW 2 +#define TC_SPL_FIRE2 3 + +enum +{ + FX_I_SWORD, + FX_I_SPEAR, + FX_I_SP_MSL_HIT, + FX_I_GLOBE, + FX_I_GLOW, + FX_I_STAFF, + FX_I_ST_MSL_HIT, + FX_I_RREFS, + FX_I_SPEAR2, + FX_I_SP_MSL_HIT2 +}; diff --git a/Toolkit/Programming/GameCode/game/m_tcheckrik_anim.c b/Toolkit/Programming/GameCode/game/m_tcheckrik_anim.c new file mode 100644 index 0000000..216010a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_tcheckrik_anim.c @@ -0,0 +1,980 @@ +//============================================================================== +// +// m_insect_anim.c +// +// Heretic II +// Copyright 1998 Raven Software +// +//============================================================================== + +#include "g_local.h" + +#pragma hdrstop("g_local.pch") +// PRECOMPILED HEADER ABOVE +// WARNING: DO NOT CHANGE THE ABOVE HEADERS OR THE PRECOMPILED STUFF WILL BREAK! +// ADD ANY ADDITIONAL FILES BELOW + +#include "m_tcheckrik_anim.h" +#include "m_tcheckrik.h" +#include "c_ai.h" +#include "g_monster.h" + +//all of the anim frames that used to live in m_insect.h + +/*---------------------------------------------------------------------- +// +// Non - Cinematic frames +// +/*---------------------------------------------------------------------- + + +/*---------------------------------------------------------------------- + insect backpedalling +-----------------------------------------------------------------------*/ +animframe_t insect_frames_back [] = +{ + FRAME_backpeddle1, NULL, 0, 0, 0, ai_charge, -18, NULL,//insectgrowl, + FRAME_backpeddle2, NULL, 0, 0, 0, ai_charge, -16, NULL, + FRAME_backpeddle3, NULL, 0, 0, 0, ai_charge, -12, NULL, + FRAME_backpeddle4, NULL, 0, 0, 0, ai_charge, -8, NULL, + FRAME_backpeddle5, NULL, 0, 0, 0, ai_charge, -16, NULL, + FRAME_backpeddle6, NULL, 0, 0, 0, ai_charge, -12, NULL, + FRAME_backpeddle7, NULL, 0, 0, 0, ai_charge, -20, NULL, + FRAME_backpeddle8, NULL, 0, 0, 0, ai_charge, -18, NULL, + FRAME_backpeddle9, NULL, 0, 0, 0, ai_charge, -10, NULL, + FRAME_backpeddle10, NULL, 0, 0, 0, ai_charge, -6, NULL, +}; +animmove_t insect_move_back = {10, insect_frames_back, insect_pause}; + +/*------------------------------------------------------------------------- + insect_frames_death3 +-------------------------------------------------------------------------*/ +animframe_t insect_frames_deathfr [] = +{ + FRAME_deathfr1, NULL, 0, 0, 0, ai_move, -24, NULL, + FRAME_deathfr2, NULL, 0, 0, 0, ai_move, -18, NULL, //after this frame, goes into knockback?!!?!? + FRAME_deathfr3, NULL, 0, 0, 0, ai_move, -12, NULL, + FRAME_deathfr4, NULL, 0, 0, 0, ai_move, -8, NULL, + FRAME_deathfr5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr7, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr8, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr9, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr10, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr11, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr16, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr17, NULL, 0, 0, 0, ai_move, 4, NULL, + FRAME_deathfr18, NULL, 0, 0, 0, ai_move, 6, MG_NoBlocking, + FRAME_deathfr19, NULL, 0, 0, 0, ai_move, 12, NULL, + FRAME_deathfr20, insect_sound, CHAN_BODY, SND_THUD, ATTN_NORM, ai_move, 4, NULL, + FRAME_deathfr21, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr22, NULL, 0, 0, 0, NULL, 0, insect_dead, +}; +animmove_t insect_move_deathfr = {22, insect_frames_deathfr, NULL}; + +/*------------------------------------------------------------------------- + insect death +-------------------------------------------------------------------------*/ +/*------------------------------------------------------------------ + insect knock -- the insect +-------------------------------------------------------------------*/ +animframe_t insect_frames_knock1_go [] = +{ + FRAME_knock1, NULL, 0, 0, 0, NULL, 0, insect_flyback_move, +}; +animmove_t insect_move_knock1_go = { 1, insect_frames_knock1_go, insect_flyback_loop }; + +animframe_t insect_frames_knock1_loop [] = +{ + FRAME_knock2, NULL, 0, 0, 0, NULL, 0, insect_flyback_move, +}; +animmove_t insect_move_knock1_loop = { 1, insect_frames_knock1_loop, NULL }; + +animframe_t insect_frames_knock1_end [] = +{ + FRAME_knock3, insect_sound, CHAN_BODY, SND_THUD, ATTN_NORM, ai_move, -4, insect_flyback_move, + FRAME_knock4, NULL, 0, 0, 0, ai_move, -3, insect_flyback_move, + FRAME_knock5, NULL, 0, 0, 0, ai_move, -3, insect_flyback_move, + FRAME_knock6, NULL, 0, 0, 0, ai_move, -3, insect_flyback_move, + FRAME_knock7, NULL, 0, 0, 0, ai_move, -2, insect_flyback_move, + FRAME_knock8, NULL, 0, 0, 0, ai_move, -2, insect_flyback_move, + FRAME_knock9, NULL, 0, 0, 0, ai_move, -2, insect_flyback_move, + FRAME_knock10, NULL, 0, 0, 0, ai_move, -1, insect_flyback_move, + FRAME_knock11, NULL, 0, 0, 0, ai_move, -1, insect_flyback_move, + FRAME_knock12, NULL, 0, 0, 0, ai_move, 0, insect_flyback_move, + FRAME_knock13, NULL, 0, 0, 0, ai_move, 0, insect_flyback_move, + FRAME_knock14, NULL, 0, 0, 0, ai_move, 0, insect_flyback_move, + FRAME_knock15, NULL, 0, 0, 0, ai_move, 0, MG_NoBlocking, + FRAME_knock15, NULL, 0, 0, 0, NULL, 0, insect_wait_twitch, +}; +animmove_t insect_move_knock1_end = { 14, insect_frames_knock1_end, NULL }; + +animframe_t insect_frames_twitch [] = +{//takes a couple steps back.. may clip!!! + FRAME_knock16, NULL, 0, 0, 0, NULL, 0, insect_random_idle_sound, + FRAME_knock17, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_knock18, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_knock19, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_knock19, NULL, 0, 0, 0, NULL, 0, insect_wait_twitch, +}; +animmove_t insect_move_twitch = {5, insect_frames_twitch, NULL}; + +/*---------------------------------------------------------------------- + insect standing around +-----------------------------------------------------------------------*/ +animframe_t insect_frames_idle [] = +{ + FRAME_idle1, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle2, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle3, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle4, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle5, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle6, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle7, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle8, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle9, NULL, 0, 0, 0, ai_stand, 0, insectgrowl, + FRAME_idle10, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle11, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle12, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle13, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle14, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle15, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle16, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle17, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle18, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle19, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle20, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle21, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle22, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle23, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle24, NULL, 0, 0, 0, ai_stand, 0, insectgrowl, + FRAME_idle25, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle26, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle27, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle28, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle29, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle30, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle31, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle32, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle33, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle34, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle35, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle36, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle37, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle38, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle39, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle40, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle41, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle42, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle43, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle44, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle45, NULL, 0, 0, 0, ai_stand, 0, insectgrowl, + FRAME_idle46, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle47, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle48, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle49, NULL, 0, 0, 0, ai_stand, 0, NULL, + FRAME_idle50, NULL, 0, 0, 0, ai_stand, 0, NULL +}; +animmove_t insect_move_idle = { 50, insect_frames_idle, insect_pause}; + +/*---------------------------------------------------------------------- + insect land +-----------------------------------------------------------------------*/ +animframe_t insect_frames_land [] = +{ + FRAME_jump11, insect_sound, CHAN_BODY, SND_THUD, ATTN_NORM, NULL, 0, NULL,//sound + FRAME_jump12, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump13, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump14, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump15, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump16, NULL, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t insect_move_land = {6, insect_frames_land, insect_pause}; + +/*---------------------------------------------------------------------- + insect in air +-----------------------------------------------------------------------*/ +animframe_t insect_frames_inair [] = +{ + FRAME_jump10, MG_InAirMove, 50, 0, 0, MG_CheckLanded, ANIM_LAND, NULL//hang here until land +}; +animmove_t insect_move_inair = {1, insect_frames_inair, NULL}; + +/*---------------------------------------------------------------------- + insect forced jump +-----------------------------------------------------------------------*/ +animframe_t insect_frames_forcedjump [] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, MG_ApplyJump,//off ground + FRAME_jump5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump7, MG_InAirMove, 50, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump8, MG_InAirMove, 50, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump9, MG_InAirMove, 50, 0, 0, MG_CheckLanded, ANIM_LAND, NULL +}; +animmove_t insect_move_forcedjump = {9, insect_frames_forcedjump, insect_go_inair}; + +/*---------------------------------------------------------------------- + insect in air +-----------------------------------------------------------------------*/ +animframe_t insect_frames_finair [] = +{ + FRAME_jump10, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL//hang here until land +}; +animmove_t insect_move_finair = {1, insect_frames_finair, NULL}; + +/*---------------------------------------------------------------------- + insect forced jump +-----------------------------------------------------------------------*/ +animframe_t insect_frames_fjump [] = +{ + FRAME_jump1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_jump4, NULL, 0, 0, 0, ai_charge, 0, MG_ApplyJump,//off ground + FRAME_jump5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_jump7, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump8, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL, + FRAME_jump9, NULL, 0, 0, 0, MG_CheckLanded, ANIM_LAND, NULL +}; +animmove_t insect_move_fjump = {9, insect_frames_fjump, insect_go_finair}; + +/*---------------------------------------------------------------------- + insect Pain - insect gets hit +-----------------------------------------------------------------------*/ +animframe_t insect_frames_paina [] = +{ + FRAME_paina1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina6, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina7, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_paina = {7, insect_frames_paina, insect_pause}; + +/*---------------------------------------------------------------------- + insect Pain - insect gets hit +-----------------------------------------------------------------------*/ +animframe_t insect_frames_painc [] = +{ + FRAME_paina1, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina2, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina3, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina4, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina5, NULL, 0, 0, 0, NULL, 0, NULL, + FRAME_paina6, NULL, 0, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_painc = {6, insect_frames_painc, insect_pause}; + +/*---------------------------------------------------------------------- + insect Running - insect running +-----------------------------------------------------------------------*/ +animframe_t insect_frames_run [] = +{ + FRAME_Run1, NULL, 0, 0, 0, ai_run, 12, insectgrowl, + FRAME_Run2, NULL, 0, 0, 0, ai_run, 13, insect_pause, + FRAME_Run3, NULL, 0, 0, 0, ai_run, 14, insect_pause, + FRAME_Run4, NULL, 0, 0, 0, ai_run, 14, insect_pause, + FRAME_Run5, NULL, 0, 0, 0, ai_run, 14, insect_pause, + FRAME_Run6, NULL, 0, 0, 0, ai_run, 14, insect_pause, + FRAME_Run7, NULL, 0, 0, 0, ai_run, 14, insect_pause, + FRAME_Run8, NULL, 0, 0, 0, ai_run, 11, insect_pause, + FRAME_Run9, NULL, 0, 0, 0, ai_run, 14, insect_pause, + FRAME_Run10, NULL, 0, 0, 0, ai_run, 14, insect_pause, + FRAME_Run10, NULL, 0, 0, 0, ai_run, 14, insect_pause +}; +animmove_t insect_move_run = {11, insect_frames_run, insect_pause}; + +/*---------------------------------------------------------------------- + insect spear - insect attacking +-----------------------------------------------------------------------*/ +animframe_t insect_frames_spear [] = +{ + FRAME_SpearB1, NULL, 0, 0, 0, ai_charge, 0, insectgrowl, + FRAME_SpearB2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_SpearB3, NULL, 0, 0, 0, ai_charge, 0, insectStaff, + FRAME_SpearB4, NULL, 0, 0, 0, ai_charge, 0, insectStaff, + FRAME_SpearB5, NULL, 0, 0, 0, ai_charge, 0, insectStaff, + FRAME_SpearB6, NULL, 0, 0, 0, ai_charge, 0, insectStaff, + FRAME_SpearB7, NULL, 0, 0, 0, insectCheckLoop, 3, NULL, + FRAME_SpearB8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_SpearB9, NULL, 0, 0, 0, ai_charge, 0, NULL,//check for loop + FRAME_SpearB10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_SpearB11, NULL, 0, 0, 0, ai_charge, 0, NULL +}; +animmove_t insect_move_spear = {11, insect_frames_spear, insect_pause}; + +/*---------------------------------------------------------------------- + insect sword - insect attacking +-----------------------------------------------------------------------*/ +animframe_t insect_frames_sword [] = +{ + FRAME_sword1, NULL, 0, 0, 0, ai_charge, 0, insectgrowl, + FRAME_sword2, insect_sound, CHAN_WEAPON, SND_SWIPE, ATTN_NORM, ai_charge, 0, NULL, + FRAME_sword3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_sword4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_sword5, NULL, 0, 0, 0, insectCut, TC_ATK_HACK, NULL, + FRAME_sword6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_sword7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_sword8, NULL, 0, 0, 0, insectCheckLoop, 1, NULL, + FRAME_sword9, NULL, 0, 0, 0, ai_charge, 0, NULL//check for loop +}; +animmove_t insect_move_sword = {9, insect_frames_sword, insect_pause}; + +/*---------------------------------------------------------------------- + insect spell - insect attacking +-----------------------------------------------------------------------*/ + +animframe_t insect_frames_spell [] = +{ + FRAME_spell1, NULL, 0, 0, 0, insectSpell, TC_SPL_GLOW, NULL, + FRAME_spell2, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell3, NULL, 0, 0, 0, insectSpell, TC_SPL_FIRE, NULL, + FRAME_spell4, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell6, NULL, 0, 0, 0, insectSpell, TC_SPL_FIRE, NULL, + FRAME_spell7, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell9, NULL, 0, 0, 0, insectSpell, TC_SPL_FIRE, NULL, + FRAME_spell10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell11, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell12, NULL, 0, 0, 0, insectSpell, TC_SPL_FIRE, NULL, + FRAME_spell13, NULL, 0, 0, 0, ai_charge, 0, insectReleaseSpell,//here if forwards + FRAME_spell14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell16, NULL, 0, 0, 0, ai_charge, 0, NULL,//check for loop? + FRAME_spell17, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t insect_move_spell = {17, insect_frames_spell, insect_pause}; + +/*---------------------------------------------------------------------- + insect spell - insect attacking 2nd spell +-----------------------------------------------------------------------*/ + +animframe_t insect_frames_spell2 [] = +{ + FRAME_spell1, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell3, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell8, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell10, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell12, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell13, NULL, 0, 0, 0, insectSpell, TC_SPL_FIRE2, NULL, + FRAME_spell14, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell15, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell16, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell17, NULL, 0, 0, 0, ai_charge, 0, NULL, +}; +animmove_t insect_move_spell2 = {12, insect_frames_spell2, insect_pause}; + +/* +animframe_t insect_frames_spell [] = +{ + FRAME_spell1, NULL, 0, 0, 0, ai_charge, 0, insectSpell, + FRAME_spell2, NULL, 0, 0, 0, ai_charge, 0, insectSpell, + FRAME_spell3, NULL, 0, 0, 0, ai_charge, 0, insectSpell, + FRAME_spell4, NULL, 0, 0, 0, ai_charge, 0, insectSpell, + FRAME_spell5, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell6, NULL, 0, 0, 0, ai_charge, 0, NULL, + FRAME_spell7, NULL, 0, 0, 0, ai_charge, 0, NULL,//check for loop? + FRAME_spell8, NULL, 0, 0, 0, ai_charge, 0, NULL +}; +animmove_t insect_move_spell = {8, insect_frames_spell, insect_pause}; +*/ +/*---------------------------------------------------------------------- + insect Walking - insect walking +-----------------------------------------------------------------------*/ +animframe_t insect_frames_walk [] = +{ + FRAME_Walk1, NULL, 0, 0, 0, ai_walk, 6, insectgrowl, + FRAME_Walk2, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk3, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk4, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk5, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk6, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk7, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk8, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk9, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk10, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk11, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk12, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk13, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk14, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk15, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk16, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk17, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk18, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk19, NULL, 0, 0, 0, ai_walk, 6, NULL, + FRAME_Walk20, NULL, 0, 0, 0, ai_walk, 6, NULL +}; +animmove_t insect_move_walk = {20, insect_frames_walk, insect_pause}; + +/* + + Insect standing by- not thinking, just waiting for a door or plat or something + +*/ +animframe_t insect_frames_delay [] = +{ + FRAME_idle1, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle2, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle3, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle4, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle5, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle6, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle7, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle8, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle9, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle10, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle11, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle12, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle13, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle14, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle15, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle16, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle17, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle18, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle19, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle20, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle21, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle22, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle23, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle24, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle25, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle26, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle27, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle28, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle29, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle30, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle31, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle32, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle33, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle34, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle35, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle36, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle37, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle38, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle39, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle40, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle41, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle42, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle43, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle44, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle45, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle46, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle47, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle48, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle49, NULL, 0, 0, 0, NULL, 0, insect_pause, + FRAME_idle50, NULL, 0, 0, 0, NULL, 0, insect_pause +}; +animmove_t insect_delay = {50 , insect_frames_delay, insect_pause}; + + + + +/*---------------------------------------------------------------------- +// +// Cinematic Frames +// +/*---------------------------------------------------------------------- + + +/*---------------------------------------------------------------------- + insect +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_action1 [] = +{ + FRAME_ts_lean2talk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_ts_lean2talk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_ts_lean2talk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_ts_lean2talk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_ts_lean2talk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_ts_lean2talk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_ts_lean2talk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_ts_lean2talk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_ts_lean2talk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, +}; +animmove_t insect_move_c_action1 = {9, insect_frames_c_action1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + insect +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_action2 [] = +{ + FRAME_ts_listen1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_listen60, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_c_action2 = { 60, insect_frames_c_action2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + insect +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_action3 [] = +{ + FRAME_ts_spear1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_spear2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_spear3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_spear4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_spear5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_spear6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_spear7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_spear8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_spear9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_spear10, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t insect_move_c_action3 = { 10, insect_frames_c_action3, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + insect +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_action4 [] = +{ + FRAME_ts_talk1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_talk60, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_c_action4 = { 60, insect_frames_c_action4, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + insect standing around +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_idle1 [] = +{ + FRAME_idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_idle50, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_c_idle1 = { 50, insect_frames_c_idle1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + insect standing around +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_idle2 [] = +{ + FRAME_ts_rdy2idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_rdy2idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_rdy2idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_rdy2idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, +}; +animmove_t insect_move_c_idle2 = { 4, insect_frames_c_idle2, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + insect standing around +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_idle3 [] = +{ + FRAME_ts_idle1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle22, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle23, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle24, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle25, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle26, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle27, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle28, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle29, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle30, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle31, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle32, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle33, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle34, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle35, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle36, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle37, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle38, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle39, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle40, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle41, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle42, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle43, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle44, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle45, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle46, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle47, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle48, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle49, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle50, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle51, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle52, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle53, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle54, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle55, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle56, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle57, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle58, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle59, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_ts_idle60, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_c_idle3 = { 60, insect_frames_c_idle3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + insect Running - insect running +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_run [] = +{ + FRAME_Run1, ai_c_move, 12, 0, 0, NULL, 0, NULL, + FRAME_Run2, ai_c_move, 13, 0, 0, NULL, 0, NULL, + FRAME_Run3, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_Run4, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_Run5, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_Run6, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_Run7, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_Run8, ai_c_move, 11, 0, 0, NULL, 0, NULL, + FRAME_Run9, ai_c_move, 14, 0, 0, NULL, 0, NULL, + FRAME_Run10, ai_c_move, 14, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_c_run = {10, insect_frames_c_run, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + insect spear - insect attacking +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_attack1 [] = +{ + FRAME_SpearB1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_SpearB2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_SpearB3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_SpearB4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_SpearB5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_SpearB6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_SpearB7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_SpearB8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_SpearB9, ai_c_move, 0, 0, 0, NULL, 0, NULL,//check for loop + FRAME_SpearB10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_SpearB11, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_c_attack1 = {11, insect_frames_c_attack1, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + insect spell - insect attacking +-----------------------------------------------------------------------*/ + +animframe_t insect_frames_c_attack2 [] = +{ + FRAME_spell1, ai_c_move, 0, 0, 0, NULL, TC_SPL_GLOW, NULL, + FRAME_spell2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spell3, ai_c_move, 0, 0, 0, NULL, TC_SPL_FIRE, NULL, + FRAME_spell4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spell5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spell6, ai_c_move, 0, 0, 0, NULL, TC_SPL_FIRE, NULL, + FRAME_spell7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spell8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spell9, ai_c_move, 0, 0, 0, NULL, TC_SPL_FIRE, NULL, + FRAME_spell10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spell11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spell12, ai_c_move, 0, 0, 0, NULL, TC_SPL_FIRE, NULL, + FRAME_spell13, ai_c_move, 0, 0, 0, NULL, 0, NULL,//here if forwards + FRAME_spell14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spell15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_spell16, ai_c_move, 0, 0, 0, NULL, 0, NULL,//check for loop? + FRAME_spell17, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_c_attack2 = {17, insect_frames_c_attack2, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + insect sword - insect attacking +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_attack3 [] = +{ + FRAME_sword1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_sword2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_sword3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_sword4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_sword5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_sword6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_sword7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_sword8, ai_c_move, 0, 0, 0, NULL, 1, NULL, + FRAME_sword9, ai_c_move, 0, 0, 0, NULL, 0, NULL//check for loop +}; +animmove_t insect_move_c_attack3 = {9, insect_frames_c_attack3, ai_c_cycleend}; + +/*---------------------------------------------------------------------- + insect backpedalling +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_backpedal [] = +{ + FRAME_backpeddle1, ai_c_move, -10, 0, 0, NULL, 0, NULL, + FRAME_backpeddle2, ai_c_move, -12, 0, 0, NULL, 0, NULL, + FRAME_backpeddle3, ai_c_move, -10, 0, 0, NULL, 0, NULL, + FRAME_backpeddle4, ai_c_move, -12, 0, 0, NULL, 0, NULL, + FRAME_backpeddle5, ai_c_move, -10, 0, 0, NULL, 0, NULL, + FRAME_backpeddle6, ai_c_move, -12, 0, 0, NULL, 0, NULL, + FRAME_backpeddle7, ai_c_move, -10, 0, 0, NULL, 0, NULL, + FRAME_backpeddle8, ai_c_move, -12, 0, 0, NULL, 0, NULL, + FRAME_backpeddle9, ai_c_move, -10, 0, 0, NULL, 0, NULL, + FRAME_backpeddle10, ai_c_move, -12, 0, 0, NULL, 0, NULL, +}; +animmove_t insect_move_c_backpedal = {10, insect_frames_c_backpedal, ai_c_cycleend}; + + +/*------------------------------------------------------------------------- + insect_frames_death1 +-------------------------------------------------------------------------*/ +animframe_t insect_frames_c_death1 [] = +{//takes a couple steps back.. may clip!!! + FRAME_deathfr1, ai_c_move, -24, 0, 0, NULL, 0, insectdeathsqueal, + FRAME_deathfr2, ai_c_move, -18, 0, 0, NULL, 0, NULL, + FRAME_deathfr3, ai_c_move, -12, 0, 0, NULL, 0, NULL, + FRAME_deathfr4, ai_c_move, -8, 0, 0, NULL, 0, NULL, + FRAME_deathfr5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr7, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr8, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr9, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr10, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr11, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr12, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr13, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr14, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr15, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr16, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr17, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr18, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr19, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr20, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr21, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_deathfr22, insect_sound, CHAN_BODY, SND_THUD, ATTN_NORM, NULL, 0, NULL, +}; +animmove_t insect_move_c_death1 = {22, insect_frames_c_death1, insect_c_reallydead}; + +/*---------------------------------------------------------------------- + insect Pain - insect gets hit +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_pain1 [] = +{ + FRAME_paina1, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_paina2, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_paina3, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_paina4, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_paina5, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_paina6, ai_c_move, 0, 0, 0, NULL, 0, NULL, + FRAME_paina7, ai_c_move, 0, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_c_pain1 = {7, insect_frames_c_pain1, ai_c_cycleend}; + + +/*---------------------------------------------------------------------- + insect Walking - insect walking +-----------------------------------------------------------------------*/ +animframe_t insect_frames_c_walk [] = +{ + FRAME_Walk1, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk2, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk3, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk4, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk5, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk6, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk7, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk8, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk9, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk10, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk11, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk12, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk13, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk14, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk15, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk16, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk17, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk18, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk19, ai_c_move, 4, 0, 0, NULL, 0, NULL, + FRAME_Walk20, ai_c_move, 4, 0, 0, NULL, 0, NULL +}; +animmove_t insect_move_c_walk = {20, insect_frames_c_walk, ai_c_cycleend}; + diff --git a/Toolkit/Programming/GameCode/game/m_tcheckrik_anim.h b/Toolkit/Programming/GameCode/game/m_tcheckrik_anim.h new file mode 100644 index 0000000..e4bd463 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_tcheckrik_anim.h @@ -0,0 +1,427 @@ +// R:\Art\models/monsters\tcheckrik\male + +// This file generated by qdata - Do NOT Modify + +#define FRAME_partfly 0 +#define FRAME_deathfr1 1 +#define FRAME_deathfr2 2 +#define FRAME_deathfr3 3 +#define FRAME_deathfr4 4 +#define FRAME_deathfr5 5 +#define FRAME_deathfr6 6 +#define FRAME_deathfr7 7 +#define FRAME_deathfr8 8 +#define FRAME_deathfr9 9 +#define FRAME_deathfr10 10 +#define FRAME_deathfr11 11 +#define FRAME_deathfr12 12 +#define FRAME_deathfr13 13 +#define FRAME_deathfr14 14 +#define FRAME_deathfr15 15 +#define FRAME_deathfr16 16 +#define FRAME_deathfr17 17 +#define FRAME_deathfr18 18 +#define FRAME_deathfr19 19 +#define FRAME_deathfr20 20 +#define FRAME_deathfr21 21 +#define FRAME_deathfr22 22 +#define FRAME_deathfr23 23 +#define FRAME_backpeddle1 24 +#define FRAME_backpeddle2 25 +#define FRAME_backpeddle3 26 +#define FRAME_backpeddle4 27 +#define FRAME_backpeddle5 28 +#define FRAME_backpeddle6 29 +#define FRAME_backpeddle7 30 +#define FRAME_backpeddle8 31 +#define FRAME_backpeddle9 32 +#define FRAME_backpeddle10 33 +#define FRAME_idle1 34 +#define FRAME_idle2 35 +#define FRAME_idle3 36 +#define FRAME_idle4 37 +#define FRAME_idle5 38 +#define FRAME_idle6 39 +#define FRAME_idle7 40 +#define FRAME_idle8 41 +#define FRAME_idle9 42 +#define FRAME_idle10 43 +#define FRAME_idle11 44 +#define FRAME_idle12 45 +#define FRAME_idle13 46 +#define FRAME_idle14 47 +#define FRAME_idle15 48 +#define FRAME_idle16 49 +#define FRAME_idle17 50 +#define FRAME_idle18 51 +#define FRAME_idle19 52 +#define FRAME_idle20 53 +#define FRAME_idle21 54 +#define FRAME_idle22 55 +#define FRAME_idle23 56 +#define FRAME_idle24 57 +#define FRAME_idle25 58 +#define FRAME_idle26 59 +#define FRAME_idle27 60 +#define FRAME_idle28 61 +#define FRAME_idle29 62 +#define FRAME_idle30 63 +#define FRAME_idle31 64 +#define FRAME_idle32 65 +#define FRAME_idle33 66 +#define FRAME_idle34 67 +#define FRAME_idle35 68 +#define FRAME_idle36 69 +#define FRAME_idle37 70 +#define FRAME_idle38 71 +#define FRAME_idle39 72 +#define FRAME_idle40 73 +#define FRAME_idle41 74 +#define FRAME_idle42 75 +#define FRAME_idle43 76 +#define FRAME_idle44 77 +#define FRAME_idle45 78 +#define FRAME_idle46 79 +#define FRAME_idle47 80 +#define FRAME_idle48 81 +#define FRAME_idle49 82 +#define FRAME_idle50 83 +#define FRAME_jump1 84 +#define FRAME_jump2 85 +#define FRAME_jump3 86 +#define FRAME_jump4 87 +#define FRAME_jump5 88 +#define FRAME_jump6 89 +#define FRAME_jump7 90 +#define FRAME_jump8 91 +#define FRAME_jump9 92 +#define FRAME_jump10 93 +#define FRAME_jump11 94 +#define FRAME_jump12 95 +#define FRAME_jump13 96 +#define FRAME_jump14 97 +#define FRAME_jump15 98 +#define FRAME_jump16 99 +#define FRAME_paina1 100 +#define FRAME_paina2 101 +#define FRAME_paina3 102 +#define FRAME_paina4 103 +#define FRAME_paina5 104 +#define FRAME_paina6 105 +#define FRAME_paina7 106 +#define FRAME_painc1 107 +#define FRAME_painc2 108 +#define FRAME_painc3 109 +#define FRAME_painc4 110 +#define FRAME_painc5 111 +#define FRAME_painc6 112 +#define FRAME_Run1 113 +#define FRAME_Run2 114 +#define FRAME_Run3 115 +#define FRAME_Run4 116 +#define FRAME_Run5 117 +#define FRAME_Run6 118 +#define FRAME_Run7 119 +#define FRAME_Run8 120 +#define FRAME_Run9 121 +#define FRAME_Run10 122 +#define FRAME_SpearB1 123 +#define FRAME_SpearB2 124 +#define FRAME_SpearB3 125 +#define FRAME_SpearB4 126 +#define FRAME_SpearB5 127 +#define FRAME_SpearB6 128 +#define FRAME_SpearB7 129 +#define FRAME_SpearB8 130 +#define FRAME_SpearB9 131 +#define FRAME_SpearB10 132 +#define FRAME_SpearB11 133 +#define FRAME_spell1 134 +#define FRAME_spell2 135 +#define FRAME_spell3 136 +#define FRAME_spell4 137 +#define FRAME_spell5 138 +#define FRAME_spell6 139 +#define FRAME_spell7 140 +#define FRAME_spell8 141 +#define FRAME_spell9 142 +#define FRAME_spell10 143 +#define FRAME_spell11 144 +#define FRAME_spell12 145 +#define FRAME_spell13 146 +#define FRAME_spell14 147 +#define FRAME_spell15 148 +#define FRAME_spell16 149 +#define FRAME_spell17 150 +#define FRAME_sword1 151 +#define FRAME_sword2 152 +#define FRAME_sword3 153 +#define FRAME_sword4 154 +#define FRAME_sword5 155 +#define FRAME_sword6 156 +#define FRAME_sword7 157 +#define FRAME_sword8 158 +#define FRAME_sword9 159 +#define FRAME_Walk1 160 +#define FRAME_Walk2 161 +#define FRAME_Walk3 162 +#define FRAME_Walk4 163 +#define FRAME_Walk5 164 +#define FRAME_Walk6 165 +#define FRAME_Walk7 166 +#define FRAME_Walk8 167 +#define FRAME_Walk9 168 +#define FRAME_Walk10 169 +#define FRAME_Walk11 170 +#define FRAME_Walk12 171 +#define FRAME_Walk13 172 +#define FRAME_Walk14 173 +#define FRAME_Walk15 174 +#define FRAME_Walk16 175 +#define FRAME_Walk17 176 +#define FRAME_Walk18 177 +#define FRAME_Walk19 178 +#define FRAME_Walk20 179 +#define FRAME_knock1 180 +#define FRAME_knock2 181 +#define FRAME_knock3 182 +#define FRAME_knock4 183 +#define FRAME_knock5 184 +#define FRAME_knock6 185 +#define FRAME_knock7 186 +#define FRAME_knock8 187 +#define FRAME_knock9 188 +#define FRAME_knock10 189 +#define FRAME_knock11 190 +#define FRAME_knock12 191 +#define FRAME_knock13 192 +#define FRAME_knock14 193 +#define FRAME_knock15 194 +#define FRAME_knock16 195 +#define FRAME_knock17 196 +#define FRAME_knock18 197 +#define FRAME_knock19 198 +#define FRAME_ts_idle1 199 +#define FRAME_ts_idle2 200 +#define FRAME_ts_idle3 201 +#define FRAME_ts_idle4 202 +#define FRAME_ts_idle5 203 +#define FRAME_ts_idle6 204 +#define FRAME_ts_idle7 205 +#define FRAME_ts_idle8 206 +#define FRAME_ts_idle9 207 +#define FRAME_ts_idle10 208 +#define FRAME_ts_idle11 209 +#define FRAME_ts_idle12 210 +#define FRAME_ts_idle13 211 +#define FRAME_ts_idle14 212 +#define FRAME_ts_idle15 213 +#define FRAME_ts_idle16 214 +#define FRAME_ts_idle17 215 +#define FRAME_ts_idle18 216 +#define FRAME_ts_idle19 217 +#define FRAME_ts_idle20 218 +#define FRAME_ts_idle21 219 +#define FRAME_ts_idle22 220 +#define FRAME_ts_idle23 221 +#define FRAME_ts_idle24 222 +#define FRAME_ts_idle25 223 +#define FRAME_ts_idle26 224 +#define FRAME_ts_idle27 225 +#define FRAME_ts_idle28 226 +#define FRAME_ts_idle29 227 +#define FRAME_ts_idle30 228 +#define FRAME_ts_idle31 229 +#define FRAME_ts_idle32 230 +#define FRAME_ts_idle33 231 +#define FRAME_ts_idle34 232 +#define FRAME_ts_idle35 233 +#define FRAME_ts_idle36 234 +#define FRAME_ts_idle37 235 +#define FRAME_ts_idle38 236 +#define FRAME_ts_idle39 237 +#define FRAME_ts_idle40 238 +#define FRAME_ts_idle41 239 +#define FRAME_ts_idle42 240 +#define FRAME_ts_idle43 241 +#define FRAME_ts_idle44 242 +#define FRAME_ts_idle45 243 +#define FRAME_ts_idle46 244 +#define FRAME_ts_idle47 245 +#define FRAME_ts_idle48 246 +#define FRAME_ts_idle49 247 +#define FRAME_ts_idle50 248 +#define FRAME_ts_idle51 249 +#define FRAME_ts_idle52 250 +#define FRAME_ts_idle53 251 +#define FRAME_ts_idle54 252 +#define FRAME_ts_idle55 253 +#define FRAME_ts_idle56 254 +#define FRAME_ts_idle57 255 +#define FRAME_ts_idle58 256 +#define FRAME_ts_idle59 257 +#define FRAME_ts_idle60 258 +#define FRAME_ts_lean2talk1 259 +#define FRAME_ts_lean2talk2 260 +#define FRAME_ts_lean2talk3 261 +#define FRAME_ts_lean2talk4 262 +#define FRAME_ts_lean2talk5 263 +#define FRAME_ts_lean2talk6 264 +#define FRAME_ts_lean2talk7 265 +#define FRAME_ts_lean2talk8 266 +#define FRAME_ts_lean2talk9 267 +#define FRAME_ts_listen1 268 +#define FRAME_ts_listen2 269 +#define FRAME_ts_listen3 270 +#define FRAME_ts_listen4 271 +#define FRAME_ts_listen5 272 +#define FRAME_ts_listen6 273 +#define FRAME_ts_listen7 274 +#define FRAME_ts_listen8 275 +#define FRAME_ts_listen9 276 +#define FRAME_ts_listen10 277 +#define FRAME_ts_listen11 278 +#define FRAME_ts_listen12 279 +#define FRAME_ts_listen13 280 +#define FRAME_ts_listen14 281 +#define FRAME_ts_listen15 282 +#define FRAME_ts_listen16 283 +#define FRAME_ts_listen17 284 +#define FRAME_ts_listen18 285 +#define FRAME_ts_listen19 286 +#define FRAME_ts_listen20 287 +#define FRAME_ts_listen21 288 +#define FRAME_ts_listen22 289 +#define FRAME_ts_listen23 290 +#define FRAME_ts_listen24 291 +#define FRAME_ts_listen25 292 +#define FRAME_ts_listen26 293 +#define FRAME_ts_listen27 294 +#define FRAME_ts_listen28 295 +#define FRAME_ts_listen29 296 +#define FRAME_ts_listen30 297 +#define FRAME_ts_listen31 298 +#define FRAME_ts_listen32 299 +#define FRAME_ts_listen33 300 +#define FRAME_ts_listen34 301 +#define FRAME_ts_listen35 302 +#define FRAME_ts_listen36 303 +#define FRAME_ts_listen37 304 +#define FRAME_ts_listen38 305 +#define FRAME_ts_listen39 306 +#define FRAME_ts_listen40 307 +#define FRAME_ts_listen41 308 +#define FRAME_ts_listen42 309 +#define FRAME_ts_listen43 310 +#define FRAME_ts_listen44 311 +#define FRAME_ts_listen45 312 +#define FRAME_ts_listen46 313 +#define FRAME_ts_listen47 314 +#define FRAME_ts_listen48 315 +#define FRAME_ts_listen49 316 +#define FRAME_ts_listen50 317 +#define FRAME_ts_listen51 318 +#define FRAME_ts_listen52 319 +#define FRAME_ts_listen53 320 +#define FRAME_ts_listen54 321 +#define FRAME_ts_listen55 322 +#define FRAME_ts_listen56 323 +#define FRAME_ts_listen57 324 +#define FRAME_ts_listen58 325 +#define FRAME_ts_listen59 326 +#define FRAME_ts_listen60 327 +#define FRAME_ts_rdy2idle1 328 +#define FRAME_ts_rdy2idle2 329 +#define FRAME_ts_rdy2idle3 330 +#define FRAME_ts_rdy2idle4 331 +#define FRAME_ts_spear1 332 +#define FRAME_ts_spear2 333 +#define FRAME_ts_spear3 334 +#define FRAME_ts_spear4 335 +#define FRAME_ts_spear5 336 +#define FRAME_ts_spear6 337 +#define FRAME_ts_spear7 338 +#define FRAME_ts_spear8 339 +#define FRAME_ts_spear9 340 +#define FRAME_ts_spear10 341 +#define FRAME_ts_talk1 342 +#define FRAME_ts_talk2 343 +#define FRAME_ts_talk3 344 +#define FRAME_ts_talk4 345 +#define FRAME_ts_talk5 346 +#define FRAME_ts_talk6 347 +#define FRAME_ts_talk7 348 +#define FRAME_ts_talk8 349 +#define FRAME_ts_talk9 350 +#define FRAME_ts_talk10 351 +#define FRAME_ts_talk11 352 +#define FRAME_ts_talk12 353 +#define FRAME_ts_talk13 354 +#define FRAME_ts_talk14 355 +#define FRAME_ts_talk15 356 +#define FRAME_ts_talk16 357 +#define FRAME_ts_talk17 358 +#define FRAME_ts_talk18 359 +#define FRAME_ts_talk19 360 +#define FRAME_ts_talk20 361 +#define FRAME_ts_talk21 362 +#define FRAME_ts_talk22 363 +#define FRAME_ts_talk23 364 +#define FRAME_ts_talk24 365 +#define FRAME_ts_talk25 366 +#define FRAME_ts_talk26 367 +#define FRAME_ts_talk27 368 +#define FRAME_ts_talk28 369 +#define FRAME_ts_talk29 370 +#define FRAME_ts_talk30 371 +#define FRAME_ts_talk31 372 +#define FRAME_ts_talk32 373 +#define FRAME_ts_talk33 374 +#define FRAME_ts_talk34 375 +#define FRAME_ts_talk35 376 +#define FRAME_ts_talk36 377 +#define FRAME_ts_talk37 378 +#define FRAME_ts_talk38 379 +#define FRAME_ts_talk39 380 +#define FRAME_ts_talk40 381 +#define FRAME_ts_talk41 382 +#define FRAME_ts_talk42 383 +#define FRAME_ts_talk43 384 +#define FRAME_ts_talk44 385 +#define FRAME_ts_talk45 386 +#define FRAME_ts_talk46 387 +#define FRAME_ts_talk47 388 +#define FRAME_ts_talk48 389 +#define FRAME_ts_talk49 390 +#define FRAME_ts_talk50 391 +#define FRAME_ts_talk51 392 +#define FRAME_ts_talk52 393 +#define FRAME_ts_talk53 394 +#define FRAME_ts_talk54 395 +#define FRAME_ts_talk55 396 +#define FRAME_ts_talk56 397 +#define FRAME_ts_talk57 398 +#define FRAME_ts_talk58 399 +#define FRAME_ts_talk59 400 +#define FRAME_ts_talk60 401 + +#define MODEL_SCALE 1.000000 + +#define NUM_MESH_NODES 16 + +#define MESH_MASTER 0 +#define MESH__LLEG 1 +#define MESH__HEAD 2 +#define MESH__LMANDIBLE 3 +#define MESH__RMANDIBLE 4 +#define MESH__CROWN 5 +#define MESH__L2NDARM 6 +#define MESH__SPEAR 7 +#define MESH__FEMHAND 8 +#define MESH__MALEHAND 9 +#define MESH__STAFF 10 +#define MESH__GEM 11 +#define MESH__R2NDARM 12 +#define MESH__RWINGS 13 +#define MESH__LWINGS 14 +#define MESH__RLEG 15 diff --git a/Toolkit/Programming/GameCode/game/m_tcheckrik_spells.c b/Toolkit/Programming/GameCode/game/m_tcheckrik_spells.c new file mode 100644 index 0000000..16687ae --- /dev/null +++ b/Toolkit/Programming/GameCode/game/m_tcheckrik_spells.c @@ -0,0 +1,654 @@ +// +// spl_flyingfist.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "vector.h" +#include "random.h" +#include "decals.h" +#include "m_tcheckrik.h" +#include "Utilities.h" +#include "m_stats.h" +#include "g_playstats.h" + + +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean sound_alert); +static void InsectStaffThink(edict_t *self); +static void InsectStaffTouch(edict_t *self,edict_t *Other,cplane_t *Plane,csurface_t *Surface); + +void create_insect_staff_bolt(edict_t *InsectStaff); + +// ************************************************************************************************ +// InsectStaffThink +// ************************************************************************************************ + +static void InsectStaffThink(edict_t *self) +{ + vec3_t Forward; + + // Grow myself a bit. + + self->s.scale=1.0; + + // Do autotargeting. + + if(self->enemy) + { + // I have a target (pointed at by self->enemy) so aim myself at it. + + VectorCopy(self->s.origin,Forward); + + VectorSubtract(self->enemy->s.origin,Forward,Forward); + + Forward[0]+=(self->enemy->mins[0]+self->enemy->maxs[0])/2.0; + Forward[1]+=(self->enemy->mins[1]+self->enemy->maxs[1])/2.0; + Forward[2]+=(self->enemy->mins[2]+self->enemy->maxs[2])/2.0; + + VectorNormalize(Forward); + } + else + { + // I don't have a target so just I'll just fly straight forward. + + AngleVectors(self->s.angles,Forward,0,0); + } + + // Give myself a velocity of 500 in my forward direction. + + VectorScale(Forward,INSECT_STAFF_AIMED_SPEED,self->velocity); + + self->think = NULL; +} + +// ************************************************************************************************ +// InsectStaffTouch +// ************************************************************************************************ + +static void InsectStaffTouch(edict_t *self,edict_t *Other,cplane_t *Plane,csurface_t *Surface) +{ + vec3_t Origin; + byte makescorch; + edict_t *InsectStaff; + + if(Surface&&(Surface->flags&SURF_SKY)) + { + SkyFly(self); + return; + } + + if(EntReflecting(Other, true, true)) + { + InsectStaff=G_Spawn(); + + create_insect_staff_bolt(InsectStaff); + + InsectStaff->owner = self->owner; + InsectStaff->enemy = NULL; + InsectStaff->s.scale= self->s.scale; + + VectorCopy(self->s.origin, InsectStaff->s.origin); + Create_rand_relect_vect(self->velocity, InsectStaff->velocity); + VectorCopy(InsectStaff->velocity, InsectStaff->movedir); + Vec3ScaleAssign(INSECT_STAFF_SPEED,InsectStaff->velocity); + vectoangles(InsectStaff->velocity, InsectStaff->s.angles); + + G_LinkMissile(InsectStaff); + + gi.CreateEffect(&InsectStaff->s, + FX_I_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_I_SP_MSL_HIT, + vec3_origin); + + G_SetToFree(self); + + return; + } + + // Calculate the position for the explosion entity. + + VectorMA(self->s.origin,-0.02,self->velocity,Origin); + + + if(Other->takedamage) + { + T_Damage(Other, self, self->owner, self->movedir, self->s.origin, Plane->normal, self->dmg, 0, DAMAGE_SPELL, MOD_DIED); + } + else + { + // Back off the origin for the damage a bit. We are a point and this will + // help fix hitting base of a stair and not hurting a guy on next step up. + VectorMA(self->s.origin,-8.0,self->movedir,self->s.origin); + } + + // Attempt to apply a scorchmark decal to the thing I hit. + makescorch = 0; + if(IsDecalApplicable(self,Other,self->s.origin,Surface,Plane,NULL)) + { + makescorch = CEF_FLAG6; + } + + if(!self->count) + { + gi.CreateEffect(NULL, + FX_I_EFFECTS, + makescorch, + self->s.origin, + "bv", + FX_I_ST_MSL_HIT, + self->movedir); + + } + else + { + gi.sound(self, CHAN_BODY, gi.soundindex("monsters/imp/fbfire.wav"), 1, ATTN_NORM, 0); + + gi.CreateEffect(&self->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN, + self->s.origin, + "bv", + FX_IMP_FBEXPL, + vec3_origin); + + } + + G_SetToFree(self); +} + +// create the guts of the insect staff bolt +void create_insect_staff_bolt(edict_t *InsectStaff) +{ + InsectStaff->s.effects = EF_NODRAW_ALWAYS_SEND|EF_CAMERA_NO_CLIP; + InsectStaff->movetype = MOVETYPE_FLYMISSILE; + InsectStaff->solid = SOLID_BBOX; + InsectStaff->classname = "Spell_InsectStaff"; + InsectStaff->touch = InsectStaffTouch; + InsectStaff->dmg = irand(TC_FEMALE_DMG_HACK_MIN, TC_FEMALE_DMG_HACK_MAX) * (skill->value + 1)/3; + InsectStaff->clipmask = MASK_MONSTERSOLID|MASK_SHOT; + VectorClear(InsectStaff->mins); + VectorClear(InsectStaff->maxs); + InsectStaff->think = InsectStaffThink; + InsectStaff->nextthink = level.time+0.1; +} + +// ************************************************************************************************ +// SpellCastInsectStaff +// ************************************************************************************************ + +void SpellCastInsectStaff(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,qboolean power) +{ + vec3_t forward; + edict_t *InsectStaff; + + InsectStaff = G_Spawn(); + + VectorCopy(StartPos, InsectStaff->s.origin); + VectorCopy(AimAngles, InsectStaff->s.angles); + VectorScale(AimDir, INSECT_STAFF_SPEED, InsectStaff->velocity); + AngleVectors(AimAngles, forward, NULL,NULL); + VectorCopy(forward, InsectStaff->movedir); + + create_insect_staff_bolt(InsectStaff); + + InsectStaff->s.scale = 0.1; + InsectStaff->owner = Caster; + InsectStaff->enemy = Caster->enemy; + + G_LinkMissile(InsectStaff); + + if(power) + { + Vec3ScaleAssign(2, InsectStaff->velocity); + InsectStaff->dmg *= 2; + InsectStaff->count = 1; + gi.CreateEffect(&InsectStaff->s, + FX_M_EFFECTS,//just so I don't have to make a new FX_ id + CEF_OWNERS_ORIGIN, + NULL, + "bv", + FX_IMP_FIRE, + InsectStaff->velocity); + } + else + { + InsectStaff->count = 0; + gi.CreateEffect(&InsectStaff->s, + FX_I_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_I_STAFF, + vec3_origin); + } +} + + + +#define GLOBE_MAX_SCALE 1.8 +#define GLOBE_SCALE_RANGE 0.8 +#define GLOBE_FLY_SPEED 600.0 + +static void GlobeOfOuchinessGrowThink(edict_t *self); + +// **************************************************************************** +// GlobeOfOuchinessGrowThink +// **************************************************************************** + +static void GlobeOfOuchinessGrowThink(edict_t *self) +{ + vec3_t Forward,Up; + + if(self->owner->s.effects&EF_DISABLE_EXTRA_FX) + { + gi.RemoveEffects(&self->s,0); + G_FreeEdict(self); + return; + } + + if (self->owner->client) + AngleVectors(self->owner->client->aimangles,Forward,NULL,Up); + else + AngleVectors(self->owner->s.angles,Forward,NULL,Up); + + // whether or not I have been released. Would like a dedicated value in the 'edict_t' but this + // is unlikely to happen, sooooo... + + if(!self->owner->damage_debounce_time) + { +// self->svflags |= SVF_NOCLIENT; + + self->count+=irand(1,2); + + if((self->count>10)&&(self->s.scalecount>20) + { + self->s.scale-=0.01; + } + else + { + self->s.scale+=0.1; + } + + if(self->count>25) + { + self->count&=3; + } + } + + self->velocity[0]=8.0*((self->owner->s.origin[0]+Forward[0]*22.0+flrand(-2.0F,2.0F))-self->s.origin[0]); + self->velocity[1]=8.0*((self->owner->s.origin[1]+Forward[1]*22.0+flrand(-2.0F,2.0F))-self->s.origin[1]); + self->velocity[2]=8.0*((self->owner->s.origin[2]+Up[2]*10.0)-self->s.origin[2]); + + self->nextthink=level.time+0.1; + } + else + { + self->owner->damage_debounce_time = true; + + G_FreeEdict(self); + return; + + } +} + +// **************************************************************************** +// SpellCastGlobeOfOuchiness +// **************************************************************************** + +void SpellCastGlobeOfOuchiness(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir) +{ + edict_t *Globe; + vec3_t tempvec; + + // Spawn the globe of annihilation as an invisible entity (i.e. modelindex=0). + + Globe=G_Spawn(); + + VectorCopy(Caster->s.origin,Globe->s.origin); + Globe->s.origin[0]+=AimDir[0]*20.0; + Globe->s.origin[1]+=AimDir[1]*20.0; + Globe->s.origin[2]+=Caster->viewheight-5.0; + + vectoangles(AimAngles,Globe->s.angles); + + Globe->avelocity[YAW]=100.0; + Globe->avelocity[ROLL]=100.0; + + // whether or not I have been released. Would like a dedicated value in the 'edict_t' but this + // is unlikely to happen, sooooo... + + Globe->svflags |= SVF_ALWAYS_SEND; + Globe->s.effects |= EF_ALWAYS_ADD_EFFECTS|EF_MARCUS_FLAG1|EF_CAMERA_NO_CLIP; + Globe->owner=Caster; + Globe->classname="Spell_GlobeOfOuchiness"; + Globe->dmg=0; + Globe->s.scale=1.0; + Globe->enemy=Caster->enemy; + Globe->count=0; + Globe->clipmask=MASK_MONSTERSOLID; + Globe->movetype = PHYSICSTYPE_FLY; + Globe->solid=SOLID_NOT; + Globe->nextthink=level.time+0.1; + Globe->think=GlobeOfOuchinessGrowThink; + + G_LinkMissile(Globe); + + VectorSet(tempvec, (float)(Caster->s.number), 0, 0); + + gi.CreateEffect(&Globe->s, + FX_I_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_I_GLOBE, + tempvec); + + gi.CreateEffect(&Globe->s, + FX_I_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_I_GLOW, + tempvec); + +// gi.sound(Globe,CHAN_WEAPON,gi.soundindex("weapons/GlobeOfOuchinessGrow.wav"),1,ATTN_NORM,0); +} + +//Spear Projectiles +static void SpearProjTouch(edict_t *self,edict_t *Other,cplane_t *Plane,csurface_t *Surface); + +// Radius of zero seems to prevent collision between bolts + +#define SPEARPROJ_RADIUS 0.0 +#define SPEARPROJ_SPEED 600.0 + +// guts of creating a spearproj +void create_spearproj(edict_t *spearproj) +{ + + spearproj->s.effects |= EF_ALWAYS_ADD_EFFECTS|EF_CAMERA_NO_CLIP; + spearproj->svflags |= SVF_ALWAYS_SEND; + spearproj->movetype = MOVETYPE_FLYMISSILE; + + VectorSet(spearproj->mins, -SPEARPROJ_RADIUS, -SPEARPROJ_RADIUS, -SPEARPROJ_RADIUS); + VectorSet(spearproj->maxs, SPEARPROJ_RADIUS, SPEARPROJ_RADIUS, SPEARPROJ_RADIUS); + + spearproj->solid = SOLID_BBOX; + spearproj->clipmask = MASK_SHOT; + spearproj->touch = SpearProjTouch; + + if(spearproj->count) + spearproj->dmg = irand(TC_DMG_YSPEAR_MIN, TC_DMG_YSPEAR_MAX); + else if(skill->value > 1) + spearproj->dmg = TC_DMG_SPEAR_MAX; + else if(!skill->value) + spearproj->dmg = TC_DMG_SPEAR_MIN; + else + spearproj->dmg = irand(TC_DMG_SPEAR_MIN, TC_DMG_SPEAR_MAX); + + spearproj->classname = "Spell_SpearProj"; +} + + +// **************************************************************************** +// SpearProjTouch +// **************************************************************************** + +static void SpearProjTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + edict_t *spearproj; + byte makeScorch = 0; + + // did we hit the sky ? + if(surface && (surface->flags & SURF_SKY)) + { + SkyFly(self); + return; + } + + // did we hit someone where reflection is functional ? + if (self->reflect_debounce_time) + { + if(EntReflecting(other, true, true)) + { + spearproj = G_Spawn(); + + VectorCopy(self->s.origin, spearproj->s.origin); + Create_rand_relect_vect(self->velocity, spearproj->velocity); + VectorCopy(spearproj->velocity, spearproj->movedir); + Vec3ScaleAssign(SPEARPROJ_SPEED/2,spearproj->velocity); + create_spearproj(spearproj); + spearproj->owner = self->owner; + spearproj->reflect_debounce_time = self->reflect_debounce_time -1; + G_LinkMissile(spearproj); + gi.CreateEffect(&spearproj->s, + FX_I_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_I_SPEAR, + spearproj->velocity); + + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + return; + } + } + + if(other->takedamage) + { + if(level.fighting_beast) + { + if(other->classID == CID_TBEAST) + { + if(other->enemy != self->owner) + { + other->enemy = self->owner; + } + } + else if(other->classID == CID_BBRUSH) + { + self->dmg = 0; + VectorMA(self->s.origin, -4.0, self->movedir, self->s.origin); + } + } + + if(self->dmg)//HACK = so can't collapse trial beast bridge + T_Damage(other, self, self->owner, self->movedir, self->s.origin, plane->normal, self->dmg, 0, DAMAGE_SPELL,MOD_SPEAR); + } + else + { + // Back off the origin for the damage a bit. We are a point and this will + // help fix hitting base of a stair and not hurting a guy on next step up. + VectorMA(self->s.origin, -4.0, self->movedir, self->s.origin); + } + + makeScorch = 0; + if(IsDecalApplicable(self, other, self->s.origin, surface, plane, NULL)) + { + makeScorch = CEF_FLAG6; + } + + if(self->count) + { + gi.CreateEffect(&self->s, + FX_I_EFFECTS, + makeScorch, + vec3_origin, + "bv", + FX_I_SP_MSL_HIT2, + self->movedir); + } + else + { + gi.CreateEffect(&self->s, + FX_I_EFFECTS, + makeScorch, + vec3_origin, + "bv", + FX_I_SP_MSL_HIT, + self->movedir); + } + + G_SetToFree(self); +} + +/* +==================================================== +void Veer(float amount) +MG +This function will make a projectile +wander from it's course in a random +manner. It does not actually directly +use the .veer value, you must send the +veer amount value to the function as +a parameter. But this allows it to +be used in other ways (call it once, +etc.) So you can call it by using +Veer(self.veer) or Veer(random()*300) +or Veer([any number]), etc. +===================================================== +*/ +void projectile_veer(edict_t *self, float amount); +void projectile_homethink (edict_t *self); + +void yellowjacket_proj_think (edict_t *self) +{ + vec3_t vdir, edir; + //No enemy, stop tracking + if (!self->enemy) + { + self->think = NULL; + return; + } + + VectorCopy(self->velocity, vdir); + VectorNormalize(vdir); + VectorSubtract(self->enemy->s.origin, self->s.origin, edir); + VectorNormalize(edir); + + if(DotProduct(edir, vdir) > 0 && irand(2, 24) > self->count) + projectile_homethink(self); + + self->count++; + + if(self->random < 100) + self->random += 10; + + self->nextthink = level.time + 0.1; +} +// **************************************************************************** +// SpellCastSpearProj +// **************************************************************************** + + +void SpellCastInsectSpear(edict_t *caster, vec3_t StartPos, vec3_t AimAngles, int offset) +{ + edict_t *spearproj; + trace_t trace; + vec3_t endpos, forward, right, up, dir; + float dist; + + // Spawn the magic-missile. + + if(!caster->enemy) + return; + + spearproj = G_Spawn(); + + VectorCopy(StartPos, spearproj->s.origin); + VectorSubtract(caster->enemy->s.origin, StartPos, dir); + dist = VectorLength(dir); + + if(offset && dist > 128) + { + AngleVectors(AimAngles, forward, right, up); + switch(offset) + { + default: + case 1: + VectorAverage(forward, right, forward); + break; + + case 2: + Vec3ScaleAssign(-1, right); + VectorAverage(forward, right, forward); + break; + + case 3: + VectorAverage(forward, up, forward); + break; + } + VectorScale(forward, SPEARPROJ_SPEED, spearproj->velocity); + } + else + { + //Check ahead first to see if it's going to hit anything at this angle + AngleVectors(AimAngles, forward, NULL, NULL); + VectorMA(StartPos, SPEARPROJ_SPEED, forward, endpos); + gi.trace(StartPos, vec3_origin, vec3_origin, endpos, caster, MASK_MONSTERSOLID,&trace); + if(trace.ent && ok_to_autotarget(caster, trace.ent)) + {//already going to hit a valid target at this angle- so don't autotarget + VectorScale(forward, SPEARPROJ_SPEED, spearproj->velocity); + } + else + {//autotarget current enemy + GetAimVelocity(caster->enemy, spearproj->s.origin, SPEARPROJ_SPEED, AimAngles, spearproj->velocity); + } + } + + spearproj->owner = caster; + VectorNormalize2(spearproj->velocity, spearproj->movedir); + create_spearproj(spearproj); + spearproj->reflect_debounce_time = MAX_REFLECT; + + G_LinkMissile(spearproj); + + gi.trace(spearproj->s.origin, vec3_origin, vec3_origin, spearproj->s.origin, caster, MASK_PLAYERSOLID,&trace); + if (trace.startsolid) + { + SpearProjTouch(spearproj, trace.ent, &trace.plane, trace.surface); + return; + } + + if(caster->spawnflags & MSF_INSECT_YELLOWJACKET) + { + spearproj->think = yellowjacket_proj_think; + spearproj->nextthink = level.time + 0.1; + spearproj->enemy = caster->enemy; + Vec3ScaleAssign(0.5, spearproj->velocity); + spearproj->ideal_yaw = SPEARPROJ_SPEED/2; + spearproj->random = 30; + spearproj->delay = 1.5; + spearproj->count = 1; + spearproj->red_rain_count = 1; + + gi.CreateEffect(&spearproj->s, + FX_I_EFFECTS, + CEF_OWNERS_ORIGIN, + NULL, + "bv", + FX_I_SPEAR2, + vec3_origin); + } + else + { + spearproj->count = 0; + gi.CreateEffect(&spearproj->s, + FX_I_EFFECTS, + CEF_OWNERS_ORIGIN, + vec3_origin, + "bv", + FX_I_SPEAR, + spearproj->velocity); + } +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/mg_ai.c b/Toolkit/Programming/GameCode/game/mg_ai.c new file mode 100644 index 0000000..a1da958 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/mg_ai.c @@ -0,0 +1,2923 @@ +/* +============================== + + MG AI + NEW LOW-LEVEL MOVEMENT CODE + +============================== +*/ + +#include +#include "g_local.h" +#include "g_monster.h" +#include "Random.h" +#include "vector.h" +#include "buoy.h" +#include "g_HitLocation.h" +#include "Utilities.h" +#include "m_stats.h" +#include "g_playstats.h" +#include "fx.h" + +#define STEPSIZE 18 +#define YAW_IDEAL 1 +#define YAW_BEST_MOVE 0 + +extern cvar_t *maxclients; + +//void gkrokon_maintain_waypoints(edict_t *self, float mintel, float foo1, float foo2); +void ssithraCheckJump (edict_t *self); +void SV_FixCheckBottom (edict_t *ent); +qboolean clear_visible (edict_t *self, edict_t *other); +float ai_face_goal (edict_t *self); +void ai_flee (edict_t *self, float dist); +void pitch_roll_for_slope (edict_t *forwhom, vec3_t *slope); +void BecomeDebris(edict_t *self); +qboolean MG_MoveToGoal (edict_t *self, float dist); +void MG_BuoyNavigate(edict_t *self); +qboolean MG_GoToRandomBuoy(edict_t *self); + +qboolean TB_CheckBottom (edict_t *self); +qboolean TB_CheckJump (edict_t *self); + +// AI Targeting Globals +qboolean enemy_vis; // TRUE if enemy is visible +qboolean enemy_infront; // TRUE if enemy is in front +int enemy_range; // range from enemy RANGE_MELEE, RANGE_NEAR, RANGE_MID, RANGE_FAR +float enemy_yaw; // ideal yaw to face enemy +vec3_t JUMP_MINS = {-8, -8, 0}; +vec3_t JUMP_MAXS = {8, 8, 4}; + +char *HitLocName [hl_Max] = +{ + "NonSpecific",//0 + "Head",//1 + "TorsoFront", + "TorsoBack", + "ArmUpperLeft", + "ArmLowerLeft", + "ArmUpperRight", + "ArmLowerRight", + "LegUpperLeft", + "LegLowerLeft", + "LegUpperRight", + "LegLowerRight", + "BipedPoints", + "WingedPoints", + "extra14", + "extra15", + "MeleeHit",//16 +}; + +//============================================================================ + +/* +============= +ahead + +returns 1 if the entity is in front (dot > 0.8) of self +============= +*/ +qboolean ahead (edict_t *self, edict_t *other) +{ + vec3_t vec; + float dot; + vec3_t forward, check_angles; + + if(Vec3NotZero(self->v_angle_ofs)) + VectorAdd(self->v_angle_ofs,self->s.angles,check_angles); + else + VectorCopy(self->s.angles,check_angles); + + AngleVectors (check_angles, forward, NULL, NULL); + VectorSubtract (other->s.origin, self->s.origin, vec); + VectorNormalize (vec); + dot = DotProduct (vec, forward); + + if (dot > 0.8) + return true; + return false; +} + +/* +============= +LOS + +returns true if there is an unobstructed spot from point1 to point2 +============= +*/ +qboolean LOS (edict_t *self, vec3_t point1, vec3_t point2) +{ + trace_t trace; + + gi.trace (point1, vec3_origin, vec3_origin, point2, self, MASK_SOLID,&trace); + + if (trace.fraction == 1.0) + return true; + return false; +} + +/* +============= +visible_pos + +returns 1 if the entity is visible to self, even if not infront () +============= +*/ +qboolean visible_pos (edict_t *self, vec3_t spot2) +{ + vec3_t spot1; + trace_t trace; + + VectorCopy (self->s.origin, spot1); + spot1[2] += self->viewheight; + gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE,&trace); + + if (trace.fraction == 1.0) + return true; + return false; +} + +/* +============= +MG_CheckBottom + +Returns false if any 2 adjacent cornerpoints of the bottom of the +entity is off an edge that is not a staircase. +============= +*/ +qboolean MG_CheckBottom (edict_t *ent) +{ + vec3_t mins, maxs, start, stop; + trace_t trace; + int x, y, corner; + float stepsize; + + qboolean corner_ok[4]; + qboolean easy_ok[2][2]; + qboolean realcheck = false; + +//normal corner checking + if(ent->classID==CID_TBEAST) + { + return TB_CheckBottom(ent); +// VectorAdd (ent->s.origin, ent->mins, mins); +// VectorAdd (ent->s.origin, ent->maxs, maxs); +// stepsize = 54;//ent->size[2];//very lenient for stepping off stuff + } + else//lenient, max 16 corner checking + { + VectorCopy (ent->mins, mins); + VectorCopy (ent->maxs, maxs); + + //some leniency is ok here, no? + mins[0] *= 0.75; + mins[1] *= 0.75; + maxs[0] *= 0.75; + maxs[1] *= 0.75; + + //keep corner checks within 16 of center + if(mins[0] < -16) + mins[0] = -16; + if(mins[1] < -16) + mins[1] = -16; + if(maxs[0] > 16) + maxs[0] = 16; + if(maxs[1] > 16) + maxs[1] = 16; + + if(ent->maxs[0] > maxs[0]) + stepsize = STEPSIZE + (ent->maxs[0] - maxs[0]); + + VectorAdd (ent->s.origin, mins, mins); + VectorAdd (ent->s.origin, maxs, maxs); + } + +// if all of the points under the corners are solid world, don't bother +// with the tougher checks +// the corners must be within 16 of the midpoint + + start[2] = mins[2] - 1; + corner = 0; + for (x=0 ; x<=1 ; x++)//0, 0; 0, 1; 1, 0; 1, 1; + { + for (y=0 ; y<=1 ; y++) + { + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + if (gi.pointcontents (start) != CONTENTS_SOLID) + {//only do realcheck if two adjecent corners off ledge + switch(corner) + { + case 0: + break; + case 1: + case 2: + if(!corner_ok[0]) + realcheck = true; + break; + case 3: + if(!corner_ok[2] || !corner_ok[1]) + realcheck = true; + break; + } + easy_ok[x][y] = corner_ok[corner] = false; + } + else + { +// if(ent->classID==CID_TBEAST) +// { +// ent->groundentity = world; +// return true;//super hack- let big guy go up slopes +// } + //check them all to make realcheck faster + easy_ok[x][y] = corner_ok[corner] = true; + } + + corner++; + } + } + + if(!realcheck) + return true; // we got out easy + +// +// check it for real... +// + start[2] = mins[2];//bottom + stop[2] = start[2] - stepsize + 1;//2*STEPSIZE;//bottom - 36 + +// the corners must be within 16 of the midpoint + corner = 0; + for (x=0 ; x<=1 ; x++) + { + for (y=0 ; y<=1 ; y++) + { + if(!easy_ok[x][y]) + {//don't trace the ones that were ok in the easy check + start[0] = stop[0] = x ? maxs[0] : mins[0]; + start[1] = stop[1] = y ? maxs[1] : mins[1]; + + gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID,&trace); + + if (trace.fraction >= 1.0)// || start[2] - trace.endpos[2] > STEPSIZE) + {//this point is off too high of a step + switch(corner) + { + case 0: + break; + case 1: + case 2: + if(!corner_ok[0]) + return false; + break; + case 3: + if(!corner_ok[2] || !corner_ok[1]) + return false; + break; + } + corner_ok[corner] = false; + } + else//only return false if two adjacent corners off a ledge + { + if(ent->classID==CID_TBEAST) + { +// ent->groundentity = trace.ent; + return true;//super hack- let big guy go up slopes + } + corner_ok[corner] = true; + } + } + else + corner_ok[corner] = true; + + corner++; + } + } + + return true; +} + +/* +============= +MG_MoveStep + +Called by monster program code. +The move will be adjusted for slopes and stairs, but if the move isn't +possible, no move is done, false is returned, and +pr_global_struct->trace_normal is set to the normal of the blocking wall +============= +*/ +//FIXME since we need to test end position contents here, can we avoid doing +//it again later in catagorize position? +trace_t MG_MoveStep (edict_t *self, vec3_t move, qboolean relink) +{//only relinks if move succeeds + float dz; + vec3_t save_org, test_org, end; + trace_t trace; + int i; + float stepsize; + vec3_t test; + int contents, clipmask; + qboolean slip_under = false; + + trace.succeeded = false; + // try the move + VectorCopy (self->s.origin, save_org); + if(self->monsterinfo.scale) + {//scale movement by monster's scale + //scale here, not before since any function can call this + VectorScale(move, self->monsterinfo.scale, move); + } + + VectorAdd (self->s.origin, move, test_org); + + +//SWIM AND FLY MONSTERS + // flying monsters don't step up + if ( self->flags & (FL_SWIM | FL_FLY) ) + { + // try one move with vertical motion, then one without + for (i=0 ; i<2 ; i++) + { + VectorAdd (self->s.origin, move, test_org); + if (i == 0 && self->enemy) + { + if (!self->goalentity) + self->goalentity = self->enemy; + dz = self->s.origin[2] - self->goalentity->s.origin[2]; + if (self->goalentity->client) + { + if (dz > 40) + test_org[2] -= 8; + if (!((self->flags & FL_SWIM) && (self->waterlevel < 2))) + if (dz < 30) + test_org[2] += 8; + } + else + { + if (dz > 8) + test_org[2] -= 8; + else if (dz > 0) + test_org[2] -= dz; + else if (dz < -8) + test_org[2] += 8; + else + test_org[2] += dz; + } + } + gi.trace (self->s.origin, self->mins, self->maxs, test_org, self, MASK_MONSTERSOLID,&trace); + + // fly monsters don't enter water voluntarily + if (self->flags & FL_FLY) + { + if (!self->waterlevel) + { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + self->mins[2] + 1; + contents = gi.pointcontents(test); + if (contents & MASK_WATER) + { + QPostMessage(self, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return trace; + } + } + } + + // swim monsters don't exit water voluntarily + if (self->flags & FL_SWIM) + { + if (self->waterlevel < 2) + { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + self->mins[2] + 1; + contents = gi.pointcontents(test); + if (!(contents & MASK_WATER)) + { + QPostMessage(self, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return trace; + } + } + } + + if (trace.fraction == 1) + { + VectorCopy (trace.endpos, self->s.origin); + if (relink) + { + gi.linkentity (self); + G_TouchTriggers (self); + } + return trace;//true + } + + if (!self->enemy) + break; + } + + return trace; + } +//WALK MONSTERS +// push down from a step height above the wished position + clipmask = MASK_MONSTERSOLID; + if (!(self->monsterinfo.aiflags & AI_NOSTEP)) + { + if(self->classID==CID_TBEAST) + { + clipmask = MASK_SOLID; + stepsize = STEPSIZE * 3; + } + else + stepsize = STEPSIZE; + } + else + stepsize = 1; + + test_org[2] += stepsize; + VectorCopy (test_org, end); + end[2] -= stepsize*2; + + gi.trace (test_org, self->mins, self->maxs, end, self, clipmask,&trace); + + if (trace.allsolid) + {//the step up/down is all solid in front + QPostMessage(self, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return trace; + } + + //NOTE: if did the forward trace above, CAN'T have startsolid, so this is ok + if (trace.startsolid) + {//can't step up, try down + test_org[2] -= stepsize; + gi.trace (test_org, self->mins, self->maxs, end, self, clipmask,&trace); + if (trace.allsolid || trace.startsolid) + { + if(trace.ent) + { + if(trace.ent->client) + { + slip_under = true;//lets rats walk between legs + } + } + if(!slip_under) + { + QPostMessage(self, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return trace; + } + } + } + + // don't go in to water unless only 40% hieght deep or an amphibian + if (self->waterlevel == 0) + {//not currently in water + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + self->mins[2];// + 1; + test[2] += (self->maxs[2] - self->mins[2]) * 0.4; + contents = gi.pointcontents(test); + + if (contents & MASK_WATER && !(self->flags & FL_AMPHIBIAN)) + return trace; + } + + if (trace.fraction == 1) + {//too long of a step down + if ( self->flags & FL_PARTIALGROUND || + self->svflags & SVF_FLOAT || + self->classID == CID_TBEAST || + (contents&MASK_WATER && self->flags & FL_AMPHIBIAN))//allow swimming monsters to step off ledges into water + {// if monster had the ground pulled out, go ahead and fall + //DO THE MOVE! + VectorAdd (self->s.origin, move, self->s.origin); + if (relink) + { + gi.linkentity (self); + G_TouchTriggers (self); + } + self->groundentity = NULL; +// SV_Printf ("fall down\n"); + trace.succeeded = true; + return trace;//true! + } + QPostMessage(self, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return trace; // walked off an edge + } + +// check point traces down for dangling corners + //DO THE MOVE! + //ok, put me there + VectorCopy (trace.endpos, self->s.origin); + + if(contents&MASK_WATER && self->flags & FL_AMPHIBIAN); + else if (!MG_CheckBottom(self))// && self->classID!=CID_TBEAST) + {//uh oh, not completely on solid ground + if ( self->flags & FL_PARTIALGROUND || self->svflags & SVF_FLOAT) + { // entity had floor mostly pulled out from underneath it + // and is trying to correct or can float + if (relink) + { + gi.linkentity (self); + G_TouchTriggers (self); + } + trace.succeeded = true; + return trace;//true! + } + //whoops, let's not make that move after all + VectorCopy (save_org, self->s.origin); + QPostMessage(self, MSG_BLOCKED, PRI_DIRECTIVE, NULL); + return trace; + } + + //OK, we're on the ground completely now + if ( self->flags & FL_PARTIALGROUND ) + { + self->flags &= ~FL_PARTIALGROUND; + } + self->groundentity = trace.ent; + self->groundentity_linkcount = trace.ent->linkcount; + +// the move is ok + if (relink) + { + gi.linkentity (self); + G_TouchTriggers (self); + } + else + VectorCopy (save_org, self->s.origin); + + trace.succeeded = true; + return trace;//true! +} + +/* +=============== +MG_ChangeYaw + +=============== +*/ +float MG_ChangeWhichYaw (edict_t *self, qboolean ideal_yaw) +{ + float ideal; + float current; + float move; + float speed; + + current = anglemod(self->s.angles[YAW]); + if(ideal_yaw) + ideal = self->ideal_yaw; + else + ideal = self->best_move_yaw; + + if (current == ideal) + return false; + + move = ideal - current; + speed = self->yaw_speed; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + //normal anglemod doesn't have the precision I need to slide along walls + self->s.angles[YAW] = anglemod_old(current + move); + return move; +} + +float MG_ChangeYaw (edict_t *self) +{ + return MG_ChangeWhichYaw(self, YAW_IDEAL); +} + +qboolean MG_GetGoalPos (edict_t *self, vec3_t goalpos) +{ + qboolean charge_enemy = false; + + if(self->monsterinfo.aiflags&AI_STRAIGHT_TO_ENEMY && self->enemy) + charge_enemy = true; + + if (self->monsterinfo.searchType == SEARCH_BUOY && !charge_enemy) + { + if(self->buoy_index < 0 || self->buoy_index > level.active_buoys) + { +#ifdef _DEVEL + gi.dprintf("Error: SEARCH_BUOY but invalid index!!!\n"); +#endif + return false; + } + + VectorCopy(level.buoy_list[self->buoy_index].origin, self->monsterinfo.nav_goal); + VectorCopy(self->monsterinfo.nav_goal, goalpos); + } + else if(self->goalentity && !charge_enemy) + { + if(self->goalentity == self->enemy && self->ai_mood_flags & AI_MOOD_FLAG_PREDICT && !(self->spawnflags & MSF_FIXED)) + {//predict where he's goin + M_PredictTargetPosition( self->enemy, self->enemy->velocity, 8, goalpos); + } + else + { + VectorCopy(self->goalentity->s.origin, goalpos); + } + } + else if(self->enemy) + { + if (self->ai_mood_flags & AI_MOOD_FLAG_PREDICT && !(self->spawnflags & MSF_FIXED)) + {//predict where he's goin + M_PredictTargetPosition( self->enemy, self->enemy->velocity, 8, goalpos); + } + else + { + VectorCopy(self->enemy->s.origin, goalpos); + } + } + else + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("No goal to face!\n"); +#endif + VectorClear(goalpos); + return false; + } + + return true; +} + +float MG_FaceGoal (edict_t *self, qboolean doturn) +{ + vec3_t vec, goalpos; + + if(MG_GetGoalPos(self, goalpos)) + { + VectorSubtract(goalpos, self->s.origin, vec); + } + else + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("No goal to face!\n"); +#endif + return false; + } + + self->ideal_yaw = vectoyaw(vec); + + if(doturn) + return MG_ChangeYaw(self); + + return 0; +} + +/* +====================== +MG_StepDirection + +Turns to the movement direction, and walks the current distance if +facing it. + +====================== +*/ +qboolean MG_StepDirection (edict_t *self, float yaw, float dist) +{ + vec3_t move, forward, test_angles; + trace_t trace; + + //find vector offset (move to add to origin) + test_angles[PITCH] = test_angles[ROLL] = 0; + test_angles[YAW] = yaw; + AngleVectors(test_angles, forward, NULL, NULL); + VectorScale(forward, dist, move); + + //see if can move that way, but don't actually move + trace = MG_MoveStep (self, move, false); + + if (trace.succeeded) + {//move was allowed + self->best_move_yaw = yaw;//new + self->monsterinfo.idle_time = level.time + flrand(0.5, 1.25); +// MG_ChangeWhichYaw (self, YAW_BEST_MOVE);//new + return true; + } + return false; +} + +/* +================ +MG_NewDir + +================ +*/ +#define DI_NODIR -1 +void MG_NewDir (edict_t *self, float dist) +{ + float deltax, deltay; + float d[3]; + float test_ideal_yaw, old_yaw, turnaround;//, save_yaw; + vec3_t goal_org; + + //FIXME: how did we get here with no enemy + if(!MG_GetGoalPos (self, goal_org)) + return; + + old_yaw = anglemod( (int)(self->ideal_yaw/45)*45 ); + turnaround = anglemod(old_yaw - 180); + + deltax = goal_org[0] - self->s.origin[0]; + deltay = goal_org[1] - self->s.origin[1]; + if (deltax>10) + d[1]= 0; + else if (deltax<-10) + d[1]= 180; + else + d[1]= DI_NODIR; + if (deltay<-10) + d[2]= 270; + else if (deltay>10) + d[2]= 90; + else + d[2]= DI_NODIR; + +// try direct route + if (d[1] != DI_NODIR && d[2] != DI_NODIR) + { + if (d[1] == 0) + test_ideal_yaw = d[2] == 90 ? 45 : 315; + else + test_ideal_yaw = d[2] == 90 ? 135 : 215; + + if (test_ideal_yaw != turnaround && MG_StepDirection(self, test_ideal_yaw, dist)) + return; + } + +// try other directions + if ( irand(0, 1) || abs(deltay)>abs(deltax)) + { + test_ideal_yaw=d[1]; + d[1]=d[2]; + d[2]=test_ideal_yaw; + } + + if (d[1]!=DI_NODIR && d[1]!=turnaround + && MG_StepDirection(self, d[1], dist)) + return; + + if (d[2]!=DI_NODIR && d[2]!=turnaround + && MG_StepDirection(self, d[2], dist)) + return; + +/* there is no direct path to the player, so pick another direction */ + + if (old_yaw!=DI_NODIR && MG_StepDirection(self, old_yaw, dist)) + return; + + if (irand(0, 1)) /*randomly determine direction of search*/ + { + for (test_ideal_yaw=0 ; test_ideal_yaw<=315 ; test_ideal_yaw += 45) + if (test_ideal_yaw!=turnaround && MG_StepDirection(self, test_ideal_yaw, dist) ) + return; + } + else + { + for (test_ideal_yaw=315 ; test_ideal_yaw >=0 ; test_ideal_yaw -= 45) + if (test_ideal_yaw!=turnaround && MG_StepDirection(self, test_ideal_yaw, dist) ) + return; + } + + if (turnaround != DI_NODIR && MG_StepDirection(self, turnaround, dist) ) + return; + + // can't move, restore yaw? + +// if a bridge was pulled out from underneath a monster, it may not have +// a valid standing position at all + + if (!MG_CheckBottom (self))// && self->classID!=CID_TBEAST) + SV_FixCheckBottom (self); +} + +/* +============= +infront_pos + +returns 1 if the spot is in front (in sight) of self +============= +*/ +qboolean infront_pos (edict_t *self, vec3_t pos) +{ + vec3_t vec; + float dot; + vec3_t forward, check_angles; + + if(Vec3NotZero(self->v_angle_ofs)) + VectorAdd(self->v_angle_ofs,self->s.angles,check_angles); + else + VectorCopy(self->s.angles,check_angles); + + AngleVectors (check_angles, forward, NULL, NULL); + VectorSubtract (pos, self->s.origin, vec); + VectorNormalize (vec); + dot = DotProduct (vec, forward); + + if (dot > 0.3) + return true; + return false; +} + +qboolean MG_ExtraCheckJump (edict_t *self) +{ + vec3_t vf, source, source2, targ_org, targ_mins; + vec3_t maxs, mins, save_org; + trace_t trace; + float hgt_diff, jump_fdist; + qboolean jump_up_check = false; + qboolean check_down = false; + qboolean can_move = false; + +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Extra Check Jump\n"); +#endif + if (self->monsterinfo.searchType == SEARCH_BUOY) + { + if(self->buoy_index < 0 || self->buoy_index > level.active_buoys) + return false; + + VectorCopy(level.buoy_list[self->buoy_index].origin, targ_org); + + if (!(infront_pos(self, targ_org))) + return false; + + if (targ_org[2] < self->s.origin[2] - 28) + { + check_down = true; + } + else + { + check_down = false; + } + VectorClear(targ_mins); + } + else + { + if(!self->goalentity) + return false; + + if (!(infront(self, self->goalentity))) + return false; + + if (self->goalentity->s.origin[2] < self->s.origin[2] - 28) + { + check_down = true; + } + else + { + check_down = false; + } + + VectorCopy(self->goalentity->s.origin, targ_org); + VectorCopy(self->goalentity->mins, targ_mins); + } + + if (check_down) + {//jumping down + //Setup the trace + int inwater; + +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("check jump down\n"); +#endif + inwater = (gi.pointcontents(self->s.origin) & CONTENTS_WATER); + +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("checking jump down: "); +#endif + if(inwater) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("checkdown allsolid\n"); +#endif + return false; + } + + VectorCopy(self->maxs, maxs); + VectorCopy(self->s.origin, source); + AngleVectors(self->s.angles, vf, NULL, NULL); + jump_fdist = vhlen(targ_org, self->s.origin); + if(jump_fdist > 128) + jump_fdist = 128; + + VectorMA(source, 128, vf, source); + + maxs[2] += 16; + gi.trace (self->s.origin, self->mins, maxs, source, self, MASK_MONSTERSOLID,&trace); + + if (trace.fraction == 1) + {//clear ahead and above + VectorCopy(source, source2); + + source2[2] -= 1024; + //trace down + gi.trace (source, self->mins, self->maxs, source2, self, MASK_ALL,&trace); + + if (trace.allsolid || trace.startsolid) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("checkdown allsolid\n"); +#endif + return false; + } + + if (trace.fraction == 1) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("checkdown- too far\n"); +#endif + return false; + } + else + { + if (trace.contents != CONTENTS_SOLID && trace.ent != self->enemy) + {//didn't hit ground + return false; + } + else + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("checkjump down->whichjump\n"); +#endif + VectorSubtract(trace.endpos, self->s.origin, source2); + VectorNormalize(source2); + self->ideal_yaw = vectoyaw(source2); + + VectorMA(self->velocity, 300, vf, self->velocity); + self->velocity[2]+=150; + + if(classStatics[self->classID].msgReceivers[MSG_JUMP]) + { + if(self->classID != CID_RAT && self->classID != CID_SSITHRA) + {//save vel so can crouch first + VectorCopy(self->velocity, self->movedir); + VectorClear(self->velocity); + } + QPostMessage(self, MSG_JUMP, PRI_DIRECTIVE, NULL); + self->nextthink = level.time + 0.01; + } + else + self->nextthink = level.time + 0.3; + + self->monsterinfo.jump_time = level.time + 1; +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Extra jump down\n"); +#endif + } + } + } +#ifdef _DEVEL + else if(MGAI_DEBUG) + gi.dprintf("checkdown: not clear infront\n"); +#endif + } + else + { + VectorCopy(self->s.origin, save_org); + can_move = M_walkmove (self, self->s.angles[YAW], 64); + VectorCopy(save_org, self->s.origin); + + if(can_move) + return false; + else + {//check to jump over something + +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("check jump over\n"); +#endif + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorCopy(self->s.origin, source); + VectorMA(source, 128, vf, source2); + VectorCopy(self->mins, mins); + mins[2]+=24;//can clear it + gi.trace(source, mins, self->maxs, source2, self, MASK_SOLID,&trace); + + if((!trace.allsolid&&!trace.startsolid&&trace.fraction==1.0) || trace.ent == self->enemy) + {//Go for it! + + VectorMA(self->velocity, 500*trace.fraction, vf, self->velocity); + self->velocity[2] += 225; + + if(classStatics[self->classID].msgReceivers[MSG_JUMP]) + { + if(self->classID != CID_RAT && self->classID != CID_SSITHRA) + {//save vel so can crouch first + VectorCopy(self->velocity, self->movedir); + VectorClear(self->velocity); + } + QPostMessage(self, MSG_JUMP, PRI_DIRECTIVE, NULL); + self->nextthink = level.time + 0.01; + } + else + self->nextthink = level.time + 0.3; +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Extra jump over\n"); +#endif + } + else + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("check jump up\n"); +#endif + VectorCopy(self->maxs, maxs); + VectorCopy(self->s.origin, source); + + hgt_diff = (targ_org[2] + targ_mins[2]) - (self->s.origin[2] + self->mins[2]) + 32; + source[2] += hgt_diff; + gi.trace (self->s.origin, self->mins, self->maxs, source, self, MASK_MONSTERSOLID,&trace); + + if (trace.fraction == 1) + {//clear above + VectorCopy(source, source2); + + AngleVectors(self->s.angles, vf, NULL, NULL); + VectorMA(source, 64, vf, source2); + source2[2] -= 24; + //trace forward and down a little + gi.trace (source, self->mins, self->maxs, source2, self, MASK_ALL,&trace); + + if (trace.allsolid || trace.startsolid) + return false; + + if (trace.fraction < 0.1) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Can't jump up, no ledge\n"); +#endif + return false; + } + // { + // if (stricmp(trace.ent->classname, "worldspawn")) + // return; + // } + else + { + VectorSubtract(trace.endpos, self->s.origin, source2); + source2[2] = 0; + VectorNormalize(source2); + self->ideal_yaw = vectoyaw(source2); + + VectorMA(self->s.origin, 64, source2, source); + gi.trace(self->s.origin, vec3_origin, vec3_origin, source, self, MASK_SOLID,&trace); + + VectorScale(source2, 480*trace.fraction, self->velocity); + self->velocity[2] = hgt_diff*3 + 200; + + if(classStatics[self->classID].msgReceivers[MSG_JUMP]) + { + if(self->classID != CID_RAT && self->classID != CID_SSITHRA) + {//save vel so can crouch first + VectorCopy(self->velocity, self->movedir); + VectorClear(self->velocity); + } + QPostMessage(self, MSG_JUMP, PRI_DIRECTIVE, NULL); + self->nextthink = level.time + 0.01; + } + else + self->nextthink = level.time + 0.3; + self->monsterinfo.jump_time = level.time + 1; +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Extra jump up\n"); +#endif + } + } + else + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Can't jump up, blocked\n"); +#endif + return false; + } + + } + } + + } + return true; +} + +/* +================================================================== +MG_CheckJump() +Checks to see if the enemy is not at the same level as monster +or something is blocking the path of the monster. If there is +a clear jump arc to the enemy and the monster will not land in +water or lava, the monster will attempt to jump the distance. +================================================================== +*/ +qboolean MG_CheckJump (edict_t *self) +{ + vec3_t spot1, spot2, jumpdir, forward, right, targ_absmin; + vec3_t up, cont_spot, vis_check_spot, end_spot, targ_org; + float jump_height, sub_len; + int contents; + qboolean ignore_height; + qboolean jumpup = false; + trace_t trace; + + if(irand(1,100) > self->jump_chance)//JumpChanceForClass[self->classID]) + return false; + + if(self->classID == CID_TBEAST) + return TB_CheckJump(self); + +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Check Jump\n"); +#endif + //FIXME: Allow jump in/out of water if not too deep + if(self->flags & FL_INWATER)// && !(self->flags&FL_AMPHIBIAN))? + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Can't jump- inwater\n"); +#endif + return false; + } + + if (self->monsterinfo.searchType == SEARCH_BUOY) + { + if(self->buoy_index < 0 || self->buoy_index > level.active_buoys) + return false; + + VectorCopy(level.buoy_list[self->buoy_index].origin, targ_org); + VectorCopy(targ_org, targ_absmin); + + if (!(infront_pos(self, targ_org))) + return false; + } + else + { + if(!self->goalentity) + return false; + + if (!(infront(self, self->goalentity))) + return false; + + if(!self->goalentity->groundentity && self->classID != CID_GORGON) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("goalentity in air\n"); +#endif + return false; + } + + VectorCopy(self->goalentity->s.origin, targ_org); + VectorAdd(targ_org, self->goalentity->mins, targ_absmin); + } + + AngleVectors(self->s.angles, forward, right, up); + VectorSubtract(targ_org, self->s.origin, jumpdir); + VectorNormalize(jumpdir); + jumpdir[2] = 0; + jump_height=DotProduct(jumpdir, forward); + + if(jump_height<0.3) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("jump direction more than 60 degrees off of forward\n"); +#endif + return false; + } + + VectorCopy(self->s.origin, spot1); + VectorCopy(targ_org, spot2); + + jump_height = 16; + + VectorMA(spot1, 24, forward, cont_spot); + cont_spot[2] -= 10; + if(!(gi.pointcontents(cont_spot)&CONTENTS_SOLID)) + ignore_height = true; + + sub_len = vhlen(spot1, spot2); +// if(self->classname!="monster_mezzoman"&&!self->spiderType&&self->model!="models/yakman.mdl") + if(sub_len > 256) + ignore_height = false; + + VectorMA(spot1, self->size[0] * 2, forward, vis_check_spot); + VectorMA(vis_check_spot, self->size[2] * 1.5, up, vis_check_spot); +//also check to make sure you can't walkmove forward + if(self->monsterinfo.jump_time > level.time) //Don't jump too many times in a row + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("just jumped\n"); +#endif + return false; + } + else if(!ignore_height&&targ_absmin[2]+36>=self->absmin[2])//&&self->think!=SpiderJumpBegin&&self->classname!="monster_mezzoman"&&self->model!="models/yakman.mdl") + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("not above goalentity, and not spider\n"); +#endif + return false; + } + else if(!self->groundentity)//flags&FL_ONGROUND) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("not on ground\n"); +#endif + return false; + } + else if(sub_len>777 && !ignore_height) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("too far away\n"); +#endif + return false; + } + else if(sub_len <= 100)//&&self->think!=SpiderMeleeBegin) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("too close & not spider\n"); +#endif + return false; + } + //sfs--sure, it's just a dotproduct, but the other checks are a little cheaper + else if(!infront_pos(self, targ_org)) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("goalentity not in front\n"); +#endif + return false; + } + //sfs--save the trace line for after the easy checks + else if(!clear_visible_pos(self, targ_org)&&!LOS(self, vis_check_spot, spot2)) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("can't see goalentity\n"); +#endif + return false; + } + + //sfs--holding off on the point contents too + contents = gi.pointcontents(spot2); + if(!(self->monsterinfo.aiflags&AI_SWIM_OK)&& + (contents&CONTENTS_WATER||contents&CONTENTS_SLIME||contents&CONTENTS_LAVA)) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("goalentity in water or lava\n"); +#endif + return false; + } + + VectorCopy(self->s.origin, spot1); + // spot1=self->s.origin; + spot1[2] += self->maxs[2]; + //spot1_z=self->absmax_z; + VectorCopy(spot1, spot2); + //spot2=spot1; + spot2[2] += 36; + //spot2_z+=36; + + gi.trace(spot1, self->mins, self->maxs, spot2, self, MASK_MONSTERSOLID,&trace); + + if(trace.fraction<1.0||trace.allsolid||trace.startsolid) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("not enough room above\n"); +#endif + return false; + } + + if(!jumpup) // This variable is used without being initialised + { +// spot1+=normalize(v_forward)*((self->maxs_x+self->maxs_y)*0.5); + VectorMA(spot1, (self->maxs[0]+self->maxs[1])*0.5, jumpdir, spot1); + //spot1+=jumpdir*((self->maxs_x+self->maxs_y)*0.5); + VectorCopy(spot1, end_spot); + end_spot[2] += 36; + + gi.trace(self->s.origin, self->mins, self->maxs, end_spot, self, MASK_MONSTERSOLID,&trace); + + if(trace.fraction<1.0||trace.allsolid||trace.startsolid) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("not enough room in front\n"); +#endif + return false; + } + VectorMA(spot1, 64, jumpdir, end_spot); + end_spot[2] -= 500; + gi.trace(spot1, JUMP_MINS, JUMP_MAXS, end_spot, self, MASK_MONSTERSOLID,&trace); +// traceline(spot1,spot1+jumpdir*64 - '0 0 500',false,self); + + contents = gi.pointcontents(trace.endpos); + if(contents&CONTENTS_WATER||contents&CONTENTS_SLIME||contents&CONTENTS_LAVA) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("won't jump in water\n"); +#endif + return false; + } + } + + MG_FaceGoal(self, true); +//FIXME: make them do whatever jump function they have if they have one + self->monsterinfo.jump_time = level.time + 2; //Only try to jump once every 7 seconds + if(!self->s.scale) + self->s.scale = 1.0; + if(!jumpup) + { + VectorScale(jumpdir, jump_height*18*self->s.scale, self->velocity); + //self->velocity=jumpdir*jump_height*18*self->scale;//was 18 + self->velocity[2] = jump_height*14*self->s.scale;//was 12 + } + else + { + VectorScale(jumpdir, jump_height*14*self->s.scale, self->velocity); + //self->velocity=jumpdir*jump_height*14*self->scale;//was 10 + self->velocity[2] = jump_height*17*self->s.scale;//was 14 + } + //self->groundentity = NULL? + if(classStatics[self->classID].msgReceivers[MSG_JUMP]) + { + if(self->classID != CID_RAT && self->classID != CID_SSITHRA) + {//save vel so can crouch first + VectorCopy(self->velocity, self->movedir); + VectorClear(self->velocity); + } + QPostMessage(self, MSG_JUMP, PRI_DIRECTIVE, NULL); + self->nextthink = level.time + 0.01; + } + else + self->nextthink = level.time + 0.3; + +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("JUMP!!!\n"); +#endif + return true; +} + +/* +=============== +MG_WalkMove + + Tries to step forward dist, returns the trace +=============== +*/ +trace_t MG_WalkMove (edict_t *self, float yaw, float dist) +{ + vec3_t move, endpos; + trace_t trace; + + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + trace = MG_MoveStep(self, move, true); + if(trace.succeeded) + { + return trace; + } +//FaileD? ok, so what's in front of us + VectorAdd(self->s.origin, move, endpos); + //up mins for stairs? + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&trace); + trace.succeeded = false; + return trace; +} + +/* +=============== +MG_BoolWalkMove + + Tries to step forward dist, returns true/false +=============== +*/ +qboolean MG_BoolWalkMove (edict_t *self, float yaw, float dist) +{ + vec3_t move; + trace_t trace; + + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + trace = MG_MoveStep(self, move, true); + if(trace.succeeded) + { + return true; + } + + return false; +} + +/* +=============== +MG_TestMove + + Sees if it can step dist in yaw, but doesn't do the move +=============== +*/ +qboolean MG_TestMove (edict_t *self, float yaw, float dist) +{ + vec3_t move; + trace_t trace; + + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + trace = MG_MoveStep(self, move, false); + if(trace.succeeded) + return true; + + return false; +} + +void MG_CheckEvade (edict_t *self) +{//FIXME: only check my enemy? See if he's fired (last_attack) recently? + int hl; + float ent_dist, proj_offset; + vec3_t proj_dir, endpos, bad_dir; + trace_t trace; + edict_t *ent = NULL; + vec3_t total_dist; + float eta; + + if(!skill->value) + return; + //else if(flrand(0, 3) > skill->value) + // return; + + while(ent = findradius(ent, self->s.origin, 500)) + { + if(ent->movetype == MOVETYPE_FLYMISSILE && ent->solid && ent->owner!=self) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Monster checking evade from %s projectile\n", ent->classname); +#endif + if(Vec3IsZero(ent->velocity)) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("ERROR: NULL velocity on %s projectile!\n", ent->classname); +#endif + } + else + { + VectorCopy(ent->velocity, proj_dir); + VectorNormalize(proj_dir); + VectorMA(ent->s.origin, 600, proj_dir, endpos); + + gi.trace(ent->s.origin, ent->mins, ent->maxs, endpos, ent, MASK_MONSTERSOLID,&trace); + if(trace.ent == self) + {//going to get hit! +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Dodging projectile impact, going to hit %s\n", HitLocName[hl]); +#endif + hl = T_GetHitLocation(self, ent, trace.endpos); + VectorSubtract(trace.endpos, ent->s.origin, total_dist); + eta = VectorLength(total_dist)/VectorLength(ent->velocity); + QPostMessage(self, MSG_EVADE, PRI_DIRECTIVE, "eif", ent, hl, eta); + } + else if(!irand(0,2)) + { + VectorSubtract(self->s.origin, ent->s.origin, bad_dir); + ent_dist = VectorNormalize(bad_dir); + proj_offset = DotProduct(bad_dir, proj_dir); +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Proj dot prod: %f\n", proj_offset); +#endif + if(proj_offset > ent_dist/600)//farther it is, smaller angle deviation allowed for evasion + {//coming pretty close + VectorMA(ent->s.origin, ent_dist, proj_dir, endpos);//extrapolate to close to me + gi.trace(endpos, ent->mins, ent->maxs, self->s.origin, ent, MASK_MONSTERSOLID,&trace); + if(trace.ent == self) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Dodging projectile close pass, going to hit %s\n", HitLocName[hl]); +#endif + hl = T_GetHitLocation(self, ent, trace.endpos); + VectorSubtract(trace.endpos, ent->s.origin, total_dist); + eta = VectorLength(total_dist)/VectorLength(ent->velocity); + QPostMessage(self, MSG_EVADE, PRI_DIRECTIVE, "eif", ent, hl, eta); + } + } + } + } + } + } +} + +/* +============= +ai_run + +The monster has an enemy it is trying to kill or the monster is fleeing +============= +*/ +void old_ai_run (edict_t *self, float dist); +void ai_run (edict_t *self, float dist) +{ + float turnamt, i; + + //if dumb fleeing or fleeing and can't use buoys... + if((DEACTIVATE_BUOYS||!(self->monsterinfo.aiflags & AI_USING_BUOYS)) + && + (self->monsterinfo.aiflags & AI_COWARD || + (self->monsterinfo.aiflags&AI_FLEE + && + self->monsterinfo.flee_finished >= level.time) + ) + ) + { + ai_flee(self, dist); + return; + } + else if(self->ai_mood_flags & AI_MOOD_FLAG_DUMB_FLEE) + { + if(MG_GoToRandomBuoy(self)) + self->monsterinfo.searchType = SEARCH_BUOY; + else + { + ai_flee(self, dist); + return; + } + } + + if(!DEACTIVATE_BUOYS) + { + if(self->monsterinfo.aiflags & AI_USING_BUOYS) + { + if(!(self->monsterinfo.aiflags&AI_STRAIGHT_TO_ENEMY)) + { + if(self->pathfind_nextthink<=level.time) + { + MG_BuoyNavigate(self); + self->pathfind_nextthink = level.time + 0.1;//0.3;-maybe TOO optimized, trying every frame again, take out of generic mood think? + //don't pathfind for the next 3 frames. + } + } + } + } + + if (self->monsterinfo.aiflags & AI_STAND_GROUND) + {//just face enemy + turnamt = Q_fabs(ai_face_goal(self)); + return; + } + +#ifdef _DEVEL + if(self->goalentity == self->enemy) + { + //sfs--only do this visibility check when debugging (gets expensive at big distances) + if(MGAI_DEBUG && !visible(self, self->enemy)) + { + gi.dprintf("ERROR: goal is invis enemy!\n"); + } + } +#endif + + if(dist) + if(!MG_MoveToGoal (self, dist)) + { + if(self->classID == CID_SSITHRA) + ssithraCheckJump(self); + } + else + i = 0; + + if(self->classID!=CID_ASSASSIN)//does his own checks + if(classStatics[self->classID].msgReceivers[MSG_EVADE]) + {//check for if going to be hit and evade + MG_CheckEvade(self); + } +} + +void mg_ai_charge (edict_t *self, float dist) +{ + vec3_t v; + + if(!self->enemy) + { +#ifdef _DEVEL + gi.dprintf("ERROR: AI_CHARGE at a NULL enemy!\n"); +#endif + return;//send stand MSG? + } + + VectorSubtract (self->enemy->s.origin, self->s.origin, v); + + self->ideal_yaw = vectoyaw(v); + + MG_ChangeYaw (self); + + if (dist) + MG_WalkMove (self, self->s.angles[YAW], dist); + + if(self->classID!=CID_ASSASSIN)//does his own checks + if(classStatics[self->classID].msgReceivers[MSG_EVADE]) + {//check for if going to be hit and evade + MG_CheckEvade(self); + } +} + +qboolean canmove (edict_t *self) +{ + if( self->movetype!=PHYSICSTYPE_NONE && + self->movetype!=PHYSICSTYPE_PUSH) + return true; + return false; +} + +void mg_remove_body(edict_t *self) +{ + vec3_t origin; + int flag = 0; + + VectorCopy(self->s.origin, origin); + origin[2] += (self->mins[2] + 8.0f); + if(self->classID == CID_RAT) + flag |= CEF_FLAG6; + gi.CreateEffect(NULL, FX_CORPSE_REMOVE, flag, origin, ""); + G_SetToFree(self); +} + +void body_phase_out (edict_t *self) +{ + int interval = 30; + + if(self->s.color.a > interval) + { + self->s.color.a -= irand(interval/2, interval); + self->post_think = body_phase_out; + self->next_post_think = level.time + 0.05; + } + else + { + self->s.color.a = 0; + self->post_think = NULL; + self->next_post_think = -1; + + G_SetToFree(self); + } +} + +trace_t MG_AirMove(edict_t *self, vec3_t goalpos, float dist) +{ + trace_t trace; + vec3_t endpos, movedir; + + VectorSubtract(goalpos, self->s.origin, movedir); + VectorNormalize(movedir); + + VectorMA(self->s.origin, dist, movedir, endpos); + + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID, &trace); + + if(trace.allsolid || trace.startsolid || trace.fraction <= 0.01) + { + trace.succeeded = false; + return trace; + } + + VectorCopy(trace.endpos, self->s.origin); + + gi.linkentity(self); + + trace.succeeded = true; + return trace; +} + +static int FRONT = 0; +static int BACK = 1; +static int RIGHT = 2; +static int LEFT = 3; +static float MIN_DROP_DIST = 0.125f; + +void MG_PostDeathThink (edict_t *self) +{ + float mostdist; + trace_t trace1, trace2, trace3, trace4, movetrace; + vec3_t org, endpos, startpos, forward, right; + int whichtrace = 0; + float cornerdist[4]; + qboolean frontbackbothclear = false; + qboolean rightleftbothclear = false; + + self->post_think = body_phase_out; + self->next_post_think = level.time + 10; + + if(!self->groundentity || Vec3NotZero(self->velocity)) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Falling!\n"); +#endif + if(self->groundentity&&self->friction == 1.0)//check avelocity? + pitch_roll_for_slope(self, NULL); + + self->post_think = MG_PostDeathThink; + self->next_post_think = level.time + 0.1; + return; + } + + cornerdist[FRONT] = cornerdist[BACK] = cornerdist[RIGHT] = cornerdist[LEFT] = 0.0f; + + mostdist = MIN_DROP_DIST; + + AngleVectors(self->s.angles, forward, right, NULL); + VectorCopy(self->s.origin, org); + org[2]+=self->mins[2]; + + VectorMA(org, self->dead_size, forward, startpos); + VectorCopy(startpos, endpos); + endpos[2]-=128; + gi.trace(startpos, vec3_origin, vec3_origin, endpos, self, MASK_SOLID,&trace1); + if(!trace1.allsolid&&!trace1.startsolid) + { + cornerdist[FRONT] = trace1.fraction; + if(trace1.fraction>mostdist) + { + mostdist = trace1.fraction; + whichtrace = 1; + } + } + + VectorMA(org, -self->dead_size, forward, startpos); + VectorCopy(startpos, endpos); + endpos[2]-=128; + gi.trace(startpos, vec3_origin, vec3_origin, endpos, self, MASK_SOLID,&trace2); + if(!trace2.allsolid&&!trace2.startsolid) + { + cornerdist[BACK] = trace2.fraction; + if(trace2.fraction>mostdist) + { + mostdist = trace2.fraction; + whichtrace = 2; + } + } + + VectorMA(org, self->dead_size/2, right, startpos); + VectorCopy(startpos, endpos); + endpos[2]-=128; + gi.trace(startpos, vec3_origin, vec3_origin, endpos, self, MASK_SOLID,&trace3); + if(!trace3.allsolid&&!trace3.startsolid) + { + cornerdist[RIGHT] = trace3.fraction; + if(trace3.fraction>mostdist) + { + mostdist = trace3.fraction; + whichtrace = 3; + } + } + + VectorMA(org, -self->dead_size/2, right, startpos); + VectorCopy(startpos, endpos); + endpos[2]-=128; + gi.trace(startpos, vec3_origin, vec3_origin, endpos, self, MASK_SOLID,&trace4); + if(!trace4.allsolid&&!trace4.startsolid) + { + cornerdist[LEFT] = trace4.fraction; + if(trace4.fraction>mostdist) + { + mostdist = trace4.fraction; + whichtrace = 4; + } + } + + //OK! Now if two opposite sides are hanging, use a third if any, else, do nothing + if(cornerdist[FRONT] > MIN_DROP_DIST && cornerdist[BACK] > MIN_DROP_DIST) + frontbackbothclear = true; + + if(cornerdist[RIGHT] > MIN_DROP_DIST && cornerdist[LEFT] > MIN_DROP_DIST) + rightleftbothclear = true; + + if(frontbackbothclear && rightleftbothclear) + return; + + if(frontbackbothclear) + { + if(cornerdist[RIGHT] > MIN_DROP_DIST) + whichtrace = 3; + else if(cornerdist[LEFT] > MIN_DROP_DIST) + whichtrace = 4; + else + return; + } + + if(rightleftbothclear) + { + if(cornerdist[FRONT] > MIN_DROP_DIST) + whichtrace = 1; + else if(cornerdist[BACK] > MIN_DROP_DIST) + whichtrace = 2; + else + return; + } + + switch(whichtrace) + {//check for stuck + case 1: + VectorMA(self->s.origin, self->maxs[0], forward, endpos); + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&movetrace); + if(movetrace.allsolid||movetrace.startsolid||movetrace.fraction<1.0) + if(canmove(movetrace.ent)) + whichtrace = -1; + else + whichtrace = 0; + break; + case 2: + VectorMA(self->s.origin, -self->maxs[0], forward, endpos); + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&movetrace); + if(movetrace.allsolid||movetrace.startsolid||movetrace.fraction<1.0) + if(canmove(movetrace.ent)) + whichtrace = -1; + else + whichtrace = 0; + break; + case 3: + VectorMA(self->s.origin, self->maxs[0], right, endpos); + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&movetrace); + if(movetrace.allsolid||movetrace.startsolid||movetrace.fraction<1.0) + if(canmove(movetrace.ent)) + whichtrace = -1; + else + whichtrace = 0; + break; + case 4: + VectorMA(self->s.origin, -self->maxs[0], right, endpos); + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_MONSTERSOLID,&movetrace); + if(movetrace.allsolid||movetrace.startsolid||movetrace.fraction<1.0) + if(canmove(movetrace.ent)) + whichtrace = -1; + else + whichtrace = 0; + break; + } + + switch(whichtrace) + { + case 1: +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Forward trace %f\n", trace1.fraction); +#endif + VectorMA(self->velocity, 200, forward, self->velocity); + if(trace1.fraction >= 0.9) + { +//can't anymore, origin not in center of deathframe! +// self->avelocity[PITCH] = -300; + self->friction = 1.0; + } + else + { + pitch_roll_for_slope(self, &trace1.plane.normal); + self->friction = trace1.plane.normal[2] * 0.1; + } + self->post_think = MG_PostDeathThink; + self->next_post_think = level.time + 0.1; + return; + break; + + case 2: +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("back trace %f\n", trace2.fraction); +#endif + VectorMA(self->velocity, -200, forward, self->velocity); + if(trace2.fraction >= 0.9) + { +//can't anymore, origin not in center of deathframe! +// self->avelocity[PITCH] = 300; + self->friction = 1.0; + } + else + { + pitch_roll_for_slope(self, &trace2.plane.normal); + self->friction = trace2.plane.normal[2] * 0.1; + } + self->post_think = MG_PostDeathThink; + self->next_post_think = level.time + 0.1; + return; + break; + + case 3: +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Right trace %f\n", trace3.fraction); +#endif + VectorMA(self->velocity, 200, right, self->velocity); + if(trace3.fraction >= 0.9) + { +//can't anymore, origin not in center of deathframe! +// self->avelocity[ROLL] = -300; + self->friction = 1.0; + } + else + { + pitch_roll_for_slope(self, &trace3.plane.normal); + self->friction = trace3.plane.normal[2] * 0.1; + } + self->post_think = MG_PostDeathThink; + self->next_post_think = level.time + 0.1; + return; + break; + + case 4: +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Left trace %f\n", trace4.fraction); +#endif + VectorMA(self->velocity, -200, right, self->velocity); + if(trace4.fraction >= 0.9) + { +//can't anymore, origin not in center of deathframe! +// self->avelocity[ROLL] = 300; + self->friction = 1.0; + } + else + { + pitch_roll_for_slope(self, &trace4.plane.normal); + self->friction = trace4.plane.normal[2] * 0.1; + } + self->post_think = MG_PostDeathThink; + self->next_post_think = level.time + 0.1; + return; + break; + } + //on solid ground + if(whichtrace == -1) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Deadmonster slide = stuck! (size is %4.2f)\n", self->dead_size); +#endif + self->post_think = MG_PostDeathThink; + self->next_post_think = level.time + 2; + return; + } +#ifdef _DEVEL + else if(MGAI_DEBUG) + gi.dprintf("Deadmonster slide = On ground (size was %4.2f)\n", self->dead_size); +#endif + self->friction = 1.0; + + VectorClear(self->avelocity); + pitch_roll_for_slope(self, NULL); + + if(!self->s.color.r) + self->s.color.r = 255; + if(!self->s.color.g) + self->s.color.g = 255; + if(!self->s.color.b) + self->s.color.b = 255; + self->s.color.a = 255; + + self->post_think = body_phase_out; + if(self->classID == CID_RAT) + self->next_post_think = level.time + flrand(3, 7); + else + self->next_post_think = level.time + flrand(10, 20); + + gi.linkentity (self); +} + +void MG_CheckLanded (edict_t *self, float next_anim) +{ + vec3_t pos; + +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("self->velocity %f %f %f\n", self->velocity[0], self->velocity[1], self->velocity[2]); +#endif + + if(self->groundentity) + SetAnim(self, (int)next_anim); + else if(self->velocity[2]<0) + { + VectorCopy(self->s.origin, pos); + pos[2] += self->mins[2]; + VectorMA(pos, 0.5, self->velocity, pos); + if(gi.pointcontents(pos)&CONTENTS_SOLID) + SetAnim(self, (int)next_anim); + } +} + +void MG_InAirMove (edict_t *self, float fwdspd,float upspd,float rtspd) +{//simple addition of velocity, if on ground or not + vec3_t up, forward, right; + + if(self->groundentity)//on ground + return; + + AngleVectors(self->s.angles, forward, right, up); + + VectorMA(self->velocity, upspd, up, self->velocity); + VectorMA(self->velocity, fwdspd, forward, self->velocity); + VectorMA(self->velocity, rtspd, right, self->velocity); +} + +void MG_ApplyJump (edict_t *self) +{ + self->jump_time = level.time + 0.5; + VectorCopy(self->movedir, self->velocity); + VectorNormalize(self->movedir); +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Jump velocity will be: %4.2f %4.2f %4.2f\n", self->velocity[0], self->velocity[1], self->velocity[2]); +#endif + self->monsterinfo.aiflags &= ~AI_OVERRIDE_GUIDE; +} + +void MG_NoBlocking (edict_t *self) +{ + self->svflags |= SVF_DEADMONSTER; // now treat as a different content type + self->msgHandler = DeadMsgHandler; // no more messages at all +} + +qboolean MG_GetTargOrg (edict_t *self, vec3_t targ_org) +{ + if (self->monsterinfo.searchType == SEARCH_BUOY) + { + if(self->buoy_index < 0 || self->buoy_index > level.active_buoys) + { + VectorClear(targ_org); + return false; + } + VectorCopy(level.buoy_list[self->buoy_index].origin, self->monsterinfo.nav_goal); + VectorCopy(self->monsterinfo.nav_goal, targ_org); + } + else + { + if(!self->goalentity) + { + VectorClear(targ_org); + return false; + } + + VectorCopy(self->goalentity->s.origin, targ_org); + } + return true; +} + +/* +qboolean EqualAngle(float angle1, float angle2, float leniency) + +Sees if the two angles are within leniency degrees of each other +*/ +qboolean EqualAngle(float angle1, float angle2, float leniency) +{ + float diff; + + if(angle1 < -180) + angle1 += 360; + else if(angle1 > 180) + angle1 -= 360; + + if(angle2 < -180) + angle2 += 360; + else if(angle2 > 180) + angle2 -= 360; + + diff = angle1 - angle2; + + if(diff < -180) + diff += 360; + else if(diff > 180) + diff -= 360; + + if(fabs(diff) > leniency) + return false; + + return true; +} + +/* +qboolean ok_to_break (edict_t *target) + + Ok to just smash this damn thing in my way? +*/ +qboolean ok_to_break (edict_t *target) +{ + if(!target) + return false; + + if(!target->takedamage) + return false; + + if(target->health>MAX_BLOCKING_THING_HEALTH)//general damage for pots, barrels, etc. + return false; + + if(target->targetname)//supposed to be triggered for some reason + return false; + + if(target->svflags&SVF_MONSTER)//another monster + return false; + + if(Vec3IsZero(target->s.origin))//breakable_brushes have no origin + return false; + + return true;//break it! +} + +qboolean MG_MoveToGoal (edict_t *self, float dist) +{ + trace_t trace; + float turnamt, distloss, adj_dist, save_yaw, save_yaw_speed, WallDot;//, save_ideal_yaw; + vec3_t mins, maxs, source, goal_dir;//, vec, save_org; + qboolean goal_vis=false, hitworld = false, new_best_yaw = false; + float stepsize, goal_dist, oby; + + if(self->classID == CID_TBEAST) + stepsize = STEPSIZE * 3; + else + stepsize = STEPSIZE; + + if(!self->groundentity&&!(self->flags&FL_SWIM)&&!(self->flags&FL_FLY)) + return false;//in air! + + trace.succeeded = false; + + if(self->classID != CID_GORGON)//they do their own yawing + MG_FaceGoal(self, false);//get ideal yaw, but don't turn + + //are we very close to our goal? problem: what if something in between? + if(!EqualAngle(self->s.angles[YAW], self->ideal_yaw, self->yaw_speed)) + {//we aren't really facing our ideal yet + if(self->monsterinfo.searchType == SEARCH_BUOY||self->ai_mood == AI_MOOD_NAVIGATE) + { + VectorSubtract(self->monsterinfo.nav_goal, self->s.origin, goal_dir); + goal_dist = VectorNormalize(goal_dir); + if(goal_dist < (self->maxs[0] + 24 + dist)) + {//we're close to our goal + MG_ChangeWhichYaw(self, YAW_IDEAL); + return true;//so close to enemy, just turn, no movement - not if rat? + } + } + else if(self->enemy) + { + VectorSubtract(self->monsterinfo.nav_goal, self->s.origin, goal_dir); + goal_dist = VectorNormalize(goal_dir); + if(goal_dist < (self->maxs[0] + self->enemy->maxs[0] + dist*2)) + {//we're close to our goal + MG_ChangeWhichYaw(self, YAW_IDEAL); + return true;//so close to enemy, just turn, no movement - not if rat? + } + } + } + + if(self->monsterinfo.idle_time == -1) + {//have been told to just turn to ideal_yaw + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_IDEAL)); + //keep turning towards ideal until facing it + if(turnamt < 1) + self->monsterinfo.idle_time = 0; + else + return true; + } + else if(self->monsterinfo.idle_time > level.time) + {//using best_move_yaw + if(EqualAngle(self->s.angles[YAW], self->best_move_yaw, 5)) + {//do a test move in the direction I would like to go: + if(MG_TestMove(self, self->ideal_yaw, dist)) + {//can move in that dir turn there for rest of this +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move in ideal tested true while using best_move...!\n"); +#endif + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_IDEAL)); + //keep turning towards ideal until facing it + if(turnamt < 1) + self->monsterinfo.idle_time = 0; + else + { + self->monsterinfo.idle_time = -1; + return true; + } + } + } + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_BEST_MOVE));//turn to temp yaw + } + else + {//using ideal_yaw + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_IDEAL)); + } + + distloss = turnamt/self->yaw_speed * 0.8;//0.3; + adj_dist = dist - (dist * distloss); + + trace = MG_WalkMove(self, self->s.angles[YAW], dist); + if(trace.succeeded) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move forward succeeded!\n"); +#endif + return true; + } + else if(self->classID == CID_TBEAST) + { + if(trace.fraction<1.0) + VectorCopy(trace.endpos, self->s.origin); + } + +//if facing best_move_yaw and can't move that way, stop trying in that dir now. + if(self->monsterinfo.idle_time > level.time && self->s.angles[YAW] == self->best_move_yaw) + { + new_best_yaw = true; + oby = self->best_move_yaw; + self->monsterinfo.idle_time = 0; + } + +//bumped into something + if(trace.ent) + { + if(!stricmp(trace.ent->classname, "worldspawn")) + hitworld = true; + else + hitworld = false; + + if(trace.ent == self->enemy) + {//bumped into enemy, go get him! + if(!(self->monsterinfo.aiflags & AI_COWARD) && + (!(self->monsterinfo.aiflags&AI_FLEE) || self->monsterinfo.flee_finished < level.time)) + { + if(!(self->monsterinfo.aiflags&AI_NO_MELEE)) + { + if(!(self->ai_mood_flags&AI_MOOD_FLAG_IGNORE_ENEMY)) + { + if(classStatics[self->classID].msgReceivers[MSG_MELEE] && infront(self, self->enemy)) + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + return true; + } + } + } + } + } + else if(trace.ent->svflags & SVF_MONSTER) + {//if bumped into a monster that's not after an enemy but not ambushing, bring him along + if(!trace.ent->enemy) + { + if(trace.ent->health>0 && !trace.ent->monsterinfo.awake) + { + if(!(trace.ent->spawnflags & MSF_AMBUSH)) + { + if(self->enemy) + { + if(self->enemy->client) + { + trace.ent->enemy = self->enemy; + FoundTarget(trace.ent, false); + } + } + } + } + } + } + +/* +//FIXME: this needs to make sure they can break it +//also: do not do this if the monsters' enemy is visible (MASK_SOLID check, though) + else if(!irand(0, 5)) + {//fixme: need to make sure the melee anims can break this + if(self->classID > CID_RAT && classStatics[self->classID].msgReceivers[MSG_MELEE]) + { + if(!(self->monsterinfo.aiflags&AI_NO_MELEE)) + { + if(ok_to_break(trace.ent)) + { + if(infront(self, trace.ent)) + {//smash it! + if(MGAI_DEBUG) + gi.dprintf("%s breaking blocking %s!\n", self->classname, trace.ent->classname); + self->monsterinfo.aiflags |= AI_STRAIGHT_TO_ENEMY;//go straight at enemy, not buoys + self->oldenemy_debounce_time = level.time + 7;//attack it for 7 seconds max + self->oldenemy = self->enemy;//remember who I was after + self->enemy = self->goalentity = trace.ent;//let's nail this sucker + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL);//SMACK! + return true; + } + } + } + } + } +*/ + if(!hitworld) + { + if(self->monsterinfo.idle_time < level.time) + {//not already following a weird dir +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move forward hit wall, newdir\n"); +#endif + self->monsterinfo.idle_time = level.time + flrand(0.5, 1.2); + self->best_move_yaw = anglemod(180 + self->ideal_yaw); + MG_NewDir(self, dist); + } + return false; + } +#ifdef _DEVEL + else if(MGAI_DEBUG) + gi.dprintf("Bumped world - t_f: %f t_allsolid: %d, t_startsolid %d\n",trace.fraction, trace.allsolid, trace.startsolid); +#endif + } + +//Ledge? + if((trace.fraction >= 0.5 + distloss ||self->classID == CID_ASSASSIN) && !trace.allsolid && !trace.startsolid)//a ledge + {//why not tracefraction == 1.0? + if(!(self->spawnflags & MSF_FIXED)) + { + if(MG_CheckJump(self))//can jump off it + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move forward jumped off ledge!\n"); +#endif + return true; + } + else if(self->classID == CID_ASSASSIN) + { + if(MG_ExtraCheckJump(self)) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move straight to goal extra jumped off ledge!\n"); +#endif + return true; + } + } + } + + if(trace.fraction >= 0.5)//even assassins skip this + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Can't jump off, getting newdir\n"); +#endif + if(self->monsterinfo.idle_time < level.time) + {//not already following some other dir, pick one + self->monsterinfo.idle_time = level.time + flrand(1, 2); + self->best_move_yaw = anglemod(180 + self->ideal_yaw); + MG_NewDir(self, dist);//what if this fails to set one? + } + return false; + } + } + +#ifdef _DEVEL + if(MGAI_DEBUG) + if(trace.allsolid || trace.startsolid) + gi.dprintf("Move forward allsolid or startsolid!\n"); +#endif + //FROM HERE ON, ONLY CHANGES DIR, WILL NOT MOVE! + + //otherwise, go around it... this ONLY??? + //lock into this new yaw for a bit + if(self->monsterinfo.idle_time > level.time) + {//heading somewhere for a few secs, turn here +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Turning to newdir, not bumping\n"); +#endif + /* turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_BEST_MOVE)); + distloss = turnamt/self->yaw_speed * 0.3; + dist -= (dist * distloss);*/ + return false; + } + + if((hitworld || irand(0,10)<6)&&!goal_vis) + self->monsterinfo.idle_time = level.time + flrand(1, 2); + else + self->monsterinfo.idle_time = level.time + flrand(0.5, 1.25); + + self->best_move_yaw = anglemod(180 + self->ideal_yaw); + + //if hit a wall and close to ideal yaw (with 5), try a new dir + if(Vec3NotZero(trace.plane.normal)&& + EqualAngle(self->s.angles[YAW], self->ideal_yaw, 5)) + {//a wall? + vec3_t wall_angles, wall_right, self_forward, new_forward, vf; +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move forward hit wall, checking left/right/back...\n"); +#endif + + //If facing a wall, turn faster, more facing the wall, faster the turn + save_yaw_speed = self->yaw_speed; + AngleVectors(self->s.angles, self_forward, NULL, NULL); + WallDot = DotProduct(trace.plane.normal, self_forward); + if(WallDot>0) + WallDot = 0;//-1 to 0 + self->yaw_speed *= 1.25 - WallDot;//facing wall head-on = 2.25 times normal yaw speed + + vectoangles(trace.plane.normal, wall_angles); + AngleVectors(wall_angles, NULL, wall_right, NULL); + + if(goal_vis) + {//can see goal, turn towards IT first + VectorSubtract(self->goalentity->s.origin, self->s.origin, self_forward); + VectorNormalize(self_forward); + } + + //Get closest angle off that wall to move in + if(DotProduct(wall_right,self_forward)>0) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("turning left\n"); +#endif + VectorCopy(wall_right, new_forward); + } + else + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("turning right\n"); +#endif + VectorScale(wall_right, -1, new_forward); + } + + if(irand(0,10)<3)//30% chance of trying other way first + VectorScale(new_forward, -1, new_forward); + + self->best_move_yaw=vectoyaw(new_forward); + + if(new_best_yaw && self->best_move_yaw == oby) + { + VectorScale(new_forward, -1, new_forward); + + self->best_move_yaw=vectoyaw(new_forward); + } + + //make sure we can move in chosen dir + //set up mins and maxes for these moves + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + //Account for STEPSIZE + mins[2] += stepsize; + if(mins[2] >= self->maxs[2]) + mins[2] = self->maxs[2] - 1; + //remember yaw in case all these fail! + save_yaw = self->s.angles[YAW]; + + //Haven't yawed yet, so this is okay + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_BEST_MOVE)); + distloss = turnamt/self->yaw_speed * 0.8;//0.3; + adj_dist = dist - (dist * distloss); + + VectorCopy(new_forward, vf); + //AngleVectors(self->s.angles, vf, NULL, NULL); + + VectorCopy(self->s.origin, source); + VectorMA(source, adj_dist, vf, source); + + gi.trace (self->s.origin, mins, self->maxs, source, self, MASK_SOLID,&trace);//was MASK_SHOT + + if (trace.fraction < 1||trace.allsolid||trace.startsolid) + {//Uh oh, try other way +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("turn other way\n"); +#endif + VectorScale(new_forward, -1, new_forward); + self->best_move_yaw=vectoyaw(new_forward); + //restore yaw + self->s.angles[YAW] = save_yaw; + //try new dir + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_BEST_MOVE)); + distloss = turnamt/self->yaw_speed * 0.8;//0.3; + adj_dist = dist - (dist * distloss); + + VectorCopy(new_forward, vf); + //AngleVectors(self->s.angles, vf, NULL, NULL); + + VectorMA(source, adj_dist, vf, source); + + //Account for STEPSIZE + mins[2] += stepsize; + if(mins[2] >= self->maxs[2]) + mins[2] = self->maxs[2] - 1; + + gi.trace (self->s.origin, mins, self->maxs, source, self, MASK_SOLID,&trace);//was MASK_SHOT + if (trace.fraction < 1||trace.allsolid||trace.startsolid) + {//Uh oh! Go straight away from wall +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("turn all the way around\n"); +#endif + self->best_move_yaw=wall_angles[YAW]; + //restore yaw + self->s.angles[YAW] = save_yaw; + //start turning this move, but don't actually move until next time + MG_ChangeWhichYaw(self, YAW_BEST_MOVE); + } + } + self->yaw_speed = save_yaw_speed; + return false; + } + else//keep turning to ideal + self->monsterinfo.idle_time = 0; + + //Must have bumped into something very strange (other monster?) + //just pick a new random dir +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Don't know what I hit, choosing newdir for a second\n"); +#endif + MG_NewDir(self, dist); + return false; +} + +qboolean MG_SwimFlyToGoal (edict_t *self, float dist) +{ + trace_t trace; + float turnamt, distloss, adj_dist, save_yaw, save_yaw_speed, WallDot;//, save_ideal_yaw; + vec3_t mins, maxs, source, goal_dir, goalpos;//, vec, save_org; + qboolean goal_vis=false, hitworld = false, new_best_yaw = false; + float goal_dist, oby; + + trace.succeeded = false; + + if(self->classID != CID_GORGON)//they do their own yawing + MG_FaceGoal(self, false);//get ideal yaw, but don't turn + + //are we very close to our goal? problem: what if something in between? + if(!EqualAngle(self->s.angles[YAW], self->ideal_yaw, self->yaw_speed)) + {//we aren't really facing our ideal yet + if(self->monsterinfo.searchType == SEARCH_BUOY||self->ai_mood == AI_MOOD_NAVIGATE) + { + VectorSubtract(self->monsterinfo.nav_goal, self->s.origin, goal_dir); + goal_dist = VectorNormalize(goal_dir); + if(goal_dist < (self->maxs[0] + 24 + dist)) + {//we're close to our goal + MG_ChangeWhichYaw(self, YAW_IDEAL); + return true;//so close to enemy, just turn, no movement - not if rat? + } + } + else if(self->enemy) + { + VectorSubtract(self->monsterinfo.nav_goal, self->s.origin, goal_dir); + goal_dist = VectorNormalize(goal_dir); + if(goal_dist < (self->maxs[0] + self->enemy->maxs[0] + dist*2)) + {//we're close to our goal + MG_ChangeWhichYaw(self, YAW_IDEAL); + return true;//so close to enemy, just turn, no movement - not if rat? + } + } + } + + if(self->monsterinfo.idle_time == -1) + {//have been told to just turn to ideal_yaw + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_IDEAL)); + //keep turning towards ideal until facing it + if(turnamt < 1) + self->monsterinfo.idle_time = 0; + else + return true; + } + else if(self->monsterinfo.idle_time > level.time) + {//using best_move_yaw + if(EqualAngle(self->s.angles[YAW], self->best_move_yaw, 5)) + {//do a test move in the direction I would like to go: + if(MG_TestMove(self, self->ideal_yaw, dist)) + {//can move in that dir turn there for rest of this +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move in ideal tested true while using best_move...!\n"); +#endif + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_IDEAL)); + //keep turning towards ideal until facing it + if(turnamt < 1) + self->monsterinfo.idle_time = 0; + else + { + self->monsterinfo.idle_time = -1; + return true; + } + } + } + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_BEST_MOVE));//turn to temp yaw + } + else + {//using ideal_yaw + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_IDEAL)); + } + + distloss = turnamt/self->yaw_speed * 0.8;//0.3; + adj_dist = dist - (dist * distloss); + + MG_GetGoalPos(self, goalpos); + + trace = MG_AirMove(self, goalpos, dist); + if(trace.succeeded) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move forward succeeded!\n"); +#endif + return true; + } + +//if facing best_move_yaw and can't move that way, stop trying in that dir now. + if(self->monsterinfo.idle_time > level.time && self->s.angles[YAW] == self->best_move_yaw) + { + new_best_yaw = true; + oby = self->best_move_yaw; + self->monsterinfo.idle_time = 0; + } + +//bumped into something + if(trace.ent) + { + if(!stricmp(trace.ent->classname, "worldspawn")) + hitworld = true; + else + hitworld = false; + + if(trace.ent == self->enemy) + {//bumped into enemy, go get him! + if(!(self->monsterinfo.aiflags & AI_COWARD) && + (!(self->monsterinfo.aiflags&AI_FLEE) || self->monsterinfo.flee_finished < level.time)) + { + if(!(self->monsterinfo.aiflags&AI_NO_MELEE)) + { + if(!(self->ai_mood_flags&AI_MOOD_FLAG_IGNORE_ENEMY)) + { + if(classStatics[self->classID].msgReceivers[MSG_MELEE] && infront(self, self->enemy)) + { + QPostMessage(self, MSG_MELEE, PRI_DIRECTIVE, NULL); + return true; + } + } + } + } + } + else if(trace.ent->svflags & SVF_MONSTER) + {//if bumped into a monster that's not after an enemy but not ambushing, bring him along + if(!trace.ent->enemy) + { + if(trace.ent->health>0 && !trace.ent->monsterinfo.awake) + { + if(!(trace.ent->spawnflags & MSF_AMBUSH)) + { + if(self->enemy) + { + if(self->enemy->client) + { + trace.ent->enemy = self->enemy; + FoundTarget(trace.ent, false); + } + } + } + } + } + } + + if(!hitworld) + { + if(self->monsterinfo.idle_time < level.time) + {//not already following a weird dir +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move forward hit wall, newdir\n"); +#endif + self->monsterinfo.idle_time = level.time + flrand(0.5, 1.2); + self->best_move_yaw = anglemod(180 + self->ideal_yaw); + MG_NewDir(self, dist); + } + return false; + } +#ifdef _DEVEL + else if(MGAI_DEBUG) + gi.dprintf("Bumped world - t_f: %f t_allsolid: %d, t_startsolid %d\n",trace.fraction, trace.allsolid, trace.startsolid); +#endif + } + +//Ledge? +/* if(trace.fraction >= 0.5 + distloss && !trace.allsolid && !trace.startsolid)//a ledge + {//why not tracefraction == 1.0? + if(trace.fraction >= 0.5)//even assassins skip this + { + if(MGAI_DEBUG) + gi.dprintf("Can't jump off, getting newdir\n"); + + if(self->monsterinfo.idle_time < level.time) + {//not already following some other dir, pick one + self->monsterinfo.idle_time = level.time + flrand(1, 2); + self->best_move_yaw = anglemod(180 + self->ideal_yaw); + MG_NewDir(self, dist);//what if this fails to set one? + } + return false; + } + }*/ + +#ifdef _DEVEL + if(MGAI_DEBUG) + if(trace.allsolid || trace.startsolid) + gi.dprintf("Move forward allsolid or startsolid!\n"); +#endif + //FROM HERE ON, ONLY CHANGES DIR, WILL NOT MOVE! + + //otherwise, go around it... this ONLY??? + //lock into this new yaw for a bit + if(self->monsterinfo.idle_time > level.time) + {//heading somewhere for a few secs, turn here +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Turning to newdir, not bumping\n"); +#endif + /* turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_BEST_MOVE)); + distloss = turnamt/self->yaw_speed * 0.3; + dist -= (dist * distloss);*/ + return false; + } + + if((hitworld || irand(0,10)<6)&&!goal_vis) + self->monsterinfo.idle_time = level.time + flrand(1, 2); + else + self->monsterinfo.idle_time = level.time + flrand(0.5, 1.25); + + self->best_move_yaw = anglemod(180 + self->ideal_yaw); + + //if hit a wall and close to ideal yaw (with 5), try a new dir + if(Vec3NotZero(trace.plane.normal)&& + EqualAngle(self->s.angles[YAW], self->ideal_yaw, 5)) + {//a wall? + vec3_t wall_angles, wall_right, self_forward, new_forward, vf; +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Move forward hit wall, checking left/right/back...\n"); +#endif + //If facing a wall, turn faster, more facing the wall, faster the turn + save_yaw_speed = self->yaw_speed; + AngleVectors(self->s.angles, self_forward, NULL, NULL); + WallDot = DotProduct(trace.plane.normal, self_forward); + if(WallDot>0) + WallDot = 0;//-1 to 0 + self->yaw_speed *= 1.25 - WallDot;//facing wall head-on = 2.25 times normal yaw speed + + vectoangles(trace.plane.normal, wall_angles); + AngleVectors(wall_angles, NULL, wall_right, NULL); + + if(goal_vis) + {//can see goal, turn towards IT first + VectorSubtract(self->goalentity->s.origin, self->s.origin, self_forward); + VectorNormalize(self_forward); + } + + //Get closest angle off that wall to move in + if(DotProduct(wall_right,self_forward)>0) + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("turning left\n"); +#endif + VectorCopy(wall_right, new_forward); + } + else + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("turning right\n"); +#endif + VectorScale(wall_right, -1, new_forward); + } + + if(irand(0,10)<3)//30% chance of trying other way first + VectorScale(new_forward, -1, new_forward); + + self->best_move_yaw=vectoyaw(new_forward); + + if(new_best_yaw && self->best_move_yaw == oby) + { + VectorScale(new_forward, -1, new_forward); + + self->best_move_yaw=vectoyaw(new_forward); + } + + //make sure we can move in chosen dir + //set up mins and maxes for these moves + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + + //remember yaw in case all these fail! + save_yaw = self->s.angles[YAW]; + + //Haven't yawed yet, so this is okay + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_BEST_MOVE)); + distloss = turnamt/self->yaw_speed * 0.8;//0.3; + adj_dist = dist - (dist * distloss); + + VectorCopy(new_forward, vf); + //AngleVectors(self->s.angles, vf, NULL, NULL); + + VectorCopy(self->s.origin, source); + VectorMA(source, adj_dist, vf, source); + + gi.trace (self->s.origin, mins, self->maxs, source, self, MASK_SOLID,&trace);//was MASK_SHOT + + if (trace.fraction < 1||trace.allsolid||trace.startsolid) + {//Uh oh, try other way +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("turn other way\n"); +#endif + VectorScale(new_forward, -1, new_forward); + self->best_move_yaw=vectoyaw(new_forward); + //restore yaw + self->s.angles[YAW] = save_yaw; + //try new dir + turnamt = Q_fabs(MG_ChangeWhichYaw(self, YAW_BEST_MOVE)); + distloss = turnamt/self->yaw_speed * 0.8;//0.3; + adj_dist = dist - (dist * distloss); + + VectorCopy(new_forward, vf); + //AngleVectors(self->s.angles, vf, NULL, NULL); + + VectorMA(source, adj_dist, vf, source); + + gi.trace (self->s.origin, mins, self->maxs, source, self, MASK_SOLID,&trace);//was MASK_SHOT + if (trace.fraction < 1||trace.allsolid||trace.startsolid) + {//Uh oh! Go straight away from wall +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("turn all the way around\n"); +#endif + self->best_move_yaw=wall_angles[YAW]; + //restore yaw + self->s.angles[YAW] = save_yaw; + //start turning this move, but don't actually move until next time + MG_ChangeWhichYaw(self, YAW_BEST_MOVE); + } + } + self->yaw_speed = save_yaw_speed; + return false; + } + else//keep turning to ideal + self->monsterinfo.idle_time = 0; + + //Must have bumped into something very strange (other monster?) + //just pick a new random dir +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("Don't know what I hit, choosing newdir for a second\n"); +#endif + + MG_NewDir(self, dist); + return false; +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/mg_guide.c b/Toolkit/Programming/GameCode/game/mg_guide.c new file mode 100644 index 0000000..2e585d9 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/mg_guide.c @@ -0,0 +1,2594 @@ +// **************************************************************************** +// mg_guide +// +// High level monster guide information using BUOYAH! Navigation System(tm) +// +// Heretic II +// Copyright 1998 Raven Software +// +// Mike Gummelt & Josh Weier +// +// FIXME: +// +// 1) Way to send monsters to a buoy out of water/lava if they are drowning +// or burning. +// +// 2) When you get to a buoy, do a trace to the next if it's blocked, you +// need to find another way... +// +// 3) Way to handle lots of monsters gathered around the same buoy... the one +// that is at it can't get out, the others cant get to it, they just crowd it. +// +// **************************************************************************** + +#include "g_local.h" +#include "Angles.h" +#include "Utilities.h" +#include "random.h" +#include "vector.h" +#include "buoy.h" +#include "g_monster.h" +#include "m_stats.h" +#include "fx.h" +#include "mg_guide.h" + +#define BUOY_SEARCH_TIME 10//10 seconds between choosing a buoy and getting there + +#define BUOY_SEARCH_PASSES 6//sfs--number of passes through buoy list when searching + // (only accept buoys closer than 1/BUOY_SEARCH_PASSES * MAX_BUOY_DIST + // for first pass, etc.). if a buoy is found after a pass, + // we know we've got the closest buoy, and further passes can + // be skipped. + +buoy_t *find_next_buoy(edict_t *self, int sb_id, int fb_id); +qboolean Clear_Path(edict_t *self, vec3_t end); +void MG_AddBuoyEffect(edict_t *self, qboolean endbuoy); +qboolean MG_MakeConnection(edict_t *self, buoy_t *first_buoy, qboolean skipjump); +void assassinPrepareTeleportDest(edict_t *self, vec3_t spot); +qboolean MG_CheckClearPathToSpot(edict_t *self, vec3_t spot); + +/* + * + * + * Helper functions + * + * + */ + +qboolean MG_ReachedBuoy (edict_t *self, vec3_t pspot) +{ + float len, radius, z_diff, center; + vec3_t spot; + + if(!pspot) + VectorCopy(self->monsterinfo.nav_goal, spot); + else + VectorCopy(pspot, spot); + + center = (self->absmin[2] + self->absmax[2]) * 0.5; + z_diff = Q_fabs(spot[2] - center); + if(z_diff > self->size[2]) + return false; + + len = vhlen(spot, self->s.origin); + + if(self->maxs[0]>16) + radius = 24 + self->maxs[0]; + else + radius = 40;//24 + 16 + + if (len < (24+radius)) + return true; + + return false; +} + +qboolean Clear_Path(edict_t *self, vec3_t end) +{ + trace_t trace; + vec3_t mins, maxs; + + if(DEACTIVATE_BUOYS) + return false; + + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + + //sfs--i guess it's an ob/com thing, since msdev can probably be relied on to + // optimize it during compile, but mults are faster than divides. + + mins[0] *= 0.5; + mins[1] *= 0.5; + mins[2] *= 0.5; + + maxs[0] *= 0.5; + maxs[1] *= 0.5; + maxs[2] *= 0.5; + + if(self->mins[2] + 18 > mins[2])//need to account for stepheight + {//took off less than 18 + mins[2] = self->mins[2] + 18; + if(mins[2] > maxs[2]) + maxs[2] = mins[2]; + } + + //quicker way to discard points that are very not in a clear path + if (!gi.inPVS(self->s.origin, end)) + return false; + + gi.trace(self->s.origin, mins, maxs, end, self, MASK_SOLID,&trace); + + if ((trace.fraction < 1) && (trace.ent != self->enemy)) + return false; + + return true; +} + +/* +============= +clear_visible_pos + +returns 1 if the spot is visible, but not through transparencies +============= +*/ +qboolean clear_visible_pos (edict_t *self, vec3_t spot2) +{ + vec3_t spot1; + trace_t trace; + + if (!self) + return false; + + VectorCopy (self->s.origin, spot1); + spot1[2] += self->viewheight; + if(self->classID == CID_TBEAST) + { + vec3_t forward; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(spot1, self->maxs[0], forward, spot1); + } + + //quicker way to discard points that are very not visible + if (!gi.inPVS(self->s.origin, spot2)) + return false; + + gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, MASK_SOLID,&trace); + + if (trace.fraction == 1.0) + return true; + return false; +} + +int MG_SetFirstBuoy(edict_t *self) +{ + buoy_t *found_buoy = NULL; + buoy_t *bestbuoy = NULL; + qboolean vis; + vec3_t vec; + float bestdist, len; + int i = 0; + int tracecount=0; + float buoy_passes = BUOY_SEARCH_PASSES; + + float search_pass_interval = MAX_BUOY_DIST / buoy_passes; + float j; + + bestdist = 9999999; + + if(!self->client) + { + if(!(self->monsterinfo.aiflags & AI_USING_BUOYS)) + { + self->ai_mood = AI_MOOD_PURSUE; + return NULL_BUOY; + } + } + + if(DEACTIVATE_BUOYS) + return NULL_BUOY; + //first, precalc all distances + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + VectorSubtract(self->s.origin, found_buoy->origin, vec); + found_buoy->temp_dist = VectorLength(vec); + } + + //now, do all the passes, going from closest to farthest + for(j = 0; (j < buoy_passes)&&(!bestbuoy); j++) + { + for(i = 0; i <= level.active_buoys; i++) + { + vis = false; + + found_buoy = &level.buoy_list[i]; + len = found_buoy->temp_dist; + + //only consider buoys in the current interval--closer ones have already been + //checked, and we'll save farther ones for later + if (len < bestdist && len > search_pass_interval*j && len < search_pass_interval*(j+1.0)) + { + tracecount++; + vis = Clear_Path(self, found_buoy->origin); + } + + if (vis) + { + bestdist = len; + bestbuoy = found_buoy; + } + } + } + + if (!bestbuoy) + return NULL_BUOY; + + if(!self->client) + { + self->lastbuoy = NULL_BUOY; + self->buoy_index = bestbuoy->id; + VectorCopy(bestbuoy->origin, self->monsterinfo.nav_goal); + } + + return bestbuoy->id; +} + +qboolean MG_GoToRandomBuoy(edict_t *self) +{ + buoy_t *found_buoy; + qboolean searching; + qboolean dead_end = false; + int i, nextbranch, j; + int branches_checked; + qboolean branch_checked[MAX_BUOY_BRANCHES]; + int last_buoy = NULL_BUOY; + + if(MG_SetFirstBuoy(self) == NULL_BUOY) + return false; + + found_buoy = &level.buoy_list[self->buoy_index]; + for(i = 0; i < self->mintel; i++) + { + searching = true; + for(j = 0; jnextbuoy[nextbranch] > NULL_BUOY && + found_buoy->nextbuoy[nextbranch] != self->buoy_index && + (found_buoy->nextbuoy[nextbranch] != self->lastbuoy || branches_checked >= MAX_BUOY_BRANCHES)&& + (found_buoy->nextbuoy[nextbranch] != last_buoy || branches_checked >= MAX_BUOY_BRANCHES)) + {//nextbuoy off this one is not null, not my start buoy, not my last buoy, and not last buoy found + last_buoy = found_buoy->id; + found_buoy = &level.buoy_list[found_buoy->nextbuoy[nextbranch]]; + searching = false; + } + else if (branches_checked >= MAX_BUOY_BRANCHES) + {//a dead end, checked all 3 branches + if(i < 3)//can't run away far enough + return false; + searching = false; + dead_end = true; + } + } + if(dead_end) + break; + } + + if(self->ai_mood == AI_MOOD_FLEE) + self->ai_mood_flags|=AI_MOOD_FLAG_IGNORE_ENEMY; + else + self->ai_mood = AI_MOOD_NAVIGATE;//wander? + + self->ai_mood_flags &= ~AI_MOOD_FLAG_DUMB_FLEE; + self->ai_mood_flags|=AI_MOOD_FLAG_FORCED_BUOY; + self->forced_buoy = found_buoy->id; + + QPostMessage(self, MSG_RUN,PRI_DIRECTIVE, NULL); + + MG_RemoveBuoyEffects(self); + MG_MakeConnection(self, NULL, false); + + return true; +} + +/* +MG_AssignMonsterNextBuoy(edict_t *self, buoy_t *startbuoy, buoy_t *endbuoy) + +Actually assigns the bstartbuoy as the monster's buoy +*/ + +void MG_AssignMonsterNextBuoy(edict_t *self, buoy_t *startbuoy, buoy_t *endbuoy) +{ + edict_t *showme; + + VectorCopy(startbuoy->origin, self->monsterinfo.nav_goal); + if(self->buoy_index!=NULL_BUOY) + self->lastbuoy = self->buoy_index; + else + self->lastbuoy = NULL_BUOY; + self->buoy_index = startbuoy->id; + self->last_buoy_time = level.time; + if(BUOY_DEBUG>1) + { + showme = G_Find(NULL, FOFS(targetname), startbuoy->targetname); + if(showme) + { + self->nextbuoy[0] = showme; + MG_AddBuoyEffect(self, false); + } + + if(endbuoy) + { + showme = G_Find(NULL, FOFS(targetname), endbuoy->targetname); + if(showme) + { + self->nextbuoy[1] = showme; + MG_AddBuoyEffect(self, true); + } + } + } +} + +/* +======================== + +MG_ValidBestBuoyForEnt + + Just see if this entity and this buoy are ok to be associated (clear path, etc.) + +======================== +*/ +qboolean MG_ValidBestBuoyForEnt (edict_t *ent, buoy_t *test_buoy) +{ + vec3_t v; + float dist; + + VectorSubtract(ent->s.origin, test_buoy->origin, v); + dist = VectorLengthSquared(v); + if(dist > 250000)//500 squared + return false;//to damn far! + + return MG_CheckClearPathToSpot(ent, test_buoy->origin); +// return Clear_Path(ent, test_buoy->origin); +} + +/* +======================== + +MG_ResolveBuoyConnection + + Actually makes the connection between two buoys + +======================== +*/ +qboolean MG_ResolveBuoyConnection(edict_t *self, buoy_t *bestbuoy, buoy_t *e_bestbuoy, vec3_t goalpos, qboolean dont_use_last, qboolean skipjump) +{//When called directly, this does not and should not set player_buoy + buoy_t *found_buoy = NULL; + buoy_t *dest = NULL; + vec3_t vec; + float len, e_len; + edict_t *showme = NULL; + + //FIXME: Allow assassins to take any buoy even if can;t make a connection, since they can teleport + //- Basically, pick the player's buoy and randomly pick one off of it or even that one...? + + if(self->lastbuoy == e_bestbuoy->id) + { + if(!MG_ReachedBuoy(self, e_bestbuoy->origin) && !clear_visible_pos(self, goalpos)) + { + self->lastbuoy = NULL_BUOY; + dont_use_last = false; + } + } + + if (bestbuoy->modflags&BUOY_JUMP && bestbuoy->jump_target_id == e_bestbuoy->id) + { + if(skipjump) + dest = e_bestbuoy; + else + dest = bestbuoy; + + self->monsterinfo.searchType = SEARCH_BUOY; + + if(self->ai_mood != AI_MOOD_FLEE) + self->ai_mood = AI_MOOD_NAVIGATE; + + VectorCopy(dest->origin, self->monsterinfo.nav_goal); + +#ifdef _DEVEL + if (BUOY_DEBUG) + gi.dprintf("Found 1-step JUMP connection at %s\n", dest->targetname); +#endif + if(self->buoy_index!=NULL_BUOY) + self->lastbuoy = self->buoy_index; + else + self->lastbuoy = NULL_BUOY; + + self->buoy_index =dest->id; + + self->last_buoy_time = level.time; + return true; + } + + //hey what if we're touching our e_bestbuoy buoy? - also, if this is a jump buoy and e_bestboy is the target of it, foce use of bestbuoy + if (bestbuoy == e_bestbuoy) + { + if(dont_use_last) + if(self->lastbuoy == bestbuoy->id)//found same buoy just touched as next buoy + return false; + + self->monsterinfo.searchType = SEARCH_BUOY; + + if(self->ai_mood != AI_MOOD_FLEE) + self->ai_mood = AI_MOOD_NAVIGATE; + + VectorCopy(bestbuoy->origin, self->monsterinfo.nav_goal); + +#ifdef _DEVEL + if (BUOY_DEBUG) + gi.dprintf("Found 1-step connection at %s\n", bestbuoy->targetname); +#endif + if(self->buoy_index!=NULL_BUOY) + self->lastbuoy = self->buoy_index; + else + self->lastbuoy = NULL_BUOY; + self->buoy_index = bestbuoy->id; + self->last_buoy_time = level.time; + return true; + } + + if (bestbuoy && e_bestbuoy) + { + VectorSubtract(goalpos, self->s.origin, vec); + e_len = VectorLength(vec); + + VectorSubtract(e_bestbuoy->origin, goalpos, vec); + len = VectorLength(vec); + + dest = find_next_buoy(self, bestbuoy->id, e_bestbuoy->id); + + if (dest != NULL) + { +#ifdef _DEVEL + if (BUOY_DEBUG) + { + gi.dprintf("Found connection from %s to %s\n", bestbuoy->targetname, e_bestbuoy->targetname); + } +#endif + if(dont_use_last) + { + if(self->lastbuoy == dest->id)//found same buoy just touched as next buoy + return false; + } + + self->monsterinfo.searchType = SEARCH_BUOY; + + if(self->ai_mood != AI_MOOD_FLEE) + self->ai_mood = AI_MOOD_NAVIGATE; + + if((!(bestbuoy->modflags&BUOY_JUMP)||skipjump) && MG_ReachedBuoy(self, bestbuoy->origin)) + { + MG_AssignMonsterNextBuoy(self, dest, e_bestbuoy); + } + else + { + MG_AssignMonsterNextBuoy(self, bestbuoy, e_bestbuoy); + } + return true; + } +#ifdef _DEVEL + else if (BUOY_DEBUG) + { + gi.dprintf("Failed to find a path\n"); + } +#endif + } + + //EXPERIMENTAL + //ok, now you can backtrack since couldn't get there + //self->lastbuoy = NULL_BUOY; + +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + { + if (!bestbuoy) + gi.dprintf("%s COULDN'T FIND BUOYS FOR SELF!!!\n", self->classname); + else if (!e_bestbuoy) + gi.dprintf("%s COULDN'T FIND BUOYS FOR %s!!!\n", self->classname, self->enemy->classname); + } +#endif + return false; +} + +/* +======================== + +MG_MakeStartForcedConnection + + Attempts to make a connection between a buoy and a monster's enemy + This function itself just finds the two buoys to attempt to make the connection between, + MG_ResolveBuoyConnection actually makes the connection between two buoys + +======================== +*/ +qboolean MG_MakeStartForcedConnection(edict_t *self, int sforced_buoy, qboolean dont_use_last, qboolean skipjump) +{ + buoy_t *found_buoy = NULL; + buoy_t *e_bestbuoy = NULL; + buoy_t *bestbuoy = NULL; + buoy_t *dest = NULL; + qboolean e_vis; + vec3_t vec, goalpos, e_buoyvec; + float bestdist, e_bestdist, e_len, e_buoydist; + int i; + int tracecount = 0; + float tracedist_total=0; + float buoy_passes = BUOY_SEARCH_PASSES; + float e_radius; + + float search_pass_interval = MAX_BUOY_DIST / buoy_passes; + float k; + + if(DEACTIVATE_BUOYS) + return false; + + bestbuoy = &level.buoy_list[sforced_buoy]; + bestdist = 0; + e_bestdist = 9999999; + + self->last_buoyed_enemy = self->enemy;//Remember the last enemy I looked for + + VectorCopy(self->enemy->s.origin, goalpos); + goalpos[2] += self->viewheight; + + if(self->enemy->maxs[0]>16) + e_radius = 24 + self->enemy->maxs[0]; + else + e_radius = 40;//24 + 16 + + //first, precalc all distances + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + VectorSubtract(goalpos, found_buoy->origin, vec); + found_buoy->temp_e_dist = VectorLength(vec); + if (found_buoy->temp_e_dist < (24+e_radius)) + { + e_bestbuoy = found_buoy; + e_bestdist = found_buoy->temp_dist; + break; + } + } + + //now, do all the passes, going from closest to farthest + for(k = 0; (k < buoy_passes)&&(!bestbuoy || !e_bestbuoy); k++) + { + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + + e_vis = false; + e_len = found_buoy->temp_e_dist; + + //only consider buoys in the current interval--closer ones have already been + //checked, and we'll save farther ones for later + if (e_len < e_bestdist && e_len > search_pass_interval*k && e_len < search_pass_interval*(k+1.0)) + { + tracecount++; + tracedist_total+=e_len; + e_vis = Clear_Path(self->enemy, found_buoy->origin); + } + + if (e_vis) + { + e_bestdist = e_len; + e_bestbuoy = found_buoy; + } + } + } + + tracecount=0; + tracedist_total=0; + + if (!e_bestbuoy && irand(0,10) < 5) + {//ok, Clear_Path too restrictive, try just clear_visible + + //distances precalced already, so skip that step + + //now, do all the passes, going from closest to farthest + for(k = 0; (k < buoy_passes)&&(!e_bestbuoy); k++) + { + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + e_vis = false; + + e_len = found_buoy->temp_e_dist; + + //only consider buoys in the current interval--closer ones have already been + //checked, and we'll save farther ones for later + if (e_len < e_bestdist && e_len > search_pass_interval*k && e_len < search_pass_interval*(k+1.0)) + { + tracecount++; + tracedist_total+=e_len; + e_vis = clear_visible_pos(self->enemy, found_buoy->origin); + } + + if (e_vis) + { + e_bestdist = e_len; + e_bestbuoy = found_buoy; + } + } + } + } + + if (e_bestdist > MAX_BUOY_DIST) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s's %s CLOSEST BUOY TOO FAR AWAY (%4.2f)\n", self->enemy->classname, vtos(self->s.origin), e_bestdist); +#endif + return false; + } + + if(!(bestbuoy->modflags&BUOY_JUMP)||skipjump) + {//don't skip jump buoys, they're crucial + if(e_bestbuoy) + { + VectorSubtract(e_bestbuoy->origin, self->s.origin, e_buoyvec); + e_buoydist = VectorLength(e_buoyvec); + if (bestbuoy != e_bestbuoy && e_buoydist > bestdist) + {//enemy best buoy is farther away from me and not my buoy + if(Clear_Path(self, e_bestbuoy->origin)) + {//can go straight at enemy best buoy even though farther away +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s going after %s's buoy even though farther\n", self->classname, self->enemy->classname); +#endif + bestbuoy = e_bestbuoy; + bestdist = e_bestdist; + } + } + } + } + + + if(e_bestbuoy) + {//if going after a player, set his buoy for other monsters this frame + if(self->enemy->client) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s setting player_buoy %d to %s\n", self->classname, self->enemy->s.number, e_bestbuoy->targetname); +#endif + level.player_buoy[self->enemy->s.number - 1] = e_bestbuoy->id; + } + } + + return MG_ResolveBuoyConnection(self, bestbuoy, e_bestbuoy, goalpos, dont_use_last, skipjump); +} + +/* +======================== + +MG_MakeForcedConnection + + Attempts to make a connection between a monster and its forced_buoy + This function itself just finds the two buoys to attempt to make the connection between, + MG_ResolveBuoyConnection actually makes the connection between two buoys + +======================== +*/ +qboolean MG_MakeForcedConnection(edict_t *self, int forced_buoy, qboolean dont_use_last, qboolean skipjump) +{ + buoy_t *found_buoy = NULL; + buoy_t *e_bestbuoy = NULL; + buoy_t *bestbuoy = NULL; + buoy_t *dest = NULL; + qboolean vis; + vec3_t vec, goalpos, e_buoyvec; + float bestdist, e_bestdist, len, e_buoydist; + int i; + int tracecount = 0; + float tracedist_total=0; + float buoy_passes = BUOY_SEARCH_PASSES; + float radius; + + float search_pass_interval = MAX_BUOY_DIST / buoy_passes; + float k; + + bestdist = 9999999; + e_bestdist = 9999999; + + if(DEACTIVATE_BUOYS) + return false; + + e_bestbuoy = &level.buoy_list[forced_buoy]; + e_bestdist = 0; + VectorCopy(e_bestbuoy->origin, goalpos); + +#ifdef _DEVEL + if(!e_bestbuoy) + gi.dprintf("ERROR: forced_buoy not a valid buoy!!!\n"); +#endif + if(self->maxs[0]>16) + radius = 24 + self->maxs[0]; + else + radius = 40;//24 + 16 + + + //first, precalc all distances + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + VectorSubtract(self->s.origin, found_buoy->origin, vec); + found_buoy->temp_dist = VectorLength(vec); + if (found_buoy->temp_dist < (24+radius)) + { + bestbuoy = found_buoy; + bestdist = found_buoy->temp_dist; + break; + } + } + + //now, do all the passes, going from closest to farthest + for(k = 0; (k < buoy_passes)&&(!bestbuoy || !e_bestbuoy); k++) + { + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + len = found_buoy->temp_dist; + + vis = false; + + //only consider buoys in the current interval--closer ones have already been + //checked, and we'll save farther ones for later + if (len < bestdist && len > search_pass_interval*k && len < search_pass_interval*(k+1.0)) + { + tracecount++; + tracedist_total+=len; + vis = Clear_Path(self, found_buoy->origin); + } + + if (vis) + { + bestdist = len; + bestbuoy = found_buoy; + } + } + } + + tracecount=0; + tracedist_total=0; + + if (bestdist > MAX_BUOY_DIST) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s's at %s CLOSEST BUOY TOO FAR AWAY (%4.2f)\n", self->classname, vtos(self->s.origin), bestdist); +#endif + self->pathfind_nextthink = level.time + 3;//wait 3 seconds before trying to use buoys again + return false; + } + + if(!(bestbuoy->modflags&BUOY_JUMP)||skipjump) + {//don't skip jump buoys, they're crucial + VectorSubtract(e_bestbuoy->origin, self->s.origin, e_buoyvec); + e_buoydist = VectorLength(e_buoyvec); + if (bestbuoy != e_bestbuoy && e_buoydist > bestdist) + {//enemy best buoy is farther away from me and not my buoy + if(Clear_Path(self, e_bestbuoy->origin)) + {//can go straight at enemy best buoy even though farther away +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s going after forced_buoy %s even though farther\n", self->classname, e_bestbuoy->targetname); +#endif + bestbuoy = e_bestbuoy; + bestdist = e_bestdist; + } + } + } + + return MG_ResolveBuoyConnection(self, bestbuoy, e_bestbuoy, goalpos, dont_use_last, skipjump); +} + +/* +======================== + +MG_MakeNormalConnection + + Attempts to make a buoy connection between a monster and its enemy + This function itself just finds the two buoys to attempt to make the connection between, + MG_ResolveBuoyConnection actually makes the connection between two buoys + +======================== +*/ +qboolean MG_MakeNormalConnection(edict_t *self, qboolean dont_use_last, qboolean skipjump) +{ + buoy_t *found_buoy = NULL; + buoy_t *e_bestbuoy = NULL; + buoy_t *bestbuoy = NULL; + buoy_t *dest = NULL; + qboolean e_vis, vis; + vec3_t vec, goalpos, e_buoyvec; + float bestdist, e_bestdist, len, e_len, e_buoydist; + int i; + int tracecount = 0; + float tracedist_total=0; + float buoy_passes = BUOY_SEARCH_PASSES; + float radius, e_radius; + + float search_pass_interval = MAX_BUOY_DIST / buoy_passes; + float k; + + bestdist = 9999999; + e_bestdist = 9999999; + + if(DEACTIVATE_BUOYS) + return false; + + VectorCopy(self->enemy->s.origin, goalpos); + goalpos[2] += self->viewheight; + + if(self->maxs[0]>16) + radius = 24 + self->maxs[0]; + else + radius = 40;//24 + 16 + + if(self->enemy->maxs[0]>16) + e_radius = 24 + self->enemy->maxs[0]; + else + e_radius = 40;//24 + 16 + + //first, precalc all distances + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + + if(!bestbuoy) + { + VectorSubtract(self->s.origin, found_buoy->origin, vec); + found_buoy->temp_dist = VectorLength(vec); + if (found_buoy->temp_dist < (24+radius)) + { + bestbuoy = found_buoy; + bestdist = found_buoy->temp_dist; + } + } + + if(!e_bestbuoy) + { + VectorSubtract(goalpos, found_buoy->origin, vec); + found_buoy->temp_e_dist = VectorLength(vec); + if (found_buoy->temp_e_dist < (24+e_radius)) + { + e_bestbuoy = found_buoy; + e_bestdist = found_buoy->temp_dist; + } + } + if(e_bestbuoy && bestbuoy) + break; + } + + //now, do all the passes, going from closest to farthest + for(k = 0; (k < buoy_passes)&&(!bestbuoy || !e_bestbuoy); k++) + { + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + len = found_buoy->temp_dist; + + vis = false; + e_vis = false; + + //only consider buoys in the current interval--closer ones have already been + //checked, and we'll save farther ones for later + if (len < bestdist && len > search_pass_interval*k && len < search_pass_interval*(k+1.0)) + { + tracecount++; + tracedist_total+=len; + vis = Clear_Path(self, found_buoy->origin); + } + + if (vis) + { + bestdist = len; + bestbuoy = found_buoy; + } + + e_len = found_buoy->temp_e_dist; + + //only consider buoys in the current interval--closer ones have already been + //checked, and we'll save farther ones for later + if (e_len < e_bestdist && e_len > search_pass_interval*k && e_len < search_pass_interval*(k+1.0)) + { + tracecount++; + tracedist_total+=e_len; + e_vis = Clear_Path(self->enemy, found_buoy->origin); + } + + if (e_vis) + { + e_bestdist = e_len; + e_bestbuoy = found_buoy; + } + } + } + + tracecount=0; + tracedist_total=0; + + if (bestdist > MAX_BUOY_DIST) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s's %s CLOSEST BUOY TOO FAR AWAY (%4.2f)\n", self->classname, vtos(self->s.origin), bestdist); +#endif + return false; + } + + if (!bestbuoy && !e_bestbuoy) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s' %s COULDN'T FIND BUOYS FOR SELF OR %s!!!\n", self->classname, vtos(self->s.origin), self->enemy->classname); +#endif + return false; + } + + if (!e_bestbuoy && irand(0,10) < 5) + {//ok, Clear_Path too restrictive, try just clear_visible + + //distances precalced already, so skip that step + + //now, do all the passes, going from closest to farthest + for(k = 0; (k < buoy_passes)&&(!e_bestbuoy); k++) + { + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + e_vis = false; + + e_len = found_buoy->temp_e_dist; + + //only consider buoys in the current interval--closer ones have already been + //checked, and we'll save farther ones for later + if (e_len < e_bestdist && e_len > search_pass_interval*k && e_len < search_pass_interval*(k+1.0)) + { + tracecount++; + tracedist_total+=e_len; + e_vis = clear_visible_pos(self->enemy, found_buoy->origin); + } + + if (e_vis) + { + e_bestdist = e_len; + e_bestbuoy = found_buoy; + } + } + } + } + + if (e_bestdist > MAX_BUOY_DIST) + { +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s's %s CLOSEST BUOY TOO FAR AWAY (%4.2f)\n", self->enemy->classname, vtos(self->s.origin), e_bestdist); +#endif + return false; + } + + if(!(bestbuoy->modflags&BUOY_JUMP)||skipjump) + {//don't skip jump buoys, they're crucial + if(e_bestbuoy) + { + VectorSubtract(e_bestbuoy->origin, self->s.origin, e_buoyvec); + e_buoydist = VectorLength(e_buoyvec); + if (bestbuoy != e_bestbuoy && e_buoydist > bestdist) + {//enemy best buoy is farther away from me and not my buoy + if(Clear_Path(self, e_bestbuoy->origin)) + {//can go straight at enemy best buoy even though farther away +#ifdef _DEVEL + if(BUOY_DEBUG_LITE||BUOY_DEBUG) + gi.dprintf("%s going after %s's buoy even though farther\n", self->classname, self->enemy->classname); +#endif + bestbuoy = e_bestbuoy; + bestdist = e_bestdist; + } + } + } + } + + if(e_bestbuoy) + {//if going after a player, set his buoy for other monsters this frame + if(self->enemy->client) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s setting player_buoy %d to %s\n", self->classname, self->enemy->s.number, e_bestbuoy->targetname); +#endif + level.player_buoy[self->enemy->s.number - 1] = e_bestbuoy->id; + } + } + + return MG_ResolveBuoyConnection(self, bestbuoy, e_bestbuoy, goalpos, dont_use_last, skipjump); +} + + +/* +======================== + +MG_MakeConnection + + Determines if monster should be pursuing a forced_buoy, if not, calls normal + enemy-tracking buoy connection finding function + +======================== +*/ +int MG_MakeConnection_Go(edict_t *self, buoy_t *first_buoy, qboolean skipjump) +{ + qboolean found_path = false; + qboolean dont_use_last; + buoy_t *forced_buoy = NULL; + buoy_t *found_buoy = NULL; + int k; + qboolean last_buoy_clear = false; + + if(self->spawnflags & MSF_FIXED) + return false; + + MG_RemoveBuoyEffects(self); + + if(self->enemy && !(self->ai_mood_flags&AI_MOOD_FLAG_IGNORE_ENEMY) && self->ai_mood != AI_MOOD_FLEE) + { + self->ai_mood_flags &= ~AIMF_CANT_FIND_ENEMY; + + if(self->enemy!=self->last_buoyed_enemy)//Current enemywasn't the last enemy I looked for... + { + dont_use_last = false; + self->lastbuoy = NULL_BUOY;//so forget last buoy I used + } + else if(self->monsterinfo.searchType == SEARCH_BUOY) + dont_use_last = true; + else + dont_use_last = false; + + self->last_buoyed_enemy = self->enemy;//Remember the last enemy I looked for + + if(self->enemy->client) + {//see if this player already has a bestbuoy found by a previous monster this frame + if(level.player_buoy[self->enemy->s.number - 1]>NULL_BUOY)//entity numbers 0 - 8 should be players + {//FIXME: if not, try his last player_buoy first! + if(BUOY_DEBUG) + { + for(k = 0; kenemy->s.number - 1]) + { + found_buoy = &level.buoy_list[k]; + break; + } + } + if(found_buoy) + { +#ifdef _DEVEL + gi.dprintf("%s using player_buoy %d (%s) set previously this frame\n", self->classname, self->enemy->s.number, found_buoy->targetname); +#endif + } + } + self->forced_buoy = level.player_buoy[self->enemy->s.number - 1];//just stores id in player_buoy + if(first_buoy) + { + forced_buoy = &level.buoy_list[self->forced_buoy]; +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s trying connection to player_buoy %d (%s) from first_buoy %s\n", self->classname, self->enemy->s.number, found_buoy->targetname, first_buoy->targetname); +#endif + found_path = MG_ResolveBuoyConnection(self, first_buoy, forced_buoy, forced_buoy->origin, dont_use_last, skipjump); + } + else + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s trying normal connection to player_buoy %d (%s)\n", self->classname, self->enemy->s.number, found_buoy->targetname); +#endif + found_path = MG_MakeForcedConnection(self, self->forced_buoy, dont_use_last, skipjump); + } + } + } + } + else + { + dont_use_last = false; + self->last_buoyed_enemy = NULL; + + if(self->ai_mood_flags&AI_MOOD_FLAG_FORCED_BUOY && self->forced_buoy != -1) + { + if(first_buoy) + { + forced_buoy = &level.buoy_list[self->forced_buoy]; +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s trying non-enemy forced_buoy connection to %s from first_buoy %s\n", self->classname, forced_buoy->targetname, first_buoy->targetname); +#endif + return MG_ResolveBuoyConnection(self, first_buoy, forced_buoy, forced_buoy->origin, dont_use_last, skipjump); + } + else + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s trying non-enemy forced_buoy connection to %s\n", self->classname, level.buoy_list[self->forced_buoy].targetname); +#endif + return MG_MakeForcedConnection(self, self->forced_buoy, dont_use_last, skipjump); + } + } + else + { + self->lastbuoy = NULL_BUOY;//so forget last buoy I used + return false; + } + } + + if(!found_path) + { + if(self->ai_mood == AI_MOOD_FLEE) + return false; + + if(self->enemy->client) + { + if(level.player_last_buoy[self->enemy->s.number - 1] > NULL_BUOY) + {//see if the player_last_buoy is a valid buoy for the enemy, if so, go for it + if(MG_ValidBestBuoyForEnt(self->enemy, &level.buoy_list[level.player_last_buoy[self->enemy->s.number - 1]])) + { + last_buoy_clear = true; + goto last_resort; + } + } + } + +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s searching for player(%d)'s bestbuoy\n", self->classname, self->enemy->s.number); +#endif + if(first_buoy) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s making connection from forced start %s to %s\n", self->classname, first_buoy->targetname, self->enemy->classname); +#endif + found_path = MG_MakeStartForcedConnection(self, first_buoy->id, dont_use_last, skipjump); + } + else + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s making normal connection to %s\n", self->classname, self->enemy->classname); +#endif + found_path = MG_MakeNormalConnection(self, dont_use_last, skipjump); + } + } + + if(found_path) + return true; + +//OK you! Can't find ANY buoy connections, let's go with player_lastbuoy even if it can't connect to you! + self->ai_mood_flags |= AIMF_CANT_FIND_ENEMY; + +last_resort: + if(self->enemy->client) + { + if(level.player_last_buoy[self->enemy->s.number - 1] > NULL_BUOY) + {//try the player_last_buoy, don't care if it can connect to player! + //FIXME: require that the player be withing 250 of this buoy at least? + if(BUOY_DEBUG) + { + for(k = 0; kenemy->s.number - 1]) + { + found_buoy = &level.buoy_list[k]; + break; + } + } + } + //we dont actually set self->forced_buoy since we want to find a better buoy next time we look + forced_buoy = &level.buoy_list[level.player_last_buoy[self->enemy->s.number - 1]]; + if(!last_buoy_clear) + { + if(self->ai_mood_flags & AIMF_SEARCHING || MG_ReachedBuoy(self, forced_buoy->origin)) + { + return 3; + } + } + + if(first_buoy) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + { + if(last_buoy_clear) + gi.dprintf("%s using clear-path player_last_buoy %d (%s) from first_buoy %s\n", self->classname, self->enemy->s.number, found_buoy->targetname, first_buoy->targetname); + else + gi.dprintf("%s using player_last_buoy %d (%s) from first_buoy %s even though it doesn't connect to player!\n", self->classname, self->enemy->s.number, found_buoy->targetname, first_buoy->targetname); + } +#endif + if(MG_ResolveBuoyConnection(self, first_buoy, forced_buoy, forced_buoy->origin, dont_use_last, skipjump)) + { + return 2; + } + } + else + { +#ifdef _DEVEL + if(BUOY_DEBUG) + { + if(last_buoy_clear) + gi.dprintf("%s using clear-path player_last_buoy %d (%s)\n", self->classname, self->enemy->s.number, found_buoy->targetname); + else + gi.dprintf("%s using player_last_buoy %d (%s) even though it doesn't connect to player!\n", self->classname, self->enemy->s.number, found_buoy->targetname); + } +#endif + if(MG_MakeForcedConnection(self, forced_buoy->id, dont_use_last, skipjump)) + { + return 2; + } + } + } + } + //damn, lost him! Currrzzze you Corvuzzz!!! +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("FAILURE: %s Could not find %s in any way shape or form!!!\n", self->classname, self->enemy->classname); +#endif + return false; +} + +qboolean MG_MakeConnection(edict_t *self, buoy_t *first_buoy, qboolean skipjump) +{//just for debug info + qboolean result; + +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("========================================================\n %s Start MakeConnection \n========================================================\n", self->classname); +#endif + result = MG_MakeConnection_Go (self, first_buoy, skipjump); + + if(!(self->ai_mood_flags&AIMF_CANT_FIND_ENEMY)) + { + self->monsterinfo.last_successful_enemy_tracking_time = level.time; + self->ai_mood_flags &= ~AIMF_SEARCHING; + } + + if(result != true) + {//If can't find him(not including player_last_buoys) for 5 - 10 seconds, go into wander mode... +#ifdef _DEVEL + if (BUOY_DEBUG && !result) + { + gi.dprintf("MG_MakeConnection: failed\n"); + } +#endif + if(result == 3 && !(self->ai_mood_flags&AIMF_SEARCHING)) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s got to %s's last_buoy, searching normally...\n", self->classname, self->enemy->classname); +#endif + self->monsterinfo.last_successful_enemy_tracking_time = level.time; + self->monsterinfo.searchType = SEARCH_COMMON; + self->ai_mood = AI_MOOD_PURSUE; + self->ai_mood_flags |= AIMF_SEARCHING; + } + else if(self->enemy && + self->ai_mood != AI_MOOD_FLEE && + !(self->ai_mood_flags & AI_MOOD_FLAG_IGNORE_ENEMY) && + self->monsterinfo.last_successful_enemy_tracking_time + MONSTER_SEARCH_TIME < level.time) + {//give up, can't see him or find path to him for ten seconds now... + if(self->classID == CID_ASSASSIN && self->monsterinfo.last_successful_enemy_tracking_time + MONSTER_SEARCH_TIME + 20 > level.time) + {//assassins get an extra 20 seconds to look for the enemy and try to teleport to him + } + else + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s giving up finding %s, wandering around\n", self->classname, self->enemy->classname); +#endif + if(self->enemy->client) + self->oldenemy = self->enemy; + self->enemy = NULL; + + if(!result && self->ai_mood == AI_MOOD_WANDER) + self->ai_mood = AI_MOOD_STAND; + else + self->ai_mood = AI_MOOD_WANDER; + } + } + else if(!result && self->ai_mood != AI_MOOD_FLEE && self->enemy) + { + self->monsterinfo.searchType = SEARCH_COMMON; + self->ai_mood = AI_MOOD_PURSUE; + } + + if(!result && self->ai_mood == AI_MOOD_WANDER) + { + self->monsterinfo.pausetime = 0; + self->ai_mood = AI_MOOD_STAND; + } + + if(result == 3) + result = false; + } + +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("========================================================\n %s End MakeConnection \n========================================================\n", self->classname); +#endif + return result; +} + +qboolean MG_CheckClearPathToEnemy(edict_t *self) +{ + trace_t trace; + vec3_t mins, checkspot, enemy_dir, center; + float dist, i; + qboolean close_ok = false; + + if(!self->enemy) + return false; + + VectorCopy(self->mins, mins); + mins[2] += 18; + gi.trace(self->s.origin, mins, self->maxs, self->enemy->s.origin, self, MASK_SOLID,&trace); + + if(trace.ent) + { + if(trace.ent == self->enemy) + return true;//bumped into our enemy! + } + + if(trace.allsolid||trace.startsolid)//trace is through a wall next to me? + return false; + + if(trace.fraction<1.0) + {//couldn't get to enemy + VectorSubtract(self->enemy->s.origin, trace.endpos, enemy_dir); + dist = VectorLength(enemy_dir); + if(dist>48 || !visible(self, self->enemy)) + return false;//couldn't even get close to a visible enemy + } + + if(!self->groundentity || (self->flags & FL_INWATER && self->enemy->flags & FL_INWATER)) + return true; + + if(self->flags & FL_FLY || self->movetype == PHYSICSTYPE_FLY || !self->gravity || self->classID == CID_GORGON) + return true; + + if((self->flags & FL_INWATER || (self->flags & FL_SWIM) || (self->flags & FL_AMPHIBIAN))&& + self->enemy->flags & FL_INWATER) + return true; + + //Now lets see if there is a solid ground or steps path to the enemy + + //FIXME: what about jumping monsters? Call a jump message? + + VectorAverage(self->absmin, self->absmax, center); + + VectorSubtract(self->enemy->s.origin, center, enemy_dir); + dist = VectorNormalize(enemy_dir); + + VectorCopy(self->s.origin, mins); + mins[2] += self->mins[2]; + + for(i = 0; i < dist; i += 8) + {//check to see if ground is there all the way to enemy + VectorMA(mins, i, enemy_dir, checkspot); + checkspot[2] -= 3; + if(!(gi.pointcontents(checkspot) & CONTENTS_SOLID)) + {//not solid underneath + checkspot[2] -= 16; + if(!(gi.pointcontents(checkspot) & CONTENTS_SOLID)) + { + return false;//not a step down + } + } + } + return true; +} + +qboolean MG_CheckClearPathToSpot(edict_t *self, vec3_t spot) +{ + trace_t trace; + vec3_t mins, checkspot, enemy_dir; + float dist, i; + qboolean close_ok = false; + + VectorCopy(self->mins, mins); + mins[2] += 18; + gi.trace(self->s.origin, mins, self->maxs, spot, self, MASK_SOLID,&trace); + + if(trace.ent) + { + if(trace.ent == self->enemy) + return true;//bumped into our enemy! + } + + if(trace.allsolid||trace.startsolid)//trace is through a wall next to me? + return false; + + if(trace.fraction<1.0) + {//couldn't get to enemy + VectorSubtract(spot, trace.endpos, enemy_dir); + dist = VectorLength(enemy_dir); + if(dist>48 || !visible_pos(self, spot)) + return false;//couldn't even get close to a visible enemy + } + + if(!self->groundentity || (self->flags & FL_INWATER && gi.pointcontents(spot)&MASK_WATER)) + return true; + + if(self->flags & FL_FLY || self->movetype == PHYSICSTYPE_FLY || !self->gravity || self->classID == CID_GORGON) + return true; + + //Now lets see if there is a solid ground or steps path to the enemy + + //FIXME: what about jumping monsters? Call a jump message? + + VectorSubtract(spot, self->s.origin, enemy_dir); + dist = VectorNormalize(enemy_dir); + + VectorCopy(self->s.origin, mins); + mins[2] += self->mins[2]; + + for(i = 0; i < dist; i += 8) + {//check to see if ground is there all the way to enemy + VectorMA(mins, i, enemy_dir, checkspot); + checkspot[2] -= 3; + if(!(gi.pointcontents(checkspot) & CONTENTS_SOLID)) + {//not solid underneath + checkspot[2] -= 16; + if(!(gi.pointcontents(checkspot) & CONTENTS_SOLID)) + return false;//not a step down + } + } + return true; +} + +qboolean MG_OK_ToShoot(edict_t *self, edict_t *target) +{ + if(target == self->enemy || + (target->takedamage && + (target->classID == CID_RAT || + (!(target->svflags&SVF_MONSTER) && target->health<50) + ) + ) + ) + return true; + return false; +} + +qboolean MG_CheckClearShotToEnemy(edict_t *self) +{ + trace_t trace; + vec3_t startpos, endpos; + vec3_t zerovec = {0, 0, 0}; + + VectorCopy(self->s.origin, startpos); + startpos[2]+=self->viewheight; + + VectorCopy(self->enemy->s.origin, endpos); + + gi.trace(startpos, zerovec, zerovec, endpos, self, MASK_MONSTERSOLID,&trace); +// trace = gi.trace(startpos, vec3_origin, vec3_origin, endpos, self, MASK_MONSTERSOLID); + + if(MG_OK_ToShoot(self, trace.ent)) + return true; + + return false; +} + +void MG_MonsterFirePathTarget(edict_t *self, char *ptarg) +{ + edict_t *ent; + + ent = NULL; + + while ((ent = G_Find(ent, FOFS(pathtargetname), ptarg)) != NULL) + { + if (ent->use) + ent->use(ent, self, self); + } +} + +qboolean MG_MonsterAttemptTeleport(edict_t *self, vec3_t destination, qboolean ignoreLOS) +{ + qboolean no_teleport = false; + trace_t trace; + vec3_t top, bottom, mins, maxs; + edict_t *ent = NULL; + int i; + + if(self->svflags & SVF_BOSS || self->classID == CID_OGLE) + return false; + + if(self->classID != CID_ASSASSIN) + { + //if still SEE monsters cheat, re-enable the following 2 lines + //if(skill->value < 2) + // return false;//only cheat on hard + + if(!ignoreLOS) + {//check line of sight with all players + ent = g_edicts; + + for(i = 0; i <= game.maxclients; i++) + { + ent = &g_edicts[i]; + + if(ent->client) + { + edict_t *temp; + + temp = G_Spawn(); + + VectorSet(temp->s.origin, + ent->client->playerinfo.pcmd.camera_vieworigin[0] * 0.125, + ent->client->playerinfo.pcmd.camera_vieworigin[1] * 0.125, + ent->client->playerinfo.pcmd.camera_vieworigin[2] * 0.125); + + if(gi.inPVS(temp->s.origin, destination)) + { + no_teleport = true; + G_FreeEdict(temp); + break; + } + + if(gi.inPVS(temp->s.origin, self->s.origin)) + { + no_teleport = true; + G_FreeEdict(temp); + break; + } + + G_FreeEdict(temp); + } + } + } + } + + if(!no_teleport) + {//do traces + VectorCopy(destination, bottom); + bottom[2] -= self->size[2]; + + VectorCopy(self->mins, mins); + VectorCopy(self->maxs, maxs); + mins[2] = 0; + maxs[2] = 1; + + gi.trace(destination, mins, maxs, bottom, self, MASK_MONSTERSOLID, &trace);//self->clipmask + + if(trace.fraction<1.0) + { + VectorCopy(trace.endpos, bottom); + VectorCopy(bottom, top); + top[2] += self->size[2] - 1; + gi.trace(bottom, mins, maxs, top, self, MASK_MONSTERSOLID, &trace); + + if(trace.allsolid || trace.startsolid) + return false; + + if(trace.fraction == 1.0) + { + bottom[2] -= self->mins[2]; + + if(self->classID == CID_ASSASSIN) + assassinPrepareTeleportDest(self, bottom); + else + { + VectorCopy(bottom, self->s.origin); + gi.linkentity(self); + } + + MG_RemoveBuoyEffects(self); + self->lastbuoy = -1; + return true; + } + } + else if(!trace.allsolid && !trace.startsolid) + { + bottom[2] -= self->mins[2]; + if(self->classID == CID_ASSASSIN) + assassinPrepareTeleportDest(self, bottom); + else + { + VectorCopy(bottom, self->s.origin); + gi.linkentity(self); + } + MG_RemoveBuoyEffects(self); + self->lastbuoy = -1; + return true; + } + } + return false; +} + +void MG_AddBuoyEffect(edict_t *self, qboolean endbuoy) +{ + if(BUOY_DEBUG) + {//turn on sparkly effects on my start and end buoys + if(!endbuoy) + {//marking our next buoy + if(self->nextbuoy[0]) + {//check a 10 second debouce timer + if(!self->nextbuoy[0]->count) + { +#ifdef _DEVEL + gi.dprintf("Adding green effect to buoy %s\n", self->nextbuoy[0]->targetname); +#endif + gi.CreateEffect(&self->nextbuoy[0]->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN|CEF_FLAG6,//green + self->nextbuoy[0]->s.origin, + "bv", + FX_BUOY, + vec3_origin); + } + self->nextbuoy[0]->s.frame = self->nextbuoy[0]->count++; + } + } + else + {//marking our end buoy (enemy's closest buoy) + if(self->nextbuoy[1]) + { + if(!self->nextbuoy[1]->s.frame) + { +#ifdef _DEVEL + gi.dprintf("Adding red effect to buoy %s\n", self->nextbuoy[1]->targetname); +#endif + gi.CreateEffect(&self->nextbuoy[1]->s, + FX_M_EFFECTS, + CEF_OWNERS_ORIGIN,//red + self->nextbuoy[1]->s.origin, + "bv", + FX_BUOY, + vec3_origin); + } + self->nextbuoy[1]->s.frame = self->nextbuoy[1]->count++; + } + } + } +} + +void MG_RemoveBuoyEffects(edict_t *self) +{//fixme- because this is really using only one effect with flags, it's turning off both red and green when it turns either off... + if(BUOY_DEBUG) + {//turn off sparkly effects on my start and end buoys + if(self->nextbuoy[0]) + {//reset a 10 second debouce timer + if(self->nextbuoy[0]->count>1) + self->nextbuoy[0]->count--; + else + { + self->nextbuoy[0]->count = 0; + } + self->nextbuoy[0]->s.frame = self->nextbuoy[0]->count; + } + + if(self->nextbuoy[1]) + { + if(self->nextbuoy[1]->count>1) + self->nextbuoy[1]->count--; + else + { + self->nextbuoy[1]->count = 0; + } + self->nextbuoy[1]->s.frame = self->nextbuoy[1]->count; + } + } + +} + +//FIXME: If a monster CAN see player but can't get to him for a short while and does not have a clear path to him, use the buoys anyway! +void MG_Pathfind(edict_t *self, qboolean check_clear_path) +{ + buoy_t *current_buoy = NULL; + buoy_t *last_buoy = NULL; + buoy_t *jump_buoy = NULL; + qboolean clear_path = false; + + if(self->spawnflags & MSF_FIXED) + return; + + if(!(self->monsterinfo.aiflags & AI_USING_BUOYS)) + { + self->ai_mood = AI_MOOD_PURSUE; + return; + } + + if(DEACTIVATE_BUOYS) + { + self->monsterinfo.searchType = SEARCH_COMMON; + self->ai_mood = AI_MOOD_PURSUE; + return; + } + + if (self->monsterinfo.searchType == SEARCH_COMMON) + { + if(!self->enemy) + return; + + if(check_clear_path) + clear_path = MG_CheckClearPathToEnemy(self); + else + clear_path = false; + + if(!clear_path) + {//this sucks- why should I do this every time pathfind is called- I need to know if the monster can get to the player directly.. if so, no Makeconnection attempt, less traces + if(!MG_MakeConnection(self, NULL, false))//if(!MG_MakeConnection(self, true, false)) + { + } + } + } + else if (self->monsterinfo.searchType == SEARCH_BUOY) + { + current_buoy = &level.buoy_list[self->buoy_index]; + last_buoy = &level.buoy_list[self->lastbuoy]; + + if(self->ai_mood != AI_MOOD_FLEE && self->ai_mood != AI_MOOD_WANDER) + self->ai_mood = AI_MOOD_NAVIGATE; + + if (self->ai_mood == AI_MOOD_DELAY) + self->ai_mood = AI_MOOD_NAVIGATE; + + if (self->ai_mood == AI_MOOD_JUMP && self->groundentity) + self->ai_mood = AI_MOOD_NAVIGATE; + + if (MG_ReachedBuoy(self, NULL)) + { + MG_RemoveBuoyEffects(self); +#ifdef _DEVEL + if (BUOY_DEBUG) + { + gi.dprintf("Reached goal %s\n", current_buoy->targetname); + } +#endif + //Check the possibility of activating something + if ((current_buoy->modflags & BUOY_ACTIVATE) && (self->ai_mood != AI_MOOD_DELAY)) + { +#ifdef _DEVEL + if (BUOY_DEBUG) + gi.dprintf("Activating target %s\n", current_buoy->pathtarget); +#endif + if (self->wait < level.time) + { + self->wait = level.time + current_buoy->wait; + MG_MonsterFirePathTarget(self, current_buoy->pathtarget); + if (current_buoy->delay) + { + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, NULL); + self->ai_mood = AI_MOOD_DELAY; + self->mood_nextthink = level.time + current_buoy->delay; + return; + } + } + } + + + //if in AI_MOOD_FORCED_BUOY mode and this buoy is my forced_buoy, + //take off that ai_mood flag and clear forced_buoy + //also, if AI_MOOD_IGNORE_ENEMY flag, remove it + if(self->ai_mood_flags&AI_MOOD_FLAG_FORCED_BUOY && self->forced_buoy == current_buoy->id) + { + self->forced_buoy = -1; + self->ai_mood_flags &= ~AI_MOOD_FLAG_FORCED_BUOY; + + if(self->ai_mood_flags&AI_MOOD_FLAG_GOTO_STAND) + { + self->ai_mood_flags &= ~AI_MOOD_FLAG_GOTO_STAND; + self->enemy = NULL; + self->ai_mood = AI_MOOD_STAND; + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, ""); + return; + } + + if(self->ai_mood_flags&AI_MOOD_FLAG_GOTO_WANDER) + { + self->ai_mood_flags &= ~AI_MOOD_FLAG_GOTO_WANDER; + self->enemy = NULL; + self->ai_mood = AI_MOOD_WANDER; + return; + } + + if(self->ai_mood_flags&AI_MOOD_FLAG_GOTO_FIXED) + { + self->ai_mood_flags &= ~AI_MOOD_FLAG_GOTO_FIXED; + self->spawnflags |= MSF_FIXED; + if(self->enemy) + self->ai_mood = AI_MOOD_PURSUE; + else + self->ai_mood = AI_MOOD_STAND; + } + + if(self->ai_mood != AI_MOOD_FLEE) + self->ai_mood_flags &= ~AI_MOOD_FLAG_IGNORE_ENEMY; + else + {//reached buoy was fleeing to now what? + if(MG_GoToRandomBuoy(self)) + { + self->monsterinfo.searchType = SEARCH_BUOY; + return; + } + else + {//couldn't flee using buoys, use dumb fleeing + //FIXME: cowering if can't flee using buoys? + self->ai_mood_flags |= AI_MOOD_FLAG_DUMB_FLEE; + return; + } + } + + if(!M_ValidTarget(self, self->enemy)) + {//got to where I was going, no enemy, so chill, baby. + if (self->monsterinfo.pausetime == -1) + { + self->spawnflags |= MSF_WANDER; + self->ai_mood = AI_MOOD_WANDER; + } + else if (level.time > self->monsterinfo.pausetime) + self->ai_mood = AI_MOOD_WALK; + else + { + self->ai_mood = AI_MOOD_STAND; + QPostMessage(self, MSG_STAND, PRI_DIRECTIVE, ""); + } + return; + } + } + + if ((current_buoy->modflags & BUOY_JUMP) && (self->ai_mood != AI_MOOD_JUMP)) + { + if(MG_MakeConnection(self, current_buoy, true))//make a regular connection, allowing skipping of jump_buoys + { + jump_buoy = current_buoy; + current_buoy = &level.buoy_list[self->buoy_index]; + if(jump_buoy == current_buoy) + {//Shit, found same buoy, shouldn't happen with dont_use_last = true! unless switching enemies +#ifdef _DEVEL + if (BUOY_DEBUG) + gi.dprintf("Warning: %s found same next buoy as last buoy at jump buoy\n",self->classname); +#endif + } + else if(current_buoy->id == jump_buoy->jump_target_id) + {//go ahead and jump + if(self->groundentity) + { + vec3_t jumpangles, jumpfwd, jump_spot; + +#ifdef _DEVEL + if (BUOY_DEBUG) + gi.dprintf("Jumping after buoy %s at angle %4.2f with height %4.2f and speed %4.2f\n", current_buoy->targetname, jump_buoy->jump_yaw, jump_buoy->jump_uspeed, jump_buoy->jump_fspeed); +#endif + VectorSet(jumpangles, 0, jump_buoy->jump_yaw, 0); + AngleVectors(jumpangles, jumpfwd, NULL, NULL); + + //since we may not be right on the buoy, find out where they want us to go by extrapolating and finding MY dir to there + VectorMA(jump_buoy->origin, jump_buoy->jump_fspeed, jumpfwd, jump_spot); + VectorSubtract(jump_spot, self->s.origin, jumpfwd); + jumpfwd[2] = 0; + VectorNormalize(jumpfwd); + + VectorScale(jumpfwd, jump_buoy->jump_fspeed, self->movedir); + self->movedir[2] = jump_buoy->jump_uspeed; + self->ai_mood = AI_MOOD_JUMP;//don't technically need this line + self->mood_nextthink = level.time + 0.5; + //as an alternative, call self->forced_jump(self); + QPostMessage(self, MSG_CHECK_MOOD, PRI_DIRECTIVE, "i", AI_MOOD_JUMP); + return; + } + } + else + {//follow the new path +#ifdef _DEVEL + if (BUOY_DEBUG) + { + current_buoy = &level.buoy_list[self->buoy_index]; + gi.dprintf("Heading to new goal %s\n", current_buoy->targetname); + } +#endif + return; +//WAS: oops, not the right one, set it back and search down below again +// current_buoy = jump_buoy; +// MG_AssignMonsterNextBuoy(self, current_buoy, NULL); + } + } + else + { + return;//? + } + } + + if (!MG_MakeConnection(self, current_buoy, false)) + { + return;//? + } + else + { +#ifdef _DEVEL + if (BUOY_DEBUG) + { + gi.dprintf("Heading to new goal %s\n", current_buoy->targetname); + } +#endif + } + } + + if(self->last_buoy_time > 0 && self->last_buoy_time + BUOY_SEARCH_TIME < level.time) + { +#ifdef _DEVEL + if (BUOY_DEBUG) + { + gi.dprintf("Buoy search timed out trying to get to %s\n", current_buoy->targetname); + } +#endif + + if(self->classID == CID_ASSASSIN) + { + if(MG_MonsterAttemptTeleport(self, current_buoy->origin, true)) + { + self->monsterinfo.aiflags |= AI_OVERRIDE_GUIDE; +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s teleported to buoy %s (ignoring player LOS)\n", self->classname, current_buoy->targetname); +#endif + return; + } + } + else if(CHEATING_MONSTERS) + { + if(CHEATING_MONSTERS<2) + { +#ifdef _DEVEL + if(MG_MonsterAttemptTeleport(self, current_buoy->origin, false)) + if(BUOY_DEBUG) + gi.dprintf("%s cheated and teleported to buoy %s\n", self->classname, current_buoy->targetname); +#else + MG_MonsterAttemptTeleport(self, current_buoy->origin, false); +#endif + } + else + { +#ifdef _DEVEL + if(MG_MonsterAttemptTeleport(self, current_buoy->origin, true)) + if(BUOY_DEBUG) + gi.dprintf("%s cheated and teleported to buoy %s (ignoring player LOS)\n", self->classname, current_buoy->targetname); +#else + MG_MonsterAttemptTeleport(self, current_buoy->origin, true); +#endif + } + } + if (!MG_MakeConnection(self, NULL, false)) + { + } + } + else if(!irand(0, 4) && !clear_visible_pos(self, current_buoy->origin)) + {//DAMN! Lost sight of buoy, let's re-aquire +#ifdef _DEVEL + if (BUOY_DEBUG) + gi.dprintf("%s Lost sight of buoy %s looking for another...\n", self->classname, current_buoy->targetname); +#endif + if (!MG_MakeConnection(self, NULL, false)) + { + } + } + } +} + +/* + * + * + * + * + * + * + * Guide functions + * + * + * + * + * + * + */ + +void MG_BuoyNavigate(edict_t *self) +{//Only handles buoy selection, some mood changing +//called from ai_run + qboolean valid_enemy = false; + int i; + buoy_t *found_buoy = NULL; + qboolean found; + + //See if my enemy is still valid + valid_enemy = M_ValidTarget(self, self->enemy); + + if(self->spawnflags & MSF_FIXED) + return; + + if(!(self->monsterinfo.aiflags & AI_USING_BUOYS)) + { + self->ai_mood = AI_MOOD_PURSUE;//ai_mood_normal? + return; + } + +//STEP 1: See if should be running away or wandering + + if(self->monsterinfo.flee_finished < level.time) + self->monsterinfo.aiflags &= ~AI_FLEE;//clear the flee flag now + + if(self->monsterinfo.aiflags & AI_COWARD || + (self->monsterinfo.aiflags&AI_FLEE && self->monsterinfo.flee_finished >= level.time)) + self->ai_mood = AI_MOOD_FLEE; + + if(!valid_enemy) + {//no enemy, now what? + self->enemy = NULL; + if(self->spawnflags & MSF_WANDER || self->monsterinfo.pausetime == -1) + { + self->spawnflags |= MSF_WANDER; + self->ai_mood = AI_MOOD_WANDER; + } + else if (level.time > self->monsterinfo.pausetime) + self->ai_mood = AI_MOOD_WALK; + else + self->ai_mood = AI_MOOD_STAND; + } + else + { + if(self->ai_mood == AI_MOOD_WANDER) + self->ai_mood = AI_MOOD_PURSUE; + } + + if(self->ai_mood == AI_MOOD_FLEE || self->ai_mood == AI_MOOD_WANDER) + {//go off in a random buoy path + + if(!(self->ai_mood_flags&AI_MOOD_FLAG_FORCED_BUOY)) + {//first time, find closest buoy, alert other enemies + if(self->ai_mood == AI_MOOD_FLEE) + {//wake up enemies for next 10 seconds + level.sight_entity = self; + level.sight_entity_framenum = level.framenum + 100; + level.sight_entity->light_level = 128; + } + + if(MG_GoToRandomBuoy(self)) + { + self->monsterinfo.searchType = SEARCH_BUOY; + return; + } + else if(self->ai_mood == AI_MOOD_FLEE) + {//couldn't flee using buoys, use dumb fleeing + //FIXME: cowering if can't flee using buoys? + self->ai_mood_flags |= AI_MOOD_FLAG_DUMB_FLEE; + return; + + } + //otherwise, want to wander, but can't, continue down the possibilities + } + else + { + self->monsterinfo.searchType = SEARCH_BUOY; + MG_Pathfind(self, false); + return;//already wandering normal buoy navigation + } + } +//STEP 2: Not running away or wandering, see what should be doing + + if(!valid_enemy) + {//No enemy, Not wandering or can't, see if I have a homebuoy + if(self->homebuoy) + {//have a home base, let's get back there if no enemy + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + if(!stricmp(found_buoy->targetname, self->homebuoy)) + { + found = true; + break; + } + } + + if(!found) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("ERROR: %s can't find it's homebuoy %s\n", self->classname, self->homebuoy); +#endif + return; + } + + if(!MG_ReachedBuoy(self, found_buoy->origin)) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s heading for homebuoy %s\n", self->classname, self->homebuoy); +#endif + self->ai_mood_flags|=AI_MOOD_FLAG_FORCED_BUOY; + self->forced_buoy = found_buoy->id; + + if(MG_MakeConnection(self, NULL, false)) + { + self->ai_mood = AI_MOOD_NAVIGATE; + + QPostMessage(self, MSG_WALK,PRI_DIRECTIVE, NULL); + + MG_RemoveBuoyEffects(self); + } + else + { + self->ai_mood_flags &= ~AI_MOOD_FLAG_FORCED_BUOY; + self->forced_buoy = -1; + } + } + } +//No enemy Not wandering, not going to homebuoy (or can't do these for some reason), so just stand around + //do we really need to clear the enemy? mAybe we shouldn't... + if(self->enemy) + { + if(self->enemy->client) + self->oldenemy = self->enemy;//remember last player enemy + } + self->enemy = NULL; + + self->mood_nextthink = level.time + 1; + //fixme: check for a self->target also? + if (self->monsterinfo.pausetime == -1) + { + self->spawnflags |= MSF_WANDER; + self->ai_mood = AI_MOOD_WANDER; + } + else if (level.time > self->monsterinfo.pausetime) + self->ai_mood = AI_MOOD_WALK; + else + self->ai_mood = AI_MOOD_STAND; + return; + } + else if(self->ai_mood_flags&AI_MOOD_FLAG_IGNORE_ENEMY) + {//have an enemy, but being forced to use buoys, and ignore enemy until get to forced_buoy + self->ai_mood = AI_MOOD_NAVIGATE; + MG_Pathfind(self, false); + return; + } + +//Actually have a valid enemy. let's try to get him + self->ai_mood = AI_MOOD_PURSUE; + + MG_Pathfind(self, true); + if(self->ai_mood == AI_MOOD_PURSUE) + self->goalentity = self->enemy; +} + +void Cvar_SetValue (char *var_name, float value); +void MG_GenericMoodSet(edict_t *self) +{ + vec3_t v, forward, pursue_vel; + float enemydist; + qboolean coward = false; + qboolean can_attack_ranged = false; + qboolean can_attack_close = false; + qboolean clear_shot = false; + qboolean enemyvis = false; + qboolean enemyinfront = false; + qboolean found = false; + qboolean melee_go = false; + int i; + buoy_t *found_buoy; + qboolean valid_enemy = false; + + if(!level.active_buoys) + { + if(!DEACTIVATE_BUOYS) + { + gi.dprintf("WARNING: no buoys on this map!!!\n"); + if(!level.active_buoys) + {//1st buoy, initialize a couple arrays + for(i = 0; i < MAX_CLIENTS; i++) + { + level.player_buoy[i] = NULL_BUOY; //stores current bestbuoy for a player enemy (if any) + level.player_last_buoy[i] = NULL_BUOY; //when player_buoy is invalid, saves it here so monsters can check it first instead of having to do a whole search + } + } + Cvar_SetValue("deactivate_buoys", 1); + DEACTIVATE_BUOYS = true; + } + } + + if(self->mood_nextthink > level.time || self->mood_nextthink <= 0.0f) + return; + + //See if my enemy is still valid + valid_enemy = M_ValidTarget(self, self->enemy); + + if(!(self->monsterinfo.aiflags & AI_USING_BUOYS)) + {//skip buoy stuff + self->ai_mood = AI_MOOD_PURSUE; + } + else + {//use buoys +//STEP 1: See if should be running away or wandering + if(self->monsterinfo.flee_finished < level.time) + self->monsterinfo.aiflags &= ~AI_FLEE;//clear the flee flag now + + if(self->monsterinfo.aiflags & AI_COWARD || + (self->monsterinfo.aiflags&AI_FLEE && self->monsterinfo.flee_finished >= level.time)) + self->ai_mood = AI_MOOD_FLEE; + + if(!valid_enemy) + {//no enemy, now what? + self->enemy = NULL; + + if(self->spawnflags & MSF_FIXED) + return; + + if(self->spawnflags & MSF_WANDER || self->monsterinfo.pausetime == -1) + { + self->spawnflags |= MSF_WANDER; + self->ai_mood = AI_MOOD_WANDER; + } + else if (level.time > self->monsterinfo.pausetime) + self->ai_mood = AI_MOOD_WALK; + else + self->ai_mood = AI_MOOD_STAND; + } + else + { + if(self->spawnflags & MSF_FIXED) + goto checkattacks; + + if(self->ai_mood == AI_MOOD_WANDER) + self->ai_mood = AI_MOOD_PURSUE; + } + + if(self->ai_mood == AI_MOOD_FLEE || self->ai_mood == AI_MOOD_WANDER) + {//go off in a random buoy path + if(!(self->ai_mood_flags&AI_MOOD_FLAG_FORCED_BUOY)) + {//first time, find closest buoy, alert other enemies + if(self->ai_mood == AI_MOOD_FLEE) + {//wake up enemies for next 10 seconds + level.sight_entity = self; + level.sight_entity_framenum = level.framenum + 100; + level.sight_entity->light_level = 128; + } + + if(MG_GoToRandomBuoy(self)) + { + self->monsterinfo.searchType = SEARCH_BUOY; + return; + } + else if(self->ai_mood == AI_MOOD_FLEE) + {//couldn't flee using buoys, use dumb fleeing + //FIXME: cowering if can't flee using buoys? + self->ai_mood_flags |= AI_MOOD_FLAG_DUMB_FLEE; + return; + } + //otherwise, want to wander, but can't, continue down the possibilities + } + else + { + self->monsterinfo.searchType = SEARCH_BUOY; + MG_Pathfind(self, false); + return;//already wandering normal buoy navigation + } + } +//STEP 2: Not running away or wandering, see what should be doing + + if(!valid_enemy) + {//No enemy, Not wandering or can't, see if I have a homebuoy + if(self->homebuoy) + {//have a home base, let's get back there if no enemy + for(i = 0; i <= level.active_buoys; i++) + { + found_buoy = &level.buoy_list[i]; + if(!stricmp(found_buoy->targetname, self->homebuoy)) + { + found = true; + break; + } + } + + if(!found) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("ERROR: %s can't find it's homebuoy %s\n", self->classname, self->homebuoy); +#endif + return; + } + + if(!MG_ReachedBuoy(self, found_buoy->origin)) + { +#ifdef _DEVEL + if(BUOY_DEBUG) + gi.dprintf("%s heading for homebuoy %s\n", self->classname, self->homebuoy); +#endif + + self->ai_mood_flags|=AI_MOOD_FLAG_FORCED_BUOY; + self->forced_buoy = found_buoy->id; + + if(MG_MakeConnection(self, NULL, false)) + { + self->ai_mood = AI_MOOD_NAVIGATE; + + QPostMessage(self, MSG_WALK,PRI_DIRECTIVE, NULL); + + MG_RemoveBuoyEffects(self); + } + else + { + self->ai_mood_flags &= ~AI_MOOD_FLAG_FORCED_BUOY; + self->forced_buoy = -1; + } + } + } +//No enemy Not wandering, not going to homebuoy (or can't do these for some reason), so just stand around + //do we really need to clear the enemy? mAybe we shouldn't... + if(self->enemy) + { + if(self->enemy->client) + self->oldenemy = self->enemy;//remember last player enemy + } + self->enemy = NULL; + + self->mood_nextthink = level.time + 1; + //fixme: check for a self->target also? + if (self->monsterinfo.pausetime == -1) + { + self->spawnflags |= MSF_WANDER; + self->ai_mood = AI_MOOD_WANDER; + } + else if (level.time > self->monsterinfo.pausetime) + self->ai_mood = AI_MOOD_WALK; + else + self->ai_mood = AI_MOOD_STAND; + return; + } + else if(self->ai_mood_flags&AI_MOOD_FLAG_IGNORE_ENEMY) + {//have an enemy, but being forced to use buoys, and ignore enemy until get to forced_buoy + self->ai_mood = AI_MOOD_NAVIGATE; + MG_Pathfind(self, false); + return; + } + } + + if(!valid_enemy || !self->enemy) + { + if (self->monsterinfo.aiflags & AI_EATING) + self->ai_mood = AI_MOOD_EAT; + return; + } + +//STEP 3: OK, have a valid enemy, let's go get him! +checkattacks: + self->ai_mood = AI_MOOD_PURSUE; + + //get distance to target, ignore Z diff if close + VectorSubtract (self->s.origin, self->enemy->s.origin, v); + if (v[2] <= 40) + v[2] = 0; + enemydist = VectorLength(v) - self->enemy->maxs[0]; + + if ((self->monsterinfo.aiflags & AI_EATING) && (enemydist > self->wakeup_distance) && !self->monsterinfo.awake) + { + self->monsterinfo.last_successful_enemy_tracking_time = level.time; + self->ai_mood = AI_MOOD_EAT; + return; + } + + if(self->monsterinfo.aiflags & AI_NO_MISSILE) + self->spawnflags &= ~MSF_FIXED;//don't stand around if can't fire + + if(self->attack_debounce_time > level.time || self->monsterinfo.attack_finished > level.time) + {//can't attack yet + can_attack_ranged = false; + clear_shot = false; + can_attack_close = false; + } + else + { + if(classStatics[self->classID].msgReceivers[MSG_MISSILE] && !(self->monsterinfo.aiflags&AI_NO_MISSILE)) + { + can_attack_ranged = true; + clear_shot = MG_CheckClearShotToEnemy(self); + } + else + clear_shot = false; + + if(classStatics[self->classID].msgReceivers[MSG_MELEE] && !(self->monsterinfo.aiflags&AI_NO_MELEE)) + can_attack_close = true; + } + + if(enemyvis = visible(self, self->enemy)) + { + self->ai_mood_flags &= ~AIMF_CANT_FIND_ENEMY; + self->ai_mood_flags &= ~AIMF_SEARCHING; + self->monsterinfo.last_successful_enemy_tracking_time = level.time; + + if(self->ai_mood_flags&AI_MOOD_FLAG_BACKSTAB) + {//only approach and attack the enemy's back- be sure to take this off if hurt? + if(enemydist < 128) + { + self->ai_mood_flags &= ~AI_MOOD_FLAG_BACKSTAB; + } + else if(infront(self->enemy, self)) + { + self->ai_mood = AI_MOOD_DELAY; + return; + } + } + } + enemyinfront = infront(self, self->enemy); + +//HEY! What if too close- backpedal or flee for a bit? +//Also, need a chance of closing in anyway- a bypass_missile_chance? + if(enemyvis && enemyinfront && + can_attack_ranged && + clear_shot && + enemydist <= self->missile_range) + {//are they far enough away? + if(irand(0, 100)>self->bypass_missile_chance) + { + if(enemydist >= self->min_missile_range) + {//ranged attack! + self->ai_mood = AI_MOOD_ATTACK; + self->ai_mood_flags &= ~AI_MOOD_FLAG_MELEE; + self->ai_mood_flags |= AI_MOOD_FLAG_MISSILE; + self->attack_debounce_time = level.time + (3 - skill->value)/2; + return; + } + else if(!can_attack_close) + {//too close and can't melee! + goto enemy_too_close; + } + } + } + +//otherwise, close in + if (!MG_CheckClearPathToEnemy(self)&&self->classID!=CID_TBEAST) + {//can't directly approach enemy +// if(enemyinfront)//ie, failed to shoot for some other reason +// {//can't shoot enemy, use buoys to get there + MG_Pathfind(self, false);//false means don't do a mg_checkclearpath + if(self->ai_mood == AI_MOOD_PURSUE) + self->goalentity = self->enemy; + if(self->cant_attack_think) + self->cant_attack_think(self, enemydist, enemyvis, enemyinfront); + return; +// } + } + +//use dummy AI + self->monsterinfo.searchType = SEARCH_COMMON; + self->movetarget = self->goalentity = self->enemy; + +//can directly approach player + + if(self->melee_range < 0) + {//keep a distance + if(enemydist <= -self->melee_range) + {//hang back and wait until CAN fire a shot off + goto enemy_too_close; + }//else close in + } + +//check for melee range attack + + if(can_attack_close) + { + if(!enemyvis || !enemyinfront || enemydist > self->melee_range || enemydist < self->min_melee_range) + { + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorSubtract(self->s.origin, self->s.old_origin, pursue_vel); + melee_go = M_PredictTargetEvasion(self, self->enemy, pursue_vel, self->enemy->velocity, self->melee_range, 5);//predict for next half second + } + else + melee_go = true; + } + + if(melee_go) + {//Close enough to melee + self->ai_mood = AI_MOOD_ATTACK; + self->ai_mood_flags |= AI_MOOD_FLAG_MELEE; + self->ai_mood_flags &= ~AI_MOOD_FLAG_MISSILE; + self->attack_debounce_time = level.time + (3 - skill->value)/2; + //OR: ok to missile too? + return; + } + else if(enemydist < self->min_melee_range) + { + goto enemy_too_close; + return; + } + +//Can't melee, so just run blindly + self->ai_mood = AI_MOOD_PURSUE; + if(self->cant_attack_think) + self->cant_attack_think(self, enemydist, enemyvis, enemyinfront); + return; + +enemy_too_close: + if(classStatics[self->classID].msgReceivers[MSG_FALLBACK]) + {//what if I hit a wall? Go into attack anyway? + self->ai_mood = AI_MOOD_BACKUP;//walk back while firing + } + else//maybe turn and run for a bit? + { +#ifdef _DEVEL + if(MGAI_DEBUG) + gi.dprintf("%s running away to get some distance from %s\n", self->classname, self->enemy->classname); +#endif + self->monsterinfo.aiflags |= AI_FLEE; + self->monsterinfo.flee_finished = level.time + flrand(3, 6); + //self->ai_mood = AI_MOOD_DELAY;//fixme: this is not good! + } + return; +} + +void MG_InitMoods(edict_t *self) +{ + self->monsterinfo.searchType = SEARCH_COMMON; + + if(!self->mintel) + self->mintel = MaxBuoysForClass[self->classID]; + + self->mood_think = MG_GenericMoodSet;//we'll re-specialize these soon + self->mood_nextthink = level.time + 0.1; + if(self->mood_nextthink <= 0.0f) + self->mood_nextthink = 0.1; + + //setup attack ranges for the mood functions to use + //these can be set by the designer if desired and can be + //affected later by the loss of a weapon or limb... + if(!self->min_melee_range) + self->min_melee_range = 0;//rendundant, I know, but clearer to see it here with other stuff + + if(!self->melee_range) + self->melee_range = AttackRangesForClass[self->classID * 4 + 0]; + + if(!self->missile_range) + self->missile_range = AttackRangesForClass[self->classID * 4 + 1]; + + if(!self->min_missile_range) + self->min_missile_range = AttackRangesForClass[self->classID * 4 + 2]; + + if(!self->bypass_missile_chance) + self->bypass_missile_chance = AttackRangesForClass[self->classID * 4 + 3]; + + if(!self->jump_chance) + self->jump_chance = JumpChanceForClass[self->classID]; + + if(!self->wakeup_distance) + self->wakeup_distance = MAX_SIGHT_PLAYER_DIST; + + //so ai_run knows to call MG_BuoyNavigate... + if(self->mintel > 0) + self->monsterinfo.aiflags |= AI_USING_BUOYS; + + if(!skill->value)//no skill = 1/2 health monsters + self->max_health = self->health = self->health * 0.5; + + self->lastbuoy = NULL_BUOY; +} + + diff --git a/Toolkit/Programming/GameCode/game/mg_guide.h b/Toolkit/Programming/GameCode/game/mg_guide.h new file mode 100644 index 0000000..049cc4c --- /dev/null +++ b/Toolkit/Programming/GameCode/game/mg_guide.h @@ -0,0 +1,3 @@ +qboolean assassinCheckTeleport (edict_t *self, int type); + +#define MONSTER_SEARCH_TIME 10//monsters search for player for 10 seconds after losing him before giving up diff --git a/Toolkit/Programming/GameCode/game/p_client.c b/Toolkit/Programming/GameCode/game/p_client.c new file mode 100644 index 0000000..0f95c2a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/p_client.c @@ -0,0 +1,3264 @@ +#include "g_local.h" +#include "g_DefaultMessageHandler.h" +#include "g_Skeletons.h" +#include "m_player.h" +#include "P_NewMove.h" +#include "p_main2.h" +#include "p_ctrl2.h" +#include "p_chicken.h" +#include "p_funcs.h" +#include "Angles.h" +#include "compfmod.h" +#include "FX.h" +#include "vector.h" +#include "random.h" +#include "Utilities.h" +#include "g_playstats.h" +#include "g_HitLocation.h" +#include "g_misc.h" +#include "g_Physics.h" +#include "p_main2.h" +#include "g_itemstats.h" +#include "cl_strings.h" +#include "p_actions2.h" +#include "p_anim_branch2.h" + +// FIXME: include headers. +extern void InitPlayerinfo(edict_t *ent); +extern void SetupPlayerinfo(edict_t *ent); +extern void WritePlayerinfo(edict_t *ent); +extern void PlayerChickenDeath(edict_t *ent); +extern qboolean AddWeaponToInventory(gitem_t *item,edict_t *player); +extern void AddDefenseToInventory(gitem_t *item,edict_t *player); +extern void CheckContinuousAutomaticEffects(edict_t *self); +extern void CalculatePIV(edict_t *player); + +#define SWIM_ADJUST_AMOUNT 16 +#define FOV_DEFAULT 75.0 + +// NOTENOTE: The precious, delicate player bbox coords! + +vec3_t mins = {-14, -14, -34}; +vec3_t maxs = { 14, 14, 25}; + +void ClientUserinfoChanged (edict_t *ent, char *userinfo); +extern void PlayerKillShrineFX(edict_t *self); + +void SP_misc_teleporter_dest (edict_t *ent); + + +/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32) +The normal starting point for a level. +*/ +void SP_info_player_start(void) +{ +} + +/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) +potential spawning position for deathmatch games +*/ +void SP_info_player_deathmatch(edict_t *self) +{ + if (!deathmatch->value) + { + G_FreeEdict (self); + return; + } +// SP_misc_teleporter_dest (self); +} + +/*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32) +potential spawning position for coop games +*/ +void SP_info_player_coop(edict_t *self) +{ + if(!coop->value) + { + G_FreeEdict (self); + return; + } +// SP_misc_teleporter_dest (self); +} + + +/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32) +The deathmatch intermission point will be at one of these +Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw. 'pitch yaw roll' +*/ + +void SP_info_player_intermission(void) +{ +} + +int SexedSoundIndex (edict_t *ent, char *base) +{ + char buffer[MAX_QPATH]; + + Com_sprintf (buffer, sizeof(buffer), "%s/%s.wav", ent->client->playerinfo.pers.sounddir, base); + + return gi.soundindex(buffer); +} + +//======================================================================= + +char *skintable[] = { + "!Corvus", + "!Corvus_Plague1", + "!Corvus_Plague2", + "!Nubian", + "!Nubian_Plague1", + "!Nubian_Plague2", + "!Rogue", + "!Rogue_Plague1", + "!Rogue_Plague2", + "!Brigand", + "!Brigand_Plague1", + "!Brigand_Plague2", + "Valkyrie", + "Spider", + "ThiefKing", +#if DEMO_CODE + // Nothing extra +#else + "Ronin", + "SoulTaker", + "Patchwork", + "Demon", + "Amazon", +#endif // DEMO_CODE + "" +}; + + +void ClientSetSkinType(edict_t *ent, char *skinname) +{ + char *curskin; + int type; + playerinfo_t *playerinfo; + + playerinfo = &(ent->client->playerinfo); + + SetupPlayerinfo_effects(ent); + + // Start looking for a given skin string. + + type=0; + + while(1) + { + if(!(curskin=skintable[type])) + break; + + if (!stricmp(curskin, skinname)) + { + // Found a match. + + break; + } + + type++; + } + + if (curskin==NULL || ((!(coop->value)) && (!(deathmatch->value))) ) // Set to default if not found + { + type = SKIN_TYPE_COOP_CORVUS; + } + + if (!deathmatch->value) + { + // If we are NOT in deathmatch, then we are in coop or single player, and can't have a + // deathmatch skin. + + if (type >= (SKIN_NUM_COOP_TYPES*PLAGUE_NUM_LEVELS)) + playerinfo->pers.skintype = SKIN_TYPE_COOP_CORVUS; // Default to Corvus again. + else + playerinfo->pers.skintype = type / PLAGUE_NUM_LEVELS; // The skintype is actually only 0-3. Can't pick plague level. + } + else + { + // If we are in deathmatch, then you can choose any skin you want. + + if (type < (SKIN_NUM_COOP_TYPES*PLAGUE_NUM_LEVELS)) + { + // Set up the plaguelevel and skintype. + + playerinfo->pers.skintype = type / PLAGUE_NUM_LEVELS; // The skintype is actually only 0-3. + playerinfo->plaguelevel = type - (playerinfo->pers.skintype * PLAGUE_NUM_LEVELS); // Add in the plaguelevel + } + else + { + // Over deathmatch, just set up the proper type, plaguelevel 0. + + playerinfo->pers.skintype = (type - (SKIN_NUM_COOP_TYPES*PLAGUE_NUM_LEVELS)) + SKIN_NUM_COOP_TYPES; + playerinfo->plaguelevel = 0; + } + } + + PlayerUpdateModelAttributes(playerinfo); + WritePlayerinfo_effects(ent); +} + + +int player_pain (edict_t *self, edict_t *other, float kick, int damage) +{ + // player pain is handled at the end of the frame in P_DamageFeedback + return(0); +} + +void BleederThink (edict_t *self) +{ + vec3_t bleed_spot, bleed_dir, forward, right, up; + int damage; + + if(!self->owner) + goto byebye; + + if(!self->owner->client) + goto byebye; + + if(!self->owner->s.modelindex) + goto byebye; + + if(!(self->owner->client->playerinfo.flags&PLAYER_FLAG_BLEED)) + goto byebye; + + if(self->owner->health <= 0) + goto byebye; + + //FIXME: this will be a client effect attached to ref points + damage = irand(1, 3); + + AngleVectors(self->owner->s.angles, forward, right, up); + VectorMA(self->owner->s.origin, self->pos1[0], forward, bleed_spot); + VectorMA(bleed_spot, self->pos1[1], right, bleed_spot); + VectorMA(bleed_spot, self->pos1[2], up, bleed_spot); + + VectorScale(forward, self->movedir[0], bleed_dir); + VectorMA(bleed_dir, self->movedir[1], right, bleed_dir); + VectorMA(bleed_dir, self->movedir[2], up, bleed_dir); + VectorScale(bleed_dir, damage*3, bleed_dir); + + if(self->owner->materialtype == MAT_INSECT) + gi.CreateEffect(NULL, FX_BLOOD, CEF_FLAG8, bleed_spot, "ub", bleed_dir, damage); + else + gi.CreateEffect(NULL, FX_BLOOD, 0, bleed_spot, "ub", bleed_dir, damage); + + if(!irand(0,3))//25%chance to do damage + T_Damage(self->owner, self, self->activator, bleed_dir, bleed_spot, bleed_dir, damage, 0, DAMAGE_NO_BLOOD|DAMAGE_NO_KNOCKBACK|DAMAGE_BLEEDING|DAMAGE_AVOID_ARMOR,MOD_BLEED);//armor doesn't stop it + + self->nextthink = level.time + flrand(0.1, 0.5); + return; + +byebye: + G_SetToFree(self); + return; + +} + +void SpawnBleeder (edict_t *self, edict_t *other, vec3_t bleed_dir, vec3_t bleed_spot)//, byte refpoint) +{ + edict_t *bleeder; + + self->client->playerinfo.flags |= PLAYER_FLAG_BLEED; + + bleeder = G_Spawn(); + bleeder->owner = self; + bleeder->activator = other; + bleeder->classname = "bleeder"; + VectorCopy(bleed_spot, bleeder->pos1); + VectorCopy(bleed_dir, bleeder->movedir); + bleeder->think = BleederThink; + bleeder->nextthink = level.time + 0.1; +//when refpoints on arms and head in for corvus, do this: +/* gi.CreateEffect(&self->s., + FX_LINKEDBLOOD, + 0, + self->s.origin, + "bb", + 180, + refpoint);*/ +} + +void player_repair_skin (edict_t *self) +{//FIXME: make sure it doesn't turn on a hand without the arm! + int i, num_allowed_dmg_skins, to_fix; + int found_dmg_skins = 0; + int checked = 0; + int hurt_nodes[NUM_PLAYER_NODES]; + + if(!self->client) + return; + + if(!self->s.modelindex) + return; + + num_allowed_dmg_skins = 5 - floor(self->health/20); +#ifdef _DEVEL + gi.dprintf("Allowed damaged nodes: %d\n", num_allowed_dmg_skins); +#endif + + if(num_allowed_dmg_skins <= 0) + {//restore all nodes + for(i = 0; i < NUM_PLAYER_NODES; i++) + { + if(i == MESH__STOFF|| + i == MESH__BOFF|| + i == MESH__ARMOR|| + i == MESH__STAFACTV|| + i == MESH__BLADSTF|| + i == MESH__HELSTF|| + i == MESH__BOWACTV) + continue;//these shouldn't be fucked with + else + { +#ifdef _DEVEL + gi.dprintf("Healed player skin on node %d\n", i); +#endif + self->client->playerinfo.pers.altparts &= ~(1<s.fmnodeinfo[i].flags &= ~FMNI_USE_SKIN; + self->s.fmnodeinfo[i].skin = self->s.skinnum; + } + } + SetupPlayerinfo_effects(self); + PlayerUpdateModelAttributes(&self->client->playerinfo); + WritePlayerinfo_effects(self); + return; + } + + for(i = 0; is.fmnodeinfo[i].flags&FMNI_NO_DRAW)&&(self->s.fmnodeinfo[i].flags&FMNI_USE_SKIN)) + { + hurt_nodes[found_dmg_skins] = i; + found_dmg_skins++; + } + } + +#ifdef _DEVEL + gi.dprintf("Found damaged nodes: %d\n", found_dmg_skins); +#endif + if(found_dmg_skins<=num_allowed_dmg_skins)//no healing + return; + + to_fix = found_dmg_skins - num_allowed_dmg_skins; + + while(to_fix > 0 && checked<100) + {//heal num damaged nodes over allowed + i = hurt_nodes[irand(0, (found_dmg_skins - 1))]; + if(!(self->s.fmnodeinfo[i].flags&FMNI_NO_DRAW)) + { + if(self->s.fmnodeinfo[i].flags&FMNI_USE_SKIN) + { +#ifdef _DEVEL + gi.dprintf("Healed player skin on node %d\n", i); +#endif + self->s.fmnodeinfo[i].flags &= ~FMNI_USE_SKIN; + self->s.fmnodeinfo[i].skin = self->s.skinnum; + + self->client->playerinfo.pers.altparts &= ~(1<client->playerinfo.flags &= ~PLAYER_FLAG_NO_LARM; + else if(i == MESH__RARM) + self->client->playerinfo.flags &= ~PLAYER_FLAG_NO_RARM; + + to_fix--; + checked++;//to protect against infinite loops, this IS random after all + } + } + } + + SetupPlayerinfo_effects(self); + PlayerUpdateModelAttributes(&self->client->playerinfo); + WritePlayerinfo_effects(self); +} + +void ResetPlayerBaseNodes (edict_t *ent) +{ + if(!ent->client) + return; + + ent->client->playerinfo.flags &= ~PLAYER_FLAG_BLEED; + + ent->client->playerinfo.flags &= ~PLAYER_FLAG_NO_LARM; + ent->client->playerinfo.flags &= ~PLAYER_FLAG_NO_RARM; + + ent->client->playerinfo.pers.altparts = 0; + + ent->s.fmnodeinfo[MESH_BASE2].flags &= ~FMNI_NO_DRAW; + ent->s.fmnodeinfo[MESH__BACK].flags &= ~FMNI_NO_DRAW; + ent->s.fmnodeinfo[MESH__RARM].flags &= ~FMNI_NO_DRAW; + ent->s.fmnodeinfo[MESH__LARM].flags &= ~FMNI_NO_DRAW; + ent->s.fmnodeinfo[MESH__HEAD].flags &= ~FMNI_NO_DRAW; + ent->s.fmnodeinfo[MESH__RLEG].flags &= ~FMNI_NO_DRAW; + ent->s.fmnodeinfo[MESH__LLEG].flags &= ~FMNI_NO_DRAW; + + ent->s.fmnodeinfo[MESH_BASE2].flags &= ~FMNI_USE_SKIN; + ent->s.fmnodeinfo[MESH__BACK].flags &= ~FMNI_USE_SKIN; + ent->s.fmnodeinfo[MESH__RARM].flags &= ~FMNI_USE_SKIN; + ent->s.fmnodeinfo[MESH__LARM].flags &= ~FMNI_USE_SKIN; + ent->s.fmnodeinfo[MESH__HEAD].flags &= ~FMNI_USE_SKIN; + ent->s.fmnodeinfo[MESH__RLEG].flags &= ~FMNI_USE_SKIN; + ent->s.fmnodeinfo[MESH__LLEG].flags &= ~FMNI_USE_SKIN; + + ent->s.fmnodeinfo[MESH_BASE2].skin = ent->s.skinnum; + ent->s.fmnodeinfo[MESH__BACK].skin = ent->s.skinnum; + ent->s.fmnodeinfo[MESH__RARM].skin = ent->s.skinnum; + ent->s.fmnodeinfo[MESH__LARM].skin = ent->s.skinnum; + ent->s.fmnodeinfo[MESH__HEAD].skin = ent->s.skinnum; + ent->s.fmnodeinfo[MESH__RLEG].skin = ent->s.skinnum; + ent->s.fmnodeinfo[MESH__LLEG].skin = ent->s.skinnum; + + // FIXME: Turn hands back on too? But two pairs, which one? Shouldn't PlayerUpdateModelAttributes do that? + + SetupPlayerinfo_effects(ent); + PlayerUpdateModelAttributes(&ent->client->playerinfo); + WritePlayerinfo_effects(ent); +} + +#define BIT_BASE2 0// MESH_BASE2 0 - front +#define BIT_BACK 1// MESH__BACK 1 - back +#define BIT_STOFF 2// MESH__STOFF 2 - staff on leg +#define BIT_BOFF 4// MESH__BOFF 3 - bow on shoulder +#define BIT_ARMOR 8// MESH__ARMOR 4 - armor +#define BIT_RARM 16// MESH__RARM 5 - right shoulder to wrist +#define BIT_RHANDHI 32// MESH__RHANDHI 6 - right hand flat +#define BIT_STAFACTV 64// MESH__STAFACTV 7 - right hand fist & staff stub +#define BIT_BLADSTF 128// MESH__BLADSTF 8 - staff (active) +#define BIT_HELSTF 256// MESH__HELSTF 9 - hellstaff +#define BIT_LARM 512// MESH__LARM 10 - left shoulder to wrist +#define BIT_LHANDHI 1024// MESH__LHANDHI 11 - left hand flat +#define BIT_BOWACTV 2048// MESH__BOWACTV 12 - left hand fist & bow +#define BIT_RLEG 4096// MESH__RLEG 13 - right leg +#define BIT_LLEG 8192// MESH__LLEG 14 - left leg +#define BIT_HEAD 16384// MESH__HEAD 15 - head + +int Bit_for_MeshNode_player [16] = +{ + BIT_BASE2,// 0 - front + BIT_BACK,// 1 - back + BIT_STOFF,// 2 - staff on leg + BIT_BOFF,// 3 - bow on shoulder + BIT_ARMOR,// 4 - armor + BIT_RARM,// 5 - right shoulder to wrist + BIT_RHANDHI,// 6 - right hand flat + BIT_STAFACTV,// 7 - right hand fist & staff stub + BIT_BLADSTF,// 8 - staff (active) + BIT_HELSTF,// 9 - hellstaff + BIT_LARM,// 10 - left shoulder to wrist + BIT_LHANDHI,// 11 - left hand flat + BIT_BOWACTV,// 12 - left hand fist & bow + BIT_RLEG,// 13 - right leg + BIT_LLEG,// 14 - left leg + BIT_HEAD,// 15 - head +}; + +qboolean canthrownode_player (edict_t *self, int BP, int *throw_nodes) +{//see if it's on, if so, add it to throw_nodes + //turn it off on thrower + if(!(self->s.fmnodeinfo[BP].flags & FMNI_NO_DRAW)) + { + *throw_nodes |= Bit_for_MeshNode_player[BP]; + self->s.fmnodeinfo[BP].flags |= FMNI_NO_DRAW; + return true; + } + return false; +} + +void player_dropweapon (edict_t *self, int damage, int whichweaps) +{//FIXME: OR in the BIT_... to playerinfo->altparts! + vec3_t handspot, forward, right, up; + + //Current code doesn't really support dropping weapons!!! + if(deathmatch->value) + { + if(!((int)dmflags->value&DF_DISMEMBER)) + { + if(self->health > 0) + { + return; + } + } + } + else if(self->health > 0) + return; + + //FIXME: use refpoints for this? + VectorClear(handspot); + AngleVectors(self->s.angles,forward,right,up); + VectorMA(handspot,5,forward,handspot); + VectorMA(handspot,8,right,handspot); + VectorMA(handspot,-6,up,handspot); + + if(whichweaps & BIT_BLADSTF && !(self->s.fmnodeinfo[MESH__BLADSTF].flags & FMNI_NO_DRAW)) + { +// self->client->playerinfo.stafflevel = 0; + ThrowWeapon(self, &handspot, BIT_BLADSTF, damage, 0); + self->s.fmnodeinfo[MESH__BLADSTF].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__STAFACTV].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__RHANDHI].flags &= ~FMNI_NO_DRAW; + } + if(whichweaps & BIT_HELSTF && !(self->s.fmnodeinfo[MESH__HELSTF].flags & FMNI_NO_DRAW)) + { +// self->client->playerinfo.helltype = 0; + ThrowWeapon(self, &handspot, BIT_HELSTF, damage, 0); + self->s.fmnodeinfo[MESH__HELSTF].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__STAFACTV].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__RHANDHI].flags &= ~FMNI_NO_DRAW; + } + if(whichweaps & BIT_BOWACTV && !(self->s.fmnodeinfo[MESH__BOWACTV].flags & FMNI_NO_DRAW)) + { +// self->client->playerinfo.bowtype = 0; + ThrowWeapon(self, &handspot, BIT_BOFF, damage, 0); + self->s.fmnodeinfo[MESH__BOFF].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__BOWACTV].flags |= FMNI_NO_DRAW; + self->s.fmnodeinfo[MESH__LHANDHI].flags &= ~FMNI_NO_DRAW; + } +} + +void player_dismember (edict_t *self, edict_t *other, int damage, int HitLocation) +{//FIXME: Make sure you can still dismember and gib player while dying + int throw_nodes = 0; + vec3_t gore_spot, right, blood_dir, blood_spot; + qboolean dismember_ok = false; + qboolean inpolevault = false; + + if(HitLocation & hl_MeleeHit) + { + dismember_ok = true; + HitLocation &= ~hl_MeleeHit; + } + + //dismember living players in deathmatch only if that dmflag set! + if(deathmatch->value) + { + if(!((int)dmflags->value&DF_DISMEMBER)) + { + if(self->health > 0)// && !(self->flags&FL_GODMODE)) + { + dismember_ok = false; + } + } + if(dismember_ok) + { + if(self->client->playerinfo.frame > FRAME_vault3 && + self->client->playerinfo.frame < FRAME_vault15) + inpolevault = true; + else + inpolevault = false; + + if(inpolevault) + { + //Horizontal, in air, need to alter hitloc + switch(HitLocation) + { + case hl_Head: + HitLocation = hl_TorsoFront; + break; + case hl_TorsoFront: + HitLocation = hl_TorsoFront; + break; + case hl_TorsoBack: + HitLocation = hl_Head; + break; + } + } + + if(self->health > 0 && !irand(0,2) && + HitLocation != hl_Head && + HitLocation != hl_ArmUpperLeft && + HitLocation != hl_ArmUpperRight) + {//deathmatch hack + if(irand(0,1)) + HitLocation = hl_ArmUpperLeft; + else + HitLocation = hl_ArmUpperRight; + } + } + } + else if(self->health > 0)// && !(self->flags&FL_GODMODE)) + dismember_ok = false; + + if(!dismember_ok) + { + if(damage <= 3 && self->health>10) + return; + + if(damage < 10 && self->health>85) + return; + } + + if(HitLocation<1) + return; + + if(HitLocation>hl_Max) + return; + +//FIXME: special manipulations of hit locations depending on anim + + VectorClear(gore_spot); + switch(HitLocation) + { + case hl_Head: + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health) < damage*0.5 && dismember_ok) + { +// player_dropweapon (self, (int)damage, (BIT_BOWACTV|BIT_BLADSTF|BIT_HELSTF)); + + canthrownode_player(self, MESH__HEAD,&throw_nodes); + + gore_spot[2]+=18; + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + + VectorAdd(self->s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,8,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, other, other, vec3_origin, vec3_origin, vec3_origin, 10, 20,DAMAGE_AVOID_ARMOR,MOD_STAFF); + } + + goto finish; + } + else + { +// if(flrand(0,self->health)client->playerinfo.pers.altparts |= (1<s.fmnodeinfo[MESH__HEAD].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__HEAD].skin = self->s.skinnum+1; + } + break; + case hl_TorsoFront://split in half? + if(self->s.fmnodeinfo[MESH_BASE2].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH_BASE2].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)client->playerinfo.flags |= (PLAYER_FLAG_NO_LARM|PLAYER_FLAG_NO_RARM); + gore_spot[2]+=12; + canthrownode_player(self, MESH_BASE2,&throw_nodes); + canthrownode_player(self, MESH__BACK,&throw_nodes); + canthrownode_player(self, MESH__LARM,&throw_nodes); + canthrownode_player(self, MESH__RARM,&throw_nodes); + canthrownode_player(self, MESH__HEAD,&throw_nodes); + canthrownode_player(self, MESH__LHANDHI,&throw_nodes); + canthrownode_player(self, MESH__RHANDHI,&throw_nodes); + +// player_dropweapon (self, (int)damage, (BIT_BOWACTV|BIT_BLADSTF|BIT_HELSTF)); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 1); + VectorAdd(self->s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,12,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, other, other, vec3_origin, vec3_origin, vec3_origin, 10, 20,DAMAGE_AVOID_ARMOR,MOD_STAFF); + } + goto finish; + } + else + { +// if(flrand(0,self->health)client->playerinfo.pers.altparts |= (1<s.fmnodeinfo[MESH_BASE2].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH_BASE2].skin = self->s.skinnum+1; + } + break; + case hl_TorsoBack://split in half? + if(self->s.fmnodeinfo[MESH__BACK].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__BACK].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health)client->playerinfo.flags |= (PLAYER_FLAG_NO_LARM|PLAYER_FLAG_NO_RARM); + gore_spot[2]+=12; + canthrownode_player(self, MESH_BASE2,&throw_nodes); + canthrownode_player(self, MESH__BACK,&throw_nodes); + canthrownode_player(self, MESH__LARM,&throw_nodes); + canthrownode_player(self, MESH__RARM,&throw_nodes); + canthrownode_player(self, MESH__HEAD,&throw_nodes); + canthrownode_player(self, MESH__LHANDHI,&throw_nodes); + canthrownode_player(self, MESH__RHANDHI,&throw_nodes); + +// player_dropweapon (self, (int)damage, (BIT_BOWACTV|BIT_BLADSTF|BIT_HELSTF)); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 1); + VectorAdd(self->s.origin, gore_spot, gore_spot); + SprayDebris(self,gore_spot,12,damage); + + if(self->health>0) + { + self->health = 1; + T_Damage (self, other, other, vec3_origin, vec3_origin, vec3_origin, 10, 20,DAMAGE_AVOID_ARMOR,MOD_STAFF); + } + goto finish; + } + else + { +// if(flrand(0,self->health)client->playerinfo.pers.altparts |= (1<s.fmnodeinfo[MESH__BACK].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__BACK].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperLeft: + case hl_ArmLowerLeft://left arm + if(self->s.fmnodeinfo[MESH__LARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__LARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health) < damage && dismember_ok) + { + if(canthrownode_player(self, MESH__LARM, &throw_nodes)) + { + self->client->playerinfo.flags |= PLAYER_FLAG_NO_LARM; + player_dropweapon (self, (int)damage, BIT_BOWACTV); + canthrownode_player(self, MESH__LHANDHI, &throw_nodes); + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + + VectorSet(blood_dir, 0, -1, 0); + VectorSet(blood_spot, 0, -12, 10); + SpawnBleeder(self, other, blood_dir, blood_spot);//, CORVUS_LARM); + } + } + else + { +// if(flrand(0,self->health)client->playerinfo.pers.altparts |= (1<s.fmnodeinfo[MESH__LARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LARM].skin = self->s.skinnum+1; + } + break; + case hl_ArmUpperRight: + case hl_ArmLowerRight://right arm + //Knock weapon out of hand? + if(self->s.fmnodeinfo[MESH__RARM].flags & FMNI_NO_DRAW) + break; + if(self->s.fmnodeinfo[MESH__RARM].flags & FMNI_USE_SKIN) + damage*=1.5;//greater chance to cut off if previously damaged + if(flrand(0,self->health) < damage && dismember_ok) + { + if(canthrownode_player(self, MESH__RARM, &throw_nodes)) + { + self->client->playerinfo.flags |= PLAYER_FLAG_NO_RARM; + player_dropweapon (self, (int)damage, BIT_HELSTF|BIT_BLADSTF); + canthrownode_player(self, MESH__RHANDHI, &throw_nodes); + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + + VectorSet(blood_dir, 0, 1, 0); + VectorSet(blood_spot, 0, 12, 10); + SpawnBleeder(self, other, blood_dir, blood_spot);//, CORVUS_RARM); + + if(inpolevault)//oops! no staff! fall down! + KnockDownPlayer(&self->client->playerinfo); + } + } + else + { +// if(flrand(0,self->health)client->playerinfo.pers.altparts |= (1<s.fmnodeinfo[MESH__RARM].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RARM].skin = self->s.skinnum+1; + } + break; + + case hl_LegUpperLeft: + case hl_LegLowerLeft://left leg + if(self->health>0) + {//still alive + if(self->s.fmnodeinfo[MESH__LLEG].flags & FMNI_USE_SKIN) + break; + self->client->playerinfo.pers.altparts |= (1<s.fmnodeinfo[MESH__LLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__LLEG].skin = self->s.skinnum+1; + } + else + { + if(self->s.fmnodeinfo[MESH__LLEG].flags & FMNI_NO_DRAW) + break; + if(canthrownode_player(self, MESH__LLEG, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + break; + case hl_LegUpperRight: + case hl_LegLowerRight://right leg + if(self->health>0) + {//still alive + if(self->s.fmnodeinfo[MESH__RLEG].flags & FMNI_USE_SKIN) + break; + self->client->playerinfo.pers.altparts |= (1<s.fmnodeinfo[MESH__RLEG].flags |= FMNI_USE_SKIN; + self->s.fmnodeinfo[MESH__RLEG].skin = self->s.skinnum+1; + } + else + { + if(self->s.fmnodeinfo[MESH__RLEG].flags & FMNI_NO_DRAW) + break; + if(canthrownode_player(self, MESH__RLEG, &throw_nodes)) + { + AngleVectors(self->s.angles,NULL,right,NULL); + gore_spot[2]+=self->maxs[2]*0.3; + VectorMA(gore_spot,-10,right,gore_spot); + ThrowBodyPart(self, &gore_spot, throw_nodes, damage, 0); + } + break; + } + break; + + default: +// if(flrand(0,self->health)pain_debounce_time = 0; + if(!BranchCheckDismemberAction(&self->client->playerinfo, self->client->playerinfo.pers.weapon->tag)) + { + PlayerInterruptAction(&self->client->playerinfo); + PlayerAnimSetUpperSeq(&self->client->playerinfo, ASEQ_NONE); + if(irand(0, 1)) + PlayerAnimSetLowerSeq(&self->client->playerinfo, ASEQ_PAIN_A); + else + PlayerAnimSetLowerSeq(&self->client->playerinfo, ASEQ_PAIN_B); + } + } + +finish: + + SetupPlayerinfo_effects(self); + PlayerUpdateModelAttributes(&self->client->playerinfo); + WritePlayerinfo_effects(self); +} + +void player_decap (edict_t *self, edict_t *other) +{ + int throw_nodes = 0; + vec3_t gore_spot; + + //FIXME: special manipulations of hit locations depending on anim. + + VectorClear(gore_spot); + if(self->s.fmnodeinfo[MESH__HEAD].flags & FMNI_NO_DRAW) + return; + + player_dropweapon (self, 100, (BIT_BOWACTV|BIT_BLADSTF|BIT_HELSTF)); + + canthrownode_player(self, MESH__HEAD,&throw_nodes); + + gore_spot[2]+=18; + + ThrowBodyPart(self, &gore_spot, throw_nodes, 0, 0); + + VectorAdd(self->s.origin, gore_spot, gore_spot); + + SprayDebris(self, gore_spot, 8, 100); + + if(self->health > 0) + { + self->health = 0; + self->client->meansofdeath = MOD_DECAP; + player_die(self, other, other, 100, gore_spot); + } + + SetupPlayerinfo_effects(self); + PlayerUpdateModelAttributes(&self->client->playerinfo); + WritePlayerinfo_effects(self); +} + +void player_leader_effect(void) +{ + int i; + int score = 1; + int num_scored = 0; + int total_player = 0; + edict_t *ent; + + // if we don't want leader effects, bump outta here. + if(!(((int)dmflags->value) & DF_SHOW_LEADER)) + return; + + // now we decide if anyone is a leader here, and if they are, we put the glow around them. + // first, search through all clients and see what the leading score is. + for (i=0; iclient && ent->inuse) + { + total_player++; + if (ent->client->resp.score == score) + num_scored++; + else + if (ent->client->resp.score > score) + { + num_scored = 0; + score = ent->client->resp.score; + } + } + } + + // if more than 3 people have it, no one is the leader + if ((num_scored > 3) || (total_player == num_scored)) + score = 999999; + + // now loop through and turn off the persistant effect of anyone that has below the leader score + // and turn it on for anyone that does have it, if its not already turned on + for (i=0; iclient && ent->inuse) + { + // are we a leader ? + if (ent->client->resp.score == score) + { + if (!ent->Leader_PersistantCFX) + ent->Leader_PersistantCFX = gi.CreatePersistantEffect + (&ent->s, FX_SHOW_LEADER, CEF_BROADCAST|CEF_OWNERS_ORIGIN, NULL, "" ); + } + // if not, then if we have the effect, remove it + else + if (ent->Leader_PersistantCFX) + { + gi.RemovePersistantEffect(ent->Leader_PersistantCFX); + gi.RemoveEffects(&ent->s, FX_SHOW_LEADER); + ent->Leader_PersistantCFX =0; + } + + } + } + +} + + +// ************************************************************************************************ +// ClientObituary +// -------------- +// ************************************************************************************************ + +static const short KillSelf[MOD_MAX] = +{ + 0, // MOD_UNKNOWN + + 0, // MOD_STAFF + 0, // MOD_FIREBALL + 0, // MOD_MMISSILE + 0, // MOD_SPHERE + 0, // MOD_SPHERE_SPL + 0, // MOD_IRONDOOM + 0, // MOD_FIREWALL + 0, // MOD_STORM + 0, // MOD_PHOENIX + 0, // MOD_PHOENIX_SPL + 0, // MOD_HELLSTAFF + + 0, // MOD_P_STAFF + 0, // MOD_P_FIREBALL + 0, // MOD_P_MMISSILE + 0, // MOD_P_SPHERE + 0, // MOD_P_SPHERE_SPL + 0, // MOD_P_IRONDOOM + 0, // MOD_P_FIREWALL + 0, // MOD_P_STORM + 0, // MOD_P_PHOENIX + 0, // MOD_P_PHOENIX_SPL + 0, // MOD_P_HELLSTAFF + + 0, // MOD_KICKED + 0, // MOD_METEORS + 0, // MOD_ROR + 0, // MOD_SHIELD + 0, // MOD_CHICKEN + 0, // MOD_TELEFRAG + GM_OBIT_WATER, // MOD_WATER + GM_OBIT_SLIME, // MOD_SLIME + GM_OBIT_LAVA, // MOD_LAVA + GM_OBIT_CRUSH, // MOD_CRUSH + GM_OBIT_FALLING, // MOD_FALLING + GM_OBIT_SUICIDE, // MOD_SUICIDE + GM_OBIT_BARREL, // MOD_BARREL + GM_OBIT_EXIT, // MOD_EXIT + GM_OBIT_BURNT, // MOD_BURNT + 0, // MOD_BLEED + 0, // MOD_SPEAR + 0, // MOD_DIED + GM_OBIT_EXPL, // MOD_KILLED_SLF + 0 // MOD_DECAP +}; + +static const short KillBy[MOD_MAX] = +{ + 0, // MOD_UNKNOWN + + GM_OBIT_STAFF, // MOD_STAFF + GM_OBIT_FIREBALL, // MOD_FIREBALL + GM_OBIT_MMISSILE, // MOD_MMISSILE + GM_OBIT_SPHERE, // MOD_SPHERE + GM_OBIT_SPHERE_SPL, // MOD_SPHERE_SPL + GM_OBIT_IRONDOOM, // MOD_IRONDOOM + GM_OBIT_FIREWALL, // MOD_FIREWALL + GM_OBIT_STORM, // MOD_STORM + GM_OBIT_PHOENIX, // MOD_PHOENIX + GM_OBIT_PHOENIX_SPL, // MOD_PHOENIX_SPL + GM_OBIT_HELLSTAFF, // MOD_HELLSTAFF + + GM_OBIT_STAFF, // MOD_P_STAFF + GM_OBIT_FIREBALL, // MOD_P_FIREBALL + GM_OBIT_MMISSILE, // MOD_P_MMISSILE + GM_OBIT_SPHERE, // MOD_P_SPHERE + GM_OBIT_SPHERE_SPL, // MOD_P_SPHERE_SPL + GM_OBIT_IRONDOOM, // MOD_P_IRONDOOM + GM_OBIT_FIREWALL, // MOD_P_FIREWALL + GM_OBIT_STORM, // MOD_P_STORM + GM_OBIT_PHOENIX, // MOD_P_PHOENIX + GM_OBIT_PHOENIX_SPL, // MOD_P_PHOENIX_SPL + GM_OBIT_HELLSTAFF, // MOD_P_HELLSTAFF + + 0, // MOD_KICKED + GM_OBIT_METEORS, // MOD_METEORS + GM_OBIT_ROR, // MOD_ROR + GM_OBIT_SHIELD, // MOD_SHIELD + 0, // MOD_CHICKEN + GM_OBIT_TELEFRAG, // MOD_TELEFRAG + 0, // MOD_WATER + 0, // MOD_SLIME + 0, // MOD_LAVA + 0, // MOD_CRUSH + 0, // MOD_FALLING + 0, // MOD_SUICIDE + 0, // MOD_BARREL + 0, // MOD_EXIT + 0, // MOD_BURNT + 0, // MOD_BLEED + 0, // MOD_SPEAR + 0, // MOD_DIED + 0, // MOD_KILLED_SLF + 0 // MOD_DECAP +}; + +void ClientObituary(edict_t *self, edict_t *inflictor, edict_t *attacker) +{ + short message; + assert(self->client); + + if(!(deathmatch->value || coop->value)) + { + // No obituaries in single player. + + return; + } + + if(deathmatch->value || coop->value) + { + message = KillSelf[self->client->meansofdeath]; + + if(message) + { + gi.Obituary(PRINT_MEDIUM, (short)(message + irand(0, 2)), self->s.number, 0); + + if(deathmatch->value) + { + self->client->resp.score--; + player_leader_effect(); + } + + self->enemy = NULL; + return; + } + + self->enemy = attacker; + if(attacker && attacker->client) + { + message = KillBy[self->client->meansofdeath]; + + if(message) + { + gi.Obituary(PRINT_MEDIUM, (short)(message + irand(0, 2)), self->s.number, attacker->s.number); + + if(deathmatch->value) + { + attacker->client->resp.score++; + player_leader_effect(); + } + return; + } + } + } + + gi.Obituary(PRINT_MEDIUM, (short)(GM_OBIT_DIED + irand(0, 2)), self->s.number, 0); + + if (deathmatch->value) + { + self->client->resp.score--; + player_leader_effect(); + } +} + +void player_make_gib(edict_t *self, edict_t *attacker) +{ + byte magb; + float mag; + int i, num_limbs; + + if(self->client) + { + //FIXME: Have a generic GibParts effect that throws flesh and several body parts - much cheaper. + + num_limbs = irand(1, 3); + for(i = 0; i < num_limbs; i++) + player_dismember(self, attacker, flrand(80, 160), irand(hl_Head, hl_LegLowerRight) | hl_MeleeHit); + } + + mag = VectorLength(self->mins); + magb = Clamp(mag, 1.0, 255.0); + + gi.CreateEffect(NULL, + FX_FLESH_DEBRIS, + 0, + self->s.origin, + "bdb", + irand(10, 30), self->mins, magb); + + self->takedamage = DAMAGE_NO; +} + +int player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,int damage,vec3_t point) +{//FIXME: Make sure you can still dismember and gib player while dying + int i; + + assert(self->client); + + VectorClear(self->avelocity); + + if(self->health < -99) + self->health = -99;//looks better on stat bar display + + self->takedamage=DAMAGE_NO; + self->movetype=PHYSICSTYPE_STEP; + + self->s.angles[PITCH]=0.0; + self->s.angles[ROLL]=0.0; + + self->s.sound=0; + + self->maxs[2]=-8; + + self->solid=SOLID_NOT; + + // tell the leader client effect that this client is dead - so if we drawing the effect, please stop. + self->s.effects |= EF_CLIENT_DEAD; + + // Get the player off of the rope! + + if (self->client->playerinfo.flags & PLAYER_FLAG_ONROPE) + { + // Turn off the rope graphic immediately. + + self->targetEnt->count = 0; + self->targetEnt->rope_grab->s.effects &= ~EF_ALTCLIENTFX; + + self->monsterinfo.jump_time = level.time + 10; + self->client->playerinfo.flags |= PLAYER_FLAG_RELEASEROPE; + self->client->playerinfo.flags &= ~PLAYER_FLAG_ONROPE; + + self->client->playerinfo.flags |= PLAYER_FLAG_FALLBREAK | PLAYER_FLAG_FALLING; + } + // Get rid of the player's persistent effect. + if (self->PersistantCFX) + { + gi.RemovePersistantEffect(self->PersistantCFX); + self->PersistantCFX = 0; + } + + if (self->Leader_PersistantCFX) + { + gi.RemovePersistantEffect(self->Leader_PersistantCFX); + self->Leader_PersistantCFX =0; + } + + // remove any persistant meteor effects + for (i=0; i<4; i++) + { + if (self->client->Meteors[i]) + { + if (self->client->Meteors[i]->PersistantCFX) + { + gi.RemovePersistantEffect(self->client->Meteors[i]->PersistantCFX); + gi.RemoveEffects(&self->s, FX_SPELL_METEORBARRIER+i); + self->client->Meteors[i]->PersistantCFX = 0; + } + G_SetToFree(self->client->Meteors[i]); + self->client->Meteors[i] = NULL; + } + } + // we now own no meteors at all + self->client->playerinfo.meteor_count = 0; + + // Create a persistant FX_REMOVE_EFFECTS effect - this is a special hack. If we just created + // a regular FX_REMOVE_EFFECTS effect, it will overwrite the next FX_PLAYER_PERSISTANT sent + // out. Luverly jubberly!!! + gi.CreatePersistantEffect(&self->s,FX_REMOVE_EFFECTS,CEF_BROADCAST|CEF_OWNERS_ORIGIN,NULL,"s",0); + + // Remove any shrine effects we have going. + PlayerKillShrineFX(self); + + // Remove any sound effects we may be generating. + gi.sound(self, CHAN_WEAPON, gi.soundindex("misc/null.wav"), 1, ATTN_NORM,0); + + if((self->health<-40) && !(self->flags & FL_CHICKEN)) + { + gi.sound(self,CHAN_BODY,gi.soundindex("player/corvusgib.wav"),1,ATTN_NORM,0); + + player_make_gib(self, attacker); + + self->s.modelindex=0; + // Won`t get sent to client if mi 0 unless flag is set + self->svflags |= SVF_ALWAYS_SEND; + self->s.effects |= EF_NODRAW_ALWAYS_SEND | EF_ALWAYS_ADD_EFFECTS; + self->deadflag=DEAD_DEAD; + + self->client->playerinfo.deadflag=DEAD_DEAD; + } + else + { + // Make player die a normal death. + + self->health=-1; + + if(!self->deadflag) + { + self->client->respawn_time=level.time+1.0; + self->client->ps.pmove.pm_type=PM_DEAD; + + // If player died in a deathmatch or coop, show scores. + + Cmd_Score_f(self); + + // Check if a chicken? + + if (self->flags & FL_CHICKEN) + { + // We're a chicken, so die a chicken's death. + + PlayerChickenDeath(self); + player_make_gib(self, attacker); + self->s.modelindex=0; + // Won`t get sent to client if mi 0 unless flag is set + self->svflags |= SVF_ALWAYS_SEND; + self->s.effects |= EF_NODRAW_ALWAYS_SEND | EF_ALWAYS_ADD_EFFECTS; + } + else if ( (self->client->playerinfo.flags & PLAYER_FLAG_SURFSWIM) || (self->waterlevel >= 2) ) + { + PlayerAnimSetLowerSeq(&self->client->playerinfo, ASEQ_DROWN); + gi.sound(self,CHAN_BODY,gi.soundindex("player/drowndeath.wav"),1,ATTN_NORM,0); + } + else if ( !stricmp(inflictor->classname, "plague_mist")) + { + PlayerAnimSetLowerSeq(&self->client->playerinfo, ASEQ_DEATH_CHOKE); + gi.sound(self,CHAN_BODY,gi.soundindex("player/chokedeath.wav"),1,ATTN_NORM,0); + } + else if ( self->fire_damage_time == -1 ) + { + PlayerAnimSetLowerSeq(&self->client->playerinfo, ASEQ_DEATH_B); + if (blood_level && (int)(blood_level->value) <= VIOLENCE_BLOOD) // Don't scream bloody murder in Germany. + gi.sound(self,CHAN_BODY,gi.soundindex("player/corvusdeth1.wav"),1,ATTN_NORM,0); + else + gi.sound(self,CHAN_BODY,gi.soundindex("player/firedeath.wav"),1,ATTN_NORM,0); + } + else + { + PlayerAnimSetLowerSeq(&self->client->playerinfo, ASEQ_DEATH_A); + + if (irand(0,1)) + gi.sound(self,CHAN_BODY,gi.soundindex("player/corvusdeth1.wav"),1,ATTN_NORM,0); + else + gi.sound(self,CHAN_BODY,gi.soundindex("player/corvusdeth2.wav"),1,ATTN_NORM,0); + } + + // Make sure it doesn't try and finish an animation. + + PlayerAnimSetUpperSeq(&self->client->playerinfo, ASEQ_NONE); + self->client->playerinfo.upperidle = true; + + // If we're not a chicken, don't set the dying flag. + + if (!(self->client->playerinfo.edictflags & FL_CHICKEN)) // We're not set as a chicken + { + // Not a chicken so set the dying flag. + + self->deadflag=DEAD_DYING; + self->client->playerinfo.deadflag=DEAD_DYING; + } + else + { + // I WAS a chicken, but not any more, I'm dead and an Elf again. + + self->client->playerinfo.edictflags &= ~FL_CHICKEN; + } + } + } + + ClientObituary(self, inflictor, attacker); + + gi.linkentity(self); + + return(0); +} + +/* +======================================================================= + + SelectSpawnPoint + +======================================================================= +*/ + +/* +================ +PlayersRangeFromSpot + +Returns the distance to the nearest player from the given spot +================ +*/ +float PlayersRangeFromSpot (edict_t *spot) +{ + edict_t *player; + float bestplayerdistance; + vec3_t v; + int n; + float playerdistance; + + + bestplayerdistance = 9999999; + + for (n = 1; n <= maxclients->value; n++) + { + player = &g_edicts[n]; + + if (!player->inuse) + continue; + + if (player->health <= 0) + continue; + + VectorSubtract (spot->s.origin, player->s.origin, v); + playerdistance = VectorLength (v); + + if (playerdistance < bestplayerdistance) + bestplayerdistance = playerdistance; + } + + return bestplayerdistance; +} + +/* +================ +SelectRandomDeathmatchSpawnPoint + +go to a random point, but NOT the two points closest +to other players +================ +*/ +edict_t *SelectRandomDeathmatchSpawnPoint (void) +{ + edict_t *spot, *spot1, *spot2; + int count = 0; + int selection; + float range, range1, range2; + + spot = NULL; + range1 = range2 = 99999; + spot1 = spot2 = NULL; + + while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) + { +// if(spot->damage_debounce_time > level.time) +// continue;//was just used + +// if(irand(0,1)) +// continue;//50% chance to skip it- helps make it more random + + count++; + range = PlayersRangeFromSpot(spot); + if (range < range1) + { + range1 = range; + spot1 = spot; + } + else if (range < range2) + { + range2 = range; + spot2 = spot; + } + } + + if (!count) + return NULL; + + if (count <= 2) + { + spot1 = spot2 = NULL; + } + else + count -= 2; + + selection = irand(0, count -1 ); + + spot = NULL; + do + { + spot = G_Find (spot, FOFS(classname), "info_player_deathmatch"); + if (spot == spot1 || spot == spot2) + selection++; + } while(selection--); + + return spot; +} + +/* +================ +SelectFarthestDeathmatchSpawnPoint + +================ +*/ +edict_t *SelectFarthestDeathmatchSpawnPoint (void) +{ + edict_t *bestspot; + float bestdistance, bestplayerdistance; + edict_t *spot; + + + spot = NULL; + bestspot = NULL; + bestdistance = 0; + while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) + { +// if(spot->damage_debounce_time > level.time) +// continue;//was just used + + bestplayerdistance = PlayersRangeFromSpot (spot); + + if (bestplayerdistance > bestdistance) + { + bestspot = spot; + bestdistance = bestplayerdistance; + } + } + + if (bestspot) + { + return bestspot; + } + + // if there is a player just spawned on each and every start spot + // we have no choice to turn one into a telefrag meltdown + spot = G_Find (NULL, FOFS(classname), "info_player_deathmatch"); + + return spot; +} + +edict_t *SelectDeathmatchSpawnPoint (void) +{ +// if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST) + return SelectFarthestDeathmatchSpawnPoint (); +// else +// return SelectRandomDeathmatchSpawnPoint (); +} + +edict_t *SelectCoopSpawnPoint (edict_t *ent) +{ + int index; + edict_t *spot = NULL; + char *target; + + index = ent->client - game.clients; + + // Player 0 starts in normal player spawn point. + + if (!index) + return NULL; + + spot = NULL; + + // Assume there are four coop spots at each spawnpoint. + + while (1) + { + spot = G_Find (spot, FOFS(classname), "info_player_coop"); + + if (!spot) + return NULL; // we didn't have enough... + +// try not to use the same spot for a bit to prevent telefrags +// if(spot->damage_debounce_time > level.time) +// continue; + + target = spot->targetname; + if (!target) + target = ""; + if ( Q_stricmp(game.spawnpoint, target) == 0 ) + { + // This is a coop spawn point for one of the clients here. + + index--; + + if (!index) + return spot;// this is it + } + } + + return spot; +} + +/* +=========== +SelectSpawnPoint + +Chooses a player start, deathmatch start, coop start, etc +============ +*/ +void SelectSpawnPoint (edict_t *ent,vec3_t origin, vec3_t angles) +{ + edict_t *spot = NULL; + trace_t tr; + vec3_t endpos; + + if (deathmatch->value) + spot = SelectDeathmatchSpawnPoint (); + else if (coop->value) + spot = SelectCoopSpawnPoint (ent); + + // Find a single player start spot. + + if (!spot) + { + while ((spot = G_Find (spot, FOFS(classname), "info_player_start")) != NULL) + { + if (!game.spawnpoint[0] && !spot->targetname) + break; + + if (!game.spawnpoint[0] || !spot->targetname) + continue; + + if (Q_stricmp(game.spawnpoint, spot->targetname) == 0) + break; + } + + if (!spot) + { + if (!game.spawnpoint[0]) + { + // There wasn't a spawnpoint without a target, so use any. + + spot = G_Find (spot, FOFS(classname), "info_player_start"); + } + if (!spot) + gi.error ("Couldn't find spawn point %s\n", game.spawnpoint); + } + } + + //debounce tim eon use to help prevent telefragging + //spot->damage_debounce_time = level.time + 0.3; + + // Do a trace to the floor to find where to put player. + + VectorCopy(spot->s.origin, endpos); + endpos[2] -= 1000; + gi.trace (spot->s.origin, vec3_origin, vec3_origin, endpos, NULL, CONTENTS_WORLD_ONLY|MASK_PLAYERSOLID,&tr); + + VectorCopy(tr.endpos,origin); + origin[2] -= mins[2]; + + // ??? + + VectorCopy (spot->s.angles, angles); +} + +//====================================================================== + +int body_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ + BecomeDebris(self); + return true; +} + +void InitBodyQue (void) +{ + int i; + edict_t *ent; + + level.body_que = 0; + + for (i=0; iclassname = "bodyque"; + } +} + +int player_body_die(edict_t *self,edict_t *inflictor,edict_t *attacker,int damage,vec3_t point) +{ + byte magb; + float mag; + vec3_t mins; + + VectorCopy(self->mins,mins); + mins[2]=-30.0; + + gi.sound(self,CHAN_BODY,gi.soundindex("misc/fleshbreak.wav"),1,ATTN_NORM,0); + + mag = VectorLength(mins); + magb = Clamp(mag, 1.0, 255.0); + + gi.CreateEffect(NULL, + FX_FLESH_DEBRIS, + 0, + self->s.origin, + "bdb", + irand(10, 30), mins, magb); + + gi.unlinkentity(self); + + VectorClear(self->mins); + VectorClear(self->maxs); + VectorClear(self->absmin); + VectorClear(self->absmax); + VectorClear(self->size); + self->movetype=PHYSICSTYPE_NONE; + self->solid=SOLID_NOT; + self->clipmask=0; + self->takedamage=DAMAGE_NO; + self->materialtype=MAT_NONE; + self->health=0; + self->die=NULL; + self->deadflag=DEAD_DEAD; + self->s.modelindex=0; + + gi.linkentity(self); + + return(1); +} + +void CopyToBodyQue (edict_t *ent) +{ + edict_t *body; + vec3_t origin; + + // Grab a body que and cycle to the next one. + + if(!ent->s.modelindex) + { + // Safety - was gibbed? + + return; + } + + if(level.body_que == -1) + { + VectorCopy(ent->s.origin, origin); + origin[2] += (ent->mins[2] + 8.0f); + + // Put in the pretty effect when removing the corpse first. + + gi.CreateEffect(NULL, FX_CORPSE_REMOVE, 0, origin, ""); + + // No body que on this level. + + return; + } + + body = &g_edicts[((int)maxclients->value) + 1 + level.body_que]; + level.body_que = (level.body_que + 1) % BODY_QUEUE_SIZE; + + gi.unlinkentity (ent); + + // If the body was being used, then lets put an effect on it before removing it. + + if (body->inuse&&(body->s.modelindex!=0)) + { + VectorCopy(body->s.origin, origin); + origin[2] += (body->mins[2] + 8.0f); + gi.CreateEffect(NULL, FX_CORPSE_REMOVE, 0, origin, ""); + } + + gi.unlinkentity (body); + + body->s=ent->s; + body->s.number=body-g_edicts; + body->s.skeletalType=SKEL_NULL; + body->s.effects&=~(EF_JOINTED|EF_SWAPFRAME); + body->s.rootJoint=NULL_ROOT_JOINT; + body->s.swapFrame=NO_SWAP_FRAME; + body->owner=ent->owner; + VectorScale(ent->mins,0.5,body->mins); + VectorScale(ent->maxs,0.5,body->maxs); + body->maxs[2]=10; + VectorCopy(ent->absmin,body->absmin); + VectorCopy(ent->absmax,body->absmax); + body->absmax[2]=10; + VectorCopy(ent->size,body->size); + body->svflags=ent->svflags|SVF_DEADMONSTER; // Stops player getting stuck. + body->movetype=PHYSICSTYPE_STEP; + body->solid=SOLID_BBOX; + body->clipmask=MASK_PLAYERSOLID; + body->takedamage=DAMAGE_YES; + body->materialtype=MAT_FLESH; + body->health=25; + body->deadflag=DEAD_NO; + body->die=player_body_die; + + gi.linkentity (body); + + // Clear out any client effectsBuffer_t on the corpse (inherited from the player who just died) + // as the engine will take care of deallocating any effects still on the player. + + memset(&body->s.clientEffects,0,sizeof(EffectsBuffer_t)); + + // FIXME: Re-create certain client effects that were on the player when he died (e.g. fire). + + return; +} + +void respawn (edict_t *self) +{ + if (deathmatch->value || coop->value) + { + // FIXME: make bodyque objects obey gravity. + + if(!(self->flags & FL_CHICKEN)) + { + // We're not set as a chicken, so duplicate ourselves. + + CopyToBodyQue (self); + } + + // Create a persistant FX_REMOVE_EFFECTS effect - this is a special hack. If we just created + // a regular FX_REMOVE_EFFECTS effect, it will overwrite the next FX_PLAYER_PERSISTANT sent + // out. Luverly jubberly!!! + + gi.CreatePersistantEffect(&self->s,FX_REMOVE_EFFECTS,CEF_BROADCAST|CEF_OWNERS_ORIGIN,NULL,"s",0); + + if(deathmatch->value) + { + // Respawning in deathmatch always means a complete reset of the player's model. + + self->client->complete_reset=1; + } + else if(coop->value) + { + // Respawning in coop always means a partial reset of the player's model. + + self->client->complete_reset=0; + } + + PutClientInServer (self); + + // Do the teleport sound. + + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + + // Add a teleportation effect. + + gi.CreateEffect(&self->s, FX_PLAYER_TELEPORT_IN, CEF_OWNERS_ORIGIN, self->s.origin, NULL); + + // Hold in place briefly. + + self->client->ps.pmove.pm_time = 50; + + + return; + } + + // Restart the entire server. + + gi.AddCommandString ("menu_loadgame\n"); +} + +//============================================================== + + +// this makes the effects occur one frame later than the spawn, so we don't lose shadows or player effects +void DoSpawnInitialPlayerEffects(edict_t *self) +{ + if (deathmatch->value || coop->value) + player_leader_effect(); + + G_SetToFree(self); +} + +void SpawnInitialPlayerEffects(edict_t *ent) +{ + void PlayerRestartShrineFX(edict_t *self); + + edict_t *self; + + PlayerRestartShrineFX(ent); + + // Don't need to keep track of this persistant effect, since its started but never stopped. + + gi.CreatePersistantEffect(&ent->s, FX_PLAYER_PERSISTANT, + CEF_BROADCAST | CEF_OWNERS_ORIGIN, NULL, ""); + + self = G_Spawn(); + self->enemy = ent; + self->think = DoSpawnInitialPlayerEffects; + self->nextthink = level.time + 0.1; + self->solid = SOLID_NOT; + + gi.linkentity(self); +} + +/* +================== +SaveClientData + +Some information that should be persistant, like health, is still stored in the edict structure, so +it needs to be mirrored out to the game.client structure(s) before all the edicts are wiped. +================== +*/ + +void SaveClientData (void) +{ + int i; + edict_t *ent; + + for(i=0;iinuse) + continue; + + game.clients[i].playerinfo.pers.health=ent->health; + if (coop->value && game.clients[i].playerinfo.pers.health < 25) + game.clients[i].playerinfo.pers.health=25; + game.clients[i].playerinfo.pers.max_health=ent->max_health; + + game.clients[i].playerinfo.pers.mission_num1 = ent->client->ps.mission_num1; + game.clients[i].playerinfo.pers.mission_num2 = ent->client->ps.mission_num2; + + if(coop->value) + game.clients[i].playerinfo.pers.score=ent->client->resp.score; + } +} + +/* +================== +FetchClientEntData +================== +*/ + +void FetchClientEntData (edict_t *ent) +{ + ent->health=ent->client->playerinfo.pers.health; + if (coop->value && ent->health < 25) + ent->health = 25; + ent->max_health=ent->client->playerinfo.pers.max_health; + + ent->client->ps.mission_num1 = ent->client->playerinfo.pers.mission_num1; + ent->client->ps.mission_num2 = ent->client->playerinfo.pers.mission_num2; + + if(coop->value) + ent->client->resp.score=ent->client->playerinfo.pers.score; +} + +// ************************************************************************************************ +// GiveLevelItems +// -------------- +// If additional starting weapons and defences are specified by the current map, give them to the +// player (to support players joining a coop game midway through). +// ************************************************************************************************ + +void GiveLevelItems(edict_t *player) +{ + gclient_t *client; + gitem_t *item,*weapon; + + client=player->client; + + weapon=NULL; + + if(level.offensive_weapons&1) + { + item=FindItem("staff"); + if(AddWeaponToInventory(item,player)) + { + if((ITEM_INDEX(item) > ITEM_INDEX(weapon))&&(client->playerinfo.pers.autoweapon)) + { + weapon=item; + client->playerinfo.pers.newweapon=item; + client->playerinfo.switchtoweapon=WEAPON_READY_SWORDSTAFF; + } + } + } + + if(level.offensive_weapons&2) + { + item=FindItem("fball"); + if(AddWeaponToInventory(item,player)) + { + if((ITEM_INDEX(item) > ITEM_INDEX(weapon))&&(client->playerinfo.pers.autoweapon)) + { + weapon=item; + client->playerinfo.pers.newweapon=item; + client->playerinfo.switchtoweapon=WEAPON_READY_HANDS; + } + } + } + + if(level.offensive_weapons&4) + { + item=FindItem("hell"); + if(AddWeaponToInventory(item,player)) + { + if((ITEM_INDEX(item) > ITEM_INDEX(weapon))&&(client->playerinfo.pers.autoweapon)) + { + weapon=item; + client->playerinfo.pers.newweapon=item; + client->playerinfo.switchtoweapon=WEAPON_READY_HELLSTAFF; + } + } + } + + if(level.offensive_weapons&8) + { + item=FindItem("array"); + if(AddWeaponToInventory(item,player)) + { + if((ITEM_INDEX(item) > ITEM_INDEX(weapon))&&(client->playerinfo.pers.autoweapon)) + { + weapon=item; + client->playerinfo.pers.newweapon=item; + client->playerinfo.switchtoweapon=WEAPON_READY_HANDS; + } + } + } + + if(level.offensive_weapons&16) + { + item=FindItem("rain"); + if(AddWeaponToInventory(item,player)) + { + if((ITEM_INDEX(item) > ITEM_INDEX(weapon))&&(client->playerinfo.pers.autoweapon)) + { + weapon=item; + client->playerinfo.pers.newweapon=item; + client->playerinfo.switchtoweapon=WEAPON_READY_BOW; + } + } + } + + if(level.offensive_weapons&32) + { + item=FindItem("sphere"); + if(AddWeaponToInventory(item,player)) + { + if((ITEM_INDEX(item) > ITEM_INDEX(weapon))&&(client->playerinfo.pers.autoweapon)) + { + weapon=item; + client->playerinfo.pers.newweapon=item; + client->playerinfo.switchtoweapon=WEAPON_READY_HANDS; + } + } + } + + if(level.offensive_weapons&64) + { + item=FindItem("phoen"); + if(AddWeaponToInventory(item,player)) + { + if((ITEM_INDEX(item) > ITEM_INDEX(weapon))&&(client->playerinfo.pers.autoweapon)) + { + weapon=item; + client->playerinfo.pers.newweapon=item; + client->playerinfo.switchtoweapon=WEAPON_READY_BOW; + } + } + } + + if(level.offensive_weapons&128) + { + item=FindItem("mace"); + if(AddWeaponToInventory(item,player)) + { + if((ITEM_INDEX(item) > ITEM_INDEX(weapon))&&(client->playerinfo.pers.autoweapon)) + { + weapon=item; + client->playerinfo.pers.newweapon=item; + client->playerinfo.switchtoweapon=WEAPON_READY_HANDS; + } + } + } + + if(level.offensive_weapons&256) + { + item=FindItem("fwall"); + if(AddWeaponToInventory(item,player)) + { + if((ITEM_INDEX(item) > ITEM_INDEX(weapon))&&(client->playerinfo.pers.autoweapon)) + { + weapon=item; + client->playerinfo.pers.newweapon=item; + client->playerinfo.switchtoweapon=WEAPON_READY_HANDS; + } + } + } + + if(level.defensive_weapons&1) + { + item=FindItem("ring"); + AddDefenseToInventory(item,player); + } + + if(level.defensive_weapons&2) + { + item=FindItem("lshield"); + AddDefenseToInventory(item,player); + } + + if(level.defensive_weapons&4) + { + item=FindItem("tele"); + AddDefenseToInventory(item,player); + } + + if(level.defensive_weapons&8) + { + item=FindItem("morph"); + AddDefenseToInventory(item,player); + } + + if(level.defensive_weapons&16) + { + item=FindItem("meteor"); + AddDefenseToInventory(item,player); + } + + SetupPlayerinfo_effects(player); + PlayerUpdateModelAttributes(&player->client->playerinfo); + WritePlayerinfo_effects(player); +} + +// ************************************************************************************************ +// InitClientPersistant +// -------------------- +// ************************************************************************************************ + +void InitClientPersistant(edict_t *player) +{ + gclient_t *client; + gitem_t *item; + + client=player->client; + + memset(&client->playerinfo.pers, 0, sizeof(client->playerinfo.pers)); + + // ******************************************************************************************** + // Set up player's health. + // ******************************************************************************************** + + client->playerinfo.pers.health = 100; + + // ******************************************************************************************** + // Set up maximums amounts for health, mana and ammo for bows and hellstaff. + // ******************************************************************************************** + + client->playerinfo.pers.max_health = 100; + client->playerinfo.pers.max_offmana = MAX_OFF_MANA; + client->playerinfo.pers.max_defmana = MAX_DEF_MANA; + client->playerinfo.pers.max_redarrow = MAX_RAIN_AMMO; + client->playerinfo.pers.max_phoenarr = MAX_PHOENIX_AMMO; + client->playerinfo.pers.max_hellstaff = MAX_HELL_AMMO; + + // ******************************************************************************************** + // Give defensive and offensive weapons to player. + // ******************************************************************************************** + + client->playerinfo.pers.weapon=0; + client->playerinfo.pers.defence=0; + + // Give just the sword-staff and flying-fist to the player as starting weapons. + + item = FindItem("staff"); + AddWeaponToInventory(item,player); + client->playerinfo.pers.selected_item = ITEM_INDEX(item); + client->playerinfo.pers.weapon = item; + client->playerinfo.pers.lastweapon = item; + client->playerinfo.weap_ammo_index = 0; + + item=FindItem("fball"); + AddWeaponToInventory(item,player); + client->playerinfo.pers.selected_item = ITEM_INDEX(item); + client->playerinfo.pers.weapon = item; + client->playerinfo.pers.lastweapon = item; + client->playerinfo.weap_ammo_index = ITEM_INDEX(FindItem(item->ammo)); + + item=FindItem("powerup"); + AddDefenseToInventory(item,player); + client->playerinfo.pers.defence = item; + + // ******************************************************************************************** + // Start player with half offensive and defensive mana - as instructed by Brian P. + // ******************************************************************************************** + + item = FindItem("Off-mana"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = client->playerinfo.pers.max_offmana / 2; + + item = FindItem("Def-mana"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = client->playerinfo.pers.max_defmana / 2; + +#ifdef G_NOAMMO + + // Start with all weapons if G_NOAMMO is defined. + + gi.dprintf("Starting with unlimited ammo.\n"); + + item = FindItem("hell"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + item = FindItem("array"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + item = FindItem("rain"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + item = FindItem("sphere"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + item = FindItem("phoen"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + item = FindItem("mace"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + item = FindItem("fwall"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + item = FindItem("meteor"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + item = FindItem("morph"); + client->playerinfo.pers.inventory.Items[ITEM_INDEX(item)] = 1; + + client->bowtype = BOW_TYPE_REDRAIN; + client->armortype = ARMOR_TYPE_SILVER; + +#endif // G_NOAMMO + + client->playerinfo.pers.connected = true; +} + +/* +=========== +PutClientInServer + +Called when a player connects to a server or respawns in a deathmatch. +============ +*/ + +void PutClientInServer (edict_t *ent) +{ + int index; + vec3_t spawn_origin, spawn_angles; + gclient_t *client; + int i; + client_persistant_t saved; + client_respawn_t resp; + int complete_reset; + + // ******************************************************************************************** + // Find a spawn point. Do it before setting health back up, so farthest ranging doesn't count + // this client. + // ******************************************************************************************** + + SelectSpawnPoint (ent,spawn_origin, spawn_angles); + + index = ent-g_edicts-1; + client = ent->client; + + // ******************************************************************************************** + // Deathmatch wipes most client data every spawn. + // ******************************************************************************************** + + if (deathmatch->value) + { + char userinfo[MAX_INFO_STRING]; + + resp = client->resp; + + memcpy (userinfo, client->playerinfo.pers.userinfo, sizeof(userinfo)); + InitClientPersistant (ent); + ClientUserinfoChanged (ent, userinfo); + } + else if (coop->value) + { + char userinfo[MAX_INFO_STRING]; + + resp = client->resp; + + memcpy (userinfo, client->playerinfo.pers.userinfo, sizeof(userinfo)); + + ClientUserinfoChanged (ent, userinfo); + + if (resp.score > client->playerinfo.pers.score) + client->playerinfo.pers.score = resp.score; + } + else + { + memset (&resp, 0, sizeof(resp)); + } + + // Complete or partial reset of the player's model? + + if(!deathmatch->value) + { + complete_reset=client->complete_reset; + } + else + { + // Deathmatch always means a complete reset of the player's model. + + complete_reset=1; + } + + // ******************************************************************************************** + // Initialise the player's gclient_t. + // ******************************************************************************************** + + // Clear everything but the persistant data. + + saved = client->playerinfo.pers; + memset (client, 0, sizeof(gclient_t)); + client->playerinfo.pers = saved; + + // Initialise... + + if (client->playerinfo.pers.health <= 0) + InitClientPersistant(ent); + + client->resp = resp; + + // Rsestore data that is persistant accross level changes. + + FetchClientEntData (ent); + + // ******************************************************************************************** + // Initialize the player's edict_t. + // ******************************************************************************************** + + ent->groundentity = NULL; + ent->client = &game.clients[index]; + ent->takedamage = DAMAGE_AIM; + ent->materialtype = MAT_FLESH; + ent->movetype = PHYSICSTYPE_STEP; + ent->viewheight = 0; + ent->inuse = true; + ent->s.scale = 1.0f; + ent->classname = "player"; + ent->mass = 200; + ent->solid = SOLID_BBOX; + ent->deadflag = DEAD_NO; + ent->air_finished = level.time + HOLD_BREATH_TIME; + ent->clipmask = MASK_PLAYERSOLID; + ent->Leader_PersistantCFX = 0; + + // Default to making us not invunerable (may change later). + + ent->client->shrine_framenum = 0; + + // A few Multiplayer reset safeguards... i.e. if we were teleporting when we died, we aren't now. + + client->playerinfo.flags &= ~PLAYER_FLAG_TELEPORT; + client->tele_dest[0] = client->tele_dest[1] = client->tele_dest[2] = 0; + client->tele_count = 0; + ent->s.color.c = 0x00000000; // Restore model visibility. + + ent->fire_damage_time = 0; + ent->fire_timestamp = 0; + +#ifdef COMP_FMOD + ent->model = "models/player/elf/tris_c.fm"; +#else + ent->model = "models/player/elf/tris.fm"; +#endif + + ent->pain = player_pain; + ent->die = player_die; + ent->waterlevel = 0; + ent->watertype = 0; + ent->flags &= ~FL_NO_KNOCKBACK; + ent->svflags &= ~SVF_DEADMONSTER; + + VectorCopy (mins, ent->mins); + VectorCopy (maxs, ent->maxs); + VectorCopy (mins, ent->intentMins); + VectorCopy (maxs, ent->intentMaxs); + VectorClear (ent->velocity); + + // ******************************************************************************************** + // Initialize the player's gclient_t and playerstate_t. + // ******************************************************************************************** + + client->ps.pmove.origin[0] = spawn_origin[0]*8; + client->ps.pmove.origin[1] = spawn_origin[1]*8; + client->ps.pmove.origin[2] = spawn_origin[2]*8; + + client->ps.fov = atoi(Info_ValueForKey(client->playerinfo.pers.userinfo, "fov")); + + if (client->ps.fov < 1) + client->ps.fov = FOV_DEFAULT; + else if (client->ps.fov > 160) + client->ps.fov = 160; + + VectorClear(client->ps.offsetangles); + + // Set the delta angles. + + for (i=0 ; i<3 ; i++) + client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]); + + client->ps.remote_id=-1; + + // ******************************************************************************************** + // Initialize the player's entity_state_t. + // ******************************************************************************************** + + // Zero the current animation frame. + + ent->s.frame=0; + + // Modelindex is always 255 for player models. + + ent->s.modelindex=255; + + // Set up the model's origin, making sure it's off the ground. + + VectorCopy (spawn_origin, ent->s.origin); + ent->s.origin[2] += 1; + VectorCopy (ent->s.origin, ent->s.old_origin); + + ent->s.angles[PITCH] = 0; + ent->s.angles[YAW] = spawn_angles[YAW]; + ent->s.angles[ROLL] = 0; + VectorCopy (ent->s.angles, client->ps.viewangles); + VectorCopy (ent->s.angles, client->v_angle); + + if(!KillBox(ent)) + { + // could't spawn in? + } + + ent->s.effects=(EF_CAMERA_NO_CLIP|EF_SWAPFRAME|EF_JOINTED|EF_PLAYER); + + // Set up skeletal info. Note, skeleton has been created already. + + ent->s.skeletalType = SKEL_CORVUS; + + // Link us into the physics system. + + gi.linkentity (ent); + + // ******************************************************************************************** + // Initialize the player's playerinfo_t. + // ******************************************************************************************** + + // Set the player's current weapon. We might be moving levels with the sword staff, which has + // no ammo pickup name. + + if (client->playerinfo.pers.weapon->ammo) + client->playerinfo.weap_ammo_index = ITEM_INDEX(FindItem(client->playerinfo.pers.weapon->ammo)); + if (client->playerinfo.pers.defence) + client->playerinfo.def_ammo_index = ITEM_INDEX(FindItem(client->playerinfo.pers.defence->ammo)); + + VectorCopy(spawn_origin,client->playerinfo.origin); + VectorClear(client->playerinfo.velocity); + + // Make the player have the right attributes - armor that sort of thing. + + SetupPlayerinfo_effects(ent); + PlayerUpdateModelAttributes(&ent->client->playerinfo); + WritePlayerinfo_effects(ent); + + // The player's starting plague skin is determined by the worldspawn's s.skinnum. + + if (!deathmatch->value) + { + client->playerinfo.plaguelevel = g_edicts[0].s.skinnum; + + if (client->playerinfo.plaguelevel >= PLAGUE_NUM_LEVELS) + { + client->playerinfo.plaguelevel = PLAGUE_NUM_LEVELS-1; + } + else if (client->playerinfo.plaguelevel < 0) + { + client->playerinfo.plaguelevel = 0; + } + } + + // Make sure the skin attributes are transferred. + + ClientSetSkinType(ent, Info_ValueForKey (ent->client->playerinfo.pers.userinfo, "skin")); + + if(deathmatch->value||coop->value) + { + // Reset the player's fmodel nodes when spawning in deathmatch or coop. + + ResetPlayerBaseNodes(ent); + + // Just in case we were on fire when we died. + + gi.RemoveEffects(&ent->s, FX_FIRE_ON_ENTITY); + + // Make us invincible for a few seconds after spawn. + + ent->client->shrine_framenum = level.time + 3.3; + } + + InitPlayerinfo(ent); + + SetupPlayerinfo(ent); + + PlayerInit(&ent->client->playerinfo,complete_reset); + + WritePlayerinfo(ent); + + SpawnInitialPlayerEffects(ent); + + if(coop->value) + GiveLevelItems(ent); +} + +/* +===================== +InitClientResp +===================== +*/ + +void InitClientResp (gclient_t *client) +{ + memset (&client->resp, 0, sizeof(client->resp)); + client->resp.enterframe = level.framenum; + client->resp.coop_respawn = client->playerinfo.pers; +} + +/* +===================== +ClientBeginDeathmatch + +A client has just connected to the server in deathmatch mode, so clear everything out before starting them. +===================== +*/ +void ClientBeginDeathmatch (edict_t *ent) +{ + G_InitEdict (ent); + + InitClientResp (ent->client); + + // Locate ent at a spawn point. + + PutClientInServer (ent); + + // Do the teleport sound and client effect and announce the player's entry into the + // level. + + gi.sound(ent,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + gi.CreateEffect(&ent->s, FX_PLAYER_TELEPORT_IN, CEF_OWNERS_ORIGIN, ent->s.origin, NULL); + gi.Obituary(PRINT_HIGH, GM_ENTERED, ent->s.number, 0); + + // Make sure all view stuff is valid. + + ClientEndServerFrame (ent); +} + +/* +=========== +ClientBegin + +Called when a client has finished connecting, and is ready to be placed into the game. This will +happen every level load. +============ +*/ +void ClientBegin (edict_t *ent) +{ + int i; + + ent->client = game.clients + (ent - g_edicts - 1); + + if (deathmatch->value) + { + ClientBeginDeathmatch (ent); + + return; + } + + // If there is already a body waiting for us (a loadgame), just take it, otherwise spawn one + // from scratch. + + if (ent->inuse == true) + { + // The client has cleared the client side viewangles upon connecting to the server, which + // is different from the state when the game is saved, so we need to compensate with + // deltaangles. + + for (i=0 ; i<3 ; i++) + ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->ps.viewangles[i]); + + SpawnInitialPlayerEffects(ent); + + // The player has a body waiting from a (just) loaded game, so we want to do just a partial + // reset of the player's model. + + ent->client->complete_reset=0; + } + else + { + // A spawn point will completely reinitialize the entity except for the persistant data + // that was initialized at ClientConnect() time. + + G_InitEdict (ent); + ent->classname = "player"; + InitClientResp (ent->client); + PutClientInServer (ent); + + // All resets should be partial, until ClientConnect() gets called again for a new game, + // respawn() occurs (which will do the correct reset type). + + ent->client->complete_reset=0; + } + + if(level.intermissiontime) + { + MoveClientToIntermission(ent); + } + else + { + // Send effect if in a multiplayer game. + + if (game.maxclients > 1) + { + // Do the teleport sound and client effect and announce the player's entry into the + // level. + + gi.sound(ent,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + gi.CreateEffect(&ent->s, FX_PLAYER_TELEPORT_IN, CEF_OWNERS_ORIGIN, ent->s.origin, NULL); + gi.Obituary (PRINT_HIGH, GM_ENTERED, ent->s.number, 0); + } + } + + // Make sure all view stuff is valid. + + ClientEndServerFrame (ent); +} + +/* +=========== +ClientUserInfoChanged + +Called whenever the player updates a userinfo variable. The game can override any of the settings +in place (forcing skins or names, etc) before copying it off. +============ +*/ + +void ClientUserinfoChanged (edict_t *ent, char *userinfo) +{ + char *s; + int playernum; + + // set name + s = Info_ValueForKey (userinfo, "name"); + strncpy (ent->client->playerinfo.pers.netname, s, sizeof(ent->client->playerinfo.pers.netname)-1); + + // set skin + s = Info_ValueForKey (userinfo, "skin"); + + playernum = ent-g_edicts-1; + + // combine name and skin into a configstring + gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s", ent->client->playerinfo.pers.netname, s) ); + + // Change skins, but lookup the proper skintype. + ClientSetSkinType(ent, s); + + // fov + ent->client->ps.fov = atoi(Info_ValueForKey(userinfo, "fov")); + if (ent->client->ps.fov < 1) + ent->client->ps.fov = FOV_DEFAULT; + else if (ent->client->ps.fov > 160) + ent->client->ps.fov = 160; + + // autoweapon + s = Info_ValueForKey (userinfo, "autoweapon"); + if (strlen(s)) + { + ent->client->playerinfo.pers.autoweapon = atoi(s); + } + + // save off the userinfo in case we want to check something later + strncpy (ent->client->playerinfo.pers.userinfo, userinfo, sizeof(ent->client->playerinfo.pers.userinfo)-1); +} + + +/* +=========== +ClientConnect + +Called when a player begins connecting to the server. +The game can refuse entrance to a client by returning false. +If the client is allowed, the connection process will continue +and eventually get to ClientBegin() +Changing levels will NOT cause this to be called again. +============ +*/ +qboolean ClientConnect (edict_t *ent, char *userinfo, qboolean loadgame) +{ + char *value; + + // Check to see if they are on the banned IP list. + + value = Info_ValueForKey (userinfo, "ip"); + if (SV_FilterPacket(value)) + return false; + + // Check for a password. + + value = Info_ValueForKey (userinfo, "password"); + + if (strcmp(password->string, value) != 0) + return false; + + // Ok, they can connect. + + ent->client = game.clients + (ent - g_edicts - 1); + + // If there isn't already a body waiting for us (a loadgame), spawn one from scratch. otherwise, + // just take what's there already. + + if (ent->inuse == false) + { + // Clear the respawning variables. + + InitClientResp (ent->client); + + if (!ent->client->playerinfo.pers.weapon) + { + InitClientPersistant (ent); + + // This is the very frist time that this player has entered the game (be it single player, + // coop or deathmatch) so we want to do a complete reset of the player's model. + + ent->client->complete_reset=1; + } + } + else + { + // The player has a body waiting from a (just) loaded game, so we want to do just a partial + // reset of the player's model. + + ent->client->complete_reset=0; + } + + ClientUserinfoChanged (ent, userinfo); + + if (game.maxclients > 1) + gi.dprintf ("%s connected\n", ent->client->playerinfo.pers.netname); + + ent->client->playerinfo.pers.connected = true; + + return true; +} + +/* +=========== +ClientDisconnect + +called when a player drops from the server +============ +*/ +void ClientDisconnect (edict_t *ent) +{ + int playernum; + + if (!ent->client) + return; + + // Inform other players that the disconnecting client has left the game. + + gi.Obituary (PRINT_HIGH, GM_DISCON, ent->s.number, 0); + + // Do the teleport sound. + + gi.sound(ent,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + + // Send teleport effect. + + gi.CreateEffect(&ent->s, FX_PLAYER_TELEPORT_OUT, CEF_OWNERS_ORIGIN, ent->s.origin, NULL); + + // Clean up after leaving. + + if (ent->Leader_PersistantCFX) + { + gi.RemovePersistantEffect(ent->Leader_PersistantCFX); + gi.RemoveEffects(&ent->s, FX_SHOW_LEADER); + ent->Leader_PersistantCFX =0; + } + + gi.unlinkentity (ent); + ent->s.modelindex = 0; + ent->solid = SOLID_NOT; + ent->inuse = false; + ent->classname = "disconnected"; + ent->client->playerinfo.pers.connected = false; + playernum = ent-g_edicts-1; + gi.configstring (CS_PLAYERSKINS+playernum, ""); + + // redo the leader effect cos this guy has gone, and he might have had it. + player_leader_effect(); +} + +//============================================================== + +edict_t *pm_passent; + +// The pmove() routine doesn't need to know about passent and contentmask. + +void PM_trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end,trace_t *trace) +{ + // NOTENOTE All right, pmove doesn't need to know the gory details, but I need to be able to detect a water surface, bub. + // Hence, if the mins and max are NULL, then wask out water (cheezy I know, but blame me) ---Pat + + if (mins == NULL && maxs == NULL) + { + gi.trace (start, vec3_origin, vec3_origin, end, pm_passent, MASK_PLAYERSOLID | MASK_WATER,trace); + } + else if (pm_passent->health > 0) + { + gi.trace (start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID,trace); + } + else + { + gi.trace (start, mins, maxs, end, pm_passent, MASK_DEADSOLID,trace); + } +} + +unsigned CheckBlock (void *b, int c) +{ + int v,i; + v = 0; + for (i=0 ; is, sizeof(pm->s)); + c2 = CheckBlock (&pm->cmd, sizeof(pm->cmd)); +} + +/* +// ============== +// ClientThink +// ----------- +// This will be called once for each client-frame received from a client. So during a server frame, +// for a given client, ClientThink() probably be called several times, +// ============== +*/ +extern edict_t *TestEntityPosition(edict_t *self); + +void ClientThink (edict_t *ent, usercmd_t *ucmd) +{ + gclient_t *client; + edict_t *other; + int i, j; + pmove_t pm; + vec3_t LOSOrigin,ang; + float knockback; + edict_t *TargetEnt; + + level.current_entity = ent; + client = ent->client; + + CheckContinuousAutomaticEffects(ent); + + // ******************************************************************************************** + // Handle an active intermission. + // ******************************************************************************************** + + if (level.intermissiontime) + { + client->ps.pmove.pm_type = PM_INTERMISSION; + + // Can exit intermission after five seconds + + if (level.time > level.intermissiontime + 5.0 && (ucmd->buttons & BUTTON_ANY) ) + level.exitintermission = true; + + return; + } + + // ******************************************************************************************** + // Movement stuff. + // ******************************************************************************************** + + if (ent->movetype == PHYSICSTYPE_NOCLIP) + client->ps.pmove.pm_type = PM_SPECTATOR; + else if ((ent->s.modelindex != 255) && !(ent->flags & FL_CHICKEN)) // We're not set as a chicken + client->ps.pmove.pm_type = PM_GIB; + else if (ent->deadflag) + client->ps.pmove.pm_type = PM_DEAD; + else + client->ps.pmove.pm_type = PM_NORMAL; + + client->ps.pmove.gravity = sv_gravity->value; + + //If we are not currently on a rope, then clear out any ropes as valid for a check + if (!(client->playerinfo.flags & PLAYER_FLAG_ONROPE)) + { + ent->targetEnt = NULL; + } + + // If we are turn-locked, then set the PMF_LOCKTURN flag that informs the client of this (the + // client-side camera needs to know). + + if ((client->playerinfo.flags & PLAYER_FLAG_TURNLOCK) && (client->ps.pmove.pm_type == PM_NORMAL)) + { + client->ps.pmove.pm_flags|=PMF_LOCKTURN; + } + else + { + client->playerinfo.turncmd+=SHORT2ANGLE(ucmd->angles[YAW]-client->oldcmdangles[YAW]); + client->ps.pmove.pm_flags&=~PMF_LOCKTURN; + } + + if (client->playerinfo.flags & PLAYER_FLAG_TURN180) + { + client->ps.pmove.pm_flags |= PMF_JUMP_HELD; + } + else + { + client->ps.pmove.pm_flags &= ~PMF_JUMP_HELD; + } + + // Save the cmd->angles away so we may calculate the delta (on client->turncmd above) in the + // next frame. + + client->oldcmdangles[0]=ucmd->angles[0]; + client->oldcmdangles[1]=ucmd->angles[1]; + client->oldcmdangles[2]=ucmd->angles[2]; + + // If we are move-locked, don't move. As a side effect, this will also prevent us touching / + // triggering things (so may be a BAD thing). FIXME?? + + pm_passent = ent; + + // Set up inputs for a Pmove(). + + memset (&pm, 0, sizeof(pm)); + + pm.s = client->ps.pmove; + + for (i=0 ; i<3 ; i++) + { + pm.s.origin[i] = ent->s.origin[i]*8; + pm.s.velocity[i] = ent->velocity[i]*8; + } + + if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s))) + { + pm.snapinitial = true; + } + + pm.cmd = *ucmd; + client->pcmd = *ucmd; + + if (ent->movetype != PHYSICSTYPE_NOCLIP) + { + pm.cmd.forwardmove = client->playerinfo.fwdvel; + pm.cmd.sidemove = client->playerinfo.sidevel; + pm.cmd.upmove = client->playerinfo.upvel; + } + + if(client->RemoteCameraLockCount>0) + { + pm.cmd.forwardmove =0; + pm.cmd.sidemove = 0; + pm.cmd.upmove = 0; + } + + // Input the DESIRED waterheight. + // FIXME: This should be retrieved from the animation frame eventually. + + pm.desiredWaterHeight = 15.00; + pm.waterheight = client->playerinfo.waterheight; + pm.waterlevel = ent->waterlevel; + pm.viewheight = ent->viewheight; + pm.watertype = ent->watertype; + pm.groundentity = ent->groundentity; + + // This is a scale of 0 to 1 describing how much knockback to take into account. + + knockback = client->playerinfo.knockbacktime - level.time; + if (knockback > 1.0) + knockback = 1.0; + else if (knockback < 0.0) + knockback = 0.0; + pm.knockbackfactor = knockback; + + // Handle lockmove cases. + + if((client->playerinfo.flags&(PLAYER_FLAG_LOCKMOVE_WAS_SET|PLAYER_FLAG_USE_ENT_POS))&&!(client->ps.pmove.pm_flags&PMF_LOCKMOVE)) + { + // Lockmove was set last frame, but isn't now, so we copy the player edict's origin and + // velocity values to the client for use in Pmove(). NOTE: Pmove() on the SERVER needs + // pointers to specify vectors to be read and written for the origin and velocity. So + // be careful if you screw around with this crazy code. + + client->playerinfo.flags &= ~PLAYER_FLAG_USE_ENT_POS; + + VectorCopy(ent->s.origin, client->playerinfo.origin); + VectorCopy(ent->velocity, client->playerinfo.velocity); + } + + // Check to add into movement velocity through crouch and duck if underwater. + + if (!ent->deadflag && ent->waterlevel > 2) + { + // NOTENOTE: If they're pressing both, nullify it. + + if (client->playerinfo.seqcmd[ACMDL_CROUCH]) + { + client->playerinfo.velocity[2] -= SWIM_ADJUST_AMOUNT; + } + + if (client->playerinfo.seqcmd[ACMDL_JUMP]) + { + client->playerinfo.velocity[2] += SWIM_ADJUST_AMOUNT; + } + } + else if (!ent->deadflag && ent->waterlevel > 1) // On the surface trying to go down??? + { + // NOTENOTE: If they're pressing both, nullify it. + + if (client->playerinfo.seqcmd[ACMDL_CROUCH]) + { + pm.s.w_flags |= WF_SINK; + client->playerinfo.velocity[2] -= SWIM_ADJUST_AMOUNT; + } + + if (client->playerinfo.seqcmd[ACMDL_JUMP]) + { + client->playerinfo.velocity[2] += SWIM_ADJUST_AMOUNT; + } + } + + pm.origin = client->playerinfo.origin; + pm.velocity = client->playerinfo.velocity; + + // If not the chicken, and not explicitly resizing the bounding box... + + if ( (!(client->playerinfo.edictflags & FL_CHICKEN)) && (!(client->playerinfo.flags & PLAYER_FLAG_RESIZED)) ) + { + // Resize the player's bounding box. + + VectorCopy(mins, ent->intentMins); + VectorCopy(maxs, ent->intentMaxs); + + ent->physicsFlags |= PF_RESIZE; + + pm.intentMins = ent->intentMins; + pm.intentMaxs = ent->intentMaxs; + } + else + { + // Otherwise we don't want to resize. + + if ( (client->playerinfo.edictflags & FL_AVERAGE_CHICKEN) ) + { + VectorSet(ent->mins,-8,-8,-14); + VectorSet(ent->maxs,8,8,14); + } + else if ( (client->playerinfo.edictflags & FL_SUPER_CHICKEN) ) + { + VectorSet(ent->mins,-16,-16,-36); + VectorSet(ent->maxs,16,16,36); + } + + pm.intentMins = ent->mins; + pm.intentMaxs = ent->maxs; + } + + pm.GroundSurface = client->playerinfo.GroundSurface; + pm.GroundPlane = client->playerinfo.GroundPlane; + pm.GroundContents = client->playerinfo.GroundContents; + + pm.self = ent; + + pm.trace = PM_trace; // Adds default parms. + pm.pointcontents = gi.pointcontents; + + pm.viewheight = ent->viewheight; + + VectorCopy(ent->mins, pm.mins); + VectorCopy(ent->maxs, pm.maxs); + + // Perform a Pmove(). + + gi.Pmove(&pm, true); + + if(ent->waterlevel) + client->playerinfo.flags |= FL_INWATER; + else + client->playerinfo.flags &= ~FL_INWATER; + + client->playerinfo.flags &= ~(PLAYER_FLAG_COLLISION | PLAYER_FLAG_SLIDE); + + if (pm.s.c_flags & PC_COLLISION) + { + client->playerinfo.flags |= PLAYER_FLAG_COLLISION; + } + + if ((pm.s.c_flags & PC_SLIDING)) + { + client->playerinfo.flags |= PLAYER_FLAG_SLIDE; + + if(Vec3NotZero(pm.GroundPlane.normal)) + { + vectoangles(pm.GroundPlane.normal, ang); + ent->ideal_yaw = ang[YAW]; + } + } + else if (pm.s.w_flags & WF_DIVE) + { + client->playerinfo.flags |= PLAYER_FLAG_DIVE; + } + + // Save the results of the above Pmove(). + + client->ps.pmove = pm.s; + client->old_pmove = pm.s; + + client->playerinfo.GroundSurface=pm.GroundSurface; + memcpy(&client->playerinfo.GroundPlane,&pm.GroundPlane,sizeof(cplane_t)); + client->playerinfo.GroundContents=pm.GroundContents; + + // If we're move-locked, don't update the edict's origin and velocity, otherwise copy the + // origin and velocity from playerinfo (which have been written by Pmove()) into the edict's + // origin and velocity. + + if((client->ps.pmove.pm_flags&PMF_LOCKMOVE)) + { + client->playerinfo.flags |= PLAYER_FLAG_LOCKMOVE_WAS_SET; + } + else + { + client->playerinfo.flags &= ~PLAYER_FLAG_LOCKMOVE_WAS_SET; + + VectorCopy(client->playerinfo.origin, ent->s.origin); + VectorCopy(client->playerinfo.velocity, ent->velocity); + } + + // Update other player stuff. + + VectorCopy(pm.mins, ent->mins); + VectorCopy(pm.maxs, ent->maxs); + + client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]); + client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); + client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); + + client->playerinfo.waterlevel = pm.waterlevel; + client->playerinfo.waterheight = pm.waterheight; + client->playerinfo.watertype = pm.watertype; + + + ent->waterlevel = pm.waterlevel; + ent->viewheight = pm.viewheight; + ent->watertype = pm.watertype; + ent->groundentity = pm.groundentity; + + if (pm.groundentity) + { + ent->groundentity_linkcount = pm.groundentity->linkcount; + } + + if(!ent->deadflag) + { + VectorCopy(pm.viewangles,client->v_angle); + + client->aimangles[0]=SHORT2ANGLE(ucmd->aimangles[0]); + client->aimangles[1]=SHORT2ANGLE(ucmd->aimangles[1]); + client->aimangles[2]=SHORT2ANGLE(ucmd->aimangles[2]); + + VectorCopy(client->aimangles,client->ps.viewangles); + } + + gi.linkentity (ent); + + // Process touch triggers that the client could activate. + + if (ent->movetype != PHYSICSTYPE_NOCLIP) + G_TouchTriggers (ent); + + // Touch other objects. + + for (i=0 ; itouch) + continue; + other->touch (other, ent, NULL, NULL); + } + + client->playerinfo.oldbuttons = client->playerinfo.buttons; + client->playerinfo.buttons = ucmd->buttons; + client->playerinfo.latched_buttons |= client->playerinfo.buttons & ~client->playerinfo.oldbuttons; + client->playerinfo.remember_buttons |= client->playerinfo.buttons; + + // Save the light level that the player is standing on for monster sighting AI. + + ent->light_level = ucmd->lightlevel; + + // ******************************************************************************************** + // Handle autotargeting by looking for the nearest monster that: + // a) Lies in a 35 degree degree horizontal, 180 degree vertical cone from the player's facing. + // b) Lies within 0 to 500 meters of the player. + // c) Is visible (i.e. LOS exists from player to target). + // ******************************************************************************************** + + // Get the origin of the LOS (from player to target) used in identifying potential targets. + + VectorCopy(ent->s.origin,LOSOrigin); + LOSOrigin[2]+=ent->viewheight; + + // Handle autotaiming etc. + + TargetEnt=ent->enemy=NULL; + client->ps.AutotargetEntityNum=0; + + if(client->playerinfo.autoaim) + { + // Autoaiming is active so look for an enemy to autotarget. + + TargetEnt=FindNearestVisibleActorInFrustum(ent, + ent->client->aimangles, + 0.0,500.0, + 35*ANGLE_TO_RAD,160*ANGLE_TO_RAD, + SVF_MONSTER, + LOSOrigin, + NULL,NULL); + if(TargetEnt!=NULL) + { + // An enemy was successfully autotargeted, so store away the pointer to our enemy + // and inform the the client so that the client-side camera may go into combat mode. + + ent->enemy=TargetEnt; + client->ps.AutotargetEntityNum=ent->enemy->s.number; + } +/* + // Didn't autotarget an enemy, so look around for annother nearby enemy so the client-side + // camera can go into combat mode. NOTE: We take 'ent->s.angles' as our base orientation as + // it gives smoother looking results for one for thing. + + if(TargetEnt==NULL) + { + TargetEnt=FindNearestVisibleActorInFrustum(ent, + ent->s.angles, + 0.0,500.0, + 180*ANGLE_TO_RAD,160*ANGLE_TO_RAD, + SVF_MONSTER, + LOSOrigin, + NULL,NULL); + if(TargetEnt!=NULL) + { + client->ps.AutotargetEntityNum=-TargetEnt->s.number; + } + } +*/ + } + + CalculatePIV(ent); +} + +/* +============== +ClientBeginServerFrame + +This will be called once for each server frame, before running +any other entities in the world. +============== +*/ +void ClientBeginServerFrame (edict_t *ent) +{ + gclient_t *client; + int buttonMask; + + if (level.intermissiontime) + return; + + client = ent->client; + + if (ent->deadflag & DEAD_DEAD) + { + // Wait for any button just going down. + + if ( level.time > client->respawn_time) + { + // In deathmatch, only wait for attack button. + + if (deathmatch->value) + buttonMask = BUTTON_ATTACK; + else + buttonMask = -1; + + if ( ( client->playerinfo.latched_buttons & buttonMask ) || + (deathmatch->value && ((int)dmflags->value & DF_FORCE_RESPAWN) ) ) + { + respawn(ent); + + client->playerinfo.latched_buttons = 0; + } + } + return; + } + + client->playerinfo.latched_buttons = 0; +} diff --git a/Toolkit/Programming/GameCode/game/p_funcs.c b/Toolkit/Programming/GameCode/game/p_funcs.c new file mode 100644 index 0000000..89041aa --- /dev/null +++ b/Toolkit/Programming/GameCode/game/p_funcs.c @@ -0,0 +1,1399 @@ +// p_funcs.c +// +// Heretic II - Raven software +// +// Written by Marcus Whitlock +// + +#include "p_funcs.h" +#include "p_animactor.h" +#include "p_anims2.h" +#include "p_ctrl2.h" +#include "p_funcs.h" +#include "p_main2.h" +#include "p_weapon.h" +#include "g_local.h" +#include "g_Skeletons.h" +#include "g_teleport.h" +#include "angles.h" +#include "fx.h" +#include "random.h" +#include "vector.h" +#include "utilities.h" +#include "g_playstats.h" +#include "p_weapon2.h" + +// ************************************************************************************************ +// G_GetEntityStatePtr +// ------------------- +// ************************************************************************************************ + +entity_state_t *G_GetEntityStatePtr(edict_t *entity) +{ + return(&entity->s); +} + +void PlayerClimbSound(playerinfo_t *playerinfo, char *name) +{ + if(playerinfo->isclient) + { + playerinfo->CL_Sound( playerinfo->origin, + CHAN_VOICE, + name, + 0.75, + ATTN_NORM, + 0); + } + else + { + playerinfo->G_Sound( playerinfo->self, + CHAN_VOICE, + playerinfo->G_SoundIndex(name), + 0.75, + ATTN_NORM, + 0); + } +} + +// ************************************************************************************************ +// G_PlayerActionCheckRopeMove +// ------------------- +// ************************************************************************************************ + +void G_PlayerActionCheckRopeMove(playerinfo_t *playerinfo) +{ + vec3_t vr,vf; + int chance = irand(0,3); + float threshold; + + if ( (playerinfo->seqcmd[ACMDL_JUMP]) ) + { + playerinfo->flags &= ~PLAYER_FLAG_ONROPE; + VectorCopy(((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity,playerinfo->velocity); + threshold = VectorLengthSquared(playerinfo->velocity); + + if (threshold < 300*300) + { + AngleVectors(playerinfo->aimangles, vf, NULL, NULL); + VectorMA(playerinfo->velocity, 200, vf, playerinfo->velocity); + } + else + { + VectorScale(playerinfo->velocity,0.75,playerinfo->velocity); + } + + playerinfo->velocity[2]=250.0; + playerinfo->flags |= PLAYER_FLAG_USE_ENT_POS; + + ((edict_t *)playerinfo->self)->monsterinfo.jump_time = playerinfo->leveltime + 2; + + ((edict_t *)playerinfo->self)->targetEnt->rope_grab->s.effects &= ~EF_ALTCLIENTFX; + ((edict_t *)playerinfo->self)->targetEnt->enemy = NULL; + ((edict_t *)playerinfo->self)->targetEnt = NULL; + + PlayerAnimSetUpperSeq(playerinfo, ASEQ_NONE); + PlayerAnimSetLowerSeq(playerinfo, ASEQ_JUMPFWD); + + return; + } + + if (playerinfo->seqcmd[ACMDL_STRAFE_L]) + { + AngleVectors(playerinfo->angles, NULL, vr, NULL); + VectorScale(vr, -32, vr); + VectorAdd(((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity,vr,((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity); + + switch (playerinfo->lowerseq) + { + case ASEQ_CLIMB_HOLD_R: + case ASEQ_CLIMB_SETTLE_R: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + break; + + case ASEQ_CLIMB_ON: + case ASEQ_CLIMB_HOLD_L: + case ASEQ_CLIMB_SETTLE_L: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + break; + } + } + else if (playerinfo->seqcmd[ACMDL_STRAFE_R]) + { + AngleVectors(playerinfo->angles, NULL, vr, NULL); + VectorScale(vr, 32, vr); + VectorAdd(((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity,vr,((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity); + + switch (playerinfo->lowerseq) + { + case ASEQ_CLIMB_HOLD_R: + case ASEQ_CLIMB_SETTLE_R: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + break; + + case ASEQ_CLIMB_ON: + case ASEQ_CLIMB_HOLD_L: + case ASEQ_CLIMB_SETTLE_L: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + break; + } + } +} + +// ************************************************************************************************ +// G_BranchLwrClimbing +// ------------------- +// ************************************************************************************************ + +int G_BranchLwrClimbing(playerinfo_t *playerinfo) +{ + trace_t trace; + vec3_t vr, endpoint, playermin, playermax, vf; + int chance = irand(0,3); + + assert(playerinfo); + + if (playerinfo->seqcmd[ACMDU_ATTACK]) + { + if (((edict_t *)playerinfo->self)->targetEnt->rope_grab->monsterinfo.jump_time < level.time) + { + ((edict_t *)playerinfo->self)->targetEnt->rope_grab->monsterinfo.jump_time = level.time + 2; + AngleVectors(playerinfo->angles, vf, NULL, NULL); + VectorMA(vf, 400, vf, vf); + VectorAdd(((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity,vf,((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity); + } + } + + if (playerinfo->seqcmd[ACMDL_STRAFE_L]) + { + if (((edict_t *)playerinfo->self)->targetEnt->rope_grab->monsterinfo.search_time < level.time) + { + ((edict_t *)playerinfo->self)->targetEnt->rope_grab->monsterinfo.search_time = level.time + 2; + + AngleVectors(playerinfo->angles, NULL, vr, NULL); + VectorScale(vr, -64, vr); + VectorAdd(((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity,vr,((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity); + + switch (playerinfo->lowerseq) + { + case ASEQ_CLIMB_HOLD_R: + case ASEQ_CLIMB_SETTLE_R: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + return ASEQ_CLIMB_HOLD_R; + break; + + case ASEQ_CLIMB_ON: + case ASEQ_CLIMB_HOLD_L: + case ASEQ_CLIMB_SETTLE_L: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + return ASEQ_CLIMB_HOLD_L; + break; + } + } + } + else if (playerinfo->seqcmd[ACMDL_STRAFE_R]) + { + if (((edict_t *)playerinfo->self)->targetEnt->rope_grab->monsterinfo.flee_finished < level.time) + { + ((edict_t *)playerinfo->self)->targetEnt->rope_grab->monsterinfo.flee_finished = level.time + 2; + + AngleVectors(playerinfo->angles, NULL, vr, NULL); + VectorScale(vr, 64, vr); + VectorAdd(((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity,vr,((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity); + + switch (playerinfo->lowerseq) + { + case ASEQ_CLIMB_HOLD_R: + case ASEQ_CLIMB_SETTLE_R: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + return ASEQ_CLIMB_HOLD_R; + break; + + case ASEQ_CLIMB_ON: + case ASEQ_CLIMB_HOLD_L: + case ASEQ_CLIMB_SETTLE_L: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + return ASEQ_CLIMB_HOLD_L; + break; + } + } + } + + if (playerinfo->seqcmd[ACMDL_FWD]) + { + VectorCopy(playerinfo->origin, endpoint); + endpoint[2] += 32; + + VectorCopy(playerinfo->mins, playermin); + VectorCopy(playerinfo->maxs, playermax); + + playerinfo->G_Trace(playerinfo->origin, playermin, playermax, endpoint, playerinfo->self, MASK_PLAYERSOLID,&trace); + + if (trace.fraction < 1.0) + { + // We bumped into something. + + ((edict_t *)playerinfo->self)->targetEnt->rope_grab->viewheight = ((edict_t *)playerinfo->self)->targetEnt->rope_grab->accel; + + switch (playerinfo->lowerseq) + { + case ASEQ_CLIMB_HOLD_R: + case ASEQ_CLIMB_SETTLE_R: + return ASEQ_CLIMB_HOLD_R; + break; + + case ASEQ_CLIMB_ON: + case ASEQ_CLIMB_HOLD_L: + case ASEQ_CLIMB_SETTLE_L: + return ASEQ_CLIMB_HOLD_L; + break; + + case ASEQ_CLIMB_UP_L: + case ASEQ_CLIMB_DOWN_R: + case ASEQ_CLIMB_UP_START_L: + case ASEQ_CLIMB_DOWN_START_L: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + return ASEQ_CLIMB_SETTLE_R; + break; + + case ASEQ_CLIMB_UP_R: + case ASEQ_CLIMB_DOWN_L: + case ASEQ_CLIMB_UP_START_R: + case ASEQ_CLIMB_DOWN_START_R: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + return ASEQ_CLIMB_SETTLE_L; + break; + } + } + + switch( playerinfo->lowerseq ) + { + case ASEQ_CLIMB_UP_R: + case ASEQ_CLIMB_UP_START_R: + if (chance == 0) + PlayerClimbSound(playerinfo, "player/ropeclimb1.wav"); + else if (chance == 1) + PlayerClimbSound(playerinfo, "player/ropeclimb2.wav"); + + return ASEQ_CLIMB_UP_L; + break; + + case ASEQ_CLIMB_UP_L: + case ASEQ_CLIMB_UP_START_L: + if (chance == 0) + PlayerClimbSound(playerinfo, "player/ropeclimb1.wav"); + else if (chance == 1) + PlayerClimbSound(playerinfo, "player/ropeclimb2.wav"); + + return ASEQ_CLIMB_UP_R; + break; + + case ASEQ_CLIMB_ON: + case ASEQ_CLIMB_DOWN_L: + case ASEQ_CLIMB_HOLD_L: + case ASEQ_CLIMB_SETTLE_L: + case ASEQ_CLIMB_DOWN_START_L: + if (chance == 0) + PlayerClimbSound(playerinfo, "player/ropeclimb1.wav"); + else if (chance == 1) + PlayerClimbSound(playerinfo, "player/ropeclimb2.wav"); + + return ASEQ_CLIMB_UP_START_L; + break; + + case ASEQ_CLIMB_DOWN_R: + case ASEQ_CLIMB_HOLD_R: + case ASEQ_CLIMB_SETTLE_R: + case ASEQ_CLIMB_DOWN_START_R: + if (chance == 0) + PlayerClimbSound(playerinfo, "player/ropeclimb1.wav"); + else if (chance == 1) + PlayerClimbSound(playerinfo, "player/ropeclimb2.wav"); + + return ASEQ_CLIMB_UP_START_R; + break; + } + } + else if (playerinfo->seqcmd[ACMDL_BACK]) + { + VectorCopy(playerinfo->origin, endpoint); + endpoint[2] -= 32; + + VectorCopy(playerinfo->mins, playermin); + VectorCopy(playerinfo->maxs, playermax); + + playerinfo->G_Trace(playerinfo->origin, playermin, playermax, endpoint, playerinfo->self, MASK_PLAYERSOLID,&trace); + + if (trace.fraction < 1.0 || trace.endpos[2] < ((edict_t *)playerinfo->self)->targetEnt->rope_end->s.origin[2]) + { + // We bumped into something or have come to the end of the rope + + ((edict_t *)playerinfo->self)->targetEnt->rope_grab->viewheight = ((edict_t *)playerinfo->self)->targetEnt->rope_grab->accel; + + switch (playerinfo->lowerseq) + { + + case ASEQ_CLIMB_HOLD_R: + case ASEQ_CLIMB_SETTLE_R: + return ASEQ_CLIMB_HOLD_R; + break; + + case ASEQ_CLIMB_ON: + case ASEQ_CLIMB_HOLD_L: + case ASEQ_CLIMB_SETTLE_L: + return ASEQ_CLIMB_HOLD_L; + break; + + case ASEQ_CLIMB_UP_L: + case ASEQ_CLIMB_DOWN_R: + case ASEQ_CLIMB_UP_START_L: + case ASEQ_CLIMB_DOWN_START_L: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + + return ASEQ_CLIMB_SETTLE_R; + break; + + case ASEQ_CLIMB_UP_R: + case ASEQ_CLIMB_DOWN_L: + case ASEQ_CLIMB_UP_START_R: + case ASEQ_CLIMB_DOWN_START_R: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + + return ASEQ_CLIMB_SETTLE_L; + break; + } + } + + switch( playerinfo->lowerseq ) + { + case ASEQ_CLIMB_DOWN_R: + case ASEQ_CLIMB_DOWN_START_R: + if (chance == 0) + PlayerClimbSound(playerinfo, "player/ropeclimb1.wav"); + else if (chance == 1) + PlayerClimbSound(playerinfo, "player/ropeclimb2.wav"); + + return ASEQ_CLIMB_DOWN_L; + break; + + case ASEQ_CLIMB_DOWN_L: + case ASEQ_CLIMB_DOWN_START_L: + if (chance == 0) + PlayerClimbSound(playerinfo, "player/ropeclimb1.wav"); + else if (chance == 1) + PlayerClimbSound(playerinfo, "player/ropeclimb2.wav"); + + return ASEQ_CLIMB_DOWN_R; + break; + + case ASEQ_CLIMB_ON: + case ASEQ_CLIMB_UP_L: + case ASEQ_CLIMB_HOLD_R: + case ASEQ_CLIMB_SETTLE_L: + case ASEQ_CLIMB_UP_START_L: + if (chance == 0) + PlayerClimbSound(playerinfo, "player/ropeclimb1.wav"); + else if (chance == 1) + PlayerClimbSound(playerinfo, "player/ropeclimb2.wav"); + + return ASEQ_CLIMB_DOWN_START_L; + break; + + case ASEQ_CLIMB_HOLD_L: + case ASEQ_CLIMB_UP_R: + case ASEQ_CLIMB_SETTLE_R: + case ASEQ_CLIMB_UP_START_R: + if (chance == 0) + PlayerClimbSound(playerinfo, "player/ropeclimb1.wav"); + else if (chance == 1) + PlayerClimbSound(playerinfo, "player/ropeclimb2.wav"); + + return ASEQ_CLIMB_DOWN_START_R; + break; + } + } + else if ( (playerinfo->seqcmd[ACMDL_JUMP]) ) + { + playerinfo->flags &= ~PLAYER_FLAG_ONROPE; + VectorCopy(((edict_t *)playerinfo->self)->targetEnt->rope_grab->velocity,playerinfo->velocity); + playerinfo->velocity[2]=150.0; + playerinfo->flags |= PLAYER_FLAG_USE_ENT_POS; + + ((edict_t *)playerinfo->self)->monsterinfo.jump_time = playerinfo->leveltime + 2; + + ((edict_t *)playerinfo->self)->targetEnt->rope_grab->s.effects &= ~EF_ALTCLIENTFX; + ((edict_t *)playerinfo->self)->targetEnt->enemy = NULL; + ((edict_t *)playerinfo->self)->targetEnt = NULL; + + PlayerAnimSetUpperSeq(playerinfo, ASEQ_NONE); + + return ASEQ_JUMPFWD; + } + else + { + switch (playerinfo->lowerseq) + { + case ASEQ_CLIMB_HOLD_R: + case ASEQ_CLIMB_SETTLE_R: + return ASEQ_CLIMB_HOLD_R; + break; + + case ASEQ_CLIMB_ON: + case ASEQ_CLIMB_HOLD_L: + case ASEQ_CLIMB_SETTLE_L: + return ASEQ_CLIMB_HOLD_L; + break; + + case ASEQ_CLIMB_UP_L: + case ASEQ_CLIMB_DOWN_R: + case ASEQ_CLIMB_UP_START_L: + case ASEQ_CLIMB_DOWN_START_L: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + return ASEQ_CLIMB_SETTLE_R; + break; + + case ASEQ_CLIMB_UP_R: + case ASEQ_CLIMB_DOWN_L: + case ASEQ_CLIMB_UP_START_R: + case ASEQ_CLIMB_DOWN_START_R: + if (irand(0,1)) + PlayerClimbSound(playerinfo, "player/ropeto.wav"); + else + PlayerClimbSound(playerinfo, "player/ropefro.wav"); + + return ASEQ_CLIMB_SETTLE_L; + break; + } + } + + return(ASEQ_NONE); +} + +// ************************************************************************************************ +// G_PlayerActionCheckRopeGrab +// --------------------------- +// ************************************************************************************************ + +qboolean G_PlayerActionCheckRopeGrab(playerinfo_t *playerinfo, float stomp_org) +{ + edict_t *rope; + trace_t trace; + vec3_t rope_end, rope_top, rope_check, vec; + float len, dist; + int check_dist = 48; + + assert(playerinfo); + + if (playerinfo->groundentity == NULL) + check_dist = 64; + + rope = (edict_t *)playerinfo->targetEnt; + + //Get the position of the rope's end + VectorCopy(rope->rope_end->s.origin, rope_end); + + VectorCopy(rope->s.origin, rope_top); + rope_top[2] += rope->maxs[2]; + + //If we're above the rope then we can't grab it + if (playerinfo->origin[2] > rope_top[2]) + { + //((edict_t *)playerinfo->self)->targetEnt = NULL; + return false; + } + + VectorSubtract(playerinfo->origin, rope_top, vec); + len = VectorLength(vec); + + VectorSubtract(rope_end, rope_top, vec); + dist = VectorNormalize(vec); + + //Player is below the rope's length + if (len > dist) + { + //((edict_t *)playerinfo->self)->targetEnt = NULL; + return false; + } + + VectorMA(rope_top, len, vec, rope_check); + + dist = vhlen(playerinfo->origin, rope_check); + + if (dist < check_dist) + { + // Player is getting on the rope for the first time. + + if (!(playerinfo->flags & PLAYER_FLAG_ONROPE)) + { + VectorCopy(playerinfo->velocity,((edict_t *)playerinfo->targetEnt)->rope_grab->velocity); + VectorScale(((edict_t *)playerinfo->targetEnt)->rope_grab->velocity,2,((edict_t *)playerinfo->targetEnt)->rope_grab->velocity); + VectorClear(playerinfo->velocity); + VectorCopy(playerinfo->origin,((edict_t *)playerinfo->targetEnt)->rope_grab->s.origin); + VectorSubtract(playerinfo->origin,rope_top,vec); + rope->rope_grab->viewheight=VectorLength(vec); + } + else + { + playerinfo->G_Trace(playerinfo->origin, + playerinfo->mins, + playerinfo->maxs, + ((edict_t *)playerinfo->targetEnt)->rope_grab->s.origin, + playerinfo->self, + MASK_PLAYERSOLID,&trace); + + if (trace.fraction < 1.0f || trace.startsolid || trace.allsolid) + return false; + + VectorCopy(((edict_t *)playerinfo->targetEnt)->rope_grab->s.origin, playerinfo->origin); + } + + return true; + } + + //((edict_t *)playerinfo->self)->targetEnt = NULL; + return false; +} + +// ************************************************************************************************ +// G_PlayerClimbingMoveFunc +// ------------------------ +// ************************************************************************************************ + +void G_PlayerClimbingMoveFunc(playerinfo_t *playerinfo, float height, float var2, float var3) +{ + if(!playerinfo->isclient) + { + // Pull Corvus into the rope. + G_PlayerActionCheckRopeGrab(playerinfo,1); + + if (playerinfo->targetEnt) + { + //Update the rope's information about the player's position + ((edict_t *)playerinfo->targetEnt)->rope_grab->accel=((edict_t *)playerinfo->targetEnt)->rope_grab->viewheight; + ((edict_t *)playerinfo->targetEnt)->rope_grab->viewheight-=height; + } + } +} + +// ************************************************************************************************ +// G_PlayerActionCheckPuzzleGrab +// ----------------------------- +// ************************************************************************************************ + +qboolean G_PlayerActionCheckPuzzleGrab(playerinfo_t *playerinfo) +{ + vec3_t player_facing, + forward, + endpoint; + trace_t grabtrace; + + VectorCopy(playerinfo->angles,player_facing); + player_facing[PITCH]=player_facing[ROLL]=0; + AngleVectors(player_facing,forward,NULL,NULL); + VectorMA(playerinfo->origin,32,forward,endpoint); + + gi.trace(playerinfo->origin, + playerinfo->mins, + playerinfo->maxs, + endpoint, + (edict_t *)playerinfo->self, + MASK_PLAYERSOLID,&grabtrace); + + if((grabtrace.fraction==1)||(!grabtrace.ent)) + return(false); + + if(!grabtrace.ent->item) + return(false); + + if(grabtrace.ent->item->flags!=IT_PUZZLE) + return(false); + + playerinfo->targetEnt=grabtrace.ent; + + return(true); +} + +// ************************************************************************************************ +// G_PlayerActionTakePuzzle +// ------------------------ +// ************************************************************************************************ + +void G_PlayerActionTakePuzzle(playerinfo_t *playerinfo) +{ + if(((edict_t *)playerinfo->self)->targetEnt->use) + ((edict_t *)playerinfo->self)->targetEnt->use(((edict_t *)playerinfo->self)->targetEnt,((edict_t *)playerinfo->self),((edict_t *)playerinfo->self)); +} + +// ************************************************************************************************ +// G_PlayerActionUsePuzzle +// ----------------------- +// ************************************************************************************************ + +qboolean G_PlayerActionUsePuzzle(playerinfo_t *playerinfo) +{ + if (!((edict_t *)playerinfo->self)->target_ent) + return(false); + + if (strcmp(((edict_t *)playerinfo->self)->target_ent->classname,"trigger_playerusepuzzle")) + return(false); + + G_UseTargets(((edict_t *)playerinfo->self)->target_ent,((edict_t *)playerinfo->self)); + + return(true); +} + +// ************************************************************************************************ +// G_PlayerActionCheckPushPull_Ent +// ------------------------------- +// ************************************************************************************************ + +qboolean G_PlayerActionCheckPushPull_Ent(void *ent) +{ + if(!(strcmp(((edict_t *)ent)->classname,"func_train")==0)||!(((edict_t *)ent)->spawnflags&32)) + return(false); + else + return(true); +} + +// ************************************************************************************************ +// PushPull_stop +// ------------- +// ************************************************************************************************ + +void PushPull_stop(edict_t *self) +{ +/* + playerinfo_t *playerinfo; + + playerinfo=&self->target_ent->client->playerinfo; + + if((playerinfo->lowerseq!=ASEQ_PUSH)&&(playerinfo->lowerseq!=ASEQ_PULL)) + VectorClear(self->velocity); + else if (Vec3IsZero(self->target_ent->velocity)) + VectorClear(self->target_ent->velocity); +*/ +} + +// ************************************************************************************************ +// G_PlayerActionMoveItem +// ---------------------- +// ************************************************************************************************ + +void G_PlayerActionMoveItem(playerinfo_t *playerinfo,float distance) +{ + vec3_t player_facing,pushdir; + + VectorCopy(playerinfo->angles,player_facing); + player_facing[PITCH]=player_facing[ROLL]=0; + AngleVectors(player_facing, pushdir, NULL, NULL); + + VectorScale (pushdir, distance, ((edict_t *)playerinfo->target_ent)->velocity); + + ((edict_t *)(playerinfo->self))->target_ent->think = PushPull_stop; + ((edict_t *)(playerinfo->self))->target_ent->nextthink = level.time + 2 * FRAMETIME; + ((edict_t *)(playerinfo->self))->target_ent->target_ent = ((edict_t *)playerinfo->self); +} + +// ************************************************************************************************ +// G_PlayerActionCheckHitGround +// ------------------------ +// ************************************************************************************************ + +void G_PlayerActionCheckHitGround(playerinfo_t *playerinfo) +{ + trace_t trace; + vec3_t endpos; + + //FIXME: Add time debounce + + if (playerinfo->reflect_timer < playerinfo->leveltime) + PlayerAnimSetLowerSeq(playerinfo, ASEQ_DEATH_FLY1_END); + + VectorCopy(playerinfo->origin, endpos); + endpos[2] -= 8; + + gi.trace(playerinfo->origin, playerinfo->mins, playerinfo->maxs, endpos, (edict_t *)playerinfo->self, MASK_SOLID,&trace); + + if (trace.fraction < 1) + { + //We've hit the ground, finish the death animation + if (playerinfo->lowerseq == ASEQ_DEATH_FLY1_LOOP) + PlayerAnimSetLowerSeq(playerinfo, ASEQ_DEATH_FLY1_END); + } +} + +// ************************************************************************************************ +// G_PlayerActionCheckPushButton +// ----------------------------- +// ************************************************************************************************ + +#define MAX_PUSH_BUTTON_RANGE 80.0 + +qboolean G_PlayerActionCheckPushButton(playerinfo_t *playerinfo) +{ + edict_t *t; + vec3_t v,dir; + float len1, dot; + vec3_t forward; + + // Are you near a button? + + if(!((edict_t *)playerinfo->self)->target) + { + // No button so return. + + return false; + } + + // A button is nearby, so look to see if it's in reach. + + t = NULL; + t = G_Find(t,FOFS(targetname),((edict_t *)playerinfo->self)->target); + + if (!t) + return(false); + +// if (!(strcmp(t->classname,"func_train")==0)) + if (t->classID == CID_BUTTON) + { + // Get center of button + VectorAverage(t->mins, t->maxs, v); + // Get distance from player origin to center of button + Vec3SubtractAssign(playerinfo->origin, v); + len1 = VectorLength(v); + } + else + return(false); + + if (len1 < MAX_PUSH_BUTTON_RANGE) + { + VectorCopy(((edict_t *)playerinfo->self)->client->playerinfo.aimangles, dir); + dir[PITCH] = 0; + + AngleVectors(dir, forward, NULL, NULL); + VectorNormalize(v); + // Both these vectors are normalized so result is cos of angle + dot = DotProduct(v, forward); + + // 41 degree range either way + if (dot > 0.75) + return(true); + } + + return(false); +} + +// ************************************************************************************************ +// G_PlayerActionPushButton +// ------------------------ +// ************************************************************************************************ + +void G_PlayerActionPushButton(playerinfo_t *playerinfo) +{ + G_UseTargets((edict_t *)playerinfo->self,(edict_t *)playerinfo->self); +} + +// ************************************************************************************************ +// G_PlayerActionCheckPushLever +// ----------------------------- +// ************************************************************************************************ + +#define MAX_PUSH_LEVER_RANGE 80.0 + +qboolean G_PlayerActionCheckPushLever(playerinfo_t *playerinfo) +{ + edict_t *t; + vec3_t v,dir; + float len1, dot; + vec3_t forward; + edict_t *self; + + self = (edict_t *) playerinfo->self; + + // Are you near a lever? + + if(!(self->target)) + { + // No button so return. + + return false; + } + + // A button is nearby, so look to see if it's in reach. + + t = NULL; + t = G_Find(t,FOFS(targetname),self->target); + + if (!t) + return(false); + + if (t->classID == CID_LEVER) + { + // Get distance from player origin to center of lever + VectorSubtract(playerinfo->origin, t->s.origin,v); + len1 = VectorLength(v); + } + else + return(false); + + if (len1 < MAX_PUSH_LEVER_RANGE) + { + VectorCopy(((edict_t *)playerinfo->self)->client->playerinfo.aimangles, dir); + dir[PITCH] = 0; + + AngleVectors(dir, forward, NULL, NULL); + VectorSubtract (t->s.origin, self->s.origin, v); + VectorNormalize(v); + // Both these vectors are normalized so result is cos of angle + dot = DotProduct(v, forward); + + // 41 degree range either way + if (dot > 0.70) + return(true); + } + + return(false); +} + +// ************************************************************************************************ +// G_PlayerActionPushLever +// ------------------------ +// ************************************************************************************************ + +void G_PlayerActionPushLever(playerinfo_t *playerinfo) +{ + G_UseTargets((edict_t *)playerinfo->self,(edict_t *)playerinfo->self); +} + +// ************************************************************************************************ +// G_HandleTeleport +// ---------------- +// ************************************************************************************************ + +qboolean G_HandleTeleport(playerinfo_t *playerinfo) +{ + // Are we teleporting or morphing? + + if (playerinfo->flags & (PLAYER_FLAG_TELEPORT | PLAYER_FLAG_MORPHING)) + { + // Are we doing de-materialiZe or... + + if (((edict_t *)playerinfo->self)->client->tele_dest[0]!=-1) + { + // Are we done dematerialiZing? Or still fading? + + if (((edict_t *)playerinfo->self)->client->tele_count--) + { + ((edict_t *)playerinfo->self)->s.color.a -= TELE_FADE_OUT; + + return(true); + } + else + { + // We have finished dematerialiZing, let's move the character. + + if (playerinfo->flags & PLAYER_FLAG_TELEPORT) + { + Perform_Teleport((edict_t *)playerinfo->self); + } + else + { + if(playerinfo->edictflags & FL_CHICKEN) + { + // We're set as a chicken. + + reset_morph_to_elf((edict_t *)playerinfo->self); + } + else + { + Perform_Morph((edict_t *)playerinfo->self); + } + } + + return(true); + } + } + else + { + // Are we done dematerialiZing? Or still fading? + + if (((edict_t *)playerinfo->self)->client->tele_count--) + { + ((edict_t *)playerinfo->self)->s.color.a += TELE_FADE; + } + else + { + // We are done re-materialiZing, let's kill all this BS and get back to the game. + + if(playerinfo->flags & PLAYER_FLAG_TELEPORT) + CleanUpTeleport((edict_t *)playerinfo->self); + else + CleanUpMorph((edict_t *)playerinfo->self); + } + } + + if(!deathmatch->value) + return(true); + } + + return(false); +} + +// ************************************************************************************************ +// PlayerChickenDeath +// ------------------ +// ************************************************************************************************ + +void PlayerChickenDeath(edict_t *self) +{ + //FIXME: + + //gi.sound (self, CHAN_BODY, sounds[SND_GIB], 1, ATTN_NORM, 0); + self->deadflag = DEAD_DEAD; + self->client->playerinfo.deadflag = DEAD_DEAD; + gi.CreateEffect(&self->s, FX_CHICKEN_EXPLODE, CEF_OWNERS_ORIGIN, NULL, "" ); + + // fix that respawning bug + self->morph_timer = level.time -1; + + // Reset our thinking. + + self->think = self->oldthink; + self->nextthink = level.time + FRAMETIME; + +#ifdef COMP_FMOD + self->model = "models/player/elf/tris_c.fm"; +#else + self->model = "models/player/elf/tris.fm"; +#endif + self->pain = player_pain; + + // Reset our skins. + + self->s.effects = 0; + self->s.skinnum = self - g_edicts - 1; + self->s.modelindex = 255; // will use the skin specified model + self->s.frame = 0; + + // Turn our skeleton back on. + + self->s.skeletalType = SKEL_CORVUS; + self->s.effects |= (EF_SWAPFRAME|EF_JOINTED); + self->s.effects &= ~EF_CHICKEN; + self->flags &= ~FL_CHICKEN; + self->s.renderfx &= ~RF_IGNORE_REFS; + + // Reset our animations. + + PlayerAnimReset(&self->client->playerinfo); +} + +// ************************************************************************************************ +// G_SetJointAngles +// ------------------ +// Set the player model's joint angles. +// ************************************************************************************************ + +void G_SetJointAngles(playerinfo_t *playerinfo) +{ + edict_t *self; + + self=(edict_t *)playerinfo->self; + + SetJointAngVel(self->s.rootJoint+CORVUS_HEAD,PITCH,playerinfo->targetjointangles[PITCH],ANGLE_45); + SetJointAngVel(self->s.rootJoint+CORVUS_HEAD,ROLL,playerinfo->targetjointangles[YAW],ANGLE_45); + + if(!playerinfo->headjointonly) + { + SetJointAngVel(self->s.rootJoint+CORVUS_UPPERBACK,PITCH,playerinfo->targetjointangles[PITCH],ANGLE_45); + SetJointAngVel(self->s.rootJoint+CORVUS_LOWERBACK,PITCH,playerinfo->targetjointangles[PITCH],ANGLE_45); + SetJointAngVel(self->s.rootJoint+CORVUS_UPPERBACK,ROLL,playerinfo->targetjointangles[YAW],ANGLE_45); + SetJointAngVel(self->s.rootJoint+CORVUS_LOWERBACK,ROLL,playerinfo->targetjointangles[YAW],ANGLE_45); + } + else + { + SetJointAngVel(self->s.rootJoint+CORVUS_UPPERBACK,PITCH,0,ANGLE_45); + SetJointAngVel(self->s.rootJoint+CORVUS_LOWERBACK,PITCH,0,ANGLE_45); + SetJointAngVel(self->s.rootJoint+CORVUS_UPPERBACK,ROLL,0,ANGLE_45); + SetJointAngVel(self->s.rootJoint+CORVUS_LOWERBACK,ROLL,0,ANGLE_45); + } +} + +// ************************************************************************************************ +// G_ResetJointAngles +// ------------------ +// Reset the player model's joint angles. +// ************************************************************************************************ + +void G_ResetJointAngles(playerinfo_t *playerinfo) +{ + edict_t *self; + + self=(edict_t *)playerinfo->self; + + SetJointAngVel(self->s.rootJoint + CORVUS_HEAD,PITCH,0,ANGLE_45); + SetJointAngVel(self->s.rootJoint + CORVUS_UPPERBACK,PITCH,0,ANGLE_45); + SetJointAngVel(self->s.rootJoint + CORVUS_LOWERBACK,PITCH,0,ANGLE_45); + + SetJointAngVel(self->s.rootJoint + CORVUS_HEAD,ROLL,0,ANGLE_45); + SetJointAngVel(self->s.rootJoint + CORVUS_UPPERBACK,ROLL,0,ANGLE_45); + SetJointAngVel(self->s.rootJoint + CORVUS_LOWERBACK,ROLL,0,ANGLE_45); +} + +// ************************************************************************************************ +// G_PlayerActionChickenBite +// ------------------------- +// ************************************************************************************************ + +void G_PlayerActionChickenBite(playerinfo_t *playerinfo) +{ + trace_t trace; + vec3_t endpos, vf, mins; + + AngleVectors(playerinfo->aimangles, vf, NULL, NULL); + VectorMA(playerinfo->origin, 64, vf, endpos); + + + //Account for step height + VectorSet(mins, playerinfo->mins[0], playerinfo->mins[1], playerinfo->mins[2] + 18); + + gi.trace(playerinfo->origin, mins, playerinfo->maxs, endpos, ((edict_t *)playerinfo->self), MASK_SHOT,&trace); + + if (trace.ent && trace.ent->takedamage) + { + if (playerinfo->edictflags & FL_SUPER_CHICKEN) + T_Damage(trace.ent,((edict_t *)playerinfo->self),((edict_t *)playerinfo->self),vf,trace.endpos,trace.plane.normal,500,0,DAMAGE_AVOID_ARMOR,MOD_CHICKEN); + else + T_Damage(trace.ent,((edict_t *)playerinfo->self),((edict_t *)playerinfo->self),vf,trace.endpos,trace.plane.normal,1,0,DAMAGE_AVOID_ARMOR,MOD_CHICKEN); + } +} + +// ************************************************************************************************ +// G_PlayerFallingDamage +// --------------------- +// ************************************************************************************************ + +void G_PlayerFallingDamage(playerinfo_t *playerinfo,float delta) +{ + edict_t *ent; + vec3_t dir; + float damage; + + ent=(edict_t *)playerinfo->self; + + ent->pain_debounce_time=level.time; + + if(delta > 50) + damage = delta - 30; + else if((damage = (delta - 30) * 0.8) < 1.0f) + damage = 1; + + VectorSet(dir,0.0,0.0,1.0); + + T_Damage(ent,world,world,dir,ent->s.origin,vec3_origin,damage,0,DAMAGE_AVOID_ARMOR,MOD_FALLING); + + if(deathmatch->value || coop->value) + { + if(ent->groundentity && ent->groundentity->takedamage) + { + int mod; + vec3_t victim_dir, impact_spot; + + if (playerinfo->edictflags & FL_SUPER_CHICKEN) + { + damage = 500; + mod = MOD_CHICKEN; + } + else + { + damage *= 2; + mod = 0; + } + + VectorSubtract(ent->groundentity->s.origin, ent->s.origin, victim_dir); + VectorNormalize(victim_dir); + VectorMA(ent->s.origin, -1.2 * ent->mins[2], victim_dir, impact_spot); + + T_Damage(ent->groundentity, ent, ent, victim_dir, impact_spot, vec3_origin, damage, 0, DAMAGE_AVOID_ARMOR, 0); + if(ent->groundentity->client) + { + if(ent->groundentity->health > 0) + { + if(!irand(0, 1)) + { + KnockDownPlayer(&ent->groundentity->client->playerinfo); + } + } + } + } + } +} + + +// ******************************************************* +// G_PlayerVaultKick +// ----------------------------- +// Check to kick entities inside the pole vault animation +// ******************************************************* +#define VAULTKICK_DIST 30 //Amount to trace outward from the player's origin +#define VAULTKICK_MODIFIER 0.25 //percentage of the velocity magnitude to use as damage + +void G_PlayerVaultKick(playerinfo_t *playerinfo) +{ + edict_t *self = ((edict_t *)playerinfo->self); + trace_t trace; + vec3_t endpos, vf; + float kick_vel; + + //Ignore pitch + VectorSet(vf, 0, self->s.angles[YAW], 0); + AngleVectors(vf, vf, NULL, NULL); + + //Move ahead by a small amount + VectorMA(self->s.origin, VAULTKICK_DIST, vf, endpos); + + //Trace out to see if we've hit anything + gi.trace(self->s.origin, self->mins, self->maxs, endpos, self, MASK_PLAYERSOLID,&trace); + + //If we have... + if (trace.fraction < 1 && (!(trace.startsolid || trace.allsolid)) ) + { + if (trace.ent->takedamage) + { + //Find the velocity of the kick + kick_vel = VectorLength(self->velocity); + kick_vel *= VAULTKICK_MODIFIER; + + //FIXME: Get a real sound + gi.sound(self, CHAN_WEAPON, gi.soundindex("monsters/plagueElf/hamhit.wav"), 1, ATTN_NORM, 0); + T_Damage(trace.ent, self, self, vf, trace.endpos, trace.plane.normal, kick_vel, kick_vel*2, DAMAGE_NORMAL,MOD_KICKED); + VectorMA(trace.ent->velocity, irand(300,500), vf, trace.ent->velocity); + trace.ent->velocity[2] = 150; + if(trace.ent->client) + { + if(trace.ent->health > 0) + { + if(infront(trace.ent, self) && !irand(0, 2)) + { + KnockDownPlayer(&trace.ent->client->playerinfo); + } + } + } + } + } +} + +// ******************************************************* +// G_PlayerLightningShieldDamage +// ----------------------------- +// ******************************************************* + +extern void SpellLightningShieldAttack(edict_t *self); +void G_PlayerSpellShieldAttack(playerinfo_t *playerinfo) +{ + if (irand(0, (SHIELD_ATTACK_CHANCE-1)) == 0) + SpellLightningShieldAttack((edict_t *)playerinfo->self); +} + +// stop the attack and remove the persistant effect +void G_PlayerSpellStopShieldAttack(playerinfo_t *playerinfo) +{ + edict_t *self; + + self = playerinfo->self; + if (self->PersistantCFX) + { + gi.RemovePersistantEffect(self->PersistantCFX); + self->PersistantCFX = 0; + self->s.sound = 0; + } + +} + + +// ************************************************************************************************ +// G_PlayerActionSwordAttack +// ------------------------- +// ************************************************************************************************ + +void G_PlayerActionSwordAttack(playerinfo_t *playerinfo,int value) +{ + WeaponThink_SwordStaff((edict_t *)playerinfo->self,"i",value); +} + +// ************************************************************************************************ +// G_PlayerActionSpellFireball +// --------------------------- +// ************************************************************************************************ + +void G_PlayerActionSpellFireball(playerinfo_t *playerinfo) +{ + WeaponThink_FlyingFist((edict_t *)playerinfo->self,""); +} + +// ************************************************************************************************ +// G_PlayerActionSpellBlast +// ------------------------ +// ************************************************************************************************ + +void G_PlayerActionSpellBlast(playerinfo_t *playerinfo) +{ + WeaponThink_Blast((edict_t *)playerinfo->self,""); +} + +// ************************************************************************************************ +// G_PlayerActionSpellArray +// ------------------------ +// ************************************************************************************************ + +void G_PlayerActionSpellArray(playerinfo_t *playerinfo,int value) +{ + WeaponThink_MagicMissileSpread((edict_t *)playerinfo->self,"i",value); +} + +// ************************************************************************************************ +// G_PlayerActionSpellSphereCreate +// ------------------------------- +// ************************************************************************************************ + +void G_PlayerActionSpellSphereCreate(playerinfo_t *playerinfo,qboolean *Charging) +{ + // Start a glow effect. + WeaponThink_SphereOfAnnihilation((edict_t *)playerinfo->self,"g",Charging); +} + +// ************************************************************************************************ +// G_PlayerActionSpellBigBall +// -------------------------- +// ************************************************************************************************ + +void G_PlayerActionSpellBigBall(playerinfo_t *playerinfo) +{ + WeaponThink_Maceballs((edict_t *)playerinfo->self,""); +} + +// ************************************************************************************************ +// G_PlayerActionSpellFirewall +// --------------------------- +// ************************************************************************************************ + +void G_PlayerActionSpellFirewall(playerinfo_t *playerinfo) +{ + WeaponThink_Firewall((edict_t *)playerinfo->self,""); +} + +// ************************************************************************************************ +// G_PlayerActionRedRainBowAttack +// ------------------------------ +// ************************************************************************************************ + +void G_PlayerActionRedRainBowAttack(playerinfo_t *playerinfo) +{ + WeaponThink_RedRainBow((edict_t *)playerinfo->self,""); +} + +// ************************************************************************************************ +// G_PlayerActionPhoenixBowAttack +// ------------------------------ +// ************************************************************************************************ + +void G_PlayerActionPhoenixBowAttack(playerinfo_t *playerinfo) +{ + WeaponThink_PhoenixBow((edict_t *)playerinfo->self,""); +} + +// ************************************************************************************************ +// G_PlayerActionHellstaffAttack +// ----------------------------- +// ************************************************************************************************ + +void G_PlayerActionHellstaffAttack(playerinfo_t *playerinfo) +{ + WeaponThink_HellStaff((edict_t *)playerinfo->self,""); +} + +// ************************************************************************************************ +// G_PlayerActionSpellDefensive +// ---------------------------- +// ************************************************************************************************ + +void G_PlayerActionSpellDefensive(playerinfo_t *playerinfo) +{ + int index; + gitem_t *it; + + if (playerinfo->leveltime > playerinfo->defensive_debounce) + { + playerinfo->pers.defence->use(playerinfo,playerinfo->pers.defence); + playerinfo->pers.defence->weaponthink((edict_t *)playerinfo->self,""); + playerinfo->defensive_debounce = playerinfo->leveltime + DEFENSE_DEBOUNCE; + + // if we've run out of defence shots, and we have the ring of repulsion - switch to that. + it = FindItem ("ring"); + index = ITEM_INDEX(it); + if ((Defence_CurrentShotsLeft(playerinfo, 1) <=0) && playerinfo->pers.inventory.Items[index]) + { + playerinfo->G_UseItem(playerinfo->self,"ring"); + } + + } +} + +// ************************************************************************************************ +// G_EntIsAButton - this is exceedingly gay that this has to be done this way. +// ---------------------------- +// ************************************************************************************************ + +qboolean G_EntIsAButton(edict_t *ent) +{ + if(ent->classID == CID_BUTTON) + return (true); + return (false); +} diff --git a/Toolkit/Programming/GameCode/game/p_funcs.h b/Toolkit/Programming/GameCode/game/p_funcs.h new file mode 100644 index 0000000..7017184 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/p_funcs.h @@ -0,0 +1,53 @@ +// p_funcs.h +// +// Heretic II - Raven software +// +// Written by Marcus Whitlock +// + +#ifndef _P_FUNCS_H_ +#define _P_FUNCS_H_ + +#include "g_local.h" + +extern void G_PlayerActionShrineEffect(playerinfo_t *playerinfo); +extern entity_state_t *G_GetEntityStatePtr(edict_t *entity); +extern int G_BranchLwrClimbing(playerinfo_t *playerinfo); +extern qboolean G_PlayerActionCheckRopeGrab(playerinfo_t *playerinfo, float stomp_org); +extern void G_PlayerClimbingMoveFunc(playerinfo_t *playerinfo, float height, float var2, float var3); +extern qboolean G_PlayerActionCheckPuzzleGrab(playerinfo_t *playerinfo); +extern void G_PlayerActionTakePuzzle(playerinfo_t *playerinfo); +extern qboolean G_PlayerActionUsePuzzle(playerinfo_t *playerinfo); +extern qboolean G_PlayerActionCheckPushPull_Ent(void *ent); +extern void PushPull_stop(edict_t *self); +extern void G_PlayerActionMoveItem(playerinfo_t *playerinfo,float distance); +extern qboolean G_PlayerActionCheckPushButton(playerinfo_t *playerinfo); +extern void G_PlayerActionCheckHitGround(playerinfo_t *playerinfo); +extern void G_PlayerActionPushButton(playerinfo_t *playerinfo); +extern qboolean G_PlayerActionCheckPushLever(playerinfo_t *playerinfo); +extern void G_PlayerActionPushLever(playerinfo_t *playerinfo); +extern qboolean G_HandleTeleport(playerinfo_t *playerinfo); +extern void G_SetJointAngles(playerinfo_t *playerinfo); +extern void G_ResetJointAngles(playerinfo_t *playerinfo); +extern void G_PlayerActionChickenBite(playerinfo_t *playerinfo); +extern void G_PlayerFallingDamage(playerinfo_t *playerinfo,float delta); +extern void G_PlayerActionSwordAttack(playerinfo_t *playerinfo,int value); +extern void G_PlayerActionSpellFireball(playerinfo_t *playerinfo); +extern void G_PlayerActionSpellBlast(playerinfo_t *playerinfo); +extern void G_PlayerActionSpellArray(playerinfo_t *playerinfo,int value); +extern void G_PlayerActionSpellSphereCreate(playerinfo_t *playerinfo,qboolean *Charging); +extern void G_PlayerActionSpellBigBall(playerinfo_t *playerinfo); +extern void G_PlayerActionSpellFirewall(playerinfo_t *playerinfo); +extern void G_PlayerActionRedRainBowAttack(playerinfo_t *playerinfo); +extern void G_PlayerActionPhoenixBowAttack(playerinfo_t *playerinfo); +extern void G_PlayerActionHellstaffAttack(playerinfo_t *playerinfo); +extern void G_PlayerActionSpellDefensive(playerinfo_t *playerinfo); +extern void G_PlayerActionChickenBite(playerinfo_t *playerinfo); +extern void G_PlayerSpellShieldAttack(playerinfo_t *playerinfo); +extern void G_PlayerSpellStopShieldAttack(playerinfo_t *playerinfo); +extern void G_PlayerVaultKick(playerinfo_t *playerinfo); +extern void G_PlayerActionCheckRopeMove(playerinfo_t *playerinfo); +extern qboolean G_EntIsAButton(edict_t *ent); +void Updatefmnodeinfo(edict_t *ent); +void Setfmnodeinfo(edict_t *ent); +#endif // _P_FUNCS_H_ \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/p_hud.c b/Toolkit/Programming/GameCode/game/p_hud.c new file mode 100644 index 0000000..2718dfd --- /dev/null +++ b/Toolkit/Programming/GameCode/game/p_hud.c @@ -0,0 +1,618 @@ +#include "g_local.h" +#include "random.h" +#include "vector.h" +#include "g_playstats.h" +#include "g_itemstats.h" + +qboolean PossessCorrectItem(edict_t *ent, gitem_t *item); + +#if 0 + // cursor positioning + xl + xr + yb + yt + + // drawing + statpic + pic + num + string + + // control + if + ifeq + ifbit + endif + +#endif + +char *single_statusbar = +"yb -74 " +"xl 16 " // green mana +"gm " + +"yb -44 " + +"xl 40 " +"pic 4 " // Weapon + +"xl 76 " // Ammo +"pic 2 " +"am " + +"xr -112 " +"pic 0 " +"hnum " // Health + +"if 6 " +"yb -44 " +"xr -72 " +"pic 6 " // Defence +"endif " + +"yb -74 " +"xr -32 " +"bm " // blue mana + +" yt 16 " + +"if 28 " +" xl 32 " +" lt " // Lung time left +"endif " + +"if 25 " +" xr -96 " +" pt " // Powerup time left +"endif " + +"yt 16 " + +"xc 0 " // Inventory Puzzle Item 1 +"pici 18 " + +"xc 40 " // Puzzle 2 +"pici 19 " + +"xc 80 " // Puzzle 3 +"pici 20 " + +"xc 120 " // Puzzle 4 +"pici 21 " + +"if 31 " +" xl 32 " +" bl " // Boss Life Meter +"endif " +; + +char *dm_statusbar = +"yb -74 " +"xl 16 " // green mana +"gm " + +"yb -44 " + +"xl 40 " +"pic 4 " // Weapon + +"xl 76 " // Ammo +"pic 2 " +"am " + +"xr -112 " +"pic 0 " +"hnum " // Health + +"yb -44 " +"xr -72 " +"pic 6 " // Defence + +"yb -74 " +"xr -32 " +"bm " // blue mana + +" yt 16 " + +"if 28 " +" xl 32 " +" lt " // Lung time left +"endif " + +"if 25 " +" xr -96 " +" pt " // Powerup time left +"endif " + +#if 0 +"xc 0 " // Frag +"num 3 15 " +#endif +; + +/* +====================================================================== + +INTERMISSION + +====================================================================== +*/ + +void MoveClientToIntermission(edict_t *ent) +{ + if(deathmatch->value) + ent->client->playerinfo.showscores = true; + + VectorCopy(level.intermission_origin,ent->s.origin); + + ent->client->ps.pmove.origin[0] = level.intermission_origin[0]*8; + ent->client->ps.pmove.origin[1] = level.intermission_origin[1]*8; + ent->client->ps.pmove.origin[2] = level.intermission_origin[2]*8; + + VectorCopy(level.intermission_angle,ent->client->ps.viewangles); + + ent->client->ps.pmove.pm_type = PM_INTERMISSION; + ent->client->ps.rdflags &= ~RDF_UNDERWATER; + + // Clean up powerup info. + + ent->client->invincible_framenum = 0; + + ent->viewheight = 0; + ent->s.modelindex = 0; + ent->s.effects = 0; + ent->s.sound = 0; + ent->solid = SOLID_NOT; + + // Add the layout. + + if(deathmatch->value) + { + DeathmatchScoreboardMessage(ent,NULL); + + gi.unicast(ent,true); + } +} + +void BeginIntermission(edict_t *targ) +{ + int i; + edict_t *ent, + *client; + + // Already activated? + + if(level.intermissiontime) + return; + + game.autosaved = false; + + // Respawn any dead clients. + + for (i=0 ; ivalue ; i++) + { + client = g_edicts + 1 + i; + if (!client->inuse) + continue; + if (client->health <= 0) + respawn(client); + } + + level.intermissiontime = level.time; + level.changemap = targ->map; + + if (!deathmatch->value) + { + // Go immediately to the next level if not deathmatch. + + level.exitintermission = 1; + + return; + } + + level.exitintermission = 0; + + // Find an intermission spot. + + ent = G_Find (NULL, FOFS(classname), "info_player_intermission"); + + if (!ent) + { + // The map creator forgot to put in an intermission point. + + ent = G_Find (NULL, FOFS(classname), "info_player_start"); + + if (!ent) + ent = G_Find (NULL, FOFS(classname), "info_player_deathmatch"); + } + else + { + // Chose one of four spots. + + i = irand(0, 3); + + while (i--) + { + ent = G_Find (ent, FOFS(classname), "info_player_intermission"); + + if (!ent) + { + // Wrap around the list. + + ent = G_Find (ent, FOFS(classname), "info_player_intermission"); + } + } + } + + VectorCopy (ent->s.origin, level.intermission_origin); + VectorCopy (ent->s.angles, level.intermission_angle); + + // Move all clients to the intermission point. + + for(i=0;ivalue;i++) + { + client=g_edicts+1+i; + + if(!client->inuse) + continue; + + MoveClientToIntermission(client); + } +} + + +/* +================== +DeathmatchScoreboardMessage + +================== +*/ +void DeathmatchScoreboardMessage (edict_t *ent, edict_t *killer) +{ + char entry[1024]; + char string[1400]; + int stringlength; + int i, j, k; + int sorted[MAX_CLIENTS]; + int sortedscores[MAX_CLIENTS]; + int score, total; + int x, y; + gclient_t *cl; + edict_t *cl_ent; +#if 0 + int picnum; + char *tag; +#endif + + // Sort the clients by score. + + total = 0; + for(i = 0; i < game.maxclients; i++) + { + cl_ent = g_edicts + 1 + i; + if (!cl_ent->inuse) + { + continue; + } + score = game.clients[i].resp.score; + for(j = 0; j < total; j++) + { + if(score > sortedscores[j]) + { + break; + } + } + for(k = total; k > j; k--) + { + sorted[k] = sorted[k - 1]; + sortedscores[k] = sortedscores[k - 1]; + } + sorted[j] = i; + sortedscores[j] = score; + total++; + } + + // Print level name and exit rules. + + string[0] = 0; + stringlength = strlen(string); + + // Add the clients in sorted order. + + if(total > 12) + { + total = 12; + } + + for(i = 0; i < total; i++) + { + cl = &game.clients[sorted[i]]; + cl_ent = g_edicts + 1 + sorted[i]; + x = (i >= 6) ? 160 : 0; + y = 32 + 32 * (i % 6); +#if 0 + picnum = gi.imageindex("icons/i_teleport.m8"); + // Add a dogtag. + + if (cl_ent == ent) + tag = "tag1"; + else if (cl_ent == killer) + tag = "tag2"; + else + tag = NULL; + if(tag) + { + Com_sprintf(entry, sizeof(entry), "xv %i yv %i picn %s ", x + 32, y, tag); + j = strlen(entry); + if (stringlength + j > 1024) + { + break; + } + strcpy (string + stringlength, entry); + stringlength += j; + } +#endif + // Send the layout. + + Com_sprintf (entry, sizeof(entry), "client %i %i %i %i %i %i ", + x, y, sorted[i], cl->resp.score, cl->ping, (level.framenum - cl->resp.enterframe) / 600); + j = strlen(entry); + if(stringlength + j > 1024) + { + break; + } + strcpy (string + stringlength, entry); + stringlength += j; + } + gi.WriteByte (svc_layout); + gi.WriteString (string); +} + +/* +================== +DeathmatchScoreboard + +Draw instead of help message. +Note that it isn't that hard to overflow the 1400 byte message limit! +================== +*/ +void DeathmatchScoreboard (edict_t *ent) +{ + DeathmatchScoreboardMessage (ent, ent->enemy); + gi.unicast (ent, true); +} + + +/* +================== +Cmd_Score_f + +Display the scoreboard +================== +*/ +void Cmd_Score_f (edict_t *ent) +{ + if (!deathmatch->value) + return; + + if (ent->client->playerinfo.showscores) + { + ent->client->playerinfo.showscores = false; + return; + } + + ent->client->playerinfo.showscores = true; + DeathmatchScoreboard (ent); +} + +//======================================================================= + +/* +=============== +G_GetShrineTime +=============== +*/ + +short GetShrineTime(float time) +{ + float duration; + short result; + + duration = time - level.time; + if(duration < 0.0) + { + return(0); + } + result = (short)ceil(duration); + return(result); +} + +static char *healthicons[2] = +{ + "icons/i_health.m8", + "icons/i_health2.m8", +}; + +// ************************************************************************************************ +// G_SetStats +// ---------- +// ************************************************************************************************ + +void G_SetStats (edict_t *ent) +{ + int i, count; + gitem_t *item; + gclient_t *pi; + player_state_t *ps; + client_persistant_t *pers; + float time; + + pi = ent->client; + ps = &ent->client->ps; + pers = &ent->client->playerinfo.pers; + + // ******************************************************************************************** + // Frags + // ******************************************************************************************** + + ps->stats[STAT_FRAGS] = pi->resp.score; + + // ******************************************************************************************** + // Health. + // ******************************************************************************************** + + ps->stats[STAT_HEALTH_ICON]=gi.imageindex (healthicons[Q_ftol(level.time*2)&1]); + ps->stats[STAT_HEALTH]=ent->health; + + // ******************************************************************************************** + // Weapon / defence. + // ******************************************************************************************** + + ps->stats[STAT_WEAPON_ICON]=gi.imageindex(pers->weapon->icon); + if (pers->defence) + ps->stats[STAT_DEFENCE_ICON]=gi.imageindex(pers->defence->icon); + + // ******************************************************************************************** + // Weapon ammo. + // ******************************************************************************************** + + if(pers->weapon->ammo&&pers->weapon->count_width) + { + item=FindItem(pers->weapon->ammo); + ps->stats[STAT_AMMO_ICON]=gi.imageindex(item->icon); + ps->stats[STAT_AMMO] = pers->inventory.Items[ITEM_INDEX(item)]; + } + else + { + ps->stats[STAT_AMMO_ICON] = 0; + } + + // ******************************************************************************************** + // Offensive mana. + // ******************************************************************************************** + + ps->stats[STAT_OFFMANA_ICON]=gi.imageindex("icons/green-mana.m8"); + ps->stats[STAT_OFFMANA_BACK]=gi.imageindex("icons/green-mana2.m8"); + item = FindItem("Off-mana"); + ps->stats[STAT_OFFMANA] = (pers->inventory.Items[ITEM_INDEX(item)] * 100) / MAX_OFF_MANA; + if(ps->stats[STAT_OFFMANA] < 0) + ps->stats[STAT_OFFMANA] = 0; + + // ******************************************************************************************** + // Defensive mana. + // ******************************************************************************************** + + ps->stats[STAT_DEFMANA_ICON]=gi.imageindex("icons/blue-mana.m8"); + ps->stats[STAT_DEFMANA_BACK]=gi.imageindex("icons/blue-mana2.m8"); + item = FindItem("Def-mana"); + ps->stats[STAT_DEFMANA] = (pers->inventory.Items[ITEM_INDEX(item)] * 100) / MAX_DEF_MANA; + if(ps->stats[STAT_DEFMANA] < 0) + ps->stats[STAT_DEFMANA] = 0; + + // ******************************************************************************************** + // Shrine timers. + // ******************************************************************************************** + + ps->stats[STAT_POWERUP_BACK] = gi.imageindex("icons/powerup2.m8"); + ps->stats[STAT_POWERUP_ICON] = gi.imageindex("icons/powerup.m8"); + ps->stats[STAT_POWERUP_TIMER] = (GetShrineTime(pi->playerinfo.powerup_timer) * 100) / POWERUP_DURATION; + // Cheating sets the powerup timer to something huge, so let's avoid a crash here. + if (ps->stats[STAT_POWERUP_TIMER] > 100) + ps->stats[STAT_POWERUP_TIMER]=100; + + ps->stats[STAT_LUNG_BACK] = gi.imageindex("icons/breath2.m8"); + ps->stats[STAT_LUNG_ICON] = gi.imageindex("icons/breath.m8"); + ps->stats[STAT_LUNG_TIMER] = 0; + if((ent->waterlevel > 2) && !(ent->flags & FL_INLAVA)) + { + // Make negative if we have lungs powerup. + if(pi->playerinfo.lungs_timer) + { + time = pi->playerinfo.lungs_timer + ent->air_finished - level.time; + if(time > 0) + { + ps->stats[STAT_LUNG_TIMER] = -(time * 100) / (HOLD_BREATH_TIME + LUNGS_DURATION); + } + } + else + { + time = ent->air_finished - level.time; + if(time > 0) + { + ps->stats[STAT_LUNG_TIMER] = (time * 100) / HOLD_BREATH_TIME; + } + } + } + + // ******************************************************************************************** + // Puzzle items. + // ******************************************************************************************** + + ps->stats[STAT_PUZZLE_ITEM1] = 0; + ps->stats[STAT_PUZZLE_ITEM2] = 0; + ps->stats[STAT_PUZZLE_ITEM3] = 0; + ps->stats[STAT_PUZZLE_ITEM4] = 0; + + // Scan through inventory to handle puzzle pieces. + + item = p_itemlist; + count = STAT_PUZZLE_ITEM1; + ps->stats[STAT_PUZZLE_COUNT] = 0; + for(i = 0; i < MAX_ITEMS; i++, item++) + { + if((item->flags & IT_PUZZLE) && pers->inventory.Items[i]) + { + if(count > STAT_PUZZLE_ITEM4) + { + break; + } + else + { + ps->stats[count] = gi.imageindex (item->icon); + ps->stats[STAT_PUZZLE_COUNT]++; + if(PossessCorrectItem(ent, item)) + { + ps->stats[count] |= 0x8000; + } + count++; + } + } + } + + // ******************************************************************************************** + // Layouts. + // ******************************************************************************************** + + ent->client->ps.stats[STAT_LAYOUTS] = 0; + + // Inventory gets activated when player is in a use puzzle trigger field. + + if(ent->target_ent) + { + if(!strcmp(ent->target_ent->classname, "trigger_playerusepuzzle")) + { + ps->stats[STAT_LAYOUTS] |= 4; + } + } + + if (ent->client->playerinfo.showpuzzleinventory) + { + // Show puzzle inventory. + + ps->stats[STAT_LAYOUTS] |= 4; + } + + if (deathmatch->value) + { + if (pers->health <= 0 || level.intermissiontime || ent->client->playerinfo.showscores) + ps->stats[STAT_LAYOUTS] |= 1; + } + else + { + if (ent->client->playerinfo.showscores) + ps->stats[STAT_LAYOUTS] |= 1; + } +} + +// end diff --git a/Toolkit/Programming/GameCode/game/p_item.c b/Toolkit/Programming/GameCode/game/p_item.c new file mode 100644 index 0000000..0d7993f --- /dev/null +++ b/Toolkit/Programming/GameCode/game/p_item.c @@ -0,0 +1,129 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// Created by JJS + +#include "p_types.h" +#include "g_local.h" +#include "p_weapon.h" +#include "m_player.h" +#include "fx.h" +#include "matrix.h" +#include "vector.h" +#include "g_skeletons.h" +#include "angles.h" + +void SpellCastPowerup(edict_t *Caster, vec3_t StartPos, vec3_t AimAngles, vec3_t AimDir, float value); +void SpellCastBlueRing(edict_t *Caster, vec3_t StartPos, vec3_t AimAngles, vec3_t AimDir, float value); +void SpellCastMeteorBarrier(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value); +void SpellCastTeleport(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value); +void SpellCastMorph(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value); +void SpellCastShield(edict_t *caster,vec3_t startpos,vec3_t aimangles,vec3_t aimdir,float Value); + +void Use_Defence(playerinfo_t *playerinfo, gitem_t *defence) +{ + playerinfo->pers.lastdefence = playerinfo->pers.defence; + playerinfo->pers.defence=defence; + + if(playerinfo->pers.defence&&playerinfo->pers.defence->ammo) + playerinfo->def_ammo_index=ITEM_INDEX(FindItem(playerinfo->pers.defence->ammo)); + else + playerinfo->def_ammo_index=0; +} + +// ************************************************************************************************ + +void DefenceThink_Powerup(edict_t *Caster, char *Format,...) +{ + playerinfo_t *playerinfo; + playerinfo = &Caster->client->playerinfo; + + SpellCastPowerup(Caster, Caster->s.origin, NULL,NULL, 0.0F); + + assert(playerinfo->def_ammo_index); + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + playerinfo->pers.inventory.Items[playerinfo->def_ammo_index] -= playerinfo->pers.defence->quantity; +} + +// ************************************************************************************************ + +void DefenceThink_RingOfRepulsion(edict_t *Caster, char *Format,...) +{ + playerinfo_t *playerinfo; + playerinfo = &Caster->client->playerinfo; + + SpellCastBlueRing(Caster, Caster->s.origin, NULL,NULL, 0.0F); + + assert(playerinfo->def_ammo_index); + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + playerinfo->pers.inventory.Items[playerinfo->def_ammo_index] -= playerinfo->pers.defence->quantity; +} + +// ************************************************************************************************ + +void DefenceThink_MeteorBarrier(edict_t *Caster, char *Format,...) +{ + playerinfo_t *playerinfo; + + playerinfo = &Caster->client->playerinfo; + + SpellCastMeteorBarrier(Caster, Caster->s.origin, NULL, NULL, 0.0F); + + assert(playerinfo->def_ammo_index); + +} + + +// ************************************************************************************************ + +void DefenceThink_Morph(edict_t *Caster, char *Format,...) +{ + playerinfo_t *playerinfo; + playerinfo = &Caster->client->playerinfo; + + // Set up the Meteor-barrier's aiming angles and starting position then cast the spell. + + SpellCastMorph(Caster, Caster->s.origin, Caster->client->aimangles, NULL, 0.0F); + + assert(playerinfo->def_ammo_index); + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + playerinfo->pers.inventory.Items[playerinfo->def_ammo_index] -= playerinfo->pers.defence->quantity; +} + +// ************************************************************************************************ +void DefenceThink_Teleport(edict_t *Caster, char *Format,...) +{ + playerinfo_t *playerinfo; + playerinfo = &Caster->client->playerinfo; + + // Set up the teleport and then do it + + SpellCastTeleport(Caster, Caster->s.origin, NULL, NULL, 0.0F); + + assert(playerinfo->def_ammo_index); + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + playerinfo->pers.inventory.Items[playerinfo->def_ammo_index] -= playerinfo->pers.defence->quantity; +} + +// ************************************************************************************************ +void DefenceThink_Shield(edict_t *Caster, char *Format,...) +{ + playerinfo_t *playerinfo; + assert(Caster->client); + playerinfo = &Caster->client->playerinfo; + + // Make sure that there isn't already a shield in place. + if (playerinfo->shield_timer < playerinfo->leveltime) + { // Don't do anything if there is already a shield in place. + // Set up the shield and then do it + + SpellCastShield(Caster, Caster->s.origin, NULL, NULL, 0.0F); + + assert(playerinfo->def_ammo_index); + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + playerinfo->pers.inventory.Items[playerinfo->def_ammo_index] -= playerinfo->pers.defence->quantity; + } +} diff --git a/Toolkit/Programming/GameCode/game/p_item.h b/Toolkit/Programming/GameCode/game/p_item.h new file mode 100644 index 0000000..09e8e75 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/p_item.h @@ -0,0 +1,14 @@ +#ifndef P_ITEM +#define P_ITEM 1 + +#include "p_types.h" + +void Use_Defence(playerinfo_t *playerinfo, gitem_t *defence); +void DefenceThink_Powerup(edict_t *Caster, char *Format, ...); +void DefenceThink_RingOfRepulsion(edict_t *Caster, char *Format, ...); +void DefenceThink_MeteorBarrier(edict_t *Caster, char *Format, ...); +void DefenceThink_Teleport(edict_t *Caster, char *Format, ...); +void DefenceThink_Morph(edict_t *Caster, char *Format, ...); +void DefenceThink_Shield(edict_t *Caster, char *Format, ...); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/p_view.c b/Toolkit/Programming/GameCode/game/p_view.c new file mode 100644 index 0000000..fb9779e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/p_view.c @@ -0,0 +1,1050 @@ +#include "g_Skeletons.h" +#include "g_teleport.h" +#include "m_player.h" +#include "p_types.h" +#include "p_animactor.h" +#include "p_anims2.h" +#include "p_ctrl2.h" +#include "p_funcs.h" +#include "p_main2.h" +#include "p_weapon.h" +#include "angles.h" +#include "fx.h" +#include "random.h" +#include "vector.h" +#include "utilities.h" +#include "g_playstats.h" + +static edict_t *current_player; +static gclient_t *current_client; +float xyspeed; +float bobmove; +int bobcycle; // odd cycles are right foot going forward +float bobfracsin; // sin(bobfrac*M_PI) + +extern void Cmd_WeapPrev_f (edict_t *ent); +extern void Cmd_Use_f (edict_t *ent, char *s); +extern void PrintLocalBuoyInfo(vec3_t org); + +// ************************************************************************************************ +// ClientServerRand +// ---------------- +// ************************************************************************************************ + +static int ClientServerRand(playerinfo_t *playerinfo,int mn,int mx) +{ + int t; + + if (mn>=mx) + return(mn); + + t=(int)(playerinfo->leveltime*10.0f); + t=(t>>7)^(t>>10)^(t>>5); + t%=(1+mx-mn); + + return(t+mn); +} + +// ************************************************************************************************ +// InitPlayerinfo +// -------------- +// ************************************************************************************************ + +void InitPlayerinfo(edict_t *ent) +{ + // Client side function callbacks (approximating functionality of server function callbacks). + + ent->client->playerinfo.CL_Sound=NULL; + ent->client->playerinfo.CL_Trace=NULL; + ent->client->playerinfo.CL_CreateEffect=NULL; + + // Server (game) function callbacks (approximating functionality of client-side function callbacks). + + ent->client->playerinfo.G_Sound=gi.sound; + ent->client->playerinfo.G_Trace=gi.trace; + ent->client->playerinfo.G_CreateEffect=gi.CreateEffect; + ent->client->playerinfo.G_RemoveEffects=gi.RemoveEffects; + + // Server (game) function callbacks that have no client side equivalent. + + ent->client->playerinfo.G_SoundIndex=gi.soundindex; + ent->client->playerinfo.G_SoundRemove=gi.soundremove; + ent->client->playerinfo.G_UseTargets=G_UseTargets; + ent->client->playerinfo.G_GetEntityStatePtr=G_GetEntityStatePtr; + ent->client->playerinfo.G_BranchLwrClimbing=G_BranchLwrClimbing; + ent->client->playerinfo.G_PlayerActionCheckRopeGrab=G_PlayerActionCheckRopeGrab; + ent->client->playerinfo.G_PlayerClimbingMoveFunc=G_PlayerClimbingMoveFunc; + ent->client->playerinfo.G_PlayerActionUsePuzzle=G_PlayerActionUsePuzzle; + ent->client->playerinfo.G_PlayerActionCheckPuzzleGrab=G_PlayerActionCheckPuzzleGrab; + ent->client->playerinfo.G_PlayerActionTakePuzzle=G_PlayerActionTakePuzzle; + ent->client->playerinfo.G_PlayerActionCheckPushPull_Ent=G_PlayerActionCheckPushPull_Ent; + ent->client->playerinfo.G_PlayerActionMoveItem=G_PlayerActionMoveItem; + ent->client->playerinfo.G_PlayerActionCheckPushButton=G_PlayerActionCheckPushButton; + ent->client->playerinfo.G_PlayerActionPushButton=G_PlayerActionPushButton; + ent->client->playerinfo.G_PlayerActionCheckPushLever=G_PlayerActionCheckPushLever; + ent->client->playerinfo.G_PlayerActionPushLever=G_PlayerActionPushLever; + ent->client->playerinfo.G_HandleTeleport=G_HandleTeleport; + ent->client->playerinfo.G_PlayerActionShrineEffect=G_PlayerActionShrineEffect; + ent->client->playerinfo.G_PlayerActionChickenBite=G_PlayerActionChickenBite; + ent->client->playerinfo.G_PlayerFallingDamage=G_PlayerFallingDamage; + ent->client->playerinfo.G_PlayerSpellShieldAttack=G_PlayerSpellShieldAttack; + ent->client->playerinfo.G_PlayerSpellStopShieldAttack=G_PlayerSpellStopShieldAttack; + ent->client->playerinfo.G_PlayerVaultKick = G_PlayerVaultKick; + ent->client->playerinfo.G_PlayerActionCheckRopeMove=G_PlayerActionCheckRopeMove; + ent->client->playerinfo.G_gamemsg_centerprintf=gi.gamemsg_centerprintf; + ent->client->playerinfo.G_levelmsg_centerprintf=gi.levelmsg_centerprintf; + ent->client->playerinfo.G_WeapNext=Cmd_WeapPrev_f; + ent->client->playerinfo.G_UseItem=Cmd_Use_f; + ent->client->playerinfo.G_PlayerActionCheckHitGround=G_PlayerActionCheckHitGround; + + // Common client & server (game) function callbacks. + + ent->client->playerinfo.PointContents=gi.pointcontents; + ent->client->playerinfo.SetJointAngles=G_SetJointAngles; + ent->client->playerinfo.ResetJointAngles=G_ResetJointAngles; + ent->client->playerinfo.PlayerActionSwordAttack=G_PlayerActionSwordAttack; + ent->client->playerinfo.PlayerActionSpellFireball=G_PlayerActionSpellFireball; + ent->client->playerinfo.PlayerActionSpellBlast=G_PlayerActionSpellBlast; + ent->client->playerinfo.PlayerActionSpellArray=G_PlayerActionSpellArray; + ent->client->playerinfo.PlayerActionSpellSphereCreate=G_PlayerActionSpellSphereCreate; + ent->client->playerinfo.PlayerActionSpellBigBall=G_PlayerActionSpellBigBall; + ent->client->playerinfo.PlayerActionSpellFirewall=G_PlayerActionSpellFirewall; + ent->client->playerinfo.PlayerActionRedRainBowAttack=G_PlayerActionRedRainBowAttack; + ent->client->playerinfo.PlayerActionPhoenixBowAttack=G_PlayerActionPhoenixBowAttack; + ent->client->playerinfo.PlayerActionHellstaffAttack=G_PlayerActionHellstaffAttack; + ent->client->playerinfo.PlayerActionSpellDefensive=G_PlayerActionSpellDefensive; + ent->client->playerinfo.G_EntIsAButton=G_EntIsAButton; + ent->client->playerinfo.irand=ClientServerRand; + + // So we know we are server (game) side. + + ent->client->playerinfo.isclient=false; +} + +// ************************************************************************************************ +// SetupPlayerinfo +// --------------- +// ************************************************************************************************ + +void SetupPlayerinfo(edict_t *ent) +{ + int i; + + // ******************************************************************************************** + // Inputs only. + // ******************************************************************************************** + + // Pointer to the associated player's edict_t. + + ent->client->playerinfo.self=ent; + + // Game .dll variables. + + ent->client->playerinfo.leveltime=level.time; + + // Server variables. + + ent->client->playerinfo.sv_gravity=sv_gravity->value; + ent->client->playerinfo.sv_cinematicfreeze=sv_cinematicfreeze->value; + ent->client->playerinfo.sv_jumpcinematic=sv_jumpcinematic->value; + + // From edict_t. + + ent->client->playerinfo.ideal_yaw=ent->ideal_yaw; + ent->client->playerinfo.groundentity=ent->groundentity; + + // Pointer to entity_state_t of player's enemy edict. + + if(ent->enemy) + ent->client->playerinfo.enemystate=&ent->enemy->s; + else + ent->client->playerinfo.enemystate=NULL; + + // Spell / weapon aiming direction. + + VectorCopy(ent->client->aimangles,ent->client->playerinfo.aimangles); + + // Deathmatch flags - only set this if we are in death match. + + if (deathmatch->value) + ent->client->playerinfo.dmflags = DF_DEATHMATCH_SET | (int)dmflags->value; // Send the high bit if deathmatch. + else + ent->client->playerinfo.dmflags=0; + + // ******************************************************************************************** + // Inputs & outputs. + // ******************************************************************************************** + + // If we are in a cinematic, remove certain commands from the ucmd_t the server received from + // the client. NOTE: THIS IS HIGHLY SUBJECTIVE. REQUIRES VIGOUROUS TESTING. + // Basically, just killing all buttons pressed while a cinematic is running - Probably not the best way to do this + // Jake 9/28/98 + // need to reget this constantly, since it changes on the fly. + + memcpy(&ent->client->playerinfo.pcmd,&ent->client->pcmd,sizeof(usercmd_t)); + + if (sv_cinematicfreeze->value) + { + ent->client->pcmd.buttons = 0; + ent->client->pcmd.sidemove = 0; + ent->client->pcmd.forwardmove = 0; + ent->client->playerinfo.pcmd.buttons = 0; + ent->client->playerinfo.pcmd.sidemove = 0; + ent->client->playerinfo.pcmd.forwardmove = 0; + ent->client->playerinfo.buttons = 0; + ent->client->playerinfo.remember_buttons = 0; + } + + // From edict_t. + + VectorCopy(ent->s.origin,ent->client->playerinfo.origin); + VectorCopy(ent->s.angles,ent->client->playerinfo.angles); + VectorCopy(ent->velocity,ent->client->playerinfo.velocity); + VectorCopy(ent->mins,ent->client->playerinfo.mins); + VectorCopy(ent->maxs,ent->client->playerinfo.maxs); + ent->client->playerinfo.enemy=ent->enemy; + ent->client->playerinfo.target=ent->target; + ent->client->playerinfo.targetEnt=ent->targetEnt; + ent->client->playerinfo.target_ent=ent->target_ent; + ent->client->playerinfo.nextthink=ent->nextthink; + ent->client->playerinfo.viewheight=ent->viewheight; + ent->client->playerinfo.watertype=ent->watertype; + ent->client->playerinfo.waterlevel=ent->waterlevel; + ent->client->playerinfo.deadflag=ent->deadflag; + ent->client->playerinfo.movetype=ent->movetype; + ent->client->playerinfo.edictflags=ent->flags; + + // From entity_state_t. + + ent->client->playerinfo.frame=ent->s.frame, + ent->client->playerinfo.swapFrame=ent->s.swapFrame; + ent->client->playerinfo.effects=ent->s.effects; + ent->client->playerinfo.renderfx=ent->s.renderfx; + ent->client->playerinfo.skinnum=ent->s.skinnum; + + for(i=0;iclient->playerinfo.fmnodeinfo[i]=ent->s.fmnodeinfo[i]; + } + + // From pmove_state_t. + + ent->client->playerinfo.pm_flags=ent->client->ps.pmove.pm_flags; + ent->client->playerinfo.pm_w_flags=ent->client->ps.pmove.w_flags; +} + +// ************************************************************************************************ +// WritePlayerinfo +// --------------- +// ************************************************************************************************ + +void WritePlayerinfo(edict_t *ent) +{ + int i; + + // ******************************************************************************************** + // Inputs & outputs. + // ******************************************************************************************** + + memcpy(&ent->client->pcmd,&ent->client->playerinfo.pcmd,sizeof(usercmd_t)); + + // From edict_t. + + VectorCopy(ent->client->playerinfo.origin,ent->s.origin); + VectorCopy(ent->client->playerinfo.angles,ent->s.angles); + VectorCopy(ent->client->playerinfo.velocity,ent->velocity); + VectorCopy(ent->client->playerinfo.mins,ent->mins); + VectorCopy(ent->client->playerinfo.maxs,ent->maxs); + ent->enemy=ent->client->playerinfo.enemy; + ent->targetEnt=ent->client->playerinfo.targetEnt; + ent->target_ent=ent->client->playerinfo.target_ent; + ent->target=ent->client->playerinfo.target; + ent->nextthink=ent->client->playerinfo.nextthink; + ent->viewheight=ent->client->playerinfo.viewheight; + ent->watertype=ent->client->playerinfo.watertype; + ent->waterlevel=ent->client->playerinfo.waterlevel; + ent->deadflag=ent->client->playerinfo.deadflag; + ent->movetype=ent->client->playerinfo.movetype; + ent->flags=ent->client->playerinfo.edictflags; + + // From entity_state_t. + + ent->s.frame=ent->client->playerinfo.frame, + ent->s.swapFrame=ent->client->playerinfo.swapFrame; + ent->s.effects=ent->client->playerinfo.effects; + ent->s.renderfx=ent->client->playerinfo.renderfx; + ent->s.skinnum=ent->client->playerinfo.skinnum; + + for(i=0;is.fmnodeinfo[i]=ent->client->playerinfo.fmnodeinfo[i]; + } + + // From pmove_state_t. + + ent->client->ps.pmove.pm_flags=ent->client->playerinfo.pm_flags; + ent->client->ps.pmove.w_flags=ent->client->playerinfo.pm_w_flags; + + // ******************************************************************************************** + // Outputs only. + // ******************************************************************************************** + + // From playerstate_t. + + VectorCopy(ent->client->playerinfo.offsetangles,ent->client->ps.offsetangles); +} + +// ************************************************************************************************ +// SetupPlayerinfo_effects +// ----------------------- +// ************************************************************************************************ + +void SetupPlayerinfo_effects(edict_t *ent) +{ + int i; + + ent->client->playerinfo.effects = ent->s.effects; + ent->client->playerinfo.renderfx = ent->s.renderfx; + ent->client->playerinfo.skinnum = ent->s.skinnum; + + for(i = 0; i < MAX_FM_MESH_NODES; i++) + { + ent->client->playerinfo.fmnodeinfo[i] = ent->s.fmnodeinfo[i]; + } +} + +// ************************************************************************************************ +// WritePlayerinfo_effects +// ----------------------- +// ************************************************************************************************ + +void WritePlayerinfo_effects(edict_t *ent) +{ + int i; + + ent->s.effects = ent->client->playerinfo.effects; + ent->s.renderfx = ent->client->playerinfo.renderfx; + ent->s.skinnum = ent->client->playerinfo.skinnum; + + for(i = 0; i < MAX_FM_MESH_NODES; i++) + { + ent->s.fmnodeinfo[i] = ent->client->playerinfo.fmnodeinfo[i]; + } +} + +// ************************************************************************************************ +// PlayerTimerUpdate +// ----------------- +// Deal with incidental player stuff, like setting the personal light to OFF if its should be. +// ************************************************************************************************ + +void PlayerTimerUpdate(edict_t *ent) +{ + playerinfo_t *playerinfo; + + playerinfo=&ent->client->playerinfo; + + // Disable light when we should. + + if (playerinfo->light_timer < level.time) + playerinfo->effects &= ~EF_LIGHT_ENABLED; + + // Disable powerup when we should. + + if (playerinfo->powerup_timer < level.time) + playerinfo->effects &= ~EF_POWERUP_ENABLED; + + // Disable relection when we should. + + if (playerinfo->reflect_timer < level.time) + { + // Were we relfective last frame? + + if (playerinfo->renderfx &RF_REFLECTION) + { + playerinfo->renderfx &= ~RF_REFLECTION; + + // Unset the skin. + + PlayerUpdateModelAttributes(&ent->client->playerinfo); + } + } + + // Disable ghosting when we should. + + if (playerinfo->ghost_timer < level.time) + playerinfo->renderfx &= ~RF_TRANS_GHOST; +} + +/* +=============== +P_DamageFeedback + +Handles color blends and view kicks +=============== +*/ + +void P_DamageFeedback (edict_t *player) +{ + gclient_t *client; + int count; + + client=player->client; + + // Flash the backgrounds behind the status numbers. + + client->ps.stats[STAT_FLASHES]=0; + + if (client->damage_blood) + client->ps.stats[STAT_FLASHES]|=1; + + // Total up the points of damage shot at the player this frame. + + if((count=client->damage_blood)==0) + { + // Didn't take any damage. + return; + } + + //Check for gasssss damage + if (player->pain_debounce_time < level.time && client->damage_gas) + { + if ( client->playerinfo.loweridle && client->playerinfo.upperidle ) + PlayerAnimSetLowerSeq(&client->playerinfo, ASEQ_PAIN_A); + + PlayerPlayPain(&client->playerinfo, 1); + } + else if (((!irand(0, 4)) || count > 8) && (player->pain_debounce_time < level.time)) // Play pain animation. + { + if ( client->playerinfo.loweridle && client->playerinfo.upperidle ) + PlayerAnimSetLowerSeq(&client->playerinfo, ASEQ_PAIN_A); + + if (count <= 4) + PlayerPlayPain(&client->playerinfo, 2); + else + PlayerPlayPain(&client->playerinfo, 0); + + player->pain_debounce_time = level.time + 0.5; + } + + // Reset the player's pain_debounce_time. + + if (level.time > player->pain_debounce_time) + player->pain_debounce_time = level.time + 0.7; + + // Clear damage totals. + + client->damage_blood = 0; + client->damage_knockback = 0; +} + +/* +============= +P_WorldEffects +============= +*/ + +void P_WorldEffects (void) +{ + int waterlevel,old_waterlevel; + vec3_t Origin, + Dir; + + if (current_player->client->playerinfo.deadflag > DEAD_NO) + return; + + // If we are in no clip, or we have special lungs, we don't need air. + + if(current_player->movetype==PHYSICSTYPE_NOCLIP) + { + current_player->air_finished=level.time+HOLD_BREATH_TIME; + + if(current_player->movetype==PHYSICSTYPE_NOCLIP) + return; + } + + waterlevel=current_player->waterlevel; + old_waterlevel=current_client->old_waterlevel; + current_client->old_waterlevel=waterlevel; + + // + // If the current player just entered a water volume, play a sound and start a water-ripple + // client effect. + // + + if(!old_waterlevel&&waterlevel) + { + // Clear damage_debounce, so the pain sound will play immediately. + + current_player->damage_debounce_time=level.time-1; + + if (current_player->watertype & CONTENTS_LAVA) + { + gi.sound(current_player, CHAN_BODY, gi.soundindex("player/inlava.wav"), 1, ATTN_NORM, 0); + current_player->flags |= FL_INLAVA; + } + else if (current_player->watertype & CONTENTS_SLIME) + { + gi.sound(current_player, CHAN_BODY, gi.soundindex("player/muckin.wav"), 1, ATTN_NORM, 0); + current_player->flags |= FL_INSLIME; + } + else + { + gi.sound(current_player, CHAN_BODY, gi.soundindex("player/Water Enter.wav"),1,ATTN_NORM,0); + } + current_player->flags|=FL_INWATER; + + VectorCopy(current_player->s.origin,Origin); + + Origin[2]+=current_player->client->playerinfo.waterheight; + + // Fixme: Need to determine the actual water surface normal - if we have any sloping water?? + + Dir[0]=0.0; + Dir[1]=0.0; + Dir[2]=1.0; + + VectorCopy(Origin,current_player->client->playerinfo.LastWatersplashPos); + + gi.CreateEffect(NULL, + FX_WATER_ENTRYSPLASH, + 0, + Origin, + "bd", + 128|96, // FIXME: Size propn. to entry velocity? + Dir); + } + else if (old_waterlevel&&!waterlevel) + { + + // + // If the current player just completely exited a water volume, play a sound. + // + + // INWATER is set whether in lava, slime or water. + if (current_player->flags & FL_INLAVA) + { + gi.sound (current_player, CHAN_BODY, gi.soundindex("player/inlava.wav"), 1, ATTN_NORM, 0); + current_player->flags &= ~FL_INLAVA; + } + else if (current_player->flags & FL_INSLIME) + { + gi.sound (current_player, CHAN_BODY, gi.soundindex("player/muckexit.wav"), 1, ATTN_NORM, 0); + current_player->flags &= ~FL_INSLIME; + } + else + { + gi.sound (current_player, CHAN_BODY, gi.soundindex("player/Water Exit.wav"), 1, ATTN_NORM, 0); + } + current_player->flags&=~FL_INWATER; + + VectorCopy(current_player->s.origin,Origin); + + Origin[2]=current_player->client->playerinfo.LastWatersplashPos[2]; + + // Fixme: Need to determine the actual water surface normal - if we have any sloping water?? + + Dir[0]=0.0; + Dir[1]=0.0; + Dir[2]=1.0; + + VectorCopy(Origin,current_player->client->playerinfo.LastWatersplashPos); + + gi.CreateEffect(NULL, + FX_WATER_ENTRYSPLASH, + 0, + Origin, + "bd", + 96, // FIXME: Size propn. to exit velocity. + Dir); + } + + // + // Start a waterwake effect if the current player has been in water and still is in water. + // + + if(waterlevel && (old_waterlevel&&waterlevel<3) && (VectorLength(current_player->velocity)!=0.0)) + { + if(((int)(current_client->bobtime+bobmove))!=bobcycle) + { + // FIXME: Doing more work then we need to here???? How about re-writing this so that it + // is always active on the client and does water tests itself? We'll see - currently not + // enough info. is available on the client to try this. + + vec3_t Angles, + Temp; + byte angle_byte; + + VectorCopy(current_player->velocity,Temp); + + VectorNormalize(Temp); + + vectoangles(Temp,Angles); + + VectorCopy(current_player->s.origin,Origin); + + Origin[2]+=current_player->client->playerinfo.waterheight; + + angle_byte = Q_ftol(((Angles[YAW] + DEGREE_180)/360.0) * 255.0); + + gi.CreateEffect(NULL, + FX_WATER_WAKE, + 0, + Origin, + "sbv", + (short)current_player->s.number, + angle_byte, + current_player->velocity); + } + } + + // + // Check for head just coming out of water. + // + + if (old_waterlevel == 3 && waterlevel != 3) + { + if (current_player->air_finished < level.time) + { + // Gasp for air. + if (irand(0,1)) + gi.sound (current_player, CHAN_BODY, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0); + else + gi.sound (current_player, CHAN_BODY, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0); + + } + else if (current_player->air_finished < level.time + 11) + { + // Just broke surface, no gasp + gi.sound (current_player, CHAN_BODY, gi.soundindex("player/waterresurface.wav"), 1, ATTN_NORM, 0); + } + } + + // ******************************************************************************************** + // Handle drowning. + // ******************************************************************************************** + + if (waterlevel == 3) + { + if(current_player->watertype & CONTENTS_SLIME) + { + // Slime should kill really quick. + + current_player->dmg=25; + + // Play a gurp sound instead of a normal pain sound. + + if (irand(0, 1)) + gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drowning1.wav"), 1, ATTN_NORM, 0); + else + gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drowning2.wav"), 1, ATTN_NORM, 0); + + current_player->pain_debounce_time = level.time; + + T_Damage(current_player, + world, + world, + vec3_origin, + current_player->s.origin, + vec3_origin, + current_player->dmg, + 0, + DAMAGE_SUFFOCATION, + MOD_SLIME); + } + else if ((current_player->air_finished + current_player->client->playerinfo.lungs_timer) < level.time) + { + // If out of air, start drowning. + + if (current_player->client->next_drown_time < level.time && current_player->health > 0) + { + current_player->client->next_drown_time = level.time + 1; + + // Take more damage the longer underwater. + + current_player->dmg += 2; + + if (current_player->dmg > 15) + current_player->dmg = 15; + + // Play a gurp sound instead of a normal pain sound. + + if (irand(0, 1)) + gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drowning1.wav"), 1, ATTN_NORM, 0); + else + gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drowning2.wav"), 1, ATTN_NORM, 0); + + current_player->pain_debounce_time = level.time; + + T_Damage(current_player, + world, + world, + vec3_origin, + current_player->s.origin, + vec3_origin, + current_player->dmg, + 0, + DAMAGE_SUFFOCATION, + MOD_WATER); + } + + } + // else, we aren't drowning yet, but we may well need to decrement the amount of extra lungs we have from shrines + // since we still have lungs, reset air finished till we don't anymore. + else + if (current_player->client->playerinfo.lungs_timer) + { + // floatinf point inaccuracy never lets us equal zero by ourselves + if (current_player->client->playerinfo.lungs_timer < 0.1) + current_player->client->playerinfo.lungs_timer = 0.0; + else + { + current_player->client->playerinfo.lungs_timer -= 0.1; + current_player->air_finished = level.time + HOLD_BREATH_TIME; + } + } + + if (old_waterlevel != 3) + { // We weren't underwater before this, so play a submerged sound + gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/underwater.wav"), 1, ATTN_IDLE, 0); + } + + // Play an underwater sound every 4 seconds! + if (((int)(level.time/4.0))*4.0 == level.time) + { // Underwater ambient + // Play local only? + gi.sound (current_player, CHAN_BODY, gi.soundindex("player/underwater.wav"), 1, ATTN_IDLE, 0); + } + } + else + { + current_player->air_finished = level.time + HOLD_BREATH_TIME; + current_player->dmg = 2; + } + + // ******************************************************************************************** + // Handle lava sizzle damage. + // ******************************************************************************************** + + if (waterlevel && (current_player->watertype&(CONTENTS_LAVA)) ) + { + if (current_player->health > 0 && current_player->pain_debounce_time <= level.time) + { + gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/lavadamage.wav"), 1, ATTN_NORM, 0); + + current_player->pain_debounce_time = level.time + 1; + } + + T_Damage(current_player, + world, + world, + vec3_origin, + current_player->s.origin, + vec3_origin, + (waterlevel>2)?25:(3*waterlevel), + 0, + DAMAGE_LAVA, + MOD_LAVA); + } +} + +/* +=============== +G_SetClientSound +=============== +*/ + +void G_SetClientSound (edict_t *ent) +{ + char *weap; + + if (ent->client->playerinfo.pers.weapon) + weap = ent->client->playerinfo.pers.weapon->classname; + else + weap = ""; +// this seems like a silly thing to do ? +/// ent->s.sound = 0; +} + +// ************************************************************************************************ +// ClientEndServerFrame +// -------------------- +// Called for each player at the end of the server frame and right after spawning. +// ************************************************************************************************ + +void ClientEndServerFrame (edict_t *ent) +{ + float bobtime; + int i,index; + + current_player = ent; + current_client = ent->client; + + // ******************************************************************************************** + // If end of unit layout is displayed, don't give the player any normal movement attributes. + // ******************************************************************************************** + + if (level.intermissiontime) + { + current_client->ps.fov=75; + G_SetStats(ent); + + return; + } + + // ******************************************************************************************** + // Apply world effect, e.g. burn from lava, etc. + // ******************************************************************************************** + + P_WorldEffects (); + + // ******************************************************************************************** + // Set the player entity's model angles. + // ******************************************************************************************** + + if(ent->deadflag==DEAD_NO) + { + // PITCH. + + if((ent->client->ps.pmove.w_flags & (WF_DIVING | WF_SWIMFREE))) + { + if(ent->client->v_angle[PITCH] > 180.0) + ent->s.angles[PITCH] = -(-360.0 + ent->client->v_angle[PITCH]); + else + ent->s.angles[PITCH] = -ent->client->v_angle[PITCH]; + } + else + { + ent->s.angles[PITCH] = 0.0; + } + + // YAW and ROLL. + + ent->s.angles[YAW] = ent->client->v_angle[YAW]; + ent->s.angles[ROLL] = 0.0; + } + + // ******************************************************************************************** + // Handle calcs for cyclic effects like walking / swimming. + // ******************************************************************************************** + + xyspeed = sqrt(ent->velocity[0] * ent->velocity[0] + ent->velocity[1] * ent->velocity[1]); + + if (xyspeed < 5) + { + // Start at beginning of cycle again. + + bobmove = 0; + current_client->bobtime = 0; + } + else if(ent->groundentity && !current_player->waterlevel) + { + // So bobbing only cycles when on ground. + + if(xyspeed > 210) + bobmove = 0.25; + else if(xyspeed > 100) + bobmove = 0.125; + else + bobmove = 0.0625; + } + else if(current_player->waterlevel) + { + // So bobbing only cycles when in water. + + if(xyspeed > 100) + bobmove = 1.0; + else if(xyspeed > 50) + bobmove = 0.5; + else + bobmove = 0.25; + } + + bobtime = (current_client->bobtime += bobmove); + bobcycle = (int)bobtime; + bobfracsin = Q_fabs(sin(bobtime * M_PI)); + + // ******************************************************************************************** + // Calculate damage (if any) from hitting the floor and apply the damage taken this frame from + // ALL sources. + // ******************************************************************************************** + + SetupPlayerinfo(ent); + + PlayerFallingDamage(&ent->client->playerinfo); + P_DamageFeedback(ent); + + WritePlayerinfo(ent); + + // ******************************************************************************************** + // Generate client-side status display data + // ******************************************************************************************** + + G_SetStats(ent); + G_SetClientSound(ent); + + // ******************************************************************************************** + // Handle player animation. + // ******************************************************************************************** + + SetupPlayerinfo(ent); + + PlayerUpdateCmdFlags(&ent->client->playerinfo); + + if(BUOY_DEBUG) // Note this is a bit of a hack + { + if(ent->client->playerinfo.seqcmd[ACMDL_ACTION] == true) + { + PrintLocalBuoyInfo(ent->s.origin); + } + } + + PlayerUpdate(&ent->client->playerinfo); + AnimUpdateFrame(&ent->client->playerinfo); + PlayerTimerUpdate(ent); + + WritePlayerinfo(ent); + + // ******************************************************************************************** + // Save velocity and viewangles away for use next game frame. + // ******************************************************************************************** + + VectorCopy(ent->velocity,ent->client->playerinfo.oldvelocity); + VectorCopy(ent->client->ps.viewangles,ent->client->oldviewangles); + + // ******************************************************************************************** + // If the deathmatch scoreboard is up then update it. + // ******************************************************************************************** + + if(ent->client->playerinfo.showscores && deathmatch->value && (!(level.framenum&31))) + { + DeathmatchScoreboardMessage(ent,ent->enemy); + + gi.unicast(ent,false); + } + + // ******************************************************************************************** + // Reflect remote camera views(s) in the client's playerstate. + // ******************************************************************************************** + + if(current_client->RemoteCameraLockCount>0) + current_client->ps.remote_id=current_client->RemoteCameraNumber; + else + current_client->ps.remote_id=-1; + + // ******************************************************************************************** + // Reflect inventory changes in the client's playetstate. + // ******************************************************************************************** + + current_client->ps.NoOfItems=i=0; + + for(index=0;indexplayerinfo.pers.inventory.Items[index]!=current_client->playerinfo.pers.old_inventory.Items[index]) + { + current_client->ps.inventory_changes[i]=index; + + current_client->ps.inventory_remaining[i]=current_client->playerinfo.pers.inventory.Items[index]; + + current_client->playerinfo.pers.old_inventory.Items[index]=current_client->playerinfo.pers.inventory.Items[index]; + + i++; + } + } + + current_client->ps.NoOfItems=i; + + // ******************************************************************************************** + // Reflect changes to the client's origin and velocity due to the current player animation, in + // the client's playerstate. + // ******************************************************************************************** + + current_client->ps.pmove.origin[0]=ent->s.origin[0]*8.0; + current_client->ps.pmove.origin[1]=ent->s.origin[1]*8.0; + current_client->ps.pmove.origin[2]=ent->s.origin[2]*8.0; + + current_client->ps.pmove.velocity[0]=ent->velocity[0]*8.0; + current_client->ps.pmove.velocity[1]=ent->velocity[1]*8.0; + current_client->ps.pmove.velocity[2]=ent->velocity[2]*8.0; + + // ******************************************************************************************** + // Reflect viewheight changes in client's playerstate. + // ******************************************************************************************** + + current_client->ps.viewheight=ent->viewheight; + + // ******************************************************************************************** + // Write all the shit that animation system modifies out to the playerstate (for prediction). + // ******************************************************************************************** + + current_client->ps.maxs[0]=current_client->playerinfo.maxs[0]; + current_client->ps.maxs[1]=current_client->playerinfo.maxs[1]; + current_client->ps.maxs[2]=current_client->playerinfo.maxs[2]; + + current_client->ps.mins[0]=current_client->playerinfo.mins[0]; + current_client->ps.mins[1]=current_client->playerinfo.mins[1]; + current_client->ps.mins[2]=current_client->playerinfo.mins[2]; + + current_client->ps.NonNullgroundentity=(byte)(current_client->playerinfo.groundentity?1:0); + current_client->ps.GroundPlane=current_client->playerinfo.GroundPlane; + current_client->ps.GroundContents=current_client->playerinfo.GroundContents; + current_client->ps.GroundSurface.flags= + (current_client->playerinfo.GroundSurface!=NULL)?current_client->playerinfo.GroundSurface->flags:0; + + current_client->ps.watertype=current_client->playerinfo.watertype; + current_client->ps.waterlevel=current_client->playerinfo.waterlevel; + current_client->ps.waterheight=current_client->playerinfo.waterheight; + + VectorCopy(current_client->playerinfo.grabloc,current_client->ps.grabloc); + current_client->ps.grabangle=current_client->playerinfo.grabangle; + + current_client->ps.fwdvel=current_client->playerinfo.fwdvel; + current_client->ps.sidevel=current_client->playerinfo.sidevel; + current_client->ps.upvel=current_client->playerinfo.upvel; + + current_client->ps.flags=current_client->playerinfo.flags; + + current_client->ps.edictflags=current_client->playerinfo.edictflags; + + current_client->ps.oldvelocity_z=current_client->playerinfo.oldvelocity[2]; + + current_client->ps.upperseq=current_client->playerinfo.upperseq; + current_client->ps.lowerseq=current_client->playerinfo.lowerseq; + + current_client->ps.upperframe=current_client->playerinfo.upperframe; + current_client->ps.lowerframe=current_client->playerinfo.lowerframe; + + current_client->ps.upperidle=(byte)((current_client->playerinfo.upperidle==true)?1:0); + current_client->ps.loweridle=(byte)((current_client->playerinfo.loweridle==true)?1:0); + + current_client->ps.uppermove_index=current_client->playerinfo.uppermove_index; + current_client->ps.lowermove_index=current_client->playerinfo.lowermove_index; + + current_client->ps.weapon=(byte)ITEM_INDEX(current_client->playerinfo.pers.weapon); + current_client->ps.defense=(byte)ITEM_INDEX(current_client->playerinfo.pers.defence); + current_client->ps.lastweapon=(byte)ITEM_INDEX(current_client->playerinfo.pers.lastweapon); + current_client->ps.lastdefense=(byte)ITEM_INDEX(current_client->playerinfo.pers.lastdefence); + current_client->ps.weaponready=(byte)current_client->playerinfo.pers.weaponready; + current_client->ps.switchtoweapon=(byte)current_client->playerinfo.switchtoweapon; + current_client->ps.newweapon=(byte)ITEM_INDEX(current_client->playerinfo.pers.newweapon); + current_client->ps.weap_ammo_index=(byte)current_client->playerinfo.weap_ammo_index; + current_client->ps.def_ammo_index=(byte)current_client->playerinfo.def_ammo_index; + current_client->ps.weaponcharge=(byte)current_client->playerinfo.weaponcharge; + current_client->ps.armortype=(byte)current_client->playerinfo.pers.armortype; + current_client->ps.bowtype=(byte)current_client->playerinfo.pers.bowtype; + current_client->ps.stafflevel=(byte)current_client->playerinfo.pers.stafflevel; + current_client->ps.helltype=(byte)current_client->playerinfo.pers.helltype; + current_client->ps.meteor_count=(byte)current_client->playerinfo.meteor_count; + current_client->ps.handfxtype=(byte)current_client->playerinfo.pers.handfxtype; + current_client->ps.plaguelevel=(byte)current_client->playerinfo.plaguelevel; + current_client->ps.skintype=(byte)current_client->playerinfo.pers.skintype; + current_client->ps.altparts=(byte)current_client->playerinfo.pers.altparts; + current_client->ps.deadflag=current_client->playerinfo.deadflag; + current_client->ps.ideal_yaw=ent->ideal_yaw; + current_client->ps.leveltime=level.time; + current_client->ps.idletime=current_client->playerinfo.idletime; + + current_client->ps.dmflags=current_client->playerinfo.dmflags; + + current_client->ps.cinematicfreeze=current_client->playerinfo.sv_cinematicfreeze; +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/p_weapon.c b/Toolkit/Programming/GameCode/game/p_weapon.c new file mode 100644 index 0000000..1dc72d9 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/p_weapon.c @@ -0,0 +1,660 @@ +// p_weapon.c - generic weapon handling code for all player weapons + +#include "p_types.h" +#include "g_local.h" +#include "p_weapon.h" +#include "m_player.h" +#include "fx.h" +#include "matrix.h" +#include "vector.h" +#include "g_skeletons.h" +#include "angles.h" +#include "Reference.h" +#include "Random.h" +#include "Utilities.h" +#include "g_items.h" +#include "g_playstats.h" +#include "p_main2.h" +#include "m_beast.h" + +extern void SpellCastFlyingFist(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value); +extern void SpellCastMagicMissile(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir); +extern void SpellCastMagicMissileSpread(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir, + float NoOfMissiles,float Separation); +extern void SpellCastSphereOfAnnihilation(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir, + float Value,qboolean *ReleaseFlagsPtr); +extern void SpellCastMaceball(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value); +extern void SpellCastWall(edict_t *caster, vec3_t startpos, vec3_t aimangles, vec3_t AimDir, float Value); +extern void SpellCastRipper(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir); +extern void SpellCastBlast(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir); +extern void SpellCastRedRain(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value); +extern void SpellCastPhoenix(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value); +extern void SpellCastHellstaff(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir); + +static void Weapon_CalcStartPos(vec3_t OriginToLowerJoint,vec3_t OriginToUpperJoint, + vec3_t DefaultStartPos,vec3_t ActualStartPos,edict_t *Caster); + +// ************************************************************************************************ +// Weapon_CalcStartPos +// ------------------- +// Sets up a spell missile's starting position, correct with respect to the player model's angles +// and posture. We want the start position of the missile to be the caster's hand, so we must take +// into account the caster's joint orientations and global model orientation. This is a big-arsed +// hack. We assume that if the caster is standing fully upstraight, the missile will be launched +// from default co-ordinates (relative to the caster's origin) specified in DefaultStartPos. The +// other two inputs, LowerJoint & UpperJoint specify Corvus's bone joint positions (relative to his +// model's origin) for the animation frame in which the weapon is launched. +// ************************************************************************************************* + +static void Weapon_CalcStartPos(vec3_t OriginToLowerJoint,vec3_t OriginToUpperJoint, + vec3_t DefaultStartPos,vec3_t ActualStartPos,edict_t *Caster) +{ + matrix3_t LowerRotationMatrix,UpperRotationMatrix; + vec3_t LowerbackJointAngles,UpperbackJointAngles, + LowerJoint,UpperJoint,LowerJointToUpperJoint, + Forward,Right,Up, + StartPos; + + // Get matrices corresponding to the current angles of the upper and lower back joints. + + LowerbackJointAngles[PITCH]=GetJointAngle(Caster->s.rootJoint+CORVUS_LOWERBACK,PITCH); + LowerbackJointAngles[YAW]=GetJointAngle(Caster->s.rootJoint+CORVUS_LOWERBACK,YAW); + LowerbackJointAngles[ROLL]=GetJointAngle(Caster->s.rootJoint+CORVUS_LOWERBACK,ROLL); + Matrix3FromAngles(LowerbackJointAngles,LowerRotationMatrix); + + UpperbackJointAngles[PITCH]=GetJointAngle(Caster->s.rootJoint+CORVUS_UPPERBACK,PITCH); + UpperbackJointAngles[YAW]=GetJointAngle(Caster->s.rootJoint+CORVUS_UPPERBACK,YAW); + UpperbackJointAngles[ROLL]=GetJointAngle(Caster->s.rootJoint+CORVUS_UPPERBACK,ROLL); + Matrix3FromAngles(UpperbackJointAngles,UpperRotationMatrix); + + // Get vector from player model's origin to lower joint. + + VectorAdd(Caster->s.origin,OriginToLowerJoint,LowerJoint); + + // Get vector from player model's origin to upper joint. + + VectorAdd(Caster->s.origin,OriginToUpperJoint,UpperJoint); + + // Get vector from lower joint to upper joint. + + VectorSubtract(OriginToUpperJoint,OriginToLowerJoint,LowerJointToUpperJoint); + + // Get vector from upper joint to the default flying-fist's start position. + + AngleVectors(Caster->s.angles,Forward,Right,Up); + VectorMA(Caster->s.origin,DefaultStartPos[0],Right,StartPos); + VectorMA(StartPos,DefaultStartPos[1],Forward,StartPos); + VectorMA(StartPos,DefaultStartPos[2],Up,StartPos); + VectorSubtract(StartPos,UpperJoint,StartPos); + + // Add in the contribution from the 'bone' from the lower joint to upper joint. + + Matrix3MultByVec3(UpperRotationMatrix,StartPos,StartPos); + VectorAdd(StartPos,LowerJointToUpperJoint,StartPos); + + // Add in the contribution from the model's origin to the lower joint. + + Matrix3MultByVec3(LowerRotationMatrix,StartPos,StartPos); + VectorAdd(OriginToLowerJoint,StartPos,StartPos); + + // Finally, add on the model's origin to give the correct start position for the flying-fist. + + VectorAdd(StartPos,Caster->s.origin,StartPos); + + VectorCopy(StartPos,ActualStartPos); +} + +// ************************************************************************************************ +// WeaponThink_SwordStaff +// ---------------------- +// ************************************************************************************************ + +vec3_t swordpositions[17] = +{ + { 0, 0, 0 }, // 0 + { -20, -20, 26 }, // 1 swipeA4 + { 4, -34, 22 }, // 2 swipeA5 + { 43, -16, -10 }, // 3 swipeA6 + { 33, 20, -38 }, // 4 swipeA7 + + { -24, 4, 7 }, // 5 swipeB4 + { 15, -26, 5 }, // 6 swipeB5 + { 40, -31, -27 }, // 7 swipeB6 + { 5, -22, -35 }, // 8 swipeB7 + + { -44, 10, 7 }, // 9 spnatk3 + { 34, 1, 35 }, // 10 spnatk4 + { 50, 12, -22 }, // 11 spnatk5 + { 35, 27, -44 }, // 12 spnatk6 + + { 26, 2, 32 }, // 13 spnatk17 + { 33, -19, 28 }, // 14 spnatk18 + { 56, 3, -8 }, // 15 spnatk19 + { 2, 36, -39 }, // 16 spnatk20 +}; + +/*c3_t swordpositions[17] = +{ + { 0, 0, 0 }, // 0 + { -20, -20, 40 }, // 1 swipeA4 + { 4, -34, 36 }, // 2 swipeA5 + { 43, -16, 4 }, // 3 swipeA6 + { 33, 20, -24 }, // 4 swipeA7 + + { -24, 4, 21 }, // 5 swipeB4 + { 15, -26, 19 }, // 6 swipeB5 + { 40, -31, -13 }, // 7 swipeB6 + { 5, -22, -21 }, // 8 swipeB7 + + { -44, 10, 21 }, // 9 spnatk3 + { 34, 1, 49 }, // 10 spnatk4 + { 50, 12, -8 }, // 11 spnatk5 + { 35, 27, -30 }, // 12 spnatk6 + + { 26, 2, 46 }, // 13 spnatk17 + { 33, -19, 42 }, // 14 spnatk18 + { 56, 3, 6 }, // 15 spnatk19 + { 2, 36, -25 }, // 16 spnatk20 +}; +*/ + +int sworddamage[STAFF_LEVEL_MAX][2] = +{ // MIN MAX + { 0, 0 }, // STAFF_LEVEL_NONE + { SWORD_DMG_MIN, SWORD_DMG_MAX }, // STAFF_LEVEL_BASIC + { SWORD_POWER1_DMG_MIN, SWORD_POWER1_DMG_MAX }, // STAFF_LEVEL_POWER1 + { SWORD_POWER2_DMG_MIN, SWORD_POWER2_DMG_MAX }, // STAFF_LEVEL_POWER2 +}; + +void WeaponThink_SwordStaff(edict_t *Caster,char *Format,...) +{ + va_list Marker; + char CurrentChar; + int locid; + vec3_t fwd, right, up; + vec3_t atkpos, startpos, endpos, hitdir, hitangles; + vec3_t mins={-12, -12, -12}; + vec3_t maxs={12, 12, 12}; + int damage, powerlevel, dflags; + + trace_t trace; + + if (Caster->client == NULL) + { + powerlevel = STAFF_LEVEL_BASIC; + } + else + { + powerlevel = Caster->client->playerinfo.pers.stafflevel; + if (Caster->client->playerinfo.powerup_timer > level.time) + powerlevel++; // powerups now power up your staff, too. + } + + if (powerlevel <= STAFF_LEVEL_NONE) + return; + else if (powerlevel >= STAFF_LEVEL_MAX) + powerlevel = STAFF_LEVEL_MAX-1; + + assert(strlen(Format)); + va_start(Marker,Format); + CurrentChar=Format[0]; + assert(CurrentChar=='i'); + locid=va_arg(Marker,int); + va_end(Marker); + + AngleVectors(Caster->client->aimangles, fwd, right, up); + + // Set up the area to check. + VectorCopy(swordpositions[locid], atkpos); + VectorMA(Caster->s.origin, atkpos[0], fwd, endpos); + VectorMA(endpos, -atkpos[1], right, endpos); + VectorMA(endpos, atkpos[2], up, endpos); + + // Now if we are the first attack of this sweep (1, 5, 9, 13), starting in solid means a hit. If not, then we must avoid startsolid entities. + if ((locid & 0x03) == 0x01) + { // First check of the swing. + Caster->client->lastentityhit = NULL; + VectorCopy(endpos, startpos); + } + else + { + VectorCopy(swordpositions[locid-1], atkpos); + VectorMA(Caster->s.origin, atkpos[0], fwd, startpos); + VectorMA(startpos, -atkpos[1], right, startpos); + VectorMA(startpos, atkpos[2], up, startpos); + } + startpos[2] += Caster->viewheight; + endpos[2] += Caster->viewheight; + + gi.trace(startpos, mins, maxs, endpos, Caster, MASK_PLAYERSOLID|CONTENTS_DEADMONSTER,&trace); + if(level.fighting_beast) + { + edict_t *ent; + + if(ent = check_hit_beast(startpos, trace.endpos)) + trace.ent = ent; + } + + if (trace.ent && trace.ent->takedamage) + { + if (!trace.startsolid || trace.ent != Caster->client->lastentityhit) + { + if (CanDamage (trace.ent, Caster)) + { + VectorSubtract(endpos, startpos, hitdir); + VectorNormalize2(hitdir, hitdir); + + if (powerlevel > STAFF_LEVEL_POWER2) + powerlevel = STAFF_LEVEL_POWER2; + + damage = irand(sworddamage[powerlevel][0], sworddamage[powerlevel][1]); + // Spin attacks should double damage + if (locid >= 9) + damage *= SWORD_SPIN_DMG_MOD; + + if(Caster->client) + { + if(Caster->client->playerinfo.flags & PLAYER_FLAG_NO_LARM) + { + damage = ceil(damage/3);//only one ar,m 1/3 the damage + } + } + + switch(powerlevel) + { + case STAFF_LEVEL_BASIC: + dflags = DAMAGE_EXTRA_KNOCKBACK|DAMAGE_DISMEMBER; + break; + + case STAFF_LEVEL_POWER1: + dflags = DAMAGE_EXTRA_KNOCKBACK|DAMAGE_DISMEMBER|DAMAGE_DOUBLE_DISMEMBER; + break; + + case STAFF_LEVEL_POWER2: + dflags = DAMAGE_EXTRA_KNOCKBACK|DAMAGE_DISMEMBER|DAMAGE_FIRE; + break; + } + + T_Damage (trace.ent, Caster, Caster, fwd, trace.endpos, hitdir, damage, damage*4, dflags,MOD_STAFF); + // If we hit a monster, stick a trail of blood on the staff... + if (trace.ent->svflags & SVF_MONSTER) + { + if(trace.ent->materialtype == MAT_INSECT)//yellow blood + gi.CreateEffect(&Caster->s, FX_LINKEDBLOOD, CEF_FLAG8|CEF_OWNERS_ORIGIN, NULL, "bb", 30, CORVUS_BLADE); + else + gi.CreateEffect(&Caster->s, FX_LINKEDBLOOD, CEF_OWNERS_ORIGIN, NULL, "bb", 30, CORVUS_BLADE); + } + + if (trace.ent->svflags & SVF_MONSTER || trace.ent->client) + Caster->s.effects |= EF_ALTCLIENTFX; + + //Use special hit puff + switch (powerlevel) + { + case STAFF_LEVEL_BASIC: + gi.sound(Caster,CHAN_AUTO,gi.soundindex("weapons/staffhit.wav"),1,ATTN_NORM,0); + break; + + case STAFF_LEVEL_POWER1: + gi.CreateEffect(NULL, + FX_WEAPON_STAFF_STRIKE, + 0, + trace.endpos, + "db", + trace.plane.normal, + powerlevel); + + gi.sound(Caster,CHAN_AUTO,gi.soundindex("weapons/staffhit_2.wav"),1,ATTN_NORM,0); + break; + + case STAFF_LEVEL_POWER2: + gi.CreateEffect(NULL, + FX_WEAPON_STAFF_STRIKE, + 0, + trace.endpos, + "db", + trace.plane.normal, + powerlevel); + + gi.sound(Caster,CHAN_AUTO,gi.soundindex("weapons/staffhit_3.wav"),1,ATTN_NORM,0); + break; + } + + Caster->client->lastentityhit = trace.ent; + } + } + } + else if (trace.fraction < 1.0 || trace.startsolid) + { // Hit a wall or such... + if (Caster->client->lastentityhit == NULL && Vec3NotZero(trace.plane.normal)) + { // Don't do sparks if already hit something + vectoangles(trace.plane.normal, hitangles); + gi.CreateEffect(NULL, + FX_SPARKS, + 0, + trace.endpos, + "d", + trace.plane.normal); + + AlertMonsters (Caster, Caster, 1, true); + gi.sound(Caster, CHAN_AUTO, gi.soundindex("weapons/staffhitwall.wav"), 1, ATTN_NORM, 0); + + // NOTENOTE -1 means that the last entity was a wall... + Caster->client->lastentityhit = (edict_t *)0xFFFFFFFF; + } + } +} + +// ************************************************************************************************ +// WeaponThink_FlyingFist +// ---------------------- +// ************************************************************************************************ + +void WeaponThink_FlyingFist(edict_t *Caster,char *Format,...) +{ + vec3_t OriginToLowerJoint={0.945585,2.26076,0.571354}, + OriginToUpperJoint={1.80845,2.98912,3.27800}, + DefaultStartPos={18.0,10.0,15.0}, + StartPos, + Forward; + + // Set up the Magic-missile's starting position and aiming angles then cast the spell. + + Weapon_CalcStartPos(OriginToLowerJoint,OriginToUpperJoint,DefaultStartPos,StartPos,Caster); + +// AngleVectors(Caster->client->v_angle,Forward,NULL,NULL); + AngleVectors(Caster->client->aimangles,Forward,NULL,NULL); + + StartPos[2] += Caster->viewheight - 14.0; + //SpellCastFlyingFist(Caster,StartPos,Caster->client->v_angle,Forward,0.0); + SpellCastFlyingFist(Caster,StartPos,Caster->client->aimangles,Forward,0.0); + + // Take off mana, but if there is none, then fire a wimpy fizzle-weapon. + if (Caster->client->playerinfo.pers.inventory.Items[Caster->client->playerinfo.weap_ammo_index] > 0) + { + if (!(deathmatch->value && ((int)dmflags->value & DF_INFINITE_MANA))) + Caster->client->playerinfo.pers.inventory.Items[Caster->client->playerinfo.weap_ammo_index] -= + Caster->client->playerinfo.pers.weapon->quantity; + } +} + +// ************************************************************************************************ +// WeaponThink_Maceballs +// ---------------------- +// ************************************************************************************************ + +void WeaponThink_Maceballs(edict_t *caster, char *format,...) +{ + vec3_t OriginToLowerJoint={0.945585,2.26076,0.571354}, + OriginToUpperJoint={1.80845,2.98912,3.27800}, + defaultstartpos={-4.0,15.0,15.0}, // Ripper start position + defaultstartpos2={13.0,15.0,-15.0}, // Maceball start position + startpos, + fwd; + + assert(caster->client); + + if (caster->client->playerinfo.powerup_timer > level.time) + { + // Set up the ball's starting position and aiming angles then cast the spell. + Weapon_CalcStartPos(OriginToLowerJoint, OriginToUpperJoint, defaultstartpos2, startpos, caster); + + AngleVectors(caster->client->aimangles, fwd, NULL, NULL); + startpos[2] += caster->viewheight - 14.0; + + SpellCastMaceball(caster, startpos, caster->client->aimangles, NULL, 0.0); + // Giant iron dooms require lotsa mana, but yer average ripper needs far less. + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + caster->client->playerinfo.pers.inventory.Items[caster->client->playerinfo.weap_ammo_index] -= + caster->client->playerinfo.pers.weapon->quantity * 2.0; + } + else + { + // Set up the ball's starting position and aiming angles then cast the spell. + Weapon_CalcStartPos(OriginToLowerJoint, OriginToUpperJoint,defaultstartpos,startpos,caster); + + AngleVectors(caster->client->aimangles, fwd, NULL, NULL); + startpos[2] += caster->viewheight - 14.0; + + SpellCastRipper(caster, startpos, caster->client->aimangles, NULL); + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + caster->client->playerinfo.pers.inventory.Items[caster->client->playerinfo.weap_ammo_index] -= + caster->client->playerinfo.pers.weapon->quantity; // Un-powered + } +} + +// ************************************************************************************************ +// WeaponThink_MagicMissileSpread +// ------------------------------ +// ************************************************************************************************ +#define MISSILE_YAW 7.0 +#define MISSILE_PITCH 2.0 +#define MISSILE_SEP 4.0 +void WeaponThink_MagicMissileSpread(edict_t *caster,char *format,...) +{ + va_list marker; + int missilepos, + count; + char curchar; + vec3_t OriginToLowerJoint={0.945585,2.26076,0.571354}, + OriginToUpperJoint={1.80845,2.98912,3.27800}, + DefaultStartPos={8.0,0.0,5.0}, + StartPos; + vec3_t fireangles, fwd; + + // Get number of missiles to fire off and get the separation between missiles. + + assert(strlen(format)); + + missilepos=1; + + count=0; + + va_start(marker,format); + curchar=format[0]; + assert(curchar=='i'); + missilepos=va_arg(marker,int); + va_end(marker); + + // Set up the Magic-missile's starting position and aiming angles then cast the spell. + + // Push the start position forward for earlier shots + DefaultStartPos[0] -= MISSILE_SEP*missilepos; + DefaultStartPos[1] += MISSILE_SEP*missilepos; + Weapon_CalcStartPos(OriginToLowerJoint,OriginToUpperJoint,DefaultStartPos,StartPos,caster); + StartPos[2] += caster->viewheight - 14.0; + + VectorCopy(caster->client->aimangles, fireangles); + fireangles[YAW] += missilepos*MISSILE_YAW; + fireangles[PITCH] += missilepos*MISSILE_PITCH; + AngleVectors(fireangles, fwd, NULL, NULL); + SpellCastMagicMissile(caster, StartPos, fireangles, fwd); + + if (missilepos == -1.0) + gi.sound(caster,CHAN_WEAPON,gi.soundindex("weapons/MagicMissileSpreadFire.wav"),1,ATTN_NORM,0); + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + caster->client->playerinfo.pers.inventory.Items[caster->client->playerinfo.weap_ammo_index]--; +// caster->client->playerinfo.pers.inventory.Items[caster->client->playerinfo.weap_ammo_index] -= +// caster->client->playerinfo.pers.weapon->quantity; +} + +// ************************************************************************************************ +// WeaponThink_SphereOfAnnihilation +// ------------------------------- +// ************************************************************************************************ + +void WeaponThink_SphereOfAnnihilation(edict_t *Caster,char *Format,...) +{ + va_list Marker; + qboolean *ReleaseFlagsPtr; + vec3_t Forward; + + // Get pointer to missile's release flag. + + assert(strlen(Format)); + + va_start(Marker,Format); + + assert(*Format=='g'); + + ReleaseFlagsPtr=va_arg(Marker,qboolean *); + + va_end(Marker); + + // Set up the Sphere-of-annihilation's aiming angles then cast the spell. + +// AngleVectors(Caster->client->v_angle,Forward,NULL,NULL); + AngleVectors(Caster->client->aimangles,Forward,NULL,NULL); + + SpellCastSphereOfAnnihilation(Caster, + NULL, + Caster->client->aimangles, //v_angle, + Forward, + 0.0, + ReleaseFlagsPtr); + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + Caster->client->playerinfo.pers.inventory.Items[Caster->client->playerinfo.weap_ammo_index]-= Caster->client->playerinfo.pers.weapon->quantity; +} + +// ************************************************************************************************ +// WeaponThink_Firewall +// ------------------------------- +// ************************************************************************************************ + +void WeaponThink_Firewall(edict_t *caster, char *format,...) +{ + SpellCastWall(caster, caster->s.origin, caster->client->aimangles, NULL, 0.0); + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + caster->client->playerinfo.pers.inventory.Items[caster->client->playerinfo.weap_ammo_index] -= caster->client->playerinfo.pers.weapon->quantity; +} + +// ************************************************************************************************ +// WeaponThink_RedRainBow +// ---------------------- +// ************************************************************************************************ + +void WeaponThink_RedRainBow(edict_t *caster,char *Format,...) +{ +// vec3_t StartPos, off; + vec3_t StartPos, Forward, Right; + +// VectorSet(off, 25.0, 6.0, 18.0); +// VectorGetOffsetOrigin(off, caster->s.origin, caster->client->aimangles[YAW], StartPos); + AngleVectors(caster->client->aimangles, Forward, Right, NULL); + VectorMA(caster->s.origin, 25.0F, Forward, StartPos); + VectorMA(StartPos, 6.0F, Right, StartPos); + StartPos[2] += caster->viewheight + 4.0; + + SpellCastRedRain(caster, StartPos, caster->client->aimangles, NULL, 0.0F); + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + caster->client->playerinfo.pers.inventory.Items[caster->client->playerinfo.weap_ammo_index] -= caster->client->playerinfo.pers.weapon->quantity; +} + +// ************************************************************************************************ +// WeaponThink_PhoenixBow +// ---------------------- +// ************************************************************************************************ + +void WeaponThink_PhoenixBow(edict_t *caster,char *Format,...) +{ + vec3_t StartPos, Forward, Right; + +// AngleVectors(caster->client->v_angle, Forward, Right, NULL); + AngleVectors(caster->client->aimangles, Forward, Right, NULL); + VectorMA(caster->s.origin, 25.0F, Forward, StartPos); + VectorMA(StartPos, 6.0F, Right, StartPos); + StartPos[2] += caster->viewheight + 4.0; + +// SpellCastPhoenix(caster, StartPos, caster->client->v_angle, Forward, 0.0F); + SpellCastPhoenix(caster, StartPos, caster->client->aimangles, Forward, 0.0F); + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + caster->client->playerinfo.pers.inventory.Items[caster->client->playerinfo.weap_ammo_index] -= caster->client->playerinfo.pers.weapon->quantity; +} + +// ************************************************************************************************ +// WeaponThink_HellStaff +// --------------------- +// ************************************************************************************************ + +void WeaponThink_HellStaff(edict_t *caster,char *Format,...) +{ + vec3_t StartPos; //, off; + vec3_t fwd, right; +// vec3_t startangle; + + // Set up the Hellstaff's starting position and aiming angles then cast the spell. +// VectorSet(off, 34.0, -6.0, 0.0); +// VectorGetOffsetOrigin(off, caster->s.origin, caster->client->aimangles[YAW], StartPos); + + // Two-thirds of the player angle is torso movement. +/* startangle[PITCH] = (caster->client->aimangles[PITCH] - caster->s.angles[PITCH]) * 2.0 / 3.0; + startangle[YAW] = caster->client->aimangles[YAW] - caster->s.angles[YAW]; + if (startangle[YAW] > 180.0) + startangle[YAW] -= 360.0; + else if (startangle[YAW] < -180.0) + startangle[YAW] += 360; + startangle[YAW] *= 2.0/3.0; + startangle[ROLL] = 0.0; +*/ +// VectorAdd(startangle, caster->s.angles, startangle); +// AngleVectors(startangle, fwd, right, NULL); + AngleVectors(caster->client->aimangles, fwd, right, NULL); + VectorMA(caster->s.origin,30,fwd,StartPos); + VectorMA(StartPos,10,right,StartPos); + StartPos[2] += caster->viewheight - 14.0; + + SpellCastHellstaff(caster, StartPos, caster->client->aimangles, NULL); + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + caster->client->playerinfo.pers.inventory.Items[caster->client->playerinfo.weap_ammo_index] -= caster->client->playerinfo.pers.weapon->quantity; +} + + + +// ************************************************************************************************ +// WeaponThink_Blast +// --------------------- +// ************************************************************************************************ + +void WeaponThink_Blast(edict_t *caster,char *Format,...) +{ + vec3_t startpos; + vec3_t fwd, right; + vec3_t mins={-3.0, -3.0, -3.0}, maxs={3.0, 3.0, 3.0}; + trace_t trace; + + assert(caster->client); + + // Find the firing position first. + AngleVectors(caster->client->aimangles, fwd, right, NULL); + VectorMA(caster->s.origin,10,fwd,startpos); + VectorMA(startpos, -4.0F, right, startpos); + startpos[2] += caster->viewheight; + + // Trace from the player's origin to the casting location to assure not spawning in a wall. + gi.trace(caster->s.origin, mins, maxs, startpos, caster, MASK_SHOT,&trace); + if (trace.startsolid || trace.allsolid) + { // No way to avoid spawning in a wall. + return; + } + + if (trace.fraction < 1.0) + { + VectorCopy(trace.endpos, startpos); + } + + // This weapon does not autotarget + SpellCastBlast(caster, startpos, caster->client->aimangles, NULL); + + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + caster->client->playerinfo.pers.inventory.Items[caster->client->playerinfo.weap_ammo_index] -= caster->client->playerinfo.pers.weapon->quantity; + + gi.sound(caster,CHAN_WEAPON,gi.soundindex("weapons/BlastFire.wav"),1,ATTN_NORM,0); +} + +// end diff --git a/Toolkit/Programming/GameCode/game/p_weapon.h b/Toolkit/Programming/GameCode/game/p_weapon.h new file mode 100644 index 0000000..9f28c14 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/p_weapon.h @@ -0,0 +1,31 @@ +// +// p_weapon.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef P_WEAPON_H +#define P_WEAPON_H + +// ************************************************************************************************ +// WeaponThink_XXX +// --------------- +// Player-weapon think functions, each corresponding to one weapon type. Made visible here so that +// they can be referenced from 'g_items.c'. +// ************************************************************************************************ + +void WeaponThink_SwordStaff(edict_t *Caster,char *Format,...); +void WeaponThink_FlyingFist(edict_t *Caster,char *Format,...); +void WeaponThink_MagicMissileSpread(edict_t *Caster,char *Format,...); +void WeaponThink_SphereOfAnnihilation(edict_t *Caster,char *Format,...); +void WeaponThink_Maceballs(edict_t *Caster,char *Format,...); +void WeaponThink_Firewall(edict_t *Caster,char *Format,...); +void WeaponThink_Ripper(edict_t *Caster,char *Format,...); +void WeaponThink_Blast(edict_t *Caster,char *Format,...); +void WeaponThink_RedRainBow(edict_t *Caster, char *Format,...); +void WeaponThink_PhoenixBow(edict_t *Caster, char *Format,...); +void WeaponThink_HellStaff(edict_t *Caster, char *Format,...); +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); + +#endif // P_WEAPON_H diff --git a/Toolkit/Programming/GameCode/game/pcode.h b/Toolkit/Programming/GameCode/game/pcode.h new file mode 100644 index 0000000..2dc1b3a --- /dev/null +++ b/Toolkit/Programming/GameCode/game/pcode.h @@ -0,0 +1,141 @@ +#define SCRIPT_VERSION 3 + +#define NUM_PARMS 16 + +enum OpCodes +{ + CODE_NEW_GLOBAL = 0, + CODE_NEW_GLOBAL_PLUS_ASSIGNMENT, + CODE_NEW_LOCAL, + CODE_NEW_LOCAL_PLUS_ASSIGNMENT, + CODE_NEW_PARAMETER, + CODE_NEW_PARAMETER_PLUS_DEFAULT, + CODE_FIELD, + CODE_ASSIGNMENT, + CODE_ADD, + CODE_SUBTRACT, + CODE_MULTIPLY, + CODE_DIVIDE, + CODE_ADD_ASSIGNMENT, + CODE_SUBTRACT_ASSIGNMENT, + CODE_MULTIPLY_ASSIGNMENT, + CODE_DIVIDE_ASSIGNMENT, + CODE_GOTO, + CODE_PUSH, + CODE_POP, + CODE_IF, + CODE_EXIT, + CODE_SUSPEND, + CODE_WAIT_SECONDS, + CODE_WAIT_ALL, + CODE_WAIT_ANY, + CODE_MOVE, + CODE_DEBUG, + CODE_USE, + CODE_ROTATE, + CODE_PRINT, + CODE_PLAY_SOUND, + CODE_ENABLE, + CODE_DISABLE, + CODE_ANIMATE, + CODE_DEBUG_STATEMENT, + CODE_CACHE_SOUND, + CODE_COPY_PLAYER_ATTRIBUTES, + CODE_SET_VIEW_ANGLES, + CODE_SET_CACHE_SIZE, +}; + +enum PushTypes +{ + PUSH_CONST_INT = 0, + PUSH_CONST_FLOAT, + PUSH_CONST_VECTOR, + PUSH_CONST_ENTITY, + PUSH_CONST_STRING, + PUSH_VAR, + PUSH_VAR_WITH_FIELD, + PUSH_FUNCTION, +}; + +enum ConditionTypes +{ + COND_EQUAL = 0, + COND_LESS_THAN, + COND_LESS_THAN_EQUAL, + COND_GREATER_THAN, + COND_GREATER_THAN_EQUAL, + COND_NOT_EQUAL, +}; + +enum FunctionTypes +{ + FUNC_FIND_ENTITY_WITH_TARGET = 0, + FUNC_SIN, + FUNC_COS, + FUNC_FIND_ENTITY_WITH_SCRIPT, + FUNC_SPAWN, + FUNC_GET_OTHER, + FUNC_GET_ACTIVATOR, +}; + +enum VariableT +{ + TypeINT = 0, + TypeFLOAT, + TypeVECTOR, + TypeENTITY, + TypeSTRING, + TypeUNKNOWN, +}; + +enum FeatureTypes +{ + FEATURE_TRIGGER = 0, + FEATURE_AMBIENT_SOUNDS, + FEATURE_CINEMATICS, + FEATURE_PLAGUE_SKINS, +}; + +#define VAR_LENGTH 64 + +// Command Flags +// Move +#define MOVE_DURATION 0x01 +#define MOVE_RATE 0x02 +#define MOVE_SIGNALER 0x04 +#define MOVE_ABSOLUTE 0x08 + +// Rotate +#define ROTATE_DURATION 0x01 +#define ROTATE_RATE 0x02 +#define ROTATE_SIGNALER 0x04 +#define ROTATE_ABSOLUTE 0x08 + +// Wait +#define WAIT_CLEAR 0x80 + +// Print +#define PRINT_ENTITY 0x01 +#define PRINT_CENTERED 0x02 +#define PRINT_LEVEL 0x04 +#define PRINT_CAPTIONED 0x08 + +// Play Sound +#define PLAY_SOUND_ENTITY 0x01 +#define PLAY_SOUND_VOLUME 0x02 +#define PLAY_SOUND_ATTENUATION 0x04 +#define PLAY_SOUND_CHANNEL 0x08 +#define PLAY_SOUND_TIMEDELAY 0x10 + +// Animate +#define ANIMATE_REPEAT 0x001 +#define ANIMATE_TURNING 0x002 +#define ANIMATE_MOVING 0x004 +#define ANIMATE_SIGNALER 0x008 +#define ANIMATE_SOURCE 0x010 + +// Debug +#define DEBUG_ENABLE 0x01 +#define DEBUG_MOVE 0x02 +#define DEBUG_ROTATE 0x04 +#define DEBUG_TIME 0x08 diff --git a/Toolkit/Programming/GameCode/game/q_shared.c b/Toolkit/Programming/GameCode/game/q_shared.c new file mode 100644 index 0000000..6af77e5 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/q_shared.c @@ -0,0 +1,311 @@ +#include "q_shared.h" +#include "random.h" + +/* +================== +BoxOnPlaneSide + +Returns 1, 2, or 1 + 2 +================== +*/ +#if !id386 +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p) +{ + float dist1, dist2; + int sides; + +// fast axial cases + if (p->type < 3) + { + if (p->dist <= emins[p->type]) + return 1; + if (p->dist >= emaxs[p->type]) + return 2; + return 3; + } + +// general case + switch (p->signbits) + { + case 0: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + break; + case 1: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + break; + case 2: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + break; + case 3: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + break; + case 4: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + break; + case 5: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + break; + case 6: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + break; + case 7: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + break; + default: + dist1 = dist2 = 0; // shut up compiler + assert( 0 ); + break; + } + + sides = 0; + if (dist1 >= p->dist) + sides = 1; + if (dist2 < p->dist) + sides |= 2; + + assert( sides != 0 ); + + return sides; +} +#else +#pragma warning( disable: 4035 ) + +__declspec(naked) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p) +{ + static int bops_initialized; + static int Ljmptab[8]; + + __asm { + + push ebx + + cmp bops_initialized, 1 + je initialized + mov bops_initialized, 1 + + mov Ljmptab[0*4], offset Lcase0 + mov Ljmptab[1*4], offset Lcase1 + mov Ljmptab[2*4], offset Lcase2 + mov Ljmptab[3*4], offset Lcase3 + mov Ljmptab[4*4], offset Lcase4 + mov Ljmptab[5*4], offset Lcase5 + mov Ljmptab[6*4], offset Lcase6 + mov Ljmptab[7*4], offset Lcase7 + +initialized: + + mov edx,ds:dword ptr[4+12+esp] + mov ecx,ds:dword ptr[4+4+esp] + xor eax,eax + mov ebx,ds:dword ptr[4+8+esp] + mov al,ds:byte ptr[17+edx] + cmp al,8 + jge Lerror + fld ds:dword ptr[0+edx] + fld st(0) + jmp dword ptr[Ljmptab+eax*4] +Lcase0: + fmul ds:dword ptr[ebx] + fld ds:dword ptr[0+4+edx] + fxch st(2) + fmul ds:dword ptr[ecx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[4+ebx] + fld ds:dword ptr[0+8+edx] + fxch st(2) + fmul ds:dword ptr[4+ecx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[8+ebx] + fxch st(5) + faddp st(3),st(0) + fmul ds:dword ptr[8+ecx] + fxch st(1) + faddp st(3),st(0) + fxch st(3) + faddp st(2),st(0) + jmp LSetSides +Lcase1: + fmul ds:dword ptr[ecx] + fld ds:dword ptr[0+4+edx] + fxch st(2) + fmul ds:dword ptr[ebx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[4+ebx] + fld ds:dword ptr[0+8+edx] + fxch st(2) + fmul ds:dword ptr[4+ecx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[8+ebx] + fxch st(5) + faddp st(3),st(0) + fmul ds:dword ptr[8+ecx] + fxch st(1) + faddp st(3),st(0) + fxch st(3) + faddp st(2),st(0) + jmp LSetSides +Lcase2: + fmul ds:dword ptr[ebx] + fld ds:dword ptr[0+4+edx] + fxch st(2) + fmul ds:dword ptr[ecx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[4+ecx] + fld ds:dword ptr[0+8+edx] + fxch st(2) + fmul ds:dword ptr[4+ebx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[8+ebx] + fxch st(5) + faddp st(3),st(0) + fmul ds:dword ptr[8+ecx] + fxch st(1) + faddp st(3),st(0) + fxch st(3) + faddp st(2),st(0) + jmp LSetSides +Lcase3: + fmul ds:dword ptr[ecx] + fld ds:dword ptr[0+4+edx] + fxch st(2) + fmul ds:dword ptr[ebx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[4+ecx] + fld ds:dword ptr[0+8+edx] + fxch st(2) + fmul ds:dword ptr[4+ebx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[8+ebx] + fxch st(5) + faddp st(3),st(0) + fmul ds:dword ptr[8+ecx] + fxch st(1) + faddp st(3),st(0) + fxch st(3) + faddp st(2),st(0) + jmp LSetSides +Lcase4: + fmul ds:dword ptr[ebx] + fld ds:dword ptr[0+4+edx] + fxch st(2) + fmul ds:dword ptr[ecx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[4+ebx] + fld ds:dword ptr[0+8+edx] + fxch st(2) + fmul ds:dword ptr[4+ecx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[8+ecx] + fxch st(5) + faddp st(3),st(0) + fmul ds:dword ptr[8+ebx] + fxch st(1) + faddp st(3),st(0) + fxch st(3) + faddp st(2),st(0) + jmp LSetSides +Lcase5: + fmul ds:dword ptr[ecx] + fld ds:dword ptr[0+4+edx] + fxch st(2) + fmul ds:dword ptr[ebx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[4+ebx] + fld ds:dword ptr[0+8+edx] + fxch st(2) + fmul ds:dword ptr[4+ecx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[8+ecx] + fxch st(5) + faddp st(3),st(0) + fmul ds:dword ptr[8+ebx] + fxch st(1) + faddp st(3),st(0) + fxch st(3) + faddp st(2),st(0) + jmp LSetSides +Lcase6: + fmul ds:dword ptr[ebx] + fld ds:dword ptr[0+4+edx] + fxch st(2) + fmul ds:dword ptr[ecx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[4+ecx] + fld ds:dword ptr[0+8+edx] + fxch st(2) + fmul ds:dword ptr[4+ebx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[8+ecx] + fxch st(5) + faddp st(3),st(0) + fmul ds:dword ptr[8+ebx] + fxch st(1) + faddp st(3),st(0) + fxch st(3) + faddp st(2),st(0) + jmp LSetSides +Lcase7: + fmul ds:dword ptr[ecx] + fld ds:dword ptr[0+4+edx] + fxch st(2) + fmul ds:dword ptr[ebx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[4+ecx] + fld ds:dword ptr[0+8+edx] + fxch st(2) + fmul ds:dword ptr[4+ebx] + fxch st(2) + fld st(0) + fmul ds:dword ptr[8+ecx] + fxch st(5) + faddp st(3),st(0) + fmul ds:dword ptr[8+ebx] + fxch st(1) + faddp st(3),st(0) + fxch st(3) + faddp st(2),st(0) +LSetSides: + faddp st(2),st(0) + fcomp ds:dword ptr[12+edx] + xor ecx,ecx + fnstsw ax + fcomp ds:dword ptr[12+edx] + and ah,1 + xor ah,1 + add cl,ah + fnstsw ax + and ah,1 + add ah,ah + add cl,ah + pop ebx + mov eax,ecx + ret +Lerror: + int 3 + } +} +#pragma warning( default: 4035 ) +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/q_shared.h b/Toolkit/Programming/GameCode/game/q_shared.h new file mode 100644 index 0000000..aabf8cb --- /dev/null +++ b/Toolkit/Programming/GameCode/game/q_shared.h @@ -0,0 +1,1197 @@ +#ifndef QSHARED_H +#define QSHARED_H +// q_shared.h -- included first by ALL program modules (unfortuantly this is true for all code from id) + +// unknown pragmas are SUPPOSED to be ignored, but.... +#pragma warning(disable : 4244) // MIPS -- truncation from double to float in MSDEV +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4305) // truncation from const double to float + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "H2Common.h" +#include "q_Typedef.h" + +#define DEMO_CODE 0 + +#ifdef QUAKE2_STATIC +#define QUAKE2_API +#else +#ifdef QUAKE2 +#define QUAKE2_API __declspec(dllexport) +#else +#define QUAKE2_API __declspec(dllimport) +#endif +#endif + +// These are the only 2 references to C_ONLY +// id386 could do with removing +#define C_ONLY 1 + +#if defined _M_IX86 && !defined C_ONLY +#define id386 1 +#else +#define id386 0 +#endif + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +// angle indexes +#define PITCH 0 // up / down +#define YAW 1 // left / right +#define ROLL 2 // fall over + +#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString +#define MAX_STRING_TOKENS 80 // max tokens resulting from Cmd_TokenizeString +#define MAX_TOKEN_CHARS 128 // max length of an individual token + +#define MAX_QPATH 64 // max length of a quake game pathname +#define MAX_OSPATH 128 // max length of a filesystem pathname + +// game print flags +#define PRINT_LOW 0 // pickup messages +#define PRINT_MEDIUM 1 // death messages +#define PRINT_HIGH 2 // critical messages +#define PRINT_CHAT 3 // chat messages +#define PRINT_CAPTION 4 // captioning at bottom +#define PRINT_TEAM 5 // chat message to team members + +#define ERR_FATAL 0 // exit the entire game with a popup window +#define ERR_DROP 1 // print to console and disconnect from game +#define ERR_DISCONNECT 2 // don't kill server + +#define PRINT_ALL 0 +#define PRINT_DEVELOPER 1 // only print when "developer 1" +#define PRINT_ALERT 2 + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif +#define SQRT2 1.414213562 +#define TIME_EPSILON 0.01 + +#define VectorCopy_Macro(a,b) (b[0]=a[0],b[1]=a[1],b[2]=a[2]) +#define VectorSubtract_Macro(a,b,c) (c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2]) + +H2COMMON_API int Q_log2(int val); + +H2COMMON_API void ClearBounds (vec3_t mins, vec3_t maxs); +H2COMMON_API void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); + +H2COMMON_API float anglemod(float a); +H2COMMON_API float anglemod_old(float a); +H2COMMON_API float LerpAngle (float a1, float a2, float frac); + +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane); + +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide( (emins), (emaxs), (p))) + +//============================================= + +#define MAX_COLORS 32 + +extern H2COMMON_API paletteRGBA_t TextPalette[MAX_COLORS]; + +typedef enum +{ + P_BLACK , + P_RED , + P_GREEN , + P_YELLOW , + P_BLUE , + P_PURPLE , + P_CYAN , + P_WHITE , + + P_HBLACK , + P_HRED , + P_HGREEN , + P_HYELLOW , + P_HBLUE , + P_HPURPLE , + P_HCYAN , + P_HWHITE , + + P_DESIGNER , + P_PROGRAMMER , + P_OBJ_NORMAL , + P_OBJ_BOLD , + P_OBIT , + P_CAPTION , + P_CHAT , + P_TEAM , + + P_VERSION , + P_FRAGS , + P_ALTFRAGS , + P_MENUFIELD , + P_MSGBOX , + P_HEADER , + P_CRED_TITLE , + P_CRED_CONTENT + +} PalIdx_t; + +//============================================= + +H2COMMON_API char *COM_SkipPath (char *pathname); +H2COMMON_API void COM_StripExtension (char *in, char *out); +H2COMMON_API void COM_FileBase (char *in, char *out); +H2COMMON_API void COM_FilePath (char *in, char *out); +H2COMMON_API void COM_DefaultExtension (char *path, char *extension); + +H2COMMON_API char *COM_Parse (char **data_p); +H2COMMON_API void Com_sprintf (char *dest, int size, char *fmt, ...); +H2COMMON_API void Com_PageInMemory (byte *buffer, int size); + +//============================================= + +H2COMMON_API short BigShort(short l); +H2COMMON_API int BigLong(int l); +H2COMMON_API float BigFloat(float f); + +#define LittleShort(x) (x) +#define LittleLong(x) (x) +#define LittleFloat(x) (x) + +H2COMMON_API float Clamp(float src, float min, float max); +H2COMMON_API int ClampI(int src, int min, int max); +H2COMMON_API float Approach(float curr, float dest, float rate); +H2COMMON_API char *va(char *format, ...); + +//============================================= + +// +// key / value info strings +// +#define MAX_INFO_KEY 64 +#define MAX_INFO_VALUE 64 +#define MAX_INFO_STRING 512 + +#ifdef __cplusplus +extern "C" +{ +#endif +H2COMMON_API char *Info_ValueForKey (char *s, char *key); +H2COMMON_API void Info_RemoveKey (char *s, char *key); +H2COMMON_API void Info_SetValueForKey (char *s, char *key, char *value); +H2COMMON_API void Set_Com_Printf(void (*toSet) (char *fmt, ...)); + +/* +============================================================== + +SYSTEM SPECIFIC + +============================================================== +*/ + +struct cplane_s; +extern H2COMMON_API vec3_t vec3_origin; +extern H2COMMON_API vec3_t vec3_up; + +extern int curtime; // time returned by last Sys_Milliseconds + +int Sys_Milliseconds (void); +void Sys_Mkdir (char *path); + +// large block stack allocation routines +void *Hunk_Begin (int maxsize); +void *Hunk_Alloc (int size); +void Hunk_Free (void *buf); +int Hunk_End (void); + +// directory searching +#define SFF_ARCH 0x01 +#define SFF_HIDDEN 0x02 +#define SFF_RDONLY 0x04 +#define SFF_SUBDIR 0x08 +#define SFF_SYSTEM 0x10 + +/* +** pass in an attribute mask of things you wish to REJECT +*/ +char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave ); +char *Sys_FindNext ( unsigned musthave, unsigned canthave ); +void Sys_FindClose (void); + + +// this is only here so the functions in q_shared.c and q_shwin.c can link +void Sys_Error (char *error, ...); +void Com_Printf (char *msg, ...); +void Com_ColourPrintf (PalIdx_t colour, char *msg, ...); + +#ifdef __cplusplus +} +#endif + +/* +========================================================== + +CVARS (console variables) + +========================================================== +*/ + +#ifndef CVAR +#define CVAR + +#define CVAR_ARCHIVE 1 // set to cause it to be saved to vars.rc +#define CVAR_USERINFO 2 // added to userinfo when changed +#define CVAR_SERVERINFO 4 // added to serverinfo when changed +#define CVAR_NOSET 8 // don't allow change from console at all, + // but can be set from the command line +#define CVAR_LATCH 16 // save changes until server restart + +// nothing outside the Cvar_*() functions should modify these fields! +typedef struct cvar_s +{ + char *name; + char *string; + char *latched_string; // for CVAR_LATCH vars + int flags; + qboolean modified; // set each time the cvar is changed + float value; + struct cvar_s *next; +} cvar_t; + +#endif // CVAR + +cvar_t *Cvar_Get (char *var_name, char *value, int flags); + +/************************************************************** + * palette info + **************************************************************/ + +typedef struct paletteRGB_s +{ + struct + { + byte r,g,b; + }; +} paletteRGB_t; + +/************************************************************** + * additional info for flex models with mesh nodes + **************************************************************/ + +#define MAX_FM_MESH_NODES 16 // also defined in ref_gl/fmodel.h + +typedef struct +{ + int frame; + paletteRGBA_t color; + byte flags; + int skin; +} fmnodeinfo_t; + +// flags + +#define FMNI_USE_FRAME (1<<0) +#define FMNI_USE_COLOR (1<<1) +#define FMNI_USE_SKIN (1<<2) +#define FMNI_NO_LERP (1<<3) +#define FMNI_NO_DRAW (1<<4) +#define FMNI_USE_REFLECT (1<<5) +/* +============================================================== + +COLLISION DETECTION + +============================================================== +*/ + +// ************************************************************************************************ +// CONTENTS_XXX +// ------------ +// Contents flags. +// ************************************************************************************************ + +// Lower bits are stronger, and will eat weaker brushes completely. + +#define CONTENTS_EMPTY 0x00000000 // nothing +#define CONTENTS_SOLID 0x00000001 // An eye is never valid in a solid. +#define CONTENTS_WINDOW 0x00000002 // Translucent, but not watery. +#define CONTENTS_ILLUSIONARY 0x00000004 // Was CONTENTS_AUX. +#define CONTENTS_LAVA 0x00000008 +#define CONTENTS_SLIME 0x00000010 +#define CONTENTS_WATER 0x00000020 +#define CONTENTS_MIST 0x00000040 +#define LAST_VISIBLE_CONTENTS CONTENTS_MIST + +// Remaining contents are non-visible, and don't eat brushes. + +#define CONTENTS_AREAPORTAL 0x00008000 +#define CONTENTS_PLAYERCLIP 0x00010000 +#define CONTENTS_MONSTERCLIP 0x00020000 + +// Currents can be added to any other contents, and may be mixed. + +#define CONTENTS_CURRENT_0 0x00040000 +#define CONTENTS_CURRENT_90 0x00080000 +#define CONTENTS_CURRENT_180 0x00100000 +#define CONTENTS_CURRENT_270 0x00200000 +#define CONTENTS_CURRENT_UP 0x00400000 +#define CONTENTS_CURRENT_DOWN 0x00800000 + +// Removed before bsping an entity. + +#define CONTENTS_ORIGIN 0x01000000 + +// Should never be on a brush, only in game (i.e. set by CM_ functions at map load time). + +#define CONTENTS_MONSTER 0x02000000 +#define CONTENTS_DEADMONSTER 0x04000000 + +// Brushes to be added after vis leaves. + +#define CONTENTS_DETAIL 0x08000000 + +// Auto set if any surface has transparency, e.g. water. + +#define CONTENTS_TRANSLUCENT 0x10000000 + +// This flag is special in that it is not stored in the .bsp by QuakeEd. It is passed into the trace +// functions to say that anything with CONTENTS_CAMERANOBLOCK should be ignored. So we can get away +// with defining it = CONTENTS_CAMERANOBLOCK. + +#define CONTENTS_CAMERABLOCK 0x20000000 // Was CONTENTS_LADDER. + +// This flag is special in that it is NOT passed into the trace functions, but may be stored in the +//.bsp by QuakeEd to say that traces with CONTENTS_CAMERABLOCK as the mask will ignore any brushes +// with this flag. + +#define CONTENTS_CAMERANOBLOCK 0x40000000 + +// Only do the trace against the world, not entities within it. Not stored in the .bsp and passed +// only as an argument to trace fucntions. + +#define CONTENTS_WORLD_ONLY 0x80000000 + +// ************************************************************************************************ +// MASK_XXX +// -------- +// Contents masks. +// ************************************************************************************************ + +#define MASK_ALL 0x7fffffff +#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_WINDOW) +#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER) +#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW) +#define MASK_MONSTERSOLID (CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER) +#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME) +#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA) +#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER) +#define MASK_CURRENT (CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN) +#define MASK_DRIP (CONTENTS_SOLID|CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WINDOW) + +// ************************************************************************************************ +// SURF_XXX +// -------- +// ************************************************************************************************ + +#define SURF_LIGHT 0x1 // Value will hold the light strength. +#define SURF_SLICK 0x2 // Affects game physics. +#define SURF_SKY 0x4 // Don't draw, but add to skybox. +#define SURF_WARP 0x8 // Turbulent water warp. +#define SURF_TRANS33 0x10 +#define SURF_TRANS66 0x20 +#define SURF_FLOWING 0x40 // Scroll towards angle. +#define SURF_NODRAW 0x80 // Don't bother referencing the texture. +#define SURF_TALL_WALL 0x00000400 // Face doesn't get broken up as normal. +#define SURF_ALPHA_TEXTURE 0x00000800 // texture has alpha in it, and should show through in bsp process +#define SURF_ANIMSPEED 0x00001000 // value will hold the anim speed in fps +#define SURF_UNDULATE 0x00002000 // rock surface up and down... +#define SURF_QUAKE 0x00004000 // rock surface up and down when quake value on + +// gi.BoxEdicts() can return a list of either solid or trigger entities +// FIXME: eliminate AREA_ distinction? + +#define AREA_SOLID 1 +#define AREA_TRIGGERS 2 + + +// plane_t structure +// !!! if this is changed, it must be changed in asm code too !!! +typedef struct cplane_s +{ + vec3_t normal; + float dist; + byte type; // for fast side tests + byte signbits; // signx + (signy<<1) + (signz<<1) + byte pad[2]; +} cplane_t; + +// structure offset for asm code +#define CPLANE_NORMAL_X 0 +#define CPLANE_NORMAL_Y 4 +#define CPLANE_NORMAL_Z 8 +#define CPLANE_DIST 12 +#define CPLANE_TYPE 16 +#define CPLANE_SIGNBITS 17 +#define CPLANE_PAD0 18 +#define CPLANE_PAD1 19 + +typedef struct cmodel_s +{ + vec3_t mins, maxs; + vec3_t origin; // for sounds or lights + int headnode; +} cmodel_t; + +typedef struct csurface_s +{ + char name[16]; + int flags; + int value; +} csurface_t; + +// ************************************************************************************************ +// trace_t +// ------- +// A trace is returned when a box is swept through the world. +// ************************************************************************************************ + +typedef struct trace_s +{ + byte allsolid; // if true, plane is not valid + byte startsolid; // if true, the initial point was in a solid area + byte succeeded; // not always set, just in special cases, subjective + byte architecture; // set if the moved collided with world (not entities) + // needed because the player move code doesn`t know anything + // about the location or nature of edicts + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + cplane_t plane; // surface normal at impact + csurface_t *surface; // surface hit + int contents; // contents on other side of surface hit + struct edict_s *ent; // not set by CM_*() functions +} trace_t; + +// ************************************************************************************************ +// pmtype_t +// -------- +// ************************************************************************************************ + +typedef enum +{ + PM_NORMAL, // Can accelerate and turn, clips. + PM_SPECTATOR, // Can accelerate and turn, no clip. + PM_DEAD, // No acceleration or turning, dead. + PM_GIB, // No acceleration or turning, dead, different bounding box. + PM_FREEZE, // Running a server demo. + PM_INTERMISSION, // An existing remote camera view is already underway. +} pmtype_t; + +// ************************************************************************************************ +// PMF_XXX +// ------- +// These are pmove->pm_flags. +// ************************************************************************************************ + +#define PMF_STANDSTILL 0x0001 +#define PMF_JUMP_HELD 0x0002 +#define PMF_ON_GROUND 0x0004 +#define PMF_TIME_LAND 0x0008 // pm_time is time before rejump +#define PMF_TIME_TELEPORT 0x0010 // pm_time is non-moving time +#define PMF_NO_PREDICTION 0x0020 // temporarily disables prediction (used for grappling hook) +#define PMF_LOCKMOVE 0x0040 +#define PMF_LOCKTURN 0x0080 + +#define PC_COLLISION 0x0001 // collided on a move +#define PC_SLIDING 0x0002 // sliding down a steep slope + +#define WF_SURFACE 0x0001 // On the surface +#define WF_DIVE 0x0002 // Dive on next animation +#define WF_DIVING 0x0004 // Currently diving +#define WF_SWIMFREE 0x0008 // Currently swimming freely underwater +#define WF_SINK 0x0010 // Sink below the surface of the water + +// ************************************************************************************************ +// pmove_state_t +// ------------- +// This structure contains the information necessary for client side movement prediction. It MUST +// be communicated bit-accurate from the server to the client to guarantee that prediction stays in +// sync., so no floats are used. If any part of the game code modifies this struct, it will result +// in a prediction error of some degree. +// ************************************************************************************************ + +typedef struct +{ + pmtype_t pm_type; + short origin[3]; // 12.3 + short velocity[3]; // 12.3 + byte pm_flags; // ducked, jump_held, etc + byte w_flags; // water state + byte c_flags; // collision + byte pm_time; // each unit = 8 ms + short gravity; + short delta_angles[3];// Added to command angles to get view direction. Changed by spawns, + // rotating objects and teleporters. +} pmove_state_t; + +// ************************************************************************************************ +// BUTTON_XXX +// ---------- +// ************************************************************************************************ + +#define BUTTON_ATTACK 1 +#define BUTTON_DEFEND 2 +#define BUTTON_ACTION 4 +#define BUTTON_CREEP 8 +#define BUTTON_RUN 16 +#define BUTTON_AUTOAIM 32 +#define BUTTON_LOOKAROUND 64 +#define BUTTON_QUICKTURN 128 +#define BUTTON_INVENTORY 256 +#define BUTTON_ANY 512 // Any key whatsoever. + +// ************************************************************************************************ +// usercmd_t +// --------- +// Sent to the server each client frame. +// ************************************************************************************************ + +typedef struct usercmd_s +{ + byte msec; + short buttons; + short angles[3], + aimangles[3], + camera_vieworigin[3],camera_viewangles[3], + forwardmove,sidemove,upmove; + byte prediction; + byte lightlevel; // Light level the player is standing on. +} usercmd_t; + +// ************************************************************************************************ +// pmove_t +// ------- +// ************************************************************************************************ + +#define MAXTOUCH 32 + +typedef struct +{ + // State (in / out). + + pmove_state_t s; + + // Command (in). + + usercmd_t cmd; + qboolean snapinitial; // If s has been changed outside pmove. + + // In and out. + + float waterheight; + float desiredWaterHeight; + + // Results (out). + + int numtouch; + struct edict_s *touchents[MAXTOUCH]; + + float viewheight; + vec3_t viewangles; // Clamped. + vec3_t camera_viewangles; // Camera angles from client. + + float *origin, *velocity; + vec3_t mins, maxs; // Bounding-box size. + float *intentMins, *intentMaxs; + + struct edict_s *groundentity; + csurface_t *GroundSurface; + cplane_t GroundPlane; + int GroundContents; + + int watertype; + int waterlevel; + float knockbackfactor; + + // Callbacks to test the world. + + void (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end,trace_t *trace); + int (*pointcontents) (vec3_t point); + + struct edict_s *self; +} pmove_t; + +// entity_state_t->renderfx flags +#define RF_MINLIGHT 0x00000001 // allways have some light (viewmodel) +#define RF_REFLECTION 0x00000002 // Use GL spherical mapping, if available +#define RF_WEAPONMODEL 0x00000004 // only draw through eyes +#define RF_FULLBRIGHT 0x00000008 // allways draw full intensity +#define RF_DEPTHHACK 0x00000010 // for view weapon Z crunching +#define RF_TRANSLUCENT 0x00000020 +#define RF_FRAMELERP 0x00000040 +#define RF_CUSTOMSKIN 0x00000080 // skin is an index in image_precache +#define RF_GLOW 0x00000100 // pulse lighting for bonus items +#define RF_SCALE_XYZ 0x00000200 +#define RF_SCALE_XY 0x00000400 +#define RF_SCALE_Z 0x00000800 +#define RF_PRIMITIVE 0x00001000 // line, or other primitive runtime generated by the render DLL +#define RF_FIXED 0x00002000 // the sprite has a fixed direction + // and up vector, by default, a + // sprite is always oriented to the + // view (no effect on models) +#define RF_TRANS_ADD 0x00004000 // Additive transparency +#define RF_TRANS_ADD_ALPHA 0x00008000 // Adds emulation of alpha for additive transparent objects using tint +#define RF_TRANS_GHOST 0x00010000 // Like subtractive translucency +#define RF_ALPHA_TEXTURE 0x00020000 // Object has an alpha texture map +#define RF_NODEPTHTEST 0x00080000 // Turns off depth testing for sprites only +#define RF_IGNORE_REFS 0x00100000 // don't update the ref points for a model +#define RF_NODRAW 0x00200000 +#define RF_CULL_LARGE 0x00400000 // If set on a poly that is really close to the near clip plane and occupies + // a signifiant amount of screen real-estate, the poly will be culled. Used + // for particles in software. + +#define RF_TRANS_ANY (RF_TRANS_ADD | RF_TRANS_GHOST | RF_TRANSLUCENT) + +// player_state_t->refdef flags +#define RDF_UNDERWATER 0x00000001 // warp the screen as apropriate +#define RDF_NOWORLDMODEL 0x00000002 // used for player configuration screen + +// sound channels +// channel 0 never willingly overrides +// other channels (1-7) allways override a playing sound on that channel +#define CHAN_AUTO 0 +#define CHAN_WEAPON 1 +#define CHAN_VOICE 2 +#define CHAN_ITEM 3 +#define CHAN_BODY 4 +#define CHAN_FOOTSTEP 5 +#define CHAN_FOOTSTEP2 6 +#define CHAN_WEAPON2 7 +// modifier flags +#define CHAN_NO_PHS_ADD 8 // send to all clients, not just ones in PHS (ATTN 0 will also do this) +#define CHAN_RELIABLE 16 // send by reliable message, not datagram + + +// sound attenuation values +#define ATTN_NONE 0 // full volume the entire level +#define ATTN_NORM 1 +#define ATTN_IDLE 2 +#define ATTN_STATIC 3 // diminish very rapidly with distance +#define ATTN_VERYSTATIC 4 + +// player_state->stats[] indexes +#define STAT_HEALTH_ICON 0 // Icon for health +#define STAT_HEALTH 1 // Health value +#define STAT_AMMO_ICON 2 // Icon for ammo +#define STAT_AMMO 3 // Amount of ammo +#define STAT_WEAPON_ICON 4 // Current offensive weapon +#define STAT_WEAPON 5 +#define STAT_DEFENCE_ICON 6 // Current defensive weapon +#define STAT_DEFENCE 7 +#define STAT_OFFMANA_ICON 8 // Icon describing offensive mana +#define STAT_OFFMANA_BACK 9 // Amount of offensive mana +#define STAT_OFFMANA 10 // Icon describing defensive mana +#define STAT_DEFMANA_ICON 11 // Amount of defensive mana +#define STAT_DEFMANA_BACK 12 +#define STAT_DEFMANA 13 +#define STAT_FRAGS_ICON 14 // cleared each frame, 1 = health, 2 = armor +#define STAT_FRAGS 15 // which status to print +#define STAT_FLASHES 16 +#define STAT_LAYOUTS 17 +#define STAT_PUZZLE_ITEM1 18 +#define STAT_PUZZLE_ITEM2 19 +#define STAT_PUZZLE_ITEM3 20 +#define STAT_PUZZLE_ITEM4 21 +#define STAT_PUZZLE_COUNT 22 +#define STAT_POWERUP_BACK 23 +#define STAT_POWERUP_ICON 24 +#define STAT_POWERUP_TIMER 25 +#define STAT_LUNG_BACK 26 +#define STAT_LUNG_ICON 27 +#define STAT_LUNG_TIMER 28 +#define STAT_LIFEBAR_BACK 29 +#define STAT_LIFEBAR_SIZE 30 +#define STAT_LIFEBAR_VALUE 31 + +#define MAX_STATS 32 + +// dmflags->value flags +#define DF_WEAPONS_STAY 0x0001 +#define DF_NO_SHRINE 0x0002 +#define DF_NONAMES 0x0004 +#define DF_NO_HEALTH 0x0008 +#define DF_SHOW_LEADER 0x0010 +#define DF_SHRINE_CHAOS 0x0020 +#define DF_SAME_LEVEL 0x0040 +#define DF_FORCE_RESPAWN 0x0080 +#define DF_SKINTEAMS 0x0100 +//#define DF_MODELTEAMS 0x0200 +#define DF_ALLOW_EXIT 0x0400 +#define DF_INFINITE_MANA 0x0800 +#define DF_NO_FRIENDLY_FIRE 0x1000 +#define DF_NO_OFFENSIVE_SPELL 0x2000 +#define DF_NO_DEFENSIVE_SPELL 0x4000 +#define DF_DISMEMBER 0x8000 + +#define DF_DEATHMATCH_SET 0x80000000 // High bit indicates deathmatch, so that it can be transmitted in playerinfo. + +/* +========================================================== + + ELEMENTS COMMUNICATED ACROSS THE NET + +========================================================== +*/ + +#define ANGLE2SHORT(x) ((int)((x)*65536/360) & 65535) +#define SHORT2ANGLE(x) ((x)*(360.0/65536)) + +#define DEG2RAD( a ) ( a * M_PI ) / 180.0F + +// +// config strings are a general means of communication from +// the server to all connected clients. +// Each config string can be at most MAX_QPATH characters. +// + +#define CS_NAME 0 +#define CS_CDTRACK 1 +#define CS_SKY 2 +#define CS_SKYAXIS 3 // %f %f %f format +#define CS_SKYROTATE 4 +#define CS_LEVEL_NUMBER 5 +#define CS_STATUSBAR 6 // display program string (this seems to take up several slots - hence must be last) +#define CS_MAXCLIENTS 30 +#define CS_MAPCHECKSUM 31 // for catching cheater maps +#define CS_MODELS 32 +#define CS_SOUNDS (CS_MODELS+MAX_MODELS) +#define CS_IMAGES (CS_SOUNDS+MAX_SOUNDS) +#define CS_LIGHTS (CS_IMAGES+MAX_IMAGES) +#define CS_ITEMS (CS_LIGHTS+MAX_LIGHTSTYLES) +#define CS_PLAYERSKINS (CS_ITEMS+MAX_ITEMS) +#define MAX_CONFIGSTRINGS (CS_PLAYERSKINS+MAX_CLIENTS) + +// ************************************************************************************************ +// EffectsBuffer_t +// --------------- +// ************************************************************************************************ + +#define ENTITY_FX_BUF_SIZE 64 +#define ENTITY_FX_BUF_BLOCK_SIZE 128 +#define MAX_PERSISTANT_EFFECTS 512 + +typedef struct EffectsBuffer_s +{ + byte *buf; + int bufSize; + int freeBlock; + int numEffects; +} EffectsBuffer_t; + +typedef struct PerEffectsBuffer_s +{ + byte buf[ENTITY_FX_BUF_SIZE]; + int bufSize; + int freeBlock; + int numEffects; + int send_mask; + int demo_send_mask; + int fx_num; +} PerEffectsBuffer_t; + +// ************************************************************************************************ +// entity_state_t +// -------------- +// This is the information conveyed from the server to clients in an update message, about entities +// that the client will need to render. +// ************************************************************************************************ + +typedef struct entity_state_s +{ + // Edict index. + + short number; + + // Model's current animation frame index. + + short frame; + + // Model's position and orientation in the world. + + vec3_t origin; + vec3_t angles; + vec3_t old_origin; // Used for lerping (and hijacked for other uses). + + // Tells client which model do draw. + + byte modelindex; + + // For specific path to skin. + + char skinname[MAX_QPATH]; + int skinnum; + + // Model scale. + + float scale; + + // EF_XXX. + + int effects; + + // RF_XXX. + + int renderfx; + + // What's this exactly? + + paletteRGBA_t color; + + // Entire absLight gets sent if any component changes. + + paletteRGB_t absLight; + + // Client prediction: 8*(bits 0-4) is x/y radius, 8*(bits 5-9) is z min, 8*(bits 10-15) is z max. + // Note that gi.linkentity() sets this up. + + short solid; + + // For looping sounds, to guarantee shutoff. + + byte sound; + + // For looping sounds, so we can set volume and attenuation. + + byte sound_data; + + // required so we can place sounds for bmodels correctly in 3d space + vec3_t bmodel_origin; + + // Header block for list of all client effects attatched to this entity. + + EffectsBuffer_t clientEffects; + + // Specifies which parts (nodes) of the model are on/off, node colors etc. + + fmnodeinfo_t fmnodeinfo[MAX_FM_MESH_NODES]; + + // Skeletal info. Only relevant for player models (i.e. have U_JOINTED). + + short skeletalType; + short rootJoint; + + short swapFrame; + + // Used by the client to verify is this still the same entity it last had. + + byte usageCount; +} entity_state_t; + +// ************************************************************************************************ +// player_state_t +// -------------- +// This is the information needed in addition to the 'pmove_state_t' to render a view. There will +// only be 10 'player_state_t's sent each second, but the number of pmove_state_t changes will be +// relative to client frame rates. +// ************************************************************************************************ + +typedef struct +{ + // For prediction (must be communicated bit precise). + + pmove_state_t pmove; + + // For fixed views and serverdemos. + + vec3_t viewangles; + + // For remote camera views. + + vec3_t remote_vieworigin, + remote_viewangles; + int remote_id; + + // Z displacement of player's head from origin. + + short viewheight; + + // Deltas added to the player model's client determined angles. + + vec3_t offsetangles; + + // Horizontal field of view. + + float fov; + + // Refdef flags used during rendering. + + int rdflags; + + // Index of edict currently targeted by the player's auto-targeting facility. + + int AutotargetEntityNum; + + // For showing the amount of current level completed. + + byte map_percentage; + + // Current fog density for the player. + + float fog_density; + + // Id number for primary and secondary mission statments in strings.txt. + + short mission_num1; + short mission_num2; + + byte cinematicfreeze; // Shows if currently in a cinematic + + // Current state of players in this clients view (one bit per player). + + int PIV; + + // Fast status bar updates. + + short stats[MAX_STATS]; + + // These are NEVER sent accross the net, but are purely client-side repositiories needed by + // prediction and are filled from the player's entity_state_t. + + int frame,swapFrame; + vec3_t angles; + int effects, + skinnum, + renderfx; + fmnodeinfo_t fmnodeinfo[MAX_FM_MESH_NODES]; + + // ******************************************************************************************** + // All the stuff below is required for client prediction to function. NOTE still working on + // this... expect additions / removals / packet size reduction. + // ******************************************************************************************** + + // Player's acurate mins and maxs. + + vec3_t mins,maxs; + + // Inventory changes. + + byte NoOfItems, + inventory_changes[256], + inventory_remaining[256]; + + // Ground attributes. + + byte NonNullgroundentity; // boolean + cplane_t GroundPlane; + int GroundContents; + csurface_t GroundSurface; + + // Water attributes. + + int watertype; + int waterlevel; + float waterheight; + + // Grabbing / pullup stuff. + + vec3_t grabloc; + float grabangle; + + // Velocities imparted on a per animation frame basis. + + float fwdvel,sidevel,upvel; + + // PLAYER_FLAG_XXX. + + int flags; + + // FL_XXX. + + int edictflags; + + // Player edict's oldvelocity. + + float oldvelocity_z; + + // Animation sequencing state. + + int upperseq,lowerseq; + int upperframe,lowerframe; + byte upperidle,loweridle; // boolean + int uppermove_index,lowermove_index; + byte weapon,defense,lastweapon,lastdefense; + int weaponready; + int switchtoweapon; + byte newweapon; + int weap_ammo_index,def_ammo_index; + byte weaponcharge; + int armortype; + byte bowtype; + byte stafflevel; + byte helltype; + byte meteor_count; + byte handfxtype; + byte plaguelevel; + short skintype; + unsigned int altparts; + + int deadflag; + float ideal_yaw; + float leveltime; + float idletime; + + // Deathmatch flags. + + int dmflags; +} player_state_t; + +#define DEFAULT_PLAYER_LIB "Player" + +void P_Freelib(); +void P_Load(char *name); + + +// ************************************************************* +// Inlines +// ************************************************************* + +// microsoft's fabs seems to be ungodly slow... + +_inline float Q_fabs (float _X) +{ + *((long*)&_X) &= 0x7fffffff; + return (_X); +} + +// Quick version of float to long (trunc/round undefined) + +#pragma warning (disable:4035) +_inline __declspec( naked ) long Q_ftol( float f ) +{ + static int tmp; + __asm fld dword ptr [esp+4] + __asm fistp tmp + __asm mov eax, tmp + __asm ret +} +#pragma warning (default:4035) + +_inline int Q_stricmp (char *s1, char *s2) +{ +#if defined(WIN32) + return _stricmp (s1, s2); +#else + return strcasecmp (s1, s2); +#endif +} + +_inline int Q_strncasecmp (char *s1, char *s2, int n) +{ + return strnicmp (s1, s2, n); +} + +_inline int Q_strcasecmp (char *s1, char *s2) +{ + return stricmp (s1, s2); +} + + +// For ambient sounds. +typedef enum AmbientSoundID_e +{ + AS_NOTHING = 0, + AS_FIRE, + AS_WATERLAPPING, + AS_SEAGULLS, + AS_OCEAN, + AS_BIRDS, + AS_CRICKETS, + AS_FROGS, + AS_CRYING, + AS_MOSQUITOES, + AS_BUBBLES, // 10 + + AS_BELL, + AS_FOOTSTEPS, + AS_MOANS, + AS_SEWERDRIPS, + AS_WATERDRIPS, + AS_HEAVYDRIPS, + AS_SMALLFOUNTAIN, + AS_LARGEFOUNTAIN, + AS_SEWERWATER, + AS_OUTSIDEWATERWAY, // 20 + + AS_WINDCHIME, + AS_BIRD1, + AS_BIRD2, + AS_CAULDRONBUBBLE, + AS_HUGEWATERFALL, + AS_GONG, + AS_MUDPOOL, + AS_ROCKS, + AS_WINDEERIE, + AS_WINDNOISY, // 30 + + AS_WINDSOFTHI, + AS_WINDSOFTLO, + AS_WINDSTRONG1, + AS_WINDSTRONG2, + AS_WINDWHISTLE, + AS_CONVEYOR, + AS_BUCKETCONVEYOR, + + AS_CAVECREAK, + AS_SPIT, // 39 + + AS_MAX +} AmbientSoundID_t; + +typedef enum DoorSoundID_e +{ + DS_NONE = 0, + DS_GENERIC, + DS_HEAVYSTONE, + DS_SWINGARM, + DS_SWINGBRIDGE, + DS_MEDIUMWOOD, + DS_HUGEWOOD, + DS_MEDIUMSTONE, + DS_LARGESTONE, + DS_MEDIUMMETAL, + DS_FASTSLIDING, + DS_METALSLIDING, + DS_HUGESTONE, + DS_HUGEELEVATOR, + DS_CRANEWAREHOUSE, + DS_HAMMERPUMP, + DS_METALTABLE, + DS_LABTABLE, + DS_PISTON, + DS_CLANG, + DS_UNDERWATER, + DS_BAM, + DS_MAX +} DoorSoundID_t; + + +#endif // QSHARED_H diff --git a/Toolkit/Programming/GameCode/game/spl_BlueRing.c b/Toolkit/Programming/GameCode/game/spl_BlueRing.c new file mode 100644 index 0000000..6a7bc33 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_BlueRing.c @@ -0,0 +1,264 @@ +// +// spl_bluering.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "random.h" +#include "vector.h" +#include "g_playstats.h" +#include "p_actions2.h" + +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); +extern edict_t *PhoenixMissileReflect(edict_t *missile, edict_t *other, vec3_t vel); +extern edict_t *RedRainMissileReflect(edict_t *self, edict_t *other, vec3_t vel); +extern edict_t *MeteorBarrierReflect(edict_t *self, edict_t *other, vec3_t vel); +extern edict_t *SphereReflect(edict_t *self, edict_t *other, vec3_t vel); +extern edict_t *HellboltReflect(edict_t *self, edict_t *other, vec3_t vel); +extern edict_t *MorphReflect(edict_t *self, edict_t *other, vec3_t vel); + +// Since findradius is not specific enough for our needs +// This, for one, will seek out player maceballs, arrows, and meteors. +#define NEW_RING (1) + +#if !NEW_RING +edict_t *findringradius (edict_t *from, vec3_t org, float rad, edict_t *Caster) +{ + vec3_t eorg; + int j; + + if (!from) + from = g_edicts; + else + from++; + for ( ; from < &g_edicts[globals.num_edicts]; from++) + { + if (!from->inuse || (from->solid == SOLID_NOT) || (from->reflected_time == Caster->timestamp) || (from == Caster->owner)) + continue; + // if we aren't in the same y band, don't affect anyone + if ((abs(from->s.origin[2] - Caster->s.origin[2])) > 35.0) + continue; + // if we've already reflected this, don't do it again. + from->reflected_time = Caster->timestamp; + for (j=0 ; j<3 ; j++) + eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5); + if (VectorLength(eorg) > rad) + continue; + return from; + } + + return NULL; +} +#else +edict_t *findringradius (edict_t *from, vec3_t org, float rad, edict_t *Caster) +{ + static float max2; + static vec3_t min; + static vec3_t max; + vec3_t eorg; + int j; + float elen; + + if (!from) + { + max2=rad*rad; + VectorCopy(org,min); + VectorCopy(org,max); + for (j=0 ; j<3 ; j++) + { + min[j]-=rad; + max[j]+=rad; + } + } + while (1) + { + from=findinbounds(from,min,max); + if (!from) + return 0; + if (!from->inuse|| (from->reflected_time == Caster->timestamp) || (from == Caster->owner)) + continue; + if ((abs(from->s.origin[2] - Caster->s.origin[2])) > 35.0) + continue; + // if we've already reflected this, don't do it again. + from->reflected_time = Caster->timestamp; + for (j=0 ; j<3 ; j++) + eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5); + elen = DotProduct(eorg,eorg); + if (elen > max2) + continue; + return from; + } +} +#endif + +void RingThink(edict_t *self) +{ + int hit; + edict_t *ent = NULL, *newent; + vec3_t vel, hitloc; + vec_t scale; + edict_t* (*reflect)(edict_t*, edict_t*, vec3_t); + + // kill the ring eventually + self->nextthink = level.time + 0.1; + if (!(--self->count)) + { + G_SetToFree(self); + return; + } + + // Since find radius is not specific enough for our needs, here is + while(ent = findringradius(ent, self->s.origin, RING_EFFECT_RADIUS, self)) + { + hit = false; + reflect = NULL; + if (ent->mass) + { + if(!((ent->client) && (ent->client->playerinfo.reflect_timer > level.time))) + { + VectorSubtract(ent->s.origin, self->s.origin, vel); + scale = (RING_EFFECT_RADIUS - VectorLength(vel)) + * (RING_KNOCKBACK_SCALE/RING_EFFECT_RADIUS) + * sqrt(RING_MASS_FACTOR / ent->mass) + + RING_KNOCKBACK_BASE; + VectorNormalize(vel); + if (ent->client) + { // For players, force them up more and faster. + vel[2] = 0.5; + if (vel[2] < 0.5 && vel[2] > 0.0) + { + scale *= 2.0; + VectorNormalize(vel); + } + } + // Vel is just passing the direction of the knockback. + QPostMessage(ent, MSG_REPULSE, PRI_DIRECTIVE, "fff", vel[0], vel[1], vel[2] + 30.0); + if (ent->takedamage) + { + VectorMA(ent->s.origin, -ent->maxs[0], vel, hitloc); + if (ent->client && coop->value) // Don't damage players in coop. + T_Damage (ent, ent, self, vel, hitloc, vec3_origin, 0, (int)scale, DAMAGE_RADIUS | DAMAGE_SPELL,MOD_ROR); + if (ent->movetype != PHYSICSTYPE_NONE) + T_Damage (ent, ent, self, vel, hitloc, vec3_origin, 4, (int)scale, DAMAGE_RADIUS | DAMAGE_SPELL,MOD_ROR); + else + T_Damage (ent, ent, self, vel, hitloc, vec3_origin, 4, 0, DAMAGE_RADIUS | DAMAGE_SPELL,MOD_ROR); + // if we are hitting a player, knock the bastard down +// if (ent->client) +// KnockDownPlayer(&ent->client->playerinfo); + } + } + } + else if (strcmp(ent->classname, "Spell_RedRainArrow") == 0) + { + if (ent->owner != self && ent->reflect_debounce_time) + { + hit = true; + reflect = RedRainMissileReflect; + } + } + else if (strcmp(ent->classname, "Spell_PhoenixArrow") == 0) + { + if (ent->owner != self && ent->reflect_debounce_time) + { + hit = true; + reflect = PhoenixMissileReflect; + } + } + else if (strcmp(ent->classname, "Spell_MeteorBarrier") == 0) + { + if (ent->owner != self && ent->reflect_debounce_time) + { + hit = true; + reflect = MeteorBarrierReflect; + } + } + else if (strcmp(ent->classname, "Spell_SphereOfAnnihilation") == 0) + { + if (ent->owner != self && ent->reflect_debounce_time) + { + hit = true; + reflect = SphereReflect; + } + } + else if (strcmp(ent->classname, "Spell_Hellbolt") == 0) + { + if (ent->owner != self && ent->reflect_debounce_time) + { + hit = true; + reflect = HellboltReflect; + } + } + else if (strcmp(ent->classname, "Spell_MorphArrow") == 0) + { + if (ent->owner != self && ent->reflect_debounce_time) + { + hit = true; + reflect = MorphReflect; + } + } + else if (strcmp(ent->classname, "Spell_Maceball") == 0) + { + if (ent->owner != self) + { // Don't screw up your own projectiles. + + hit = true; + // Give the self credit for stuff killed with it, or worse yet, set the originator as the enemy. + ent->enemy = ent->owner; + ent->owner = self->owner; + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&ent->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", ent->velocity); + } + } + if (hit) + { + VectorSubtract(self->s.origin, ent->s.origin, vel); + VectorNormalize(vel); + // The dot product is the velocity towards the self (normally negative), let's reverse it. + scale = DotProduct(vel, ent->velocity); + if (scale > 0) // If heading towards the self, reverse that portion of the velocity + VectorMA(ent->velocity, -2.0*scale, vel, vel); + else // Jes' double the speed away + VectorMA(ent->velocity, scale, vel, vel); + if(reflect) + { + if (Vec3IsZero(vel)) // Reflect needs a non-zero vel. If zeroed, throw it straight up. + VectorSet(vel, 0, 0, 200.0); + newent = reflect(ent, self->owner, vel); + vectoangles(newent->velocity, newent->s.angles); + } + } + } +} + + +#define RING_THINKS 4 + +// Formula for knockback: 1 to 0 (center to outside) * KNOCKBACK_SCALE + KNOCKBACK_BASE +// This total is multiplied by (MASS_FACTOR / mass). (If mass > 200, less, if < 200, more) +void SpellCastBlueRing(edict_t *Caster, vec3_t StartPos, vec3_t AimAngles, vec3_t AimDir, float value) +{ + edict_t *newent; + + // create the actual effect entity + newent = G_Spawn(); + newent->owner = Caster; + newent->solid = SOLID_NOT; + newent->svflags |= SVF_NOCLIENT; + newent->movetype = PHYSICSTYPE_NONE; + newent->classname = "Spell_Ring"; + newent->nextthink = level.time + 0.1; + newent->think = RingThink; + newent->count = RING_THINKS; + newent->timestamp = level.time; + VectorCopy(Caster->s.origin, newent->s.origin); + gi.linkentity(newent); + + // fire off a special effect. + gi.CreateEffect(&Caster->s, FX_SPELL_BLUERING, CEF_OWNERS_ORIGIN, 0, ""); +} + +// end diff --git a/Toolkit/Programming/GameCode/game/spl_HellStaff.c b/Toolkit/Programming/GameCode/game/spl_HellStaff.c new file mode 100644 index 0000000..2d668e9 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_HellStaff.c @@ -0,0 +1,341 @@ +// +// spl_hellstaff.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "Angles.h" +#include "Utilities.h" +#include "vector.h" +#include "random.h" +#include "decals.h" +#include "p_main2.h" +#include "g_playstats.h" +#include "m_beast.h" + +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); +static void HellboltThink(edict_t *Self); +static void HellboltTouch(edict_t *Self,edict_t *Other,cplane_t *Plane,csurface_t *Surface); + +// Radius of zero seems to prevent collision between bolts + +#define HELLBOLT_RADIUS 0.0 + +// guts of creating a hell bolt +void create_hellbolt(edict_t *hellbolt) +{ + + hellbolt->s.effects |= EF_ALWAYS_ADD_EFFECTS; + hellbolt->svflags |= SVF_ALWAYS_SEND; + hellbolt->movetype = MOVETYPE_FLYMISSILE; + + VectorSet(hellbolt->mins, -HELLBOLT_RADIUS, -HELLBOLT_RADIUS, -HELLBOLT_RADIUS); + VectorSet(hellbolt->maxs, HELLBOLT_RADIUS, HELLBOLT_RADIUS, HELLBOLT_RADIUS); + + hellbolt->solid = SOLID_BBOX; + hellbolt->clipmask = MASK_SHOT; + hellbolt->touch = HellboltTouch; + hellbolt->think = HellboltThink; + hellbolt->dmg = irand(HELLBOLT_DAMAGE_MIN, HELLBOLT_DAMAGE_MAX); + hellbolt->classname = "Spell_Hellbolt"; + hellbolt->nextthink = level.time + 0.1; +} + +edict_t *HellboltReflect(edict_t *self, edict_t *other, vec3_t vel) +{ + edict_t *hellbolt; + + hellbolt = G_Spawn(); + + VectorCopy(self->s.origin, hellbolt->s.origin); + create_hellbolt(hellbolt); + VectorCopy(vel, hellbolt->velocity); + hellbolt->owner = other; + hellbolt->reflect_debounce_time = self->reflect_debounce_time -1; + G_LinkMissile(hellbolt); + gi.CreateEffect(&hellbolt->s, FX_WEAPON_HELLBOLT, CEF_OWNERS_ORIGIN|CEF_FLAG6, NULL, "t", hellbolt->velocity); + + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + // Do a nasty looking blast at the impact point + // only do this rarely, since we hit alot. + if (!(irand(0,10))) + gi.CreateEffect(&hellbolt->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", hellbolt->velocity); + + return(hellbolt); +} + +// **************************************************************************** +// HellboltTouch +// **************************************************************************** + +static void HellboltTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + byte makeScorch = 0; + + // did we hit the sky ? + if(surface && (surface->flags & SURF_SKY)) + { + SkyFly(self); + return; + } + + // did we hit someone where reflection is functional ? + if (self->reflect_debounce_time) + { + if(EntReflecting(other, true, true)) + { + Create_rand_relect_vect(self->velocity, self->velocity); + Vec3ScaleAssign(HELLBOLT_SPEED/2,self->velocity); + HellboltReflect(self, other, self->velocity); + + return; + } + } + + VectorNormalize2(self->velocity, self->movedir); + + if(other->takedamage) + { + T_Damage(other, self, self->owner, self->movedir, self->s.origin, plane->normal, self->dmg, self->dmg*2, + DAMAGE_SPELL, MOD_HELLSTAFF); + } + else + { + // Back off the origin for the damage a bit. We are a point and this will + // help fix hitting base of a stair and not hurting a guy on next step up. + AlertMonsters (self, self->owner, 1, false); + VectorMA(self->s.origin, -8.0, self->movedir, self->s.origin); + } + + makeScorch = 0; + if(IsDecalApplicable(self, other, self->s.origin, surface, plane, NULL)) + { + makeScorch = CEF_FLAG6; + } + gi.CreateEffect(&self->s, FX_WEAPON_HELLBOLTEXPLODE, CEF_OWNERS_ORIGIN | makeScorch, NULL, "d", self->movedir); + G_SetToFree(self); +} + +// **************************************************************************** +// HellboltThink +// **************************************************************************** + +static void HellboltThink(edict_t *Self) +{ + // Prevent any further transmission of this entity to clients. + Self->svflags |= SVF_NOCLIENT; + Self->think = NULL; +} + + + + +// **************************************************************************** +// SpellCastHellbolt +// **************************************************************************** + +#define HELLSTAFF_LASER_MAX_TARGETS 8 +void SpellCastHellstaff(edict_t *caster, vec3_t loc, vec3_t aimangles, vec3_t unused) +{ + edict_t *hellbolt, *tracebuddy; + trace_t trace; + vec3_t endpos, startpos, forward, vect; + int numHit = 0; // can hit no more than 8 guys... + vec3_t min={-4, -4, -4}; + vec3_t max={ 4, 4, 4}; + byte blen; + float laser_dist; + vec3_t planedir; + + assert(caster->client); + if (caster->client->playerinfo.powerup_timer > level.time) + { // Powered up version of this weapon-- a laser. + // We must trace from the player's centerpoint to the casting location to assure we don't hit anything.before the laser starts + tracebuddy = caster; + VectorCopy(loc, startpos); + gi.trace(caster->s.origin, min, max, startpos, caster, MASK_SHOT,&trace); + if(level.fighting_beast) + { + edict_t *ent; + + if(ent = check_hit_beast(caster->s.origin, trace.endpos)) + trace.ent = ent; + } + if ((trace.fraction > .99) || !(trace.contents & MASK_SOLID)) + { // It's okay to continue with the shot. If not, we should skip right to the impact. + // Now then, if we hit something on the way to the start location, damage him NOW! + if (trace.ent && trace.ent->takedamage) + { + // did we hit something that reflects ? + if(EntReflecting(trace.ent, true, true)) + { + // reflect it off into space - powerless now, so it won't hurt anyone it hits + + // draw line to this point + VectorSubtract(trace.endpos, startpos, vect); + blen = (byte)(VectorLength(vect)/8.0); + + gi.CreateEffect(NULL, FX_WEAPON_HELLSTAFF_POWER, 0, startpos, "tb", + forward, blen); + // re-constitute aimangle + aimangles[1] += flrand(160,200); + aimangles[0] += flrand(-20,20); + } + else + { + T_Damage(trace.ent, caster, caster, forward, trace.endpos, forward, + irand(HELLLASER_DAMAGE_MIN, HELLLASER_DAMAGE_MAX), 0, DAMAGE_SPELL,MOD_P_HELLSTAFF); + gi.CreateEffect(NULL, FX_WEAPON_HELLSTAFF_POWER_BURN, CEF_FLAG6, trace.endpos, "t", + forward); + } + tracebuddy = trace.ent; + } // Don't trace again since there really should only be one thing between the player and startpos + + // Set up for main laser damaging loop. + laser_dist = HELLLASER_DIST; + + do + { + AngleVectors(aimangles, forward, NULL, NULL); + VectorMA(startpos, laser_dist, forward, endpos); + gi.trace(startpos, min, max, endpos, tracebuddy, MASK_SHOT,&trace); + if(level.fighting_beast) + { + edict_t *ent; + + if(ent = check_hit_beast(caster->s.origin, trace.endpos)) + trace.ent = ent; + } + + if(trace.fraction < .99 ) + { + // if we hit anything that won't take damage, kill the beam + if (!trace.ent->takedamage) + break; + + // This is possible if the tracebuddy is not the caster because a new one was on the way to startpos. + if (trace.ent != caster) + { + // did we hit something that reflects ? + if(EntReflecting(trace.ent, true, true)) + { + // reflect it off into space - powerless now, so it won't hurt anyone it hits + + // draw line to this point + VectorSubtract(trace.endpos, startpos, vect); + blen = (byte)(VectorLength(vect)/8.0); + + gi.CreateEffect(NULL, FX_WEAPON_HELLSTAFF_POWER, 0, startpos, "tb", + forward, blen); + // re-constitute aimangle + aimangles[1] += flrand(160,200); + aimangles[0] += flrand(-20,20); + } + else + { + T_Damage(trace.ent, caster, caster, forward, trace.endpos, forward, + irand(HELLLASER_DAMAGE_MIN, HELLLASER_DAMAGE_MAX), 0, DAMAGE_SPELL,MOD_P_HELLSTAFF); + gi.CreateEffect(NULL, FX_WEAPON_HELLSTAFF_POWER_BURN, CEF_FLAG6, trace.endpos, "t", + forward); + } + } + // this seems to alleviate the problem of a trace hitting the same ent multiple times... + VectorSubtract(trace.endpos, startpos, vect); + laser_dist -= VectorLength(vect); + + VectorCopy(trace.endpos, startpos); + VectorSubtract(endpos, startpos, vect); + if(VectorLength(vect) > 16.0) + { + VectorMA(startpos, 16.0, forward, startpos); + } + tracebuddy = trace.ent; + numHit++; + } + + } while((trace.fraction < .99) && !(trace.contents & MASK_SOLID) && (numHit < HELLSTAFF_LASER_MAX_TARGETS) ); + } + + // We altenate sound slots to make the quick-firing work well with the sounds. + if (caster->client->playerinfo.flags & PLAYER_FLAG_ALTFIRE) + { // Use the alternate slot, clear the flag. + gi.sound(caster, CHAN_WEAPON2, gi.soundindex("weapons/HellLaserFire.wav"), 1, ATTN_NORM, 0); + caster->client->playerinfo.flags &= ~PLAYER_FLAG_ALTFIRE; + } + else + { // Use the regular slot, set the flag. + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/HellLaserFire.wav"), 1, ATTN_NORM, 0); + caster->client->playerinfo.flags |= PLAYER_FLAG_ALTFIRE; + } + + VectorSubtract(trace.endpos, startpos, vect); + blen = (byte)(VectorLength(vect)/8.0); + + // decide if we need a scorch mark or not + if(IsDecalApplicable(caster, trace.ent, caster->s.origin, trace.surface, &trace.plane, planedir)) + gi.CreateEffect(NULL, FX_WEAPON_HELLSTAFF_POWER, CEF_FLAG6|CEF_FLAG7, startpos, "tb", + forward, blen); + else + gi.CreateEffect(NULL, FX_WEAPON_HELLSTAFF_POWER, CEF_FLAG6, startpos, "tb", + forward, blen); + } + else + { // Unpowered version of this weapon-- hellbolts. + // Spawn the hellbolt + hellbolt = G_Spawn(); + + VectorCopy(loc, hellbolt->s.origin); + + //Check ahead first to see if it's going to hit anything at this angle + AngleVectors(aimangles, forward, NULL, NULL); + if(caster->client->playerinfo.flags & PLAYER_FLAG_NO_LARM) + { + VectorScale(forward, HELLBOLT_SPEED, hellbolt->velocity); + } + else + { + VectorMA(loc, HELLBOLT_SPEED, forward, endpos); + gi.trace(loc, vec3_origin, vec3_origin, endpos, caster, MASK_MONSTERSOLID,&trace); + if(trace.ent && ok_to_autotarget(caster, trace.ent)) + {//already going to hit a valid target at this angle- so don't autotarget + VectorScale(forward, HELLBOLT_SPEED, hellbolt->velocity); + } + else + {//autotarget current enemy + GetAimVelocity(caster->enemy, hellbolt->s.origin, HELLBOLT_SPEED, aimangles, hellbolt->velocity); + } + } + + hellbolt->owner = caster; + VectorNormalize2(hellbolt->velocity, hellbolt->movedir); + create_hellbolt(hellbolt); + hellbolt->reflect_debounce_time = MAX_REFLECT; + G_LinkMissile(hellbolt); + + // This alternation avoids cutting sounds out prematurely. + if (caster->client->playerinfo.flags & PLAYER_FLAG_ALTFIRE) + { // Use the alternate slot, clear the flag. + gi.sound(caster, CHAN_WEAPON2, gi.soundindex("weapons/HellFire.wav"), 1, ATTN_NORM, 0); + caster->client->playerinfo.flags &= ~PLAYER_FLAG_ALTFIRE; + } + else + { // Use the regular slot, set the flag. + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/HellFire.wav"), 1, ATTN_NORM, 0); + caster->client->playerinfo.flags |= PLAYER_FLAG_ALTFIRE; + } + + gi.trace(hellbolt->s.origin, vec3_origin, vec3_origin, hellbolt->s.origin, caster, MASK_PLAYERSOLID,&trace); + if (trace.startsolid) + { + HellboltTouch(hellbolt, trace.ent, &trace.plane, trace.surface); + return; + } + gi.CreateEffect(&hellbolt->s, FX_WEAPON_HELLBOLT, CEF_OWNERS_ORIGIN, NULL, "t", hellbolt->velocity); + } +} +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/spl_Phoenix.c b/Toolkit/Programming/GameCode/game/spl_Phoenix.c new file mode 100644 index 0000000..01e84f6 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_Phoenix.c @@ -0,0 +1,228 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "vector.h" +#include "angles.h" +#include "matrix.h" +#include "g_volume_effect.h" +#include "Utilities.h" +#include "g_playstats.h" +#include "decals.h" + +#define ARROW_RADIUS 4.0F +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); + +void create_phoenix(edict_t *phoenix); + + +// **************************************************************************** +// PhoenixMissile Reflect +// **************************************************************************** + +edict_t *PhoenixMissileReflect(edict_t *self, edict_t *other, vec3_t vel) +{ + edict_t *phoenix; + + // create a new missile to replace the old one - this is necessary cos physics will do nasty shit + // with the existing one,since we hit something. Hence, we create a new one totally. + phoenix = G_Spawn(); + VectorCopy(self->s.origin, phoenix->s.origin); + create_phoenix(phoenix); + phoenix->owner = other; + phoenix->enemy = self->owner; + phoenix->health = self->health; + phoenix->reflect_debounce_time = self->reflect_debounce_time - 1; + + VectorCopy(vel, phoenix->velocity); + G_LinkMissile(phoenix); + gi.CreateEffect(&phoenix->s, FX_WEAPON_PHOENIXMISSILE, CEF_OWNERS_ORIGIN | (phoenix->health << 5) | CEF_FLAG8, NULL, "t", phoenix->velocity); + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + // kill the travel sound on the original weapon + gi.sound(self, CHAN_WEAPON, gi.soundindex("misc/null.wav"), 1, ATTN_NORM, 0); + + // create travel sound on the new weapon + gi.sound(phoenix, CHAN_WEAPON, gi.soundindex("weapons/PhoenixTravel.wav"), 1, ATTN_NORM, 0); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&phoenix->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", phoenix->velocity); + + return(phoenix); +} + + +// **************************************************************************** +// PhoenixMissile touch +// **************************************************************************** +void PhoenixMissileTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + int makeScorch; + vec3_t planedir; + + // did we hit the sky ? + if(surface && (surface->flags & SURF_SKY)) + { + SkyFly(self); + return; + } + + // are we reflecting ? + if (self->reflect_debounce_time) + { + if(EntReflecting(other, true, true)) + { + Create_rand_relect_vect(self->velocity, self->velocity); + Vec3ScaleAssign(PHOENIX_ARROW_SPEED/2,self->velocity); + PhoenixMissileReflect(self, other, self->velocity); + return; + } + } + + // kill the travel sound + gi.sound(self, CHAN_WEAPON, gi.soundindex("misc/null.wav"), 1, ATTN_NORM, 0); + + // I'm gonna set the enemy to what I hit... The DAMAGE_ENEMY_MAX assures that what I hit takes full damage. + // I do this rather than do direct damage AND radius because that tends to do double damage to what is hit... + if (other && other->takedamage) + self->enemy = other; + else + self->enemy = NULL; + if(self->health == 1) + { // must be powered up version - storing in health is not so good, though + // Powered up Phoenix will NOT damage the shooter. + T_DamageRadius(self, self->owner, NULL, PHOENIX_EXPLODE_RADIUS_POWER, + PHOENIX_EXPLODE_DAMAGE_POWER, PHOENIX_EXPLODE_DAMAGE_POWER>>4, + DAMAGE_NORMAL|DAMAGE_FIRE|DAMAGE_EXTRA_KNOCKBACK|DAMAGE_POWERPHOENIX|DAMAGE_ENEMY_MAX, + MOD_P_PHOENIX_SPL); + } + else + { + T_DamageRadius(self, self->owner, NULL, PHOENIX_EXPLODE_RADIUS, + PHOENIX_EXPLODE_DAMAGE, PHOENIX_EXPLODE_DAMAGE>>4, + DAMAGE_NORMAL|DAMAGE_FIRE|DAMAGE_EXTRA_KNOCKBACK|DAMAGE_ENEMY_MAX, + MOD_PHOENIX_SPL); + } + + AlertMonsters (self, self->owner, 3, false); + + // Attempt to apply a scorchmark decal to the thing I hit. + makeScorch = 0; + if(IsDecalApplicable(self, other, self->s.origin, surface, plane, planedir)) + { + makeScorch = CEF_FLAG8; + } + + VectorNormalize2(self->velocity,self->movedir); + // Start the explosion + if (plane->normal) + gi.CreateEffect(&self->s, FX_WEAPON_PHOENIXEXPLODE, CEF_BROADCAST |(self->health << 5)| makeScorch, self->s.origin, "td", plane->normal, self->movedir); + else + gi.CreateEffect(&self->s, FX_WEAPON_PHOENIXEXPLODE, CEF_BROADCAST |(self->health << 5)| makeScorch, self->s.origin, "td", self->movedir, self->movedir); + + VectorClear(self->velocity); + // Turn off the client effect + gi.RemoveEffects(&self->s, FX_WEAPON_PHOENIXMISSILE); + + G_SetToFree(self); +} + +// **************************************************************************** +// PhoenixMissile think +// **************************************************************************** + +void PhoenixMissileThink(edict_t *self) +{ + self->svflags |= SVF_NOCLIENT; + self->think = NULL; +} + +// create the guts of a phoenix arrow +void create_phoenix(edict_t *phoenix) +{ + phoenix->s.effects |= EF_ALWAYS_ADD_EFFECTS; + phoenix->svflags |= SVF_ALWAYS_SEND; + phoenix->movetype = MOVETYPE_FLYMISSILE; + + phoenix->touch = PhoenixMissileTouch; + phoenix->think = PhoenixMissileThink; + phoenix->classname = "Spell_PhoenixArrow"; + phoenix->nextthink = level.time + 0.1; + VectorSet(phoenix->mins, -ARROW_RADIUS, -ARROW_RADIUS, -ARROW_RADIUS); + VectorSet(phoenix->maxs, ARROW_RADIUS, ARROW_RADIUS, ARROW_RADIUS); + + phoenix->solid = SOLID_BBOX; + phoenix->clipmask = MASK_SHOT; + +} + + +// **************************************************************************** +// SpellCastPhoenix +// **************************************************************************** + +void SpellCastPhoenix(edict_t *Caster, vec3_t StartPos, vec3_t AimAngles, vec3_t unused, float value) +{ + edict_t *phoenix; + trace_t trace; + vec3_t forward, endpos; + + + phoenix = G_Spawn(); + + VectorCopy(StartPos, phoenix->s.origin); + //Check ahead first to see if it's going to hit anything at this angle + AngleVectors(AimAngles, forward, NULL, NULL); + VectorMA(StartPos, PHOENIX_ARROW_SPEED, forward, endpos); + gi.trace(StartPos, vec3_origin, vec3_origin, endpos, Caster, MASK_MONSTERSOLID,&trace); + if(trace.ent && ok_to_autotarget(Caster, trace.ent)) + {//already going to hit a valid target at this angle- so don't autotarget + VectorScale(forward, PHOENIX_ARROW_SPEED, phoenix->velocity); + } + else + {//autotarget current enemy + GetAimVelocity(Caster->enemy, phoenix->s.origin, PHOENIX_ARROW_SPEED, AimAngles, phoenix->velocity); + } + VectorCopy(AimAngles, phoenix->s.angles); + create_phoenix(phoenix); + phoenix->reflect_debounce_time = MAX_REFLECT; + + phoenix->owner = Caster; + G_LinkMissile(phoenix); + + // travel sound on the weapon itself + phoenix->s.sound = gi.soundindex("weapons/PhoenixTravel.wav"); + phoenix->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_NORM; + + if (Caster->client->playerinfo.powerup_timer > level.time) + { + // We still want the sound on the player. + gi.sound(Caster, CHAN_WEAPON, gi.soundindex("weapons/PhoenixPowerFire.wav"), 1, ATTN_NORM, 0); + phoenix->health = 1; + } + else + { + // We still want the sound on the player. + gi.sound(Caster, CHAN_WEAPON, gi.soundindex("weapons/PhoenixFire.wav"), 1, ATTN_NORM, 0); + phoenix->health = 0; + } + + // Trace from the player's origin because then if we hit a wall, the effect won't be inside it... + gi.trace(Caster->s.origin, phoenix->mins, phoenix->maxs, phoenix->s.origin, Caster, MASK_PLAYERSOLID,&trace); + if (trace.startsolid || trace.fraction < .99) + { + if (trace.startsolid) + VectorCopy(Caster->s.origin, phoenix->s.origin); + else + VectorCopy(trace.endpos, phoenix->s.origin); + PhoenixMissileTouch(phoenix, trace.ent, &trace.plane, trace.surface); + return; + } + gi.CreateEffect(&phoenix->s, FX_WEAPON_PHOENIXMISSILE, CEF_OWNERS_ORIGIN|(phoenix->health<<5), NULL, "t", phoenix->velocity); +} + +// end diff --git a/Toolkit/Programming/GameCode/game/spl_RedRain.c b/Toolkit/Programming/GameCode/game/spl_RedRain.c new file mode 100644 index 0000000..ad4622e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_RedRain.c @@ -0,0 +1,468 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "vector.h" +#include "angles.h" +#include "matrix.h" +#include "g_volume_effect.h" +#include "Utilities.h" +#include "g_playstats.h" +#include "random.h" + +#define ARROW_RADIUS 2.0F +#define ARROW_BACKUP (45.0F - ARROW_RADIUS) + +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); + +void create_redarrow(edict_t *redarrow); + +void RedRainRemove(edict_t *self) +{ + gi.RemoveEffects(&self->s, 0); + G_SetToFree(self); +} + +void RedRainThink(edict_t *self) +{ + edict_t *victim=NULL; + vec3_t startpos, endpos, diffpos, min, max, hitpos, vec; + trace_t trace; + qboolean poweredup; + float lradius, rradius, rad_dmg; + int damage; + + if(deathmatch->value) + rad_dmg = self->dmg * 0.25; + else + rad_dmg = self->dmg; + + // find all the entities in the volume + while(victim = findinblocking(victim, self)) + { + if(victim != self->owner && victim->takedamage && + (victim->client || victim->svflags & SVF_MONSTER) && !(victim->svflags & SVF_DEADMONSTER)) + { // No damage to casting player + VectorSubtract(self->pos1, victim->s.origin, vec); + VectorNormalize(vec); + VectorMA(victim->s.origin, victim->maxs[0], vec, hitpos); + + if (victim->svflags & SVF_BOSS) + { + T_Damage(victim, self, self->owner, vec3_origin, hitpos, vec3_origin, + rad_dmg/2, 0, DAMAGE_SPELL,MOD_STORM); + } + else + { + T_Damage(victim, self, self->owner, vec3_origin, hitpos, vec3_origin, + rad_dmg, 0, DAMAGE_SPELL,MOD_STORM); + } + } + } + + if (self->delay <= level.time || (self->owner->red_rain_count - self->red_rain_count) > NUM_STORMS_PER_PLAYER) + { + self->owner->red_rain_count--; + self->s.effects |= EF_DISABLE_EXTRA_FX; + self->nextthink = level.time + 1.0;//lasts another 1.0 secs + self->think = RedRainRemove; + } + else + { + // Powerup value comes from the health in the edict. + poweredup = self->health; + + // Check for lightning + if (self->delay - level.time < RED_RAIN_LIGHTNING_DURATION && irand(0, RED_RAIN_LIGHTNING_CHANCE) == 0) + { // First check the area for a potential victim. + if (!poweredup) + { + rradius = RED_RAIN_RADIUS; + lradius = RED_RAIN_LIGHTNING_RADIUS; + } + else + { + rradius = POWER_RAIN_RADIUS; + lradius = POWER_RAIN_LIGHTNING_RADIUS; + } + + // Find the bounds to search under. + VectorSet(min, -lradius, -lradius, self->mins[2]); + // Only search the lower half of the area for lightning hits. + VectorSet(max, lradius, lradius, self->mins[2] + ((self->maxs[2] - self->mins[2])*0.5)); + VectorAdd(self->s.origin, min, min); + VectorAdd(self->s.origin, max, max); + victim=NULL; + while (victim = findinbounds(victim, min, max)) + { + if (victim != self->owner && victim->takedamage && + (victim->client || victim->svflags & SVF_MONSTER) && !(victim->svflags & SVF_DEADMONSTER)) + break; + } + if (victim) + { // Try to zap somebody with lightning + VectorSet(startpos, + flrand(-rradius*0.6, rradius*0.6), + flrand(-rradius*0.6, rradius*0.6), + self->maxs[2]); + VectorAdd(startpos, self->s.origin, startpos); + VectorSet(endpos, + flrand(victim->mins[0]*0.5, victim->maxs[0]*0.5), + flrand(victim->mins[1]*0.5, victim->maxs[1]*0.5), + flrand(victim->mins[2]*0.5, victim->maxs[2]*0.5)); + VectorAdd(endpos, victim->s.origin, endpos); + + gi.trace(startpos, vec3_origin, vec3_origin, endpos, self->owner, MASK_SOLID,&trace); + if (!trace.startsolid && trace.fraction == 1.0) + { // FINALLY! A clear lightning strike! + VectorSubtract(endpos, startpos, diffpos); + VectorNormalize(diffpos); + if (!poweredup) + { + gi.CreateEffect(NULL, FX_LIGHTNING, CEF_FLAG6, + startpos, "vbb", endpos, (byte)RED_RAIN_LIGHTNING_WIDTH, (byte)0); + gi.sound(victim,CHAN_WEAPON,gi.soundindex("weapons/Lightning.wav"),1,ATTN_NORM,0); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&victim->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN | CEF_FLAG7, NULL, "t", diffpos); + + if(!(EntReflecting(victim, true, true))) + { + T_Damage(victim, self, self->owner, diffpos, endpos, vec3_origin, + irand(RED_RAIN_DMG_LIGHTNING_MIN, RED_RAIN_DMG_LIGHTNING_MAX), 0, DAMAGE_SPELL,MOD_STORM); + } + } + else + { + gi.CreateEffect(NULL, FX_POWER_LIGHTNING, 0, + startpos, "vb", endpos, (byte)POWER_RAIN_LIGHTNING_WIDTH); + gi.sound(victim,CHAN_WEAPON,gi.soundindex("weapons/LightningPower.wav"),1,ATTN_NORM,0); + + if(!(EntReflecting(victim, true, true))) + { + damage = irand(POWER_RAIN_DMG_LIGHTNING_MIN, POWER_RAIN_DMG_LIGHTNING_MAX); + + T_DamageRadiusFromLoc(endpos, self, self->owner, self->owner, POWER_RAIN_DMG_LIGHTNING_RADIUS, + damage, damage*0.25, DAMAGE_SPELL,MOD_P_STORM); + } + } + } + } + else + { + VectorSet(startpos, + flrand(-rradius*0.75, rradius*0.75), + flrand(-rradius*0.75, rradius*0.75), + self->maxs[2]); + VectorAdd(startpos, self->s.origin, startpos); + VectorSet(endpos, + flrand(-rradius, rradius), + flrand(-rradius, rradius), + self->mins[2]); + VectorAdd(endpos, self->s.origin, endpos); + if (!poweredup) + { + gi.CreateEffect(NULL, FX_LIGHTNING, CEF_FLAG6, + startpos, "vbb", endpos, (byte)RED_RAIN_LIGHTNING_WIDTH, (byte)0); + gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/Lightning.wav"), 2, ATTN_NORM,0); + } + else + { + gi.CreateEffect(NULL, FX_POWER_LIGHTNING, 0, + startpos, "vb", endpos, (byte)POWER_RAIN_LIGHTNING_WIDTH); + gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/LightningPower.wav"), 2, ATTN_NORM,0); + + // The lightning does radius damage even if no target. + damage = irand(POWER_RAIN_DMG_LIGHTNING_MIN, POWER_RAIN_DMG_LIGHTNING_MAX); + T_DamageRadiusFromLoc(endpos, self, self->owner, self->owner, POWER_RAIN_DMG_LIGHTNING_RADIUS, + damage, damage*0.25, DAMAGE_SPELL,MOD_P_STORM); + } + } + } + self->nextthink = level.time + self->wait; + } +} + + +// **************************************************************************** +// RedRainMissile reflect +// **************************************************************************** + +edict_t *RedRainMissileReflect(edict_t *self, edict_t *other, vec3_t vel) +{ + edict_t *redarrow; + + // create a new missile to replace the old one - this is necessary cos physics will do nasty shit + // with the existing one,since we hit something. Hence, we create a new one totally. + redarrow = G_Spawn(); + VectorCopy(self->s.origin, redarrow->s.origin); + redarrow->health = self->health; + redarrow->owner = other; + redarrow->enemy = self->owner; + redarrow->owner->red_rain_count++; + self->owner->red_rain_count--; + create_redarrow(redarrow); + + VectorCopy(vel, redarrow->velocity); + redarrow->reflect_debounce_time = self->reflect_debounce_time -1; + G_LinkMissile(redarrow); + gi.CreateEffect(&redarrow->s, FX_WEAPON_REDRAINMISSILE, + CEF_OWNERS_ORIGIN|(redarrow->health<<5)|CEF_FLAG8, NULL, "t", redarrow->velocity); + + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&redarrow->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", redarrow->velocity); + + return(redarrow); +} + + +// **************************************************************************** +// RedRainMissile touch +// **************************************************************************** + +void RedRainMissileTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + vec3_t org, end; + edict_t *damagearea; + trace_t trace; + float radius; + + // has the target got reflection turned on ? + if (self->reflect_debounce_time) + { + if(EntReflecting(other, true, true)) + { + Create_rand_relect_vect(self->velocity, self->velocity); + Vec3ScaleAssign(RED_ARROW_SPEED/2, self->velocity); + RedRainMissileReflect(self, other, self->velocity); + + return; + } + } + + if(other->takedamage) + { // Damage from direct impact of arrow, normal or powered up. + T_Damage(other, self, self->owner, self->movedir, self->s.origin, plane->normal, self->dmg, self->dmg, DAMAGE_SPELL,MOD_STORM); + } + AlertMonsters (self, self->owner, 5, false); + + // Backup effect a little so it doesn`t appear in the wall (but only if we hit the wall) + if(other->svflags & SVF_MONSTER) + { + VectorCopy(self->s.origin, org); + } + else + { + VectorNormalize2(self->velocity, org); + Vec3ScaleAssign(-ARROW_BACKUP, org); + Vec3AddAssign(self->s.origin, org); + } + VectorClear(self->velocity); + + // Create a damage handling effect + damagearea = G_Spawn(); + VectorCopy(org, damagearea->s.origin); + damagearea->think = RedRainThink; + damagearea->nextthink = level.time + RED_RAIN_DAMAGE_INTERVAL; + damagearea->solid = SOLID_NOT; + damagearea->clipmask = CONTENTS_EMPTY; + damagearea->movetype = MOVETYPE_FLYMISSILE; // Necessary for proper processing of thinkers + damagearea->wait = RED_RAIN_DAMAGE_INTERVAL; + if(deathmatch->value) + damagearea->delay = level.time + RED_RAIN_DURATION - 2;//5 secs in DM + else + damagearea->delay = level.time + RED_RAIN_DURATION; + damagearea->owner = self->owner; + damagearea->red_rain_count = self->owner->red_rain_count; + damagearea->classname = "Spell_RedRain"; + damagearea->health = self->health; // Copy over the powerup status. + damagearea->s.effects |= EF_ALWAYS_ADD_EFFECTS; + + if (self->health == 0) + { // Not powered up + damagearea->dmg = RED_RAIN_DAMAGE; + radius = RED_RAIN_RADIUS; + } + else + { // Powered up rain + damagearea->dmg = POWER_RAIN_DAMAGE; + radius = POWER_RAIN_RADIUS; + } + + // Find the top of the damage area. Check down in an area less than the max size. + VectorSet(damagearea->mins, -radius*0.5, -radius*0.5, -1.0F); + VectorSet(damagearea->maxs, radius*0.5, radius*0.5, 1.0F); + VectorCopy(org, end); + end[2] += MAX_REDRAINHEIGHT; + + gi.trace(org, damagearea->mins, damagearea->maxs, end, damagearea, MASK_SOLID,&trace); +// if(trace.startsolid) // Ignore startsolids. +// damagearea->maxs[2] = 1.0; +// else + if (trace.fraction == 1.0F) + damagearea->maxs[2] = MAX_REDRAINHEIGHT; // Put the bounds up all the way + else + damagearea->maxs[2] = trace.endpos[2] - org[2]; // Set the bounds up only part way + + // Find the bottom of the damage area. + end[2] = org[2] - MAX_REDRAINFALLDIST; + + gi.trace(org, damagearea->mins, damagearea->maxs, end, damagearea, MASK_SOLID,&trace); +// if(trace.startsolid) // Startsolids mean that the area is too close to a wall +// damagearea->mins[2] = -1.0; +// else + if (trace.fraction == 1.0F) + damagearea->mins[2] = -MAX_REDRAINFALLDIST; // Put the bounds down all the way + else + damagearea->mins[2] = trace.endpos[2] - org[2]; // Set the bounds down where the trace stopped + + // Put the bounds of the damage area out to the max position now. + damagearea->mins[0] = damagearea->mins[1] = -radius; + damagearea->maxs[0] = damagearea->maxs[1] = radius; + + VectorSet(damagearea->pos1, damagearea->s.origin[0], damagearea->s.origin[1], damagearea->maxs[2]); + + gi.linkentity(damagearea); + + // Start the red rain + // Send along the health as a flag, to indicate if powered up. + gi.CreateEffect(&damagearea->s, FX_WEAPON_REDRAIN, CEF_BROADCAST|(self->health<<5), org, ""); + +// gi.sound(damagearea, CHAN_VOICE, gi.soundindex("weapons/RedRainFall.wav"), 2, ATTN_NORM,0); + damagearea->s.sound = gi.soundindex("weapons/RedRainFall.wav"); + damagearea->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_NORM; + + // Turn off the client effect + gi.RemoveEffects(&self->s, FX_WEAPON_REDRAINMISSILE); + G_SetToFree(self); +} + + +// **************************************************************************** +// RedRainMissile think +// **************************************************************************** + +void RedRainMissileThink(edict_t *self) +{ + self->svflags |= SVF_NOCLIENT; + self->think = NULL; +} + +// create the guts of the red rain missile +void create_redarrow(edict_t *redarrow) +{ + redarrow->s.effects |= EF_ALWAYS_ADD_EFFECTS; + redarrow->svflags |= SVF_ALWAYS_SEND; + redarrow->movetype = MOVETYPE_FLYMISSILE; + + VectorSet(redarrow->mins, -ARROW_RADIUS, -ARROW_RADIUS, -ARROW_RADIUS); + VectorSet(redarrow->maxs, ARROW_RADIUS, ARROW_RADIUS, ARROW_RADIUS); + + redarrow->solid = SOLID_BBOX; + redarrow->clipmask = MASK_SHOT; + redarrow->touch = RedRainMissileTouch; + redarrow->think = RedRainMissileThink; + redarrow->classname = "Spell_RedRainArrow"; + redarrow->nextthink = level.time + 0.1; + if (redarrow->health==1) + { // powerup arrow + redarrow->dmg = irand(POWER_RAIN_DMG_ARROW_MIN, POWER_RAIN_DMG_ARROW_MAX); + } + else + { + redarrow->dmg = irand(RED_RAIN_DMG_ARROW_MIN, RED_RAIN_DMG_ARROW_MAX); + } +} + +// **************************************************************************** +// SpellCastRedRain +// **************************************************************************** + +void SpellCastRedRain(edict_t *Caster, vec3_t StartPos, vec3_t AimAngles, vec3_t unused, float value) +{ + edict_t *redarrow; + trace_t trace; + vec3_t dir, forward, endpos; + qboolean powerup; + + redarrow = G_Spawn(); + + Caster->red_rain_count++; + // health indicates a level of powerup + if (Caster->client->playerinfo.powerup_timer > level.time) + { // Shoot powered up red rain. + redarrow->health = 1; + powerup=true; + } + else + { // Normal red rain arrow + redarrow->health = 0; + powerup=false; + } + + VectorCopy(StartPos, redarrow->s.origin); + //Check ahead first to see if it's going to hit anything at this angle + AngleVectors(AimAngles, forward, NULL, NULL); + VectorMA(StartPos, RED_ARROW_SPEED, forward, endpos); + gi.trace(StartPos, vec3_origin, vec3_origin, endpos, Caster, MASK_MONSTERSOLID,&trace); + if(trace.ent && ok_to_autotarget(Caster, trace.ent)) + {//already going to hit a valid target at this angle- so don't autotarget + VectorScale(forward, RED_ARROW_SPEED, redarrow->velocity); + } + else + {//autotarget current enemy + GetAimVelocity(Caster->enemy, redarrow->s.origin, RED_ARROW_SPEED, AimAngles, redarrow->velocity); + } + VectorNormalize2(redarrow->velocity, dir); + // naughty naughty - this requires a normalised vector + AnglesFromDir(dir, redarrow->s.angles); + + create_redarrow(redarrow); + redarrow->reflect_debounce_time = MAX_REFLECT; + + redarrow->owner = Caster; + G_LinkMissile(redarrow); + + gi.RemoveEffects(&Caster->s, FX_WEAPON_REDRAINGLOW); + + if (powerup) + { // Play powerup firing sound + gi.sound(Caster, CHAN_WEAPON, gi.soundindex("weapons/RedRainPowerFire.wav"), 1, ATTN_NORM, 0); + } + else + { // Player normal red rain firing sound + gi.sound(Caster, CHAN_WEAPON, gi.soundindex("weapons/RedRainFire.wav"), 1, ATTN_NORM, 0); + } + + // Trace from the player's origin because then if we hit a wall, the effect won't be inside it... + gi.trace(Caster->s.origin, redarrow->mins, redarrow->maxs, redarrow->s.origin, Caster, MASK_PLAYERSOLID,&trace); + if (trace.startsolid || trace.fraction < .99) + { + if (trace.startsolid) + VectorCopy(Caster->s.origin, redarrow->s.origin); + else + VectorCopy(trace.endpos, redarrow->s.origin); + RedRainMissileTouch(redarrow, trace.ent, &trace.plane, trace.surface); + return; + } + + // Create the missile and trail effect only if we successfully launch the missile + if (powerup) + { // Magenta trail + gi.CreateEffect(&redarrow->s, FX_WEAPON_REDRAINMISSILE, CEF_OWNERS_ORIGIN|CEF_FLAG6, + NULL, "t", redarrow->velocity); + } + else + { // Red trail + gi.CreateEffect(&redarrow->s, FX_WEAPON_REDRAINMISSILE, CEF_OWNERS_ORIGIN, + NULL, "t", redarrow->velocity); + } +} + +// end diff --git a/Toolkit/Programming/GameCode/game/spl_blast.c b/Toolkit/Programming/GameCode/game/spl_blast.c new file mode 100644 index 0000000..cc6ee69 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_blast.c @@ -0,0 +1,79 @@ +// +// spl_blast.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "Angles.h" +#include "Utilities.h" +#include "vector.h" +#include "random.h" +#include "g_playstats.h" +#include "m_beast.h" + + + +// **************************************************************************** +// SpellCastBlast +// **************************************************************************** + +void SpellCastBlast(edict_t *caster,vec3_t startpos,vec3_t aimangles,vec3_t aimdir) +{ + vec3_t fwd, endpos, mins={-3.0, -3.0, -3.0}, maxs={3.0, 3.0, 3.0}; + trace_t trace; + int damage; + vec3_t angles, diff; + int i; + short distance[BLAST_NUM_SHOTS]; + short syaw, spitch; + + // This weapon does not autotarget + VectorCopy(aimangles, angles); + + angles[YAW] -= BLAST_ANGLE_INC * (BLAST_NUM_SHOTS-1) * 0.5; + for (i=0; itakedamage && !(EntReflecting(trace.ent, true, true))) + { + if(deathmatch->value) + damage = irand(BLAST_DMG_MIN*0.75, BLAST_DMG_MAX*0.75); + else + damage = irand(BLAST_DMG_MIN, BLAST_DMG_MAX); + T_Damage(trace.ent, caster, caster, fwd, trace.endpos, fwd, damage, damage, 0, MOD_MMISSILE); + } + + VectorSubtract(trace.endpos, startpos, diff); + distance[i] = VectorLength(diff); + + angles[YAW] += BLAST_ANGLE_INC; + } + + // The assumption is that there are 5 shot blasts. + assert(BLAST_NUM_SHOTS==5); + + // Compress the angles into two shorts. + syaw = (short)(aimangles[YAW]*(65536.0/360.0)); + spitch = (short)(aimangles[PITCH]*(65536.0/360.0)); + + gi.CreateEffect(NULL, FX_WEAPON_BLAST, 0, startpos, + "sssssss", syaw, spitch, distance[0], distance[1], distance[2], distance[3], distance[4]); +} + + + + diff --git a/Toolkit/Programming/GameCode/game/spl_flyingfist.c b/Toolkit/Programming/GameCode/game/spl_flyingfist.c new file mode 100644 index 0000000..b3083e9 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_flyingfist.c @@ -0,0 +1,294 @@ +// +// spl_flyingfist.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "vector.h" +#include "random.h" +#include "decals.h" +#include "Utilities.h" +#include "g_playstats.h" + +#define FIST_RADIUS 2.0 + +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); +static void FlyingFistThink(edict_t *self); +static void FlyingFistTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface); + + +// ************************************************************************************************ +// FlyingFistThink +// ************************************************************************************************ + +static void FlyingFistFizzleThink(edict_t *self) +{ + // Don't fizzle in deathmatch, or if powered up + if (!(deathmatch->value) && self->health==0) + { + if ( (self->dmg - 2) > FIREBALL_MIN_FIZZLE_DAMAGE ) + { + self->dmg -= 2; + } + self->nextthink = level.time + 0.1; + } +} + + + +// **************************************** +// Creation functions +// **************************************** +void FlyingFistInitThink(edict_t *self) +{ + self->svflags |= SVF_NOCLIENT; + self->think = FlyingFistFizzleThink; + FlyingFistFizzleThink(self); +} + +void CreateFlyingFist(edict_t *flyingfist) +{ + flyingfist->s.effects |= EF_ALWAYS_ADD_EFFECTS; + flyingfist->svflags |= SVF_ALWAYS_SEND; + flyingfist->movetype = MOVETYPE_FLYMISSILE; + flyingfist->s.scale = 1.0; + + flyingfist->touch = FlyingFistTouch; + flyingfist->think = FlyingFistInitThink; + flyingfist->classname = "Spell_FlyingFist"; + flyingfist->nextthink = level.time + 0.1; + VectorSet(flyingfist->mins, -FIST_RADIUS, -FIST_RADIUS, -FIST_RADIUS); + VectorSet(flyingfist->maxs, FIST_RADIUS, FIST_RADIUS, FIST_RADIUS); + + flyingfist->solid = SOLID_BBOX; + flyingfist->clipmask = MASK_SHOT; +} + + + +// ************************************************************************************************ +// FlyingFistTouch +// ************************************************************************************************ + +static void FlyingFistTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + int damage; + vec3_t planedir; + edict_t *new_missile; + qboolean powerup, wimpy; + int flags; + + if(other == self->owner) + { + return; + } + if(surface && (surface->flags & SURF_SKY)) + { + SkyFly(self); + return; + } + + if (self->health) + { // Powered up meteor + powerup=true; + flags = CEF_FLAG7; + } + else + { // Unpowered fireball + powerup=false; + flags = 0; + } + + if (self->flags & FL_NO_KNOCKBACK) + { // Wimpy out-of-ammo weapon. + wimpy=true; + flags |= CEF_FLAG8; + } + else + { + wimpy=false; + } + + // has the target got reflection turned on ? + if (self->reflect_debounce_time) + { + if(EntReflecting(other, true, true)) + { + // create a new missile to replace the old one - this is necessary cos physics will do nasty things + // with the existing one,since we hit something. Hence, we create a new one totally. + new_missile = G_Spawn(); + + // copy everything across + CreateFlyingFist(new_missile); + VectorCopy(self->s.origin, new_missile->s.origin); + new_missile->owner = other; + new_missile->touch = self->touch; + new_missile->health = self->health; + new_missile->enemy = self->enemy; + new_missile->flags |= (self->flags & FL_NO_KNOCKBACK); + + Create_rand_relect_vect(self->velocity, new_missile->velocity); + // velocity is already normalised + VectorCopy(new_missile->velocity, new_missile->movedir); + // scale speed up + Vec3ScaleAssign(FLYING_FIST_SPEED/2,new_missile->velocity); + new_missile->reflect_debounce_time = self->reflect_debounce_time -1; //so it doesn't infinitely reflect in one frame somehow + G_LinkMissile(new_missile); + + // create new trails for the new missile + gi.CreateEffect(&new_missile->s, FX_WEAPON_FLYINGFIST, CEF_OWNERS_ORIGIN | flags | CEF_FLAG6, NULL, + "t", new_missile->velocity); + + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&new_missile->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", new_missile->velocity); + + return; + } + } + + AlertMonsters (self, self->owner, 1, false); + if(other->takedamage) + { + if(powerup) // Check for powered up meteor + { + if(deathmatch->value) + damage = irand(FIREBALL_DAMAGE_MIN_POWER/2, FIREBALL_DAMAGE_MAX_POWER/2); + else + damage = irand(FIREBALL_DAMAGE_MIN_POWER, FIREBALL_DAMAGE_MAX_POWER); + if (wimpy) + { // Wimpy shots do half damage. + damage /= 2; + T_Damage(other, self, self->owner, self->movedir, self->s.origin, plane->normal, + damage, damage, DAMAGE_SPELL,MOD_FIREBALL); // No blast damage, just direct. + } + else + { + T_Damage(other, self, self->owner, self->movedir, self->s.origin, plane->normal, + damage>>1, damage, DAMAGE_SPELL|DAMAGE_EXTRA_KNOCKBACK,MOD_FIREBALL); // Half goes directly to target, blast does rest. + T_DamageRadius(self, self->owner, self->owner, FIREBALL_RADIUS, + FIREBALL_DAMAGE_MAX_POWER, FIREBALL_DAMAGE_MIN_POWER, DAMAGE_SPELL,MOD_FIREBALL); + } + } + else + { + if(deathmatch->value) + damage = irand(FIREBALL_DAMAGE_MIN/2, FIREBALL_DAMAGE_MAX/2); + else + damage = irand(FIREBALL_DAMAGE_MIN, FIREBALL_DAMAGE_MAX); + if (wimpy) // Wimpy (no mana) shots do half damage + damage /= 2; + T_Damage(other, self, self->owner, self->movedir, self->s.origin, plane->normal, damage, damage, DAMAGE_SPELL,MOD_FIREBALL); + } + } + else + { + VectorMA(self->s.origin, -8.0, self->movedir, self->s.origin); + } + + // Attempt to apply a scorchmark decal to the thing I hit. + if(IsDecalApplicable(self, other, self->s.origin, surface, plane, planedir)) + { + flags |= CEF_FLAG6; + } + + gi.CreateEffect(NULL, FX_WEAPON_FLYINGFISTEXPLODE, flags, self->s.origin, "d", self->movedir); + + G_SetToFree(self); +} + + +// ************************************************************************************************ +// SpellCastFlyingFist +// ************************************************************************************************ + + +void SpellCastFlyingFist(edict_t *caster, vec3_t startpos, vec3_t aimangles, vec3_t aimdir, float value) +{ + edict_t *flyingfist; + trace_t trace; + int flags; + qboolean powerup, wimpy; + vec3_t forward, endpos; + playerinfo_t *playerinfo; + + // Spawn the flying-fist (fireball) + flyingfist = G_Spawn(); + + playerinfo = &caster->client->playerinfo; + + if (playerinfo->pers.inventory.Items[playerinfo->weap_ammo_index] < playerinfo->pers.weapon->quantity) + { + wimpy=true; + flags = CEF_FLAG8; + } + else + { + wimpy=false; + flags = 0; + } + + if (playerinfo->powerup_timer > level.time) + { // Powered up flying fist. Make it a meteor! + powerup = true; + flags |= CEF_FLAG7; + flyingfist->health = 1; + if (wimpy) // Play it quiet + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/FireballPowerCast.wav"), 0.5, ATTN_NORM, 0); + else // Play it loud + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/FireballPowerCast.wav"), 1.0, ATTN_NORM, 0); + } + else + { // Not powered up + powerup = false; + if (wimpy) // Play special wimpy sound + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/FireballNoMana.wav"), 1.0, ATTN_NORM, 0); + else // Normal fireball sound + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/FlyingFistCast.wav"), 1.0, ATTN_NORM, 0); + } + + CreateFlyingFist(flyingfist); + flyingfist->reflect_debounce_time = MAX_REFLECT; + VectorCopy(startpos, flyingfist->s.origin); + + if (wimpy) + flyingfist->flags |= FL_NO_KNOCKBACK; // Just using the no knockback flag to indicate a wussy weapon. + + //Check ahead first to see if it's going to hit anything at this angle + AngleVectors(aimangles, forward, NULL, NULL); + VectorMA(flyingfist->s.origin, FLYING_FIST_SPEED, forward, endpos); + gi.trace(startpos, vec3_origin, vec3_origin, endpos, caster, MASK_MONSTERSOLID,&trace); + if(trace.ent && ok_to_autotarget(caster, trace.ent)) + {//already going to hit a valid target at this angle- so don't autotarget + VectorScale(forward, FLYING_FIST_SPEED, flyingfist->velocity); + } + else + {//autotarget current enemy + GetAimVelocity(caster->enemy, flyingfist->s.origin, FLYING_FIST_SPEED, aimangles, flyingfist->velocity); + } + flyingfist->owner = caster; + flyingfist->enemy = caster->enemy; + // Remember velocity in case we have to reverse it + VectorNormalize2(flyingfist->velocity, flyingfist->movedir); + + G_LinkMissile(flyingfist); + + // Make sure we don`t start in a solid + gi.trace(caster->s.origin, vec3_origin, vec3_origin, flyingfist->s.origin, caster, MASK_PLAYERSOLID,&trace); + if (trace.startsolid || trace.fraction < 1.0) + { + VectorCopy(trace.endpos, flyingfist->s.origin); + FlyingFistTouch(flyingfist, trace.ent, &trace.plane, trace.surface); + return; + } + // Spawn effect after it has been determined it has not started in wall + // This is so it won`t try to remove it before it exists + gi.CreateEffect(&flyingfist->s, FX_WEAPON_FLYINGFIST, CEF_OWNERS_ORIGIN | flags, NULL, + "t", flyingfist->velocity); +} + diff --git a/Toolkit/Programming/GameCode/game/spl_maceballs.c b/Toolkit/Programming/GameCode/game/spl_maceballs.c new file mode 100644 index 0000000..a25fe76 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_maceballs.c @@ -0,0 +1,307 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "vector.h" +#include "angles.h" +#include "matrix.h" +#include "g_volume_effect.h" +#include "Utilities.h" +#include "g_ClassStatics.h" +#include "g_Physics.h" +#include "g_playstats.h" +#include "decals.h" +#include "random.h" +#include "p_item.h" +#include "g_teleport.h" + +#define MACEBALL_UPSPEED 200.0F +#define MACEBALL_SPEED 250.0F +#define MACEBALL_DOWNSPEED 150.0F +#define MACEBALL_RADIUS 16.0 +#define MACEBALL_SCALE 0.17 +#define MACEBALL_SCALEINC 0.03 +#define MACEBALL_ROT (360*0.02) + +#define MACEBALL_SEARCHRAD 500.0 + + +// **************************************************************************** +// Maceball think +// **************************************************************************** + +void MaceballThink(edict_t *self) +{ + vec3_t movevect; + qboolean killme=false; + +// self->s.angles[YAW] += MACEBALL_ROT*0.5; +// self->s.angles[PITCH] += MACEBALL_ROT*2.0; + + if (self->s.scale < MACEBALL_SCALE) + { + self->s.scale += MACEBALL_SCALEINC; + if (self->s.scale > MACEBALL_SCALE) + self->s.scale = MACEBALL_SCALE; + } + + // Check the NOTARGET flag to see if the mace should readjust to a new target. + if (self->flags & FL_NOTARGET) + { // Head towards its enemy + self->flags &= ~FL_NOTARGET; + if (self->enemy) + { + VectorScale(self->movedir, MACEBALL_UPSPEED, self->velocity); + VectorSubtract(self->enemy->s.origin, self->s.origin, movevect); + VectorNormalize(movevect); + VectorMA(self->velocity, MACEBALL_SPEED, movevect, self->velocity); + } + + if (self->velocity[2] > 0) + { // Adjust anyway so that the ball has a consistent bounce height. + self->velocity[2] = MACEBALL_UPSPEED; + } + } + + VectorCopy(self->s.origin, self->last_org); + + self->nextthink = level.time + 0.1; + + // Now check if we should die soon. + if (killme || self->deadflag == DEAD_DYING || self->touch_debounce_time + MACEBALL_EXTRALIFE <= level.time) + { + gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/MaceBallDeath.wav"), 2, ATTN_NORM, 0); + gi.CreateEffect(NULL, + FX_WEAPON_MACEBALLEXPLODE, + 0, + self->s.origin, + "d", + self->velocity); + G_SetToFree(self); + } +} + +// **************************************************************************** +// Maceball bounce +// **************************************************************************** + +static vec3_t BoxNormals[6] = +{ + { 0.0, 0.0, 1.0 }, // up + { 0.0, 0.0, -1.0 }, // down + { 0.0, 1.0, 0.0 }, // left + { 0.0, -1.0, 0.0 }, // right + { 1.0, 0.0, 0.0 }, // front + { -1.0, 0.0, 0.0 }, // back +}; + +void GetCollisionPoint(vec3_t velocity, vec3_t origin, vec_t size, vec3_t point) +{ + int maxn = 1; + int i; + float theta; + float max = -1.0; + + for(i = 0; i < 6; i++) + { + theta = DotProduct(velocity, BoxNormals[i]); + if(theta > max) + { + max = theta; + maxn = i; + } + } + VectorMA(origin, size, BoxNormals[maxn], point); +} + +void MaceballBounce(edict_t *self, trace_t *trace) +{ + vec3_t point; + qboolean done = false; + qboolean targetowner = false; + + vec3_t movevect; + + // did we hit something we can destroy ? + if (trace->ent && trace->ent->takedamage && trace->ent->health>0) + { + VectorNormalize2(self->velocity, movevect); + if(EntReflecting(trace->ent, true, true)) + { + // do nothing except bounce if we hit someone who's reflecting + // and make whoever it bounced off the owner of the ball now + self->owner = trace->ent; + } + else + if (trace->ent->svflags & SVF_BOSS) + { + T_Damage(trace->ent, self, self->owner, movevect, trace->endpos, movevect, + MACEBALL_BOSS_DAMAGE, MACEBALL_BOSS_DAMAGE, 0,MOD_P_IRONDOOM); + self->deadflag = DEAD_DYING; + } + else + { + int no_teleport = 1; + gitem_t *Defence, + *ManaItem; + int ManaIndex; + int Quantity; + + // can we teleport the player out of danger ? + // firstly, are we a player ? + if (trace->ent->client) + { + Defence = trace->ent->client->playerinfo.pers.defence; + Quantity = p_itemlist[12].quantity; + if(Defence->ammo && Quantity) + { + // do we have enough mana to teleport ? + ManaItem = FindItem(Defence->ammo); + ManaIndex = ITEM_INDEX(ManaItem); + if (trace->ent->client->playerinfo.pers.inventory.Items[ManaIndex]/Quantity > 0) + { + // yes, do we actually have a teleport ? + if (trace->ent->client->playerinfo.pers.inventory.Items[13]) + { + SpellCastTeleport(trace->ent, trace->ent->s.origin, NULL, NULL, 0.0F); + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + trace->ent->client->playerinfo.pers.inventory.Items[ManaIndex] -= Quantity; + no_teleport = 0; + } + } + } + + } + if (no_teleport) + { + T_Damage(trace->ent, self, self->owner, movevect, trace->endpos, movevect, + self->dmg, self->dmg, 0,MOD_P_IRONDOOM); + // if we hit a player or a monster, kill this maceball + if (trace->ent->client || (trace->ent->svflags & SVF_MONSTER)) + self->deadflag = DEAD_DYING; + } + } + } + + // If it's time is up, then kill it. + if (self->touch_debounce_time <= level.time) + { + self->deadflag = DEAD_DYING; + return; + } + + if (self->health == 1) + targetowner = true; + + gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/MaceBallBounce.wav"), 1, ATTN_NORM, 0); + + // Do a spiffy hit effect + GetCollisionPoint(self->velocity, self->s.origin, self->maxs[0], point); + gi.CreateEffect(NULL, FX_WEAPON_MACEBALLBOUNCE, 0, point, "d", trace->plane.normal); + + if (trace->plane.normal[2] < .5) + { // Hit a vertical surface + return; // Don't track a target. + } + + self->flags |= FL_NOTARGET; // This indicates to the thinker to revise the trajectory. + + // It should track its target + if (self->enemy==NULL || self->enemy->health<=0) + { // Find new enemy + self->enemy = FindSpellTargetInRadius(self, MACEBALL_SEARCHRAD, self->s.origin, + self->mins, self->maxs); + + if (self->enemy == NULL) // no target, don't head for a target. + { + self->health = 1; + return; + } + } + // Since we have an enemy, set the flag to readjust next think. + VectorCopy(trace->plane.normal, self->movedir); +} + + + +// **************************************************************************** +// SpellCastMaceballs +// **************************************************************************** + +void SpellCastMaceball(edict_t *caster, vec3_t startpos, vec3_t aimangles, vec3_t unused, float value) +{ + edict_t *ball; + trace_t trace; + vec3_t orig; + + ball = G_Spawn(); + + VectorCopy(startpos, ball->s.origin); + + VectorSet(ball->mins, -MACEBALL_RADIUS, -MACEBALL_RADIUS, -MACEBALL_RADIUS); + VectorSet(ball->maxs, MACEBALL_RADIUS, MACEBALL_RADIUS, MACEBALL_RADIUS); + + VectorCopy(startpos, orig); + GetAimVelocity(caster->enemy, orig, MACEBALL_SPEED, aimangles, ball->velocity); + + // Throw the ball down. + ball->velocity[2] = -MACEBALL_DOWNSPEED; + VectorAdd(ball->velocity, caster->velocity, ball->velocity); + // If the caster has an enemy, then aim it at the enemy + ball->enemy = caster->enemy; + + // Spin it forward + ball->mass = 2500; + ball->elasticity = ELASTICITY_MACEBALL; + ball->friction = 0; + ball->gravity = MACEBALL_GRAVITY; + ball->svflags = SVF_DO_NO_IMPACT_DMG; + + ball->movetype = PHYSICSTYPE_STEP; + + ball->solid = SOLID_BBOX; + ball->clipmask = MASK_MONSTERSOLID; + ball->owner = caster; + ball->think = MaceballThink; + ball->nextthink = level.time + 0.1; + ball->bounced = MaceballBounce; + ball->classname = "Spell_Maceball"; + ball->touch_debounce_time = level.time + MACEBALL_LIFE; // The ball will expire the next bounce after this one. + ball->s.modelindex = gi.modelindex("models/spells/maceball/tris.fm"); + ball->s.scale = MACEBALL_SCALEINC; + ball->dmg = MACEBALL_DAMAGE; + ball->health = 2; + ball->s.effects |= EF_MACE_ROTATE; + VectorCopy(ball->s.origin, ball->last_org); + + gi.linkentity(ball); + + gi.trace(caster->s.origin, ball->mins, ball->maxs, startpos, caster, MASK_PLAYERSOLID,&trace); + if (trace.startsolid) + { // Spawning in something, give up now, and kill the thang. + VectorClear(ball->velocity); + + gi.sound(ball, CHAN_WEAPON, gi.soundindex("weapons/MaceBallDeath.wav"), 2, ATTN_NORM, 0); + gi.CreateEffect(NULL, + FX_WEAPON_MACEBALLEXPLODE, + 0, + ball->s.origin, + "d", + ball->velocity); + G_SetToFree(ball); + return; + } + else if (trace.fraction < 0.99) + { // Hit something along the way from the center of the player to here. + VectorCopy(trace.endpos, ball->s.origin); + VectorCopy(trace.endpos, ball->last_org); + } + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/MaceBallCast.wav"), 1, ATTN_NORM, 0); +} + + +// end + diff --git a/Toolkit/Programming/GameCode/game/spl_magicmissile.c b/Toolkit/Programming/GameCode/game/spl_magicmissile.c new file mode 100644 index 0000000..d21300e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_magicmissile.c @@ -0,0 +1,288 @@ +// +// spl_magicmissile.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "Angles.h" +#include "Utilities.h" +#include "vector.h" +#include "random.h" +#include "decals.h" +#include "g_playstats.h" + +#define ARROW_RADIUS 2.0F + +void create_magic(edict_t *MagicMissile); + +static void MagicMissileThink2(edict_t *self); +static void MagicMissileTouch(edict_t *self,edict_t *Other,cplane_t *Plane,csurface_t *Surface); +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); +// static void MagicMissileThink1(edict_t *self); + + +// **************************************************************************** +// MagicMissileThink2 +// **************************************************************************** + +static void MagicMissileThink2(edict_t *self) +{ + // Prevent any further transmission of this entity to clients. + +// self->s.effects=0; + + self->svflags|=SVF_NOCLIENT; + self->think = NULL; +} + +// **************************************************************************** +// MagicMissileTouch +// **************************************************************************** + +static void MagicMissileTouch(edict_t *self,edict_t *Other,cplane_t *Plane,csurface_t *Surface) +{ + vec3_t Origin, ScorchOrigin; + int makeScorch; + edict_t *MagicMissile; + + if(Surface&&(Surface->flags&SURF_SKY)) + { + SkyFly(self); + return; + } + + // has the target got reflection turned on ? + if (self->reflect_debounce_time) + { + if(EntReflecting(Other, true, true)) + { + + MagicMissile = G_Spawn(); + create_magic(MagicMissile); + MagicMissile->owner = Other; + MagicMissile->enemy = self->enemy; + MagicMissile->think=MagicMissileThink2; + VectorCopy(self->s.origin, MagicMissile->s.origin); + Create_rand_relect_vect(self->velocity, MagicMissile->velocity); + Vec3ScaleAssign(MAGICMISSILE_SPEED/2,MagicMissile->velocity); + G_LinkMissile(MagicMissile); + gi.CreateEffect(&MagicMissile->s, + FX_WEAPON_MAGICMISSILE, + CEF_OWNERS_ORIGIN|CEF_FLAG6, + 0, + "ss", + MagicMissile->velocity[YAW],MagicMissile->velocity[PITCH]); + + MagicMissile->reflect_debounce_time = self->reflect_debounce_time -1; + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&MagicMissile->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", MagicMissile->velocity); + + return; + } + } + + if((Other==self->owner)||(!strcmp(self->classname,Other->classname))) + { + return; + } + + VectorCopy(self->s.origin,ScorchOrigin); + + // Calculate the position for the explosion entity. + + VectorMA(self->s.origin,-0.02,self->velocity,Origin); + + AlertMonsters (self, self->owner, 1, false); + if(Other->takedamage) + { + T_Damage(Other,self,self->owner,self->movedir,self->s.origin,Plane->normal,self->dmg,self->dmg,DAMAGE_SPELL,MOD_MMISSILE); + } + else + { + // Back off the origin for the damage a bit. We are a point and this will + // help fix hitting base of a stair and not hurting a guy on next step up. + VectorMA(self->s.origin,-8.0,self->movedir,self->s.origin); + } + + // Okay, we have to do some blast damage no matter what. + // They say that blast is too much. + if (deathmatch->value) + { // Except in deathmatch the weapon is too wimpy. + T_DamageRadius(self, self->owner, self->owner, + MAGICMISSILE_RADIUS, MAGICMISSILE_DAMAGE_RAD, MAGICMISSILE_DAMAGE_RAD*0.25, + DAMAGE_SPELL|DAMAGE_EXTRA_KNOCKBACK, MOD_MMISSILE); + } + + // Attempt to apply a scorchmark decal to the thing I hit. + makeScorch = 0; + if(IsDecalApplicable(self,Other,self->s.origin,Surface,Plane,NULL)) + { + makeScorch = CEF_FLAG6; + } + gi.CreateEffect(&self->s, FX_WEAPON_MAGICMISSILEEXPLODE, CEF_OWNERS_ORIGIN | makeScorch, self->s.origin, "d", self->movedir); + gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/MagicMissileHit.wav"), 2, ATTN_NORM, 0); + + G_SetToFree(self); +} + +// create guts of magice missile +void create_magic(edict_t *MagicMissile) +{ + MagicMissile->s.effects=EF_NODRAW_ALWAYS_SEND|EF_ALWAYS_ADD_EFFECTS; + MagicMissile->movetype=MOVETYPE_FLYMISSILE; + MagicMissile->solid=SOLID_BBOX; + MagicMissile->classname="Spell_MagicMissile"; + MagicMissile->touch=MagicMissileTouch; + if(deathmatch->value) + MagicMissile->dmg=irand(MAGICMISSILE_DAMAGE_MIN/2, MAGICMISSILE_DAMAGE_MAX/2);//15 - 20 + else + MagicMissile->dmg=irand(MAGICMISSILE_DAMAGE_MIN, MAGICMISSILE_DAMAGE_MAX);//30 - 40 + MagicMissile->clipmask=MASK_SHOT; + VectorSet(MagicMissile->mins, -ARROW_RADIUS, -ARROW_RADIUS, -ARROW_RADIUS); + VectorSet(MagicMissile->maxs, ARROW_RADIUS, ARROW_RADIUS, ARROW_RADIUS); + MagicMissile->nextthink=level.time+0.1; + +} + +// **************************************************************************** +// SpellCastMagicMissile +// **************************************************************************** + +void SpellCastMagicMissile(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir) +{ + edict_t *MagicMissile; + trace_t trace; + vec3_t TempVec; + short shortyaw, shortpitch; + + // Spawn the magic-missile. + + MagicMissile=G_Spawn(); + + VectorNormalize2(AimDir, MagicMissile->movedir); + VectorMA(StartPos,1.0,AimDir,MagicMissile->s.origin); + + create_magic(MagicMissile); + MagicMissile->owner=Caster; + MagicMissile->reflect_debounce_time = MAX_REFLECT; + G_LinkMissile(MagicMissile); + + gi.trace(Caster->s.origin, MagicMissile->mins, MagicMissile->maxs, MagicMissile->s.origin, Caster, MASK_PLAYERSOLID,&trace); + if (trace.startsolid) + { + MagicMissileTouch(MagicMissile, trace.ent, &trace.plane, trace.surface); + return; + } + + // Handle autotargeting by looking for the nearest monster that: + // a) Lies in a 45 degree degree horizontal, 180 degree vertical cone from my facing. + // b) Lies within 0 to 1000 meters of myself. + // c) Is visible (i.e. LOS exists from the missile to myself). + + if(MagicMissile->enemy=FindNearestVisibleActorInFrustum(MagicMissile, + AimAngles, + 0.0, + 1000.0, + ANGLE_30, + ANGLE_180, + SVF_MONSTER, + MagicMissile->s.origin, + NULL,NULL)) + { + VectorCopy(MagicMissile->s.origin,TempVec); + VectorSubtract(MagicMissile->enemy->s.origin,TempVec,TempVec); + + TempVec[0]+=(MagicMissile->enemy->mins[0]+MagicMissile->enemy->maxs[0])/2.0; + TempVec[1]+=(MagicMissile->enemy->mins[1]+MagicMissile->enemy->maxs[1])/2.0; + TempVec[2]+=(MagicMissile->enemy->mins[2]+MagicMissile->enemy->maxs[2])/2.0; + + VectorNormalize(TempVec); + vectoangles(TempVec,MagicMissile->s.angles); + // The pitch is flipped in these? + MagicMissile->s.angles[PITCH] = -MagicMissile->s.angles[PITCH]; + VectorScale(TempVec,MAGICMISSILE_SPEED,MagicMissile->velocity); + } + else + { + VectorScale(AimDir,MAGICMISSILE_SPEED,MagicMissile->velocity); + VectorCopy(AimAngles,MagicMissile->s.angles); + } + + shortyaw = (short)(MagicMissile->s.angles[YAW]*(65536.0/360.0)); + shortpitch = (short)(MagicMissile->s.angles[PITCH]*(65536.0/360.0)); + + gi.CreateEffect(&MagicMissile->s, + FX_WEAPON_MAGICMISSILE, + CEF_OWNERS_ORIGIN, + 0, + "ss", + shortyaw, shortpitch); + + + MagicMissile->think=MagicMissileThink2; + MagicMissile->nextthink=level.time+0.1; +} + + +/* +// **************************************************************************** +// MagicMissileThink1 +// **************************************************************************** + +static void MagicMissileThink1(edict_t *self) +{ + vec3_t TempVec; + short shortyaw, shortpitch; + + // Handle autotargeting by looking for the nearest monster that: + // a) Lies in a 45 degree degree horizontal, 180 degree vertical cone from my facing. + // b) Lies within 0 to 1000 meters of myself. + // c) Is visible (i.e. LOS exists from the missile to myself). + + if(self->enemy=FindNearestVisibleActorInFrustum(self, + self->s.angles, + 0.0, + 1000.0, + ANGLE_45, + ANGLE_180, + SVF_MONSTER, + self->s.origin, + NULL,NULL)) + { + VectorCopy(self->s.origin,TempVec); + VectorSubtract(self->enemy->s.origin,TempVec,TempVec); + + TempVec[0]+=(self->enemy->mins[0]+self->enemy->maxs[0])/2.0; + TempVec[1]+=(self->enemy->mins[1]+self->enemy->maxs[1])/2.0; + TempVec[2]+=(self->enemy->mins[2]+self->enemy->maxs[2])/2.0; + + VectorNormalize(TempVec); + vectoangles(TempVec,self->s.angles); + VectorScale(TempVec,MAGICMISSILE_SPEED,self->velocity); + } + else + { + VectorScale(self->velocity,MAGICMISSILE_SPEED,self->velocity); + } + + shortyaw = (short)(self->s.angles[YAW]*(65536.0/360.0)); + shortpitch = (short)(self->s.angles[PITCH]*(65536.0/360.0)); + + gi.CreateEffect(&self->s, + FX_WEAPON_MAGICMISSILE, + CEF_OWNERS_ORIGIN, + 0, + "ss", + shortyaw, shortpitch); + + + self->think=MagicMissileThink2; + self->nextthink=level.time+0.1; +} +*/ diff --git a/Toolkit/Programming/GameCode/game/spl_meteorbarrier.c b/Toolkit/Programming/GameCode/game/spl_meteorbarrier.c new file mode 100644 index 0000000..4b6f2fb --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_meteorbarrier.c @@ -0,0 +1,450 @@ +// +// spl_meteorbarrier.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "Angles.h" +#include "Utilities.h" +#include "random.h" +#include "vector.h" +#include "decals.h" +#include "g_playstats.h" + +#define METEOR_BARRIER_DIE_EXPLODE 1 +#define METEOR_BARRIER_DIE_EXPLODEIMPACT 2 + +#define METEOR_RADIUS 4.0 +#define METEOR_HUNT_SPEED 600.0 + +static void MeteorBarrierDie(edict_t *self, int Flags); +static void MeteorBarrierSearchInitThink(edict_t *self); +static void MeteorBarrierSearchThink(edict_t *self); +static void MeteorBarrierHuntThink(edict_t *self); +static void MeteorBarrierTouch(edict_t *self, trace_t *trace); +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); + +void create_meteor(edict_t *Meteor); +vec3_t BBMin = {-5.0,-5.0,-5.0}; +vec3_t BBMax = {5.0,5.0,5.0}; + +// ************************************************************************************************ +// MeteorBarrierDie +// ---------------- +// ************************************************************************************************ + +static void MeteorBarrierDie(edict_t *self, int Flags) +{ + vec3_t ExplodeDir; + int flag = 0; + + // If required, create an explode client effect and make an explosion noise. + VectorScale(self->movedir, -1.0, ExplodeDir); + + if(Flags & METEOR_BARRIER_DIE_EXPLODE) + { + if(Flags & METEOR_BARRIER_DIE_EXPLODEIMPACT) + { + flag = CEF_FLAG6; + } + gi.CreateEffect(NULL, + FX_SPELL_METEORBARRIEREXPLODE, + CEF_BROADCAST|flag, + self->s.origin, + "d", + ExplodeDir); + + gi.sound(self, CHAN_BODY, gi.soundindex("weapons/MeteorBarrierImpact.wav"), 2, ATTN_NORM, 0); + } + + // remove the persistant effect from the persistant effect list + if (self->PersistantCFX) + { + gi.RemovePersistantEffect(self->PersistantCFX); + gi.RemoveEffects(&self->owner->s, FX_SPELL_METEORBARRIER+self->health); + self->PersistantCFX = 0; + } + + // remove the players pointer to this now in-active meteor + self->owner->client->Meteors[self->health] = NULL; + + // now we've been cast, remove us from the count of meteors the caster owns, and turn off his looping sound if need be + self->owner->client->playerinfo.meteor_count &= ~(1<health); + if (!self->owner->client->playerinfo.meteor_count) + self->owner->s.sound = 0; + + // And finally remove myself (with assoc cfx) + G_SetToFree(self); +} + +// ************************************************************************************************ +// MeteorBarrierHuntThink +// ---------------------- +// ************************************************************************************************ + +static void MeteorBarrierHuntThink(edict_t *self) +{ + vec3_t Heading, Dest; + float dist; + trace_t tr; + +// self->svflags &= ~SVF_ALWAYS_SEND; + if (deathmatch->value == 0 || self->accel == 0.0) // These don't home in on an enemy in deathmatch... too powerful. + { + if((self->enemy->health > 0) && (!strcmp(self->enemy->classname, self->targetname))) + { + VectorCopy(self->enemy->s.origin, Dest); + + Dest[0] += (self->enemy->mins[0] + self->enemy->maxs[0]) * 0.5; + Dest[1] += (self->enemy->mins[1] + self->enemy->maxs[1]) * 0.5; + Dest[2] += (self->enemy->mins[2] + self->enemy->maxs[2]) * 0.5; + + VectorSubtract(Dest, self->s.origin, Heading); + VectorScale(Heading, 10, self->velocity); + dist = VectorLength(Heading); + // are we now in the center of something ? + if (dist < 5) + { + gi.trace(self->s.origin, self->mins, self->maxs, self->s.origin, self, MASK_MONSTERSOLID, &tr); + MeteorBarrierTouch(self,&tr); + return; + } + + VectorNormalize(Heading); + VectorCopy(Heading, self->movedir); + // don't let us over shoot the enemy + if (dist > (METEOR_HUNT_SPEED * 0.1)) + VectorScale(self->movedir, METEOR_HUNT_SPEED, self->velocity); + + + self->nextthink = level.time + 0.1; + self->accel = 1.0; // Signal that we have already gotten a target speed. + } + else + { + // My enemy has died so I die too. + MeteorBarrierDie(self, METEOR_BARRIER_DIE_EXPLODE); + } + } + else + { + self->nextthink = level.time + 2.0; + self->accel = 0.0; // Un-aim at enemies... + } +} + +// ************************************************************************************************ +// MeteorBarrierHuntThink +// ---------------------- +// ************************************************************************************************ + +static void MeteorBarrierBounceThink(edict_t *self) +{ + self->random += 20; // Lifetime + if((self->enemy->health > 0) && (self->random < (5000 + (self->health * 200.0)))) + { + self->nextthink = level.time + 0.1; + } + else + { + // My enemy has died so I die too. + MeteorBarrierDie(self, METEOR_BARRIER_DIE_EXPLODE); + } +} + + + +// ************************************************************************************************ +// MeteorBarrierReflect +// ------------------ +// ************************************************************************************************ + +edict_t *MeteorBarrierReflect(edict_t *self, edict_t *other, vec3_t vel) +{ + edict_t *Meteor; + + Meteor = G_Spawn(); + VectorCopy(self->s.origin, Meteor->s.origin); + create_meteor(Meteor); + VectorCopy(vel, Meteor->velocity); + Meteor->owner = self->owner; + Meteor->enemy = self->enemy; + Meteor->health = self->health; + Meteor->count = self->count; + Meteor->random = self->random; // Lifetime count + Meteor->solid = self->solid; + VectorCopy(BBMin,Meteor->mins); + VectorCopy(BBMax,Meteor->maxs); + Meteor->movetype = PHYSICSTYPE_FLY; + Meteor->think = MeteorBarrierBounceThink; + Meteor->nextthink = level.time+0.1; + Meteor->reflect_debounce_time = self->reflect_debounce_time -1; + Meteor->s.effects |= EF_NODRAW_ALWAYS_SEND|EF_ALWAYS_ADD_EFFECTS; + Meteor->svflags = SVF_ALWAYS_SEND; + gi.linkentity(Meteor); + + // remove the persistant effect from the persistant effect list + if (self->PersistantCFX) + { + gi.RemovePersistantEffect(self->PersistantCFX); + gi.RemoveEffects(&self->owner->s, FX_SPELL_METEORBARRIER+self->health); + self->PersistantCFX = 0; + } + + // replace this new meteor in the owners meteor list + Meteor->owner->client->Meteors[Meteor->health] = Meteor; + + // create a client effect for this new meteor + gi.CreateEffect(&Meteor->s, FX_SPELL_METEORBARRIER_TRAVEL, CEF_BROADCAST|CEF_OWNERS_ORIGIN, NULL, ""); + + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&Meteor->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", Meteor->velocity); + + return(Meteor); +} + + + +// ************************************************************************************************ +// MeteorBarrierTouch +// ------------------ +// ************************************************************************************************ + +static void MeteorBarrierTouch(edict_t *self, trace_t *trace) +{ + edict_t *Other; + csurface_t *Surface; + cplane_t *Plane; + + Other = trace->ent; + Surface = trace->surface; + Plane = &trace->plane; + + // has the target got reflection turned on ? + if (self->reflect_debounce_time) + { + if(EntReflecting(Other, true, true)) + { + Create_rand_relect_vect(self->velocity, self->velocity); + Vec3ScaleAssign(METEOR_HUNT_SPEED/2,self->velocity); + MeteorBarrierReflect(self, Other, self->velocity); + + return; + } + } + + if(Surface && (Surface->flags & SURF_SKY)) + { + MeteorBarrierDie(self, METEOR_BARRIER_DIE_EXPLODE); + return; + } + + AlertMonsters (self, self->owner, 1, false); + if(Other->takedamage) + { + T_Damage(Other, self, self->owner, self->movedir, self->s.origin, Plane->normal, self->dmg, 0, DAMAGE_SPELL,MOD_METEORS); + } + else + { + // Back off the origin for the damage a bit. We are a point and this will help fix hitting + // the base of a stair and not hurting a guy on next step up. + VectorMA(self->s.origin, -8.0, self->movedir, self->s.origin); + } + MeteorBarrierDie(self, METEOR_BARRIER_DIE_EXPLODE | METEOR_BARRIER_DIE_EXPLODEIMPACT); +} + +// ************************************************************************************************ +// SpellCastMeteorBarrier +// ---------------------- +// ************************************************************************************************ + +// Make meteors orbit player + +static void MeteorBarrierSearchThink(edict_t *self) +{ + edict_t *NewTarg = NULL; + int DoneSearching = 0; + trace_t tr; + + // Only check for a target every so often as this reduces CPU requirements AND it looks much + // cooler. + // (using self->owner->enemy as the target would be much quicker...but not 360 degrees) + + if(!irand(0, METEOR_SEARCH_CHANCE)) + { + NewTarg = FindSpellTargetInRadius(self, METEOR_SEARCH_RADIUS, self->s.origin, BBMin, BBMax); + + // we found something to shoot at, lets go get it + if(NewTarg) + { + self->enemy = NewTarg; + self->solid = SOLID_BBOX; + VectorCopy(BBMin,self->mins); + VectorCopy(BBMax,self->maxs); + self->accel = 0.0; + self->think = MeteorBarrierHuntThink; + self->movetype = PHYSICSTYPE_FLY; + self->nextthink = level.time + 0.1; + self->svflags = SVF_ALWAYS_SEND; + self->s.effects |= EF_NODRAW_ALWAYS_SEND|EF_ALWAYS_ADD_EFFECTS; + self->targetname = self->enemy->classname; + + // did we start up inside someone ? - check and see + gi.trace(self->s.origin, self->mins, self->maxs, self->s.origin, self, MASK_MONSTERSOLID, &tr); + if(tr.startsolid) + { + MeteorBarrierTouch(self,&tr); + return; + } + + gi.sound(self,CHAN_BODY,gi.soundindex("weapons/MeteorBarrierSeek.wav"),1,ATTN_NORM,0); + gi.CreateEffect(&self->s, FX_SPELL_METEORBARRIER_TRAVEL, CEF_BROADCAST|CEF_OWNERS_ORIGIN, NULL, ""); + + // remove the persistant effect from the persistant effect list + if (self->PersistantCFX) + { + gi.RemovePersistantEffect(self->PersistantCFX); + gi.RemoveEffects(&self->owner->s, FX_SPELL_METEORBARRIER+self->health); + self->PersistantCFX = 0; + } + + // now we've been cast, remove us from the count of meteors the caster owns, and turn off his looping sound if need be + self->owner->client->playerinfo.meteor_count &= ~(1<health); + if (!self->owner->client->playerinfo.meteor_count) + self->owner->s.sound = 0; + return; + } + } + + self->random += 20; // Lifetime + + if((self->owner->health > 0) && (self->random < (5000 + (self->health * 200.0)))) + { + float Angle; + + Angle = ((level.time * 150.0) + (90.0 * self->health)) * ANGLE_TO_RAD; + VectorCopy(self->owner->s.origin, self->s.origin); + self->s.origin[0] += cos(Angle) * 30.0; + self->s.origin[1] += sin(Angle) * 30.0; + self->s.origin[2] += cos(Angle / (M_PI / 5)) * 10.0; + self->nextthink = level.time + 0.1; + } + else + { + // My lifetime has expired so I die. + MeteorBarrierDie(self, METEOR_BARRIER_DIE_EXPLODE); + } +} + +// Move the meteors out to radius + +static void MeteorBarrierSearchInitThink(edict_t *self) +{ + float Angle; + + if(self->owner->health > 0) + { + Angle = ((level.time * 150.0) + (90.0 * self->health)) * ANGLE_TO_RAD; + VectorCopy(self->owner->s.origin, self->s.origin); + self->s.origin[0] += cos(Angle) * 30.0 * (self->count / 5.0); + self->s.origin[1] += sin(Angle) * 30.0 * (self->count / 5.0); + self->s.origin[2] += cos(Angle / (M_PI / 5)) * 10.0; + + if(self->count++ > 5) + { + self->random = self->health * 90.0; + self->think = MeteorBarrierSearchThink; + } + self->nextthink = level.time + 0.1; + } + else + { + // My caster died so I die too. + MeteorBarrierDie(self, METEOR_BARRIER_DIE_EXPLODE); + } +} + +void create_meteor(edict_t *Meteor) +{ + Meteor->movetype = PHYSICSTYPE_NOCLIP; + Meteor->classname = "Spell_MeteorBarrier"; + Meteor->isBlocked = MeteorBarrierTouch; + Meteor->isBlocking = MeteorBarrierTouch; + Meteor->dmg = irand(METEOR_DAMAGE_MIN, METEOR_DAMAGE_MAX); + if (deathmatch->value) + Meteor->dmg *= 0.5; // These badasses do half damage in deathmatch. + Meteor->clipmask = MASK_SHOT; + VectorSet(Meteor->mins, -METEOR_RADIUS, -METEOR_RADIUS, -METEOR_RADIUS); + VectorSet(Meteor->maxs, METEOR_RADIUS, METEOR_RADIUS, METEOR_RADIUS); + Meteor->nextthink = level.time+0.1; + Meteor->takedamage = DAMAGE_NO; + // no gravity + Meteor->gravity = 0; +} + +// Spawn the meteors + +void SpellCastMeteorBarrier(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value) +{ + int I, cast; + edict_t *Meteor; + + // Now create up to 4 spinning meteors. + + cast = false; + for(I = 0; I < 4; I++) + { + // If my caster is a player, then make sure they only have one instance of me active, then + if(Caster->client) + { + if(Caster->client->Meteors[I]) + continue; + } + + // enough mana to do this ? + if (Caster->client->playerinfo.pers.inventory.Items[Caster->client->playerinfo.def_ammo_index] < Caster->client->playerinfo.pers.defence->quantity) + break; + + // decrement our mana + if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_INFINITE_MANA))) + Caster->client->playerinfo.pers.inventory.Items[Caster->client->playerinfo.def_ammo_index] -= Caster->client->playerinfo.pers.defence->quantity; + + cast = true; + Meteor = G_Spawn(); + Meteor->svflags |= SVF_NOCLIENT; + + if(Caster->client) + { + Caster->client->Meteors[I] = Meteor; + } + + VectorCopy(StartPos, Meteor->s.origin); + create_meteor(Meteor); + Meteor->reflect_debounce_time = MAX_REFLECT; + Meteor->health = I; + Meteor->think = MeteorBarrierSearchInitThink; + Meteor->count = 0; + Meteor->random = 0; // Lifetime count + Meteor->solid = SOLID_NOT; + Meteor->owner = Caster; + Caster->client->playerinfo.meteor_count |= 1<PersistantCFX = gi.CreatePersistantEffect(&Caster->s, FX_SPELL_METEORBARRIER+I, CEF_BROADCAST|CEF_OWNERS_ORIGIN|(I<<5), NULL, "" ); + + } + if(cast) + { + gi.sound(Caster,CHAN_WEAPON,gi.soundindex("weapons/MeteorBarrierCast.wav"),1,ATTN_NORM,0); + Caster->s.sound = gi.soundindex("weapons/MeteorBarrierAmbient.wav"); + Caster->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_NORM; + } +} +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/spl_morph.c b/Toolkit/Programming/GameCode/game/spl_morph.c new file mode 100644 index 0000000..0634492 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_morph.c @@ -0,0 +1,692 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// +// spl_morph.c +// +// Created by John Scott, but written by Jake Simpson and finally rodgered to be work with client +// prediction by Marcus Whitlock. +// "Rodgered" ??? No wonder he was working late :) + +#include "g_local.h" +#include "g_monster.h" +#include "g_Physics.h" +#include "g_playstats.h" +#include "g_teleport.h" +#include "g_Skeletons.h" +#include "g_volume_effect.h" +#include "m_chicken.h" +#include "m_chicken_anim.h" +#include "angles.h" +#include "fx.h" +#include "matrix.h" +#include "vector.h" +#include "Utilities.h" +#include "p_main2.h" +#include "p_anims2.h" +#include "random.h" +#include "h2common.h" + +#define ARROW_SPEED 400.0F +#define ARROW_RADIUS 2.0F +#define ANGLE_INC 360/NUM_OF_OVUMS + +char chicken_text[] = "monster_chicken"; + +extern void ED_CallSpawn (edict_t *ent); +H2COMMON_API void TurnOffPlayerEffects(playerinfo_t *playerinfo); +extern void PlayerKillShrineFX(edict_t *self); +extern void SpawnInitialPlayerEffects(edict_t *ent); +extern void MorphPlayerToChicken(edict_t *self, edict_t *caster); + +extern vec3_t mins; +extern vec3_t maxs; + +void create_morph(edict_t *morph); + +// ************************************************************************************************* +// MorphFadeIn +// ----------- +// Fade in the chicken - for MONSTERS only. +// ************************************************************************************************* + +void MorphFadeIn(edict_t *self) +{ + self->s.color.a += MORPH_TELE_FADE; + self->nextthink = level.time + 0.1; + if (!(--self->morph_timer)) + { + self->think = walkmonster_start_go; + } +} + +// ************************************************************************************************* +// MorphFadeOut +// ------------ +// Fade out the chicken model till its gone - for MONSTERS only. +// ************************************************************************************************* + +void MorphFadeOut(edict_t *self) +{ + edict_t *newent; + + self->s.color.a -= MORPH_TELE_FADE; + self->nextthink = level.time + 0.1; + if (!(--self->morph_timer)) + { + // create the Chicken object + newent = G_Spawn(); + newent->classname = chicken_text; + VectorCopy(self->s.origin, newent->s.origin); + + // if we are looking at an original model thats not got an origin at the waist, move us up in the world + if (self->mins[2] == 0) + newent->s.origin[2] += 16; + + VectorCopy(self->s.angles, newent->s.angles); + newent->enemy = self->enemy; + // keep some info around so we can return to our original persona + newent->map = self->classname; + newent->target = self->target; + // time we stay a chicken + newent->time = level.time + 20; + ED_CallSpawn(newent); + newent->s.color.c = 0xffffff; + newent->morph_timer = MORPH_TELE_TIME; + newent->think = MorphFadeIn; + gi.CreateEffect(&newent->s, FX_PLAYER_TELEPORT_IN, CEF_OWNERS_ORIGIN|CEF_FLAG6, NULL, "" ); + // do the teleport sound + gi.sound(newent,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + + G_SetToFree(self); + } +} + +// ************************************************************************************************* +// CleanUpMorph +// ------------ +// Done morphing, clean up after ourselves - for PLAYER only. Called from G_ANIMACTOR.C. +// ************************************************************************************************* + +void CleanUpMorph(edict_t *self) +{ + self->client->tele_dest[0] = self->client->tele_dest[1] = self->client->tele_dest[2] = 0; + self->client->tele_count = 0; + self->client->playerinfo.edictflags &= ~FL_LOCKMOVE; + self->client->playerinfo.renderfx &= ~RF_TRANSLUCENT; + self->client->playerinfo.flags &=~PLAYER_FLAG_MORPHING; + self->client->shrine_framenum = level.time - 1;; + self->s.color.a = 255; +} + +// ************************************************************************************************* +// reset_morph_to_elf +// ------------------ +// We are done being a chicken, let's be Corvus again - switch models from chicken back to corvus +// and do teleport fade in - for PLAYER only. Called from G_ANIMACTOR.C. +// ************************************************************************************************* + +void reset_morph_to_elf(edict_t *ent) +{ + // we have no damage, and no motion type + ent->takedamage = DAMAGE_AIM; + ent->movetype = PHYSICSTYPE_STEP; + ent->health = ent->max_health; + + // move the camera back to where it should be, and reset our lungs and stuff + ent->viewheight = 0; + ent->mass = 200; + ent->deadflag = DEAD_NO; + ent->air_finished = level.time + HOLD_BREATH_TIME; + + ent->s.scale = 1.0; + + // set the model back to corvux +#ifdef COMP_FMOD + ent->model = "models/player/elf/tris_c.fm"; +#else + ent->model = "models/player/elf/tris.fm"; +#endif + ent->pain = player_pain; + ent->die = player_die; + ent->flags &= ~FL_NO_KNOCKBACK; + ent->gravity = 1.0; + + // reset our skins + ent->client->playerinfo.effects = 0; + ent->client->playerinfo.skinnum = ent - g_edicts - 1; + ent->s.modelindex = 255; // will use the skin specified model + ent->client->playerinfo.frame = 0; + + // turn our skeleton back on + ent->s.skeletalType = SKEL_CORVUS; + ent->client->playerinfo.effects|=(EF_SWAPFRAME|EF_JOINTED|EF_CAMERA_NO_CLIP|EF_PLAYER); + ent->client->playerinfo.effects&=~EF_CHICKEN; + ent->client->playerinfo.edictflags &= ~FL_CHICKEN; + ent->client->playerinfo.renderfx &= ~RF_IGNORE_REFS; + + // reset our mins and max's. And then let the physics move us out of anyone elses bounding box + VectorCopy (mins, ent->intentMins); + VectorCopy (maxs, ent->intentMaxs); + ent->physicsFlags |= PF_RESIZE; + + // reset our thinking + ent->think = ent->oldthink; + ent->nextthink = level.time + 0.1; + + // reset our animations + PlayerBasicAnimReset(&ent->client->playerinfo); + ent->client->playerinfo.upperframe = 43; + ent->client->playerinfo.lowerframe = 43; + + PlayerUpdateModelAttributes(&ent->client->playerinfo); + PlayerAnimSetLowerSeq(&ent->client->playerinfo, ASEQ_NONE); + PlayerAnimSetLowerSeq(&ent->client->playerinfo, ASEQ_IDLE_WIPE_BROW); + + // re-spawn anything that should be - shrine effects and the like + SpawnInitialPlayerEffects(ent); + + // draw the teleport splash at the destination + gi.CreateEffect(&ent->s, FX_PLAYER_TELEPORT_IN, CEF_BROADCAST|CEF_OWNERS_ORIGIN|CEF_FLAG6, ent->s.origin, ""); + + // restart the loop and tell us next time we aren't de-materialising + ent->client->tele_count = TELE_TIME; + ent->client->tele_dest[0] = ent->client->tele_dest[1] = ent->client->tele_dest[2] = -1; + +} + +// ************************************************************************************************* +// MorphChickenToPlayer +// -------------------- +// Modify a chicken into a player - first call. Start the teleport effect on the chicken. +// For PLAYER only. +// ************************************************************************************************* + +void MorphChickenToPlayer(edict_t *self) +{ + gclient_t *playerinfo; + + playerinfo = self->client; + + // if we are teleporting or morphing, forget it + if (self->client->playerinfo.flags & (PLAYER_FLAG_TELEPORT | PLAYER_FLAG_MORPHING)) + return; + + // set the player as teleporting + self->client->playerinfo.flags |= PLAYER_FLAG_MORPHING; + + // time taken over dematerialisation + self->client->tele_count = TELE_TIME_OUT; + + // make us invunerable for a couple of seconds + self->client->shrine_framenum = level.time + 10; + + // tell us how we triggered the teleport + self->client->tele_type = 1; + + // clear the velocity and hold them in place briefly + VectorClear (self->velocity); + self->client->ps.pmove.pm_time = 50; + // make the player still + self->flags |= FL_LOCKMOVE; + // allow the player to fade out + self->s.color.a = 255; + self->s.color.r = 255; + self->s.color.g = 255; + self->s.color.b = 255; + self->s.renderfx |= RF_TRANSLUCENT; + + // make us not think at all + self->think = NULL; + + // make it so that the stuff that does the demateriasation in G_ANIM_ACTOR knows we are fading out, not in + self->client->tele_dest[0] = self->client->tele_dest[1] = self->client->tele_dest[2] = 0; + + // draw the teleport splash at the teleport source + gi.CreateEffect(&self->s, FX_PLAYER_TELEPORT_OUT, CEF_OWNERS_ORIGIN |CEF_FLAG6, NULL, "" ); + // do the teleport sound + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + + +} + +// ************************************************************************************************* +// watch_chicken +// ------------- +// Watch the chicken to see if we should become the elf again. For PLAYER only. +// ************************************************************************************************* + +void watch_chicken(edict_t *self) +{ + + // are we done yet ? + if (self->morph_timer <= level.time) + { + MorphChickenToPlayer(self); + } + self->nextthink = level.time + 0.1; +} + +// ************************************************************************************************* +// Perform_Morph +// ------------ +// Switch the models from player to chicken and then make us re-appear ala teleport. For PLAYER +// only. Called from G_ANIMACTOR.C. +// ************************************************************************************************* + +void Perform_Morph(edict_t *self) +{ + qboolean super_chicken = false; + trace_t trace; + vec3_t mins = { -16, -16, -36}; + vec3_t maxs = { 16, 16, 36}; + vec3_t pos; + int i; + + // change out our model + self->model = "models/monsters/chicken2/tris.fm"; + self->s.modelindex = gi.modelindex("models/monsters/chicken2/tris.fm"); + + self->client->playerinfo.effects &= ~(EF_JOINTED|EF_SWAPFRAME); + self->client->playerinfo.effects |= EF_CHICKEN; + self->s.skeletalType = SKEL_NULL; + self->client->playerinfo.renderfx |= RF_IGNORE_REFS; + + if (!irand(0,10)) + super_chicken = true; + + if (super_chicken) + { + VectorCopy(self->s.origin, pos); + pos[2] += 2; + + gi.trace(pos, mins, maxs, pos, self, MASK_PLAYERSOLID,&trace); + + if (trace.fraction < 1 || trace.startsolid || trace.allsolid) + super_chicken = false; + } + + if (super_chicken) + { + // reset our motion stuff + self->health = 999; + self->mass = 3000; + self->yaw_speed = 30; + self->gravity = 1.0; + + self->monsterinfo.scale = 2.5; + self->s.scale = 2.5; + + VectorSet(self->mins, -16, -16, -48); + VectorSet(self->maxs, 16, 16, 64); + + self->client->playerinfo.edictflags |= FL_SUPER_CHICKEN; + } + else + { + self->health = 1; + self->mass = 30; + self->yaw_speed = 20; + self->gravity = 0.6; + + self->monsterinfo.scale = MODEL_SCALE; + + // new mins and max's too + VectorSet(self->intentMins,-8,-8,-12); + VectorSet(self->intentMaxs,8,8,12); + + self->client->playerinfo.edictflags |= FL_AVERAGE_CHICKEN; + } + + // not being knocked back, and stepping like a chicken + self->movetype = PHYSICSTYPE_STEP; + VectorClear(self->knockbackvel); + + // reseting which skin we use, and new scale + self->client->playerinfo.skinnum = 0; + + // reset our thinking + self->oldthink = self->think; + self->think = watch_chicken; + self->nextthink = level.time + 0.1; + + self->physicsFlags |= PF_RESIZE; + + for (i=0;iclient->playerinfo.fmnodeinfo[i].flags &= ~FMNI_NO_DRAW; + + // reset our animation + PlayerAnimSetLowerSeq(&self->client->playerinfo, ASEQ_STAND); + + // draw the teleport splash at the destination + gi.CreateEffect(&self->s, FX_PLAYER_TELEPORT_IN, CEF_BROADCAST|CEF_OWNERS_ORIGIN|CEF_FLAG6, self->s.origin, ""); + + // restart the loop and tell us next time we aren't de-materialising + self->client->tele_count = TELE_TIME; + self->client->tele_dest[0] = self->client->tele_dest[1] = self->client->tele_dest[2] = -1; +} + +// ************************************************************************************************* +// MorphPlayerToChicken +// -------------------- +// Modify a player into a chicken - first call. Start the teleport effect on the player. For PLAYER +// only. +// ************************************************************************************************* + +void MorphPlayerToChicken(edict_t *self, edict_t *caster) +{ + gclient_t *playerinfo; + + playerinfo = self->client; + + // if we are teleporting or morphing, forget it + if (self->client->playerinfo.flags & (PLAYER_FLAG_TELEPORT | PLAYER_FLAG_MORPHING)) + return; + + // remove any hand or weapon effects + TurnOffPlayerEffects(&self->client->playerinfo); + + // remove any shrine effects he has + PlayerKillShrineFX(self); + + // set the player as teleporting + self->client->playerinfo.flags |= PLAYER_FLAG_MORPHING; + + // time taken over dematerialisation + self->client->tele_count = TELE_TIME_OUT; + + // make us invunerable for a couple of seconds + self->client->shrine_framenum = level.time + 10; + + // tell us how we triggered the teleport + self->client->tele_type = 1; + + // clear the velocity and hold them in place briefly + VectorClear (self->velocity); + self->client->ps.pmove.pm_time = 50; + + // make the player still + self->client->playerinfo.flags |= FL_LOCKMOVE; + + // allow the player to fade out + self->s.color.a = 255; + self->s.color.r = 255; + self->s.color.g = 255; + self->s.color.b = 255; + self->s.renderfx |= RF_TRANSLUCENT; + + // make it so that the stuff that does the demateriasation in G_ANIM_ACTOR knows we are fading out, not in + self->client->tele_dest[0] = self->client->tele_dest[1] = self->client->tele_dest[2] = 0; + + // tell us how long we have to be a chicken + self->morph_timer = level.time + MORPH_DUR; + + // draw the teleport splash at the teleport source + gi.CreateEffect(&self->s, FX_PLAYER_TELEPORT_OUT, CEF_OWNERS_ORIGIN | CEF_FLAG6, NULL, ""); + // do the teleport sound + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + +} + +// ************************************************************************************************* +// MorphPlayerToChicken2 +// --------------------- +// Modify a player into a chicken - first call. Start the teleport effect on the player. For PLAYER +// only. Temporary func. See Marcus for explaination. +// ************************************************************************************************* + +void MorphPlayerToChicken2(edict_t *self, edict_t *caster) +{ + gclient_t *playerinfo; + + playerinfo = self->client; + + // if we are teleporting or morphing, forget it + if (self->client->playerinfo.flags & (PLAYER_FLAG_TELEPORT | PLAYER_FLAG_MORPHING)) + return; + + // remove any hand or weapon effects + TurnOffPlayerEffects(&self->client->playerinfo); + + // remove any shrine effects he has + PlayerKillShrineFX(self); + + // set the player as teleporting + self->client->playerinfo.flags |= PLAYER_FLAG_MORPHING; + + // time taken over dematerialisation + self->client->tele_count = TELE_TIME_OUT; + + // make us invunerable for a couple of seconds + self->client->shrine_framenum = level.time + 10; + + // tell us how we triggered the teleport + self->client->tele_type = 1; + + // clear the velocity and hold them in place briefly + VectorClear (self->velocity); + self->client->ps.pmove.pm_time = 50; + + // make the player still + self->client->playerinfo.flags |= FL_LOCKMOVE; + + // allow the player to fade out + self->s.color.a = 255; + self->s.color.r = 255; + self->s.color.g = 255; + self->s.color.b = 255; + + self->client->playerinfo.renderfx |= RF_TRANSLUCENT; + + // make it so that the stuff that does the demateriasation in G_ANIM_ACTOR knows we are fading out, not in + self->client->tele_dest[0] = self->client->tele_dest[1] = self->client->tele_dest[2] = 0; + + // tell us how long we have to be a chicken + self->morph_timer = level.time + MORPH_DUR; + + // draw the teleport splash at the teleport source + gi.CreateEffect(&self->s, FX_PLAYER_TELEPORT_OUT, CEF_OWNERS_ORIGIN | CEF_FLAG6, NULL, ""); + // do the teleport sound + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + +} + +edict_t *MorphReflect(edict_t *self, edict_t *other, vec3_t vel) +{ + edict_t *morph; + vec3_t velocity; + byte yaw, pitch; + + // create a new missile to replace the old one - this is necessary cos physics will do nasty shit + // with the existing one,since we hit something. Hence, we create a new one totally. + morph = G_Spawn(); + create_morph(morph); + morph->reflect_debounce_time = self->reflect_debounce_time -1; + morph->owner = other; + morph->enemy = self->enemy; + VectorCopy(self->s.origin, morph->s.origin); + VectorCopy(vel, morph->velocity); + VectorNormalize2(morph->velocity, velocity); + AnglesFromDir(velocity, morph->s.angles); + G_LinkMissile(morph); + yaw = Q_ftol((morph->s.angles[YAW]/6.2831) * 255.0); + pitch = Q_ftol((morph->s.angles[PITCH]/6.2831) * 255.0); + gi.CreateEffect(&morph->s, FX_SPELL_MORPHMISSILE, CEF_OWNERS_ORIGIN|CEF_FLAG6, NULL, "bb", yaw,pitch); + + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&morph->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", morph->velocity); + return(morph); +} + + +// **************************************************************************** +// MorphMissile touch +// **************************************************************************** + +// This called when missile touches anything (world or edict) + +void MorphMissileTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + + // has the target got reflection turned on ? + if(EntReflecting(other, true, true) && self->reflect_debounce_time) + { + Create_rand_relect_vect(self->velocity, self->velocity); + Vec3ScaleAssign(ARROW_SPEED/2, self->velocity); + MorphReflect(self, other, self->velocity); + + return; + } + + // Turn target into a chicken if monster or player + if(((other->svflags & SVF_MONSTER) && !(other->svflags&SVF_BOSS) && !(other->monsterinfo.c_mode)) || + ((other->client)&&(deathmatch->value))) + { + //Don't turn a super chicken back to a player + if ( (other->client) && (other->client->playerinfo.edictflags & FL_SUPER_CHICKEN) ) + { + // Turn off the client effect + G_SetToFree(self); + return; + } + + if (other->svflags & SVF_MONSTER ) + { + // deal with the existing bad guy + other->think = MorphFadeOut; + other->nextthink = level.time + 0.1; + other->touch = NULL; + other->morph_timer = MORPH_TELE_TIME; + other->enemy = self->owner; + VectorClear(other->velocity); + gi.CreateEffect(&other->s, FX_PLAYER_TELEPORT_OUT, CEF_OWNERS_ORIGIN|CEF_FLAG6, NULL, "" ); + } + else + MorphPlayerToChicken(other, self->owner); + + if (deathmatch->value) + { + //There shouldn't be any monsters in deathmatch.. but... + assert(other->client); + + if ( (other->client) && (other->client->playerinfo.edictflags & FL_SUPER_CHICKEN) ) + gi.sound(other,CHAN_VOICE,gi.soundindex("weapons/supercrow.wav"),1,ATTN_NONE,0); + else + gi.sound(other,CHAN_VOICE,gi.soundindex("weapons/crow.wav"),1,ATTN_NONE,0); + } + else + { + gi.sound(other,CHAN_VOICE,gi.soundindex("weapons/crow.wav"),1,ATTN_NORM,0); + } + + gi.sound(other,CHAN_WEAPON,gi.soundindex("misc/null.wav"),1,ATTN_NORM,0); + gi.CreateEffect(NULL, FX_SPELL_MORPHEXPLODE, 0, self->s.origin, "d", self->movedir); + } + // else we hit a wall / object + else + { + if(plane && (plane->normal)) + // Start the explosion + gi.CreateEffect(NULL, FX_SPELL_MORPHEXPLODE, 0, self->s.origin, "d", plane->normal); + else + gi.CreateEffect(NULL, FX_SPELL_MORPHEXPLODE, 0, self->s.origin, "d", self->movedir); + } + + // Turn off the client effect + G_SetToFree(self); // Allow time to get to client +} + +// **************************************************************************** +// MorphMissile think +// **************************************************************************** + +void MorphMissileThink(edict_t *self) +{ + self->svflags |= SVF_NOCLIENT; // No messages to client after it has received velocity + self->think = NULL; // Not required to think anymore +} + + +// create the guts of the morph ovum +void create_morph(edict_t *morph) +{ + morph->s.effects |= EF_ALWAYS_ADD_EFFECTS; + morph->svflags |= SVF_ALWAYS_SEND; + morph->movetype = MOVETYPE_FLYMISSILE; + + // set up our collision boxes + VectorSet(morph->mins, -ARROW_RADIUS, -ARROW_RADIUS, -ARROW_RADIUS); + VectorSet(morph->maxs, ARROW_RADIUS, ARROW_RADIUS, ARROW_RADIUS); + + morph->solid = SOLID_BBOX; + morph->clipmask = MASK_MONSTERSOLID; + morph->touch = MorphMissileTouch; + morph->think = MorphMissileThink; + morph->classname = "Spell_MorphArrow"; + morph->nextthink = level.time + 0.1; +} + +// **************************************************************************** +// SpellCastMorph +// **************************************************************************** + +void SpellCastMorph(edict_t *Caster, vec3_t StartPos, vec3_t AimAngles, vec3_t unused, float value) +{ + edict_t *morph; + int i; + byte yaw; + float current_ang; + vec3_t temp_angles; + short morpharray[NUM_OF_OVUMS]; + +// if (!(Caster->client->playerinfo.edictflags & FL_CHICKEN)) +// { +// MorphPlayerToChicken2(Caster, Caster); +// return; +// } + + // first ovum gets sent out along our aiming angle + current_ang = AimAngles[YAW]; + for (i=0; is.origin); + + // decide its direction + morph->s.angles[YAW] = current_ang; + VectorScale(morph->s.angles, ANGLE_TO_RAD, temp_angles); + DirFromAngles(temp_angles, morph->velocity); + Vec3ScaleAssign(ARROW_SPEED,morph->velocity); + + create_morph(morph); + morph->reflect_debounce_time = MAX_REFLECT; + morph->owner = Caster; + G_LinkMissile(morph); + + // if we are the first effect, calculate our yaw + if (!i) + yaw = Q_ftol((morph->s.angles[YAW]/360.0) * 255.0); + // Store the entity numbers for sending with the effect. + morpharray[i] = morph->s.number; + + //increment current angle to get circular radius of ovums + current_ang+= ANGLE_INC; + } + // ceate the client effect that gets seen on screen + gi.CreateEffect(&morph->s, FX_SPELL_MORPHMISSILE_INITIAL, CEF_OWNERS_ORIGIN, NULL, "bssssss", + yaw, + morpharray[0], + morpharray[1], + morpharray[2], + morpharray[3], + morpharray[4], + morpharray[5]); +} + +// end + + \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/game/spl_powerup.c b/Toolkit/Programming/GameCode/game/spl_powerup.c new file mode 100644 index 0000000..5838296 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_powerup.c @@ -0,0 +1,46 @@ +// +// spl_powerup.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "g_itemstats.h" + + +void SpellCastPowerup(edict_t *Caster, vec3_t StartPos, vec3_t AimAngles, vec3_t AimDir, float value) +{ + assert(Caster->client); + + // Kill any tomes that may already be out there for this player. + + gi.RemoveEffects(&Caster->s, FX_TOME_OF_POWER); + + // if we are a chicken, lets make us a player again + if (Caster->flags & FL_CHICKEN) + { + Caster->morph_timer = level.time - 0.1; + } + else + { + // add some time in on the timer for the powerup + Caster->client->playerinfo.powerup_timer = level.time + POWERUP_DURATION; + + // turn on the light at the client effect end through client flags that are passed down + Caster->s.effects |= EF_POWERUP_ENABLED; + Caster->client->playerinfo.effects |= EF_POWERUP_ENABLED; + + // create the tome of power + gi.CreateEffect(&Caster->s, FX_TOME_OF_POWER, CEF_OWNERS_ORIGIN, NULL, ""); + } + + // start up the shrine powerup effect +// gi.CreateEffect(&Caster->s, FX_SHRINE_POWERUP, CEF_OWNERS_ORIGIN, NULL, ""); + + // do the SHRINE sound + gi.sound(Caster, CHAN_ITEM,gi.soundindex("items/shrine5.wav"),1,ATTN_NORM,0); +} + +// end diff --git a/Toolkit/Programming/GameCode/game/spl_ripper.c b/Toolkit/Programming/GameCode/game/spl_ripper.c new file mode 100644 index 0000000..9f889e4 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_ripper.c @@ -0,0 +1,269 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "vector.h" +#include "angles.h" +#include "matrix.h" +#include "g_volume_effect.h" +#include "Utilities.h" +#include "g_ClassStatics.h" +#include "g_Physics.h" +#include "g_playstats.h" +#include "decals.h" +#include "random.h" +#include "m_beast.h" + +#define RIPPER_RADIUS 12.0 +#define RIPPER_EXPLODE_BALL_RADIUS 8.0 +#define RIPPER_MAX_DISTANCE 2000 + + +void RipperThink(edict_t *Self); + +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); + + + +//--------------------- +//--------------------- +//--------------------- +// RIPPER +//--------------------- +//--------------------- +//--------------------- + + +// **************************************************************************** +// RipperExplodeBallThink +// **************************************************************************** + +static void RipperExplodeBallThink(edict_t *self) +{ + vec3_t vel; + vec3_t startpos, endpos, vect, forward; + edict_t *tracebuddy; + trace_t trace; + int numHit = 0; // can hit no more than 8 guys... + + VectorCopy(self->s.origin, startpos); + VectorCopy(self->last_org, endpos); + tracebuddy = self; + do + { + gi.trace(startpos, self->mins, self->maxs, endpos, tracebuddy, MASK_SHOT,&trace); + // if we hit anything that won't take damage, kill the beam + if (!trace.ent->takedamage) + break; + if(trace.fraction < .99 ) + { + // did we hit something that reflects ? + if(!EntReflecting(trace.ent, true, true)) + { + T_Damage(trace.ent, self, self->owner, self->movedir, trace.endpos, vec3_origin, + self->dmg, 0, DAMAGE_SPELL | DAMAGE_EXTRA_BLOOD,MOD_IRONDOOM); + + if (trace.ent->svflags & SVF_MONSTER) + { + // What the hell, let's spawn a big gush of blood in the travelling direction. + VectorScale(self->movedir, RIPPER_EXPLODE_SPEED*0.25, vel); + if(trace.ent->materialtype == MAT_INSECT) + gi.CreateEffect(NULL, FX_BLOOD, CEF_FLAG8, self->last_org, "ub", vel, (byte)20); + else + gi.CreateEffect(NULL, FX_BLOOD, 0, self->last_org, "ub", vel, (byte)20); + + gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/RipperDamage.wav"), 1, ATTN_NORM, 0); + } + } + // this seems to alleviate the problem of a trace hitting the same ent multiple times... + VectorCopy(trace.endpos, startpos); + VectorSubtract(endpos, startpos, vect); + if(VectorLength(vect) > 16.0) + { + VectorSubtract(startpos,endpos,forward); + VectorNormalize(forward); + VectorMA(startpos, 16.0, forward, startpos); + } + tracebuddy = trace.ent; + numHit++; + } + } while((trace.fraction < .99) && !(trace.contents & MASK_SOLID) && (numHit < 6) ); + + // Prevent any further transmission of this entity to clients. + self->svflags |= SVF_NOCLIENT; + + VectorCopy(self->s.origin, self->last_org); + self->nextthink = level.time + 0.1; +} + + +static void RipperExplodeBallTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surface) +{ + G_SetToFree(self); +} + + +// **************************************************************************** +// RipperImpact +// **************************************************************************** +// This is like a touch function, except since the ripper is instant now... +static void RipperImpact(edict_t *caster, edict_t *other, vec3_t startpos, vec3_t endpos, vec3_t angles) +{ + edict_t *ripper; + byte makeScorch = 0; + int i; + int dmg; + vec3_t hitpos, fwd; + short ballarray[RIPPER_BALLS]; + byte byaw; + float curyaw; + + // Get the forward vector for various calculations + AngleVectors(angles, fwd, NULL, NULL); + + // did we hit someone where reflection is functional ? + if(EntReflecting(other, true, true)) + { + // Erg... Do nothing right now. + } + + AlertMonsters (caster, caster, 2, false); + if(other && other->takedamage) + { + dmg = irand(RIPPER_DAMAGE_MIN, RIPPER_DAMAGE_MAX); + VectorCopy(endpos, hitpos); + T_Damage(other, caster, caster, fwd, endpos, fwd, dmg, dmg*2, DAMAGE_SPELL,MOD_IRONDOOM); + } + else + { + // Back off the origin for the damage a bit. We are a point and this will + // help fix hitting base of a stair and not hurting a guy on next step up. + VectorMA(endpos, -8.0, fwd, hitpos); + } + + // Shoot out ripper balls + curyaw = (angles[YAW]*ANGLE_TO_RAD) + (RIPPER_BALL_ANGLE*0.5); + // Add half an increment so that the balls don't come right back. + // STORE THE CURRENT YAW IN RADIANS FOR SIN/COS OPERATIONS + + // Reduce precision to a 0-255 byte. + byaw = (byte)(curyaw*(256.0/(M_PI*2.0))); // The byte yaw loses lots of precision here + curyaw = ((float)byaw)*((M_PI*2.0)/256.0); // ...and pass this imprecision back to the float yaw. + for (i=0; imovedir[0] = cos(curyaw); + ripper->movedir[1] = sin(curyaw); + ripper->movedir[2] = 0.0; + + // Place the ball + VectorCopy(hitpos, ripper->s.origin); + VectorScale(ripper->movedir, RIPPER_EXPLODE_SPEED, ripper->velocity); + + // Set up the net transmission attributes + ripper->s.effects |= EF_ALWAYS_ADD_EFFECTS; + ripper->svflags |= SVF_ALWAYS_SEND; + ripper->movetype = MOVETYPE_FLYMISSILE; + + // Set up the dimentsions + VectorSet(ripper->mins, -RIPPER_EXPLODE_BALL_RADIUS, -RIPPER_EXPLODE_BALL_RADIUS, -RIPPER_EXPLODE_BALL_RADIUS); + VectorSet(ripper->maxs, RIPPER_EXPLODE_BALL_RADIUS, RIPPER_EXPLODE_BALL_RADIUS, RIPPER_EXPLODE_BALL_RADIUS); + + // Set up physics attributes + ripper->solid = SOLID_BBOX; + ripper->clipmask = MASK_SOLID; + ripper->touch = RipperExplodeBallTouch; + ripper->think = RipperExplodeBallThink; + ripper->dmg = RIPPER_EXPLODE_DAMAGE; + ripper->classname = "Spell_Ripper"; + ripper->nextthink = level.time + 0.1; + + // last_org is used for damaging things + VectorCopy(ripper->s.origin, ripper->last_org); + + ripper->owner = caster; + + // Store the entity numbers for sending with the effect. + ballarray[i] = ripper->s.number; + + curyaw += RIPPER_BALL_ANGLE; + } + + gi.sound(ripper, CHAN_WEAPON, gi.soundindex("weapons/RipperImpact.wav"), 1, ATTN_NORM, 0); + + // Okay (whew) now we send the big ol' mutherlovin' effect. There's a lot here, but believe me, this is WAY more + // efficient than sending out eight (well, nine with the impact) seperate effects... + + // Send it attached to the last ball... + assert(ripper); + assert(RIPPER_BALLS == 8); + + // So we send this with: + // --The position of the caster (for the launch trail effect) + // --The byte angle to shoot things at. + // --All eight entity numbers to attach things to. + // Okay, so I only need seven (the eighth comes with the effect), but for consistency I'm going to send all eight. + // (NOTE: Further optimization would maybe pass a pitch and distance, and make the yaw precise, but that would save + // little and make things more confusing than they are...) + // Currently this sends 29 bytes plus the entity it's attached to. + // This is down from (12 plus the entity) times eight, plus another effect for impact, plus another for the trail. + gi.CreateEffect(&ripper->s, FX_WEAPON_RIPPEREXPLODE, CEF_OWNERS_ORIGIN, NULL, "vbssssssss", + startpos, + byaw, + ballarray[0], + ballarray[1], + ballarray[2], + ballarray[3], + ballarray[4], + ballarray[5], + ballarray[6], + ballarray[7]); +} + + +// **************************************************************************** +// SpellCastRipper +// **************************************************************************** + + +void SpellCastRipper(edict_t *caster, vec3_t StartPos, vec3_t AimAngles, vec3_t unused) +{ + trace_t trace; + vec3_t endpos, forward; + vec3_t mins={-RIPPER_RADIUS, -RIPPER_RADIUS, -RIPPER_RADIUS}, maxs={RIPPER_RADIUS, RIPPER_RADIUS, RIPPER_RADIUS}; + + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/RipperFire.wav"), 1, ATTN_NORM, 0); + + // Make sure we don't spawn in a wall. + gi.trace(caster->s.origin, mins, maxs, StartPos, caster, MASK_PLAYERSOLID,&trace); + if (trace.startsolid || trace.fraction<.99) + { + RipperImpact(caster, trace.ent, caster->s.origin, trace.endpos, AimAngles); + return; + } + + // Get the forward angle + AngleVectors(AimAngles, forward, NULL, NULL); + + // Now trace from the starting point to the final destination. + VectorMA(StartPos, RIPPER_MAX_DISTANCE, forward, endpos); + gi.trace(StartPos, mins, maxs, endpos, caster, MASK_SHOT,&trace); + if(level.fighting_beast) + { + edict_t *ent; + + if(ent = check_hit_beast(StartPos, trace.endpos)) + trace.ent = ent; + } + + RipperImpact(caster, trace.ent, StartPos, trace.endpos, AimAngles); +} + + +// end + diff --git a/Toolkit/Programming/GameCode/game/spl_shield.c b/Toolkit/Programming/GameCode/game/spl_shield.c new file mode 100644 index 0000000..afbf60e --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_shield.c @@ -0,0 +1,87 @@ +// +// spl_shield.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "Angles.h" +#include "Utilities.h" +#include "vector.h" +#include "random.h" +#include "g_playstats.h" + + +void SpellCastShield(edict_t *caster,vec3_t startpos,vec3_t aimangles,vec3_t aimdir,float Value) +{ + assert(caster->client); + caster->client->playerinfo.shield_timer = level.time + (float)SHIELD_DURATION; + + // Start the lightning effect. + caster->PersistantCFX = gi.CreatePersistantEffect(&caster->s, FX_SPELL_LIGHTNINGSHIELD, CEF_OWNERS_ORIGIN|CEF_BROADCAST, NULL, ""); + + gi.sound(caster,CHAN_WEAPON,gi.soundindex("weapons/Shield.wav"),1,ATTN_NORM,0); + caster->s.sound = gi.soundindex("weapons/ShieldIdle.wav"); + caster->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_NORM; +} + + + +void SpellLightningShieldAttack(edict_t *self) +{ + edict_t *found=NULL; + vec3_t dir; + int damage; + qboolean onefound=false; + + assert(self->client); + + // find all the foundities in the area + while((found = findradius(found, self->s.origin, SHIELD_DAMAGE_RADIUS))) + { // Only attack monsters and players in deathmatch + if (found == self) // don't hurt yourself + continue; + + if ((!(found->svflags & SVF_MONSTER) || (found->svflags & SVF_DEADMONSTER)) && // If we have a monster here. + !(found->client && deathmatch->value)) // Only attack players in deathmatch + continue; + + // if we have reflection on, then no damage + if(EntReflecting(found, true, true)) + continue; + + if (onefound) + { + if (irand(0, (SHIELD_ATTACK_CHANCE-1)) != 0) // Don't attack everything we find. + continue; + } + else + { // More likely to find one if none found yet. + if (irand(0, (SHIELD_ATTACK_CHANCE-2)) != 0) // Don't attack everything we find. + continue; + } + + VectorSubtract(found->s.origin, self->s.origin, dir); + VectorNormalize(dir); + damage = irand(SHIELD_DAMAGE_MIN, SHIELD_DAMAGE_MAX); + + T_Damage(found, self, self, dir, vec3_origin, vec3_origin, damage, 0, DAMAGE_SPELL,MOD_SHIELD); + + gi.CreateEffect(NULL, FX_LIGHTNING, 0, + self->s.origin, "vbb", found->s.origin, (byte)SHIELD_LIGHTNING_WIDTH, (byte)0); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&found->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", dir); + + gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/ShieldAttack.wav"), 2, ATTN_NORM,0); + + onefound = true; + } +} + + + + + diff --git a/Toolkit/Programming/GameCode/game/spl_sphereofannihlation.c b/Toolkit/Programming/GameCode/game/spl_sphereofannihlation.c new file mode 100644 index 0000000..d8662aa --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_sphereofannihlation.c @@ -0,0 +1,800 @@ +// +// spl_sphereofannihilation.c +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "random.h" +#include "vector.h" +#include "Reference.h" +#include "Utilities.h" +#include "decals.h" +#include "g_playstats.h" +#include "p_main2.h" //for ITEM_WEAPON_SPHEREOFANNIHILATION +#include "m_beast.h" + +#define SPHERE_INIT_SCALE 0.7 +#define SPHERE_MAX_SCALE 2.0 +#define SPHERE_SCALE_RANGE (SPHERE_MAX_SCALE - SPHERE_INIT_SCALE) +#define SPHERE_SCALE_PER_CHARGE (SPHERE_SCALE_RANGE / SPHERE_MAX_CHARGES) +#define SPHERE_SCALE_PULSE 0.5 + +#define SPHERE_RADIUS_DIFF (SPHERE_RADIUS_MAX - SPHERE_RADIUS_MIN) +#define SPHERE_RADIUS_PER_CHARGE (SPHERE_RADIUS_DIFF / SPHERE_MAX_CHARGES) +#define SPHERE_GROW_MIN_TIME 2 +#define SPHERE_GROW_SPEED (SPHERE_RADIUS_DIFF / SPHERE_MAX_CHARGES) +#define SPHERE_GROW_START (SPHERE_RADIUS_MIN - (SPHERE_GROW_SPEED * SPHERE_GROW_MIN_TIME)) + +#define SPHERE_COUNT_MIN 3 +#define SPHERE_COUNT_PER_CHARGE 2 + +#define SPHERE_RADIUS 2.0 + +static void SphereOfAnnihilationFlyFinnishedThink(edict_t *Self); +static void SphereOfAnnihilationGrowThink(edict_t *Self); +static void SphereOfAnnihilationTouch(edict_t *Self,edict_t *Other,cplane_t *Plane,csurface_t *Surface); +static void SphereWatcherGrowThink(edict_t *Self); +static void SphereWatcherTouch(edict_t *self, edict_t *Other, cplane_t *Plane, csurface_t *surface); + +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); +void create_sphere(edict_t *Sphere); + +// **************************************************************************** +// SphereOfAnnihilationGrowThink +// **************************************************************************** + +static void SphereOfAnnihilationGrowThink(edict_t *Self) +{ + vec3_t Forward, Up, endpos; + trace_t trace; + + + if (Self->owner->client) + AngleVectors(Self->owner->client->aimangles,Forward,NULL,Up); + else + AngleVectors(Self->owner->s.angles,Forward,NULL,Up); + + // NOTE: 'edict_t'->combattarget is used as a pointer to a 'qboolean' which flags + // whether or not I have been released. Would like a dedicated value in the 'edict_t' but this + // is unlikely to happen, sooooo... + + // if we have released, or we are dead, or a chicken, release the sphere + if(*(qboolean *)Self->combattarget && !(Self->owner->deadflag & (DEAD_DYING|DEAD_DEAD)) + && (Self->owner->client && !(Self->owner->client->playerinfo.edictflags & FL_CHICKEN)) && + (!(Self->owner->client->playerinfo.flags & PLAYER_FLAG_KNOCKDOWN))) + { + if (Self->count < SPHERE_MAX_CHARGES) + { + Self->count++; + Self->s.scale = SPHERE_INIT_SCALE + (SPHERE_SCALE_PER_CHARGE * Self->count); + } + else + { // If at max size, pulse like crazy! + Self->s.scale = SPHERE_MAX_SCALE + flrand(0, SPHERE_SCALE_PULSE); + } + + // detect if we have teleported, since we need to move with the player if thats so + if(Self->owner->client) + { + VectorCopy(Self->owner->s.origin, Self->s.origin); + Self->s.origin[0] += Forward[0]*20.0; + Self->s.origin[1] += Forward[1]*20.0; + Self->s.origin[2] += Self->owner->viewheight-5.0; + } + + Self->nextthink=level.time+0.1; + } + else + { + vec3_t angles; + // My caster has released me, so I am now a missile and I will fly like the wind. + + Self->svflags &= ~SVF_NOCLIENT; + + Self->s.effects&=~EF_MARCUS_FLAG1; + + VectorCopy(Self->owner->movedir,Self->movedir); + + //FIXME: Need to get rid of the 'client' reference so that anything can cast this spell. + + //Check ahead first to see if it's going to hit anything at this angle + if(Self->owner->client) + VectorCopy(Self->owner->client->aimangles, angles); + else + VectorCopy(Self->owner->s.angles, angles); + AngleVectors(angles, Forward, NULL, NULL); + VectorMA(Self->s.origin, SPHERE_FLY_SPEED, Forward, endpos); + gi.trace(Self->s.origin, vec3_origin, vec3_origin, endpos, Self->owner, MASK_MONSTERSOLID,&trace); + if(trace.ent && ok_to_autotarget(Self->owner, trace.ent)) + {//already going to hit a valid target at this angle- so don't autotarget + VectorScale(Forward, SPHERE_FLY_SPEED, Self->velocity); + } + else + {//autotarget current enemy + GetAimVelocity(Self->owner->enemy, Self->s.origin, SPHERE_FLY_SPEED, Self->owner->client->aimangles, Self->velocity); + } + VectorNormalize2(Self->velocity, Self->movedir); + + Self->movetype=MOVETYPE_FLYMISSILE; + Self->solid=SOLID_BBOX; + Self->health=0; + Self->dmg = SPHERE_DAMAGE; + Self->dmg_radius = SPHERE_RADIUS_MIN + (SPHERE_RADIUS_PER_CHARGE * Self->count); + Self->touch=SphereOfAnnihilationTouch; + Self->think=NULL; + + VectorSet(Self->mins, -SPHERE_RADIUS, -SPHERE_RADIUS, -SPHERE_RADIUS); + VectorSet(Self->maxs, SPHERE_RADIUS, SPHERE_RADIUS, SPHERE_RADIUS); + + Self->s.sound = 0; + gi.sound(Self,CHAN_WEAPON,gi.soundindex("weapons/SphereFire.wav"),1,ATTN_NORM,0); + + gi.trace(Self->s.origin, vec3_origin, vec3_origin, Self->s.origin, Self->owner, MASK_PLAYERSOLID,&trace); + if (trace.startsolid) + { + SphereOfAnnihilationTouch(Self, trace.ent, &trace.plane, trace.surface); + return; + } + } +} + + +static void SpherePowerLaserThink(edict_t *Self) +{ + vec3_t shootDir; + trace_t tr; + vec3_t min = {-16, -16, -16}; + vec3_t max = { 16, 16, 16}; + vec3_t startPos; + vec3_t endPos; + vec3_t tempVect; + vec3_t aimangles; + float traceDist; + edict_t *traceBuddy; + float sphere_dist; + int numHit = 0; // can hit no more than 8 guys... + vec3_t planedir; + int flags=CEF_FLAG7; + int damage; + + VectorCopy(Self->s.origin, startPos); + traceBuddy = Self; + sphere_dist = 2048.0; + VectorCopy(Self->s.angles,aimangles); + AngleVectors(aimangles, shootDir, NULL, NULL); + VectorMA(startPos, 12, shootDir, startPos); + do + { + + AngleVectors(aimangles, shootDir, NULL, NULL); + VectorMA(startPos, sphere_dist, shootDir, endPos); + gi.trace(startPos, min, max, endPos, traceBuddy, MASK_SHOT,&tr); + if(level.fighting_beast) + { + edict_t *ent; + + if(ent = check_hit_beast(startPos, tr.endpos)) + tr.ent = ent; + } + + if (!tr.ent->takedamage) + break; + + if((tr.startsolid || tr.fraction < .99) && tr.ent) + { + if(EntReflecting(tr.ent, true, true)) + { + + // reflect it off into space + + // draw line to this point + VectorSubtract(tr.endpos, startPos, tempVect); + traceDist = VectorLength(tempVect); + gi.CreateEffect(NULL, FX_WEAPON_SPHEREPOWER, 0, startPos, "xbb", + shootDir, (byte)(Self->s.scale*7.5), (byte)(traceDist/8)); + + // re-constitute aimangle + aimangles[1] += flrand(160,200); + aimangles[0] += flrand(-20,20); + + break; + } + else + { + if (tr.ent->fire_timestamp < Self->fire_timestamp) + { + damage = SPHERE_DAMAGE; + T_Damage(tr.ent,Self,Self->owner,shootDir,tr.endpos,shootDir, + damage, damage, DAMAGE_SPELL, MOD_P_SPHERE); + tr.ent->fire_timestamp = Self->fire_timestamp; + } + } + } + + VectorSubtract(tr.endpos, startPos, tempVect); + sphere_dist -= VectorLength(tempVect); + + VectorCopy(tr.endpos, startPos); + // this seems to alleviate the problem of a trace hitting the same ent multiple times... + VectorSubtract(endPos, startPos, tempVect); + if(VectorLength(tempVect) > 16.0) + { + VectorMA(startPos, 16.0, shootDir, startPos); + } + traceBuddy = tr.ent; + numHit++; + }while((tr.fraction < .99)&&(tr.contents != MASK_SOLID)&&(numHit < MAX_REFLECT)); + + VectorSubtract(tr.endpos, startPos, tempVect); + traceDist = VectorLength(tempVect); + // decide if a decal is appropriate or not + + if (Self->health==2) + flags|=CEF_FLAG8; + + if(IsDecalApplicable(Self, tr.ent, Self->s.origin, tr.surface, &tr.plane, planedir)) + flags|=CEF_FLAG6; + + gi.CreateEffect(NULL, FX_WEAPON_SPHEREPOWER, flags, startPos, "xbb", + shootDir, (byte)(Self->s.scale*7.5), (byte)(traceDist/8)); + + if (--Self->count <= 0) + G_SetToFree(Self); + else + Self->nextthink = level.time + 0.1; +} + + +static void SpherePowerLaserTouch(edict_t *Self,edict_t *Other,cplane_t *Plane, csurface_t *Surface) +{ + G_SetToFree(Self); +} + + +static void SphereOfAnnihilationGrowThinkPower(edict_t *Self) +{ + vec3_t Forward, Right, Up; + edict_t *laser; + + if (Self->owner->client) + AngleVectors(Self->owner->client->aimangles,Forward,Right,Up); + else + AngleVectors(Self->owner->s.angles,Forward,Right,Up); + + // NOTE: 'edict_t'->combattarget is used as a pointer to a 'qboolean' which flags + // whether or not I have been released. Would like a dedicated value in the 'edict_t' but this + // is unlikely to happen, sooooo... + + if(*(qboolean *)Self->combattarget && !(Self->owner->deadflag & (DEAD_DYING|DEAD_DEAD)) + && (Self->owner->client && !(Self->owner->client->playerinfo.edictflags & FL_CHICKEN)) && + (!(Self->owner->client->playerinfo.flags & PLAYER_FLAG_KNOCKDOWN))) + { + if (Self->count < SPHERE_MAX_CHARGES) + { + Self->count++; + Self->s.scale = SPHERE_INIT_SCALE + (SPHERE_SCALE_PER_CHARGE * Self->count); + } + else + { // If at max size, pulse like crazy! + Self->s.scale = SPHERE_MAX_SCALE + flrand(0, SPHERE_SCALE_PULSE); + } + + // detect if we have teleported, since we need to move with the player if thats so + if(Self->owner->client) + { + VectorCopy(Self->owner->s.origin, Self->s.origin); + Self->s.origin[0] += Forward[0]*20.0; + Self->s.origin[1] += Forward[1]*20.0; + Self->s.origin[2] += Self->owner->viewheight-5.0; + } + + Self->nextthink=level.time+0.1; + } + else + { + laser = G_Spawn(); + laser->owner = Self->owner; + laser->count = Self->count-SPHERE_COUNT_MIN; + VectorMA(Self->s.origin, 10.0, Right, laser->s.origin); + if (Self->owner->client) + VectorCopy(Self->owner->client->aimangles, laser->s.angles); + else + VectorCopy(Self->owner->s.angles, laser->s.angles); + VectorScale(Right, SPHERE_LASER_SPEED, laser->velocity); + laser->health = 1; // right + laser->movetype=MOVETYPE_FLYMISSILE; + laser->solid=SOLID_BBOX; + laser->clipmask=MASK_SOLID; + laser->think = SpherePowerLaserThink; + laser->touch = SpherePowerLaserTouch; + laser->fire_timestamp = level.time; + G_LinkMissile(laser); + SpherePowerLaserThink(laser); + + laser = G_Spawn(); + laser->owner = Self->owner; + laser->count = Self->count-SPHERE_COUNT_MIN; + VectorMA(Self->s.origin, -10.0, Right, laser->s.origin); + if (Self->owner->client) + VectorCopy(Self->owner->client->aimangles, laser->s.angles); + else + VectorCopy(Self->owner->s.angles, laser->s.angles); + VectorScale(Right, -SPHERE_LASER_SPEED, laser->velocity); + laser->health = 2; // left + laser->movetype=MOVETYPE_FLYMISSILE; + laser->solid=SOLID_BBOX; + laser->clipmask=MASK_SOLID; + laser->think = SpherePowerLaserThink; + laser->touch = SpherePowerLaserTouch; + laser->fire_timestamp = level.time; + G_LinkMissile(laser); + SpherePowerLaserThink(laser); + + gi.sound(Self->owner,CHAN_WEAPON,gi.soundindex("weapons/SpherePowerFire.wav"),1,ATTN_NORM,0); + G_SetToFree(Self); + } +} + +edict_t *SphereReflect(edict_t *self, edict_t *other, vec3_t vel) +{ + edict_t *Sphere; + Sphere = G_Spawn(); + create_sphere(Sphere); + Sphere->owner = other; + Sphere->enemy = self->enemy; + Sphere->reflect_debounce_time = self->reflect_debounce_time -1; + + Sphere->count=self->count; + Sphere->solid=self->solid; + Sphere->dmg=self->dmg; + Sphere->dmg_radius=self->dmg_radius; + Sphere->s.scale=self->s.scale; + + VectorCopy(vel, Sphere->velocity); + + Sphere->touch=SphereOfAnnihilationTouch; + Sphere->nextthink=level.time+0.1; + + VectorCopy(self->mins, Sphere->mins); + VectorCopy(self->maxs, Sphere->maxs); + + VectorCopy(self->s.origin, Sphere->s.origin); + G_LinkMissile(Sphere); + + gi.CreateEffect(&Sphere->s, + FX_WEAPON_SPHERE, + CEF_OWNERS_ORIGIN, + NULL, + "s", + (short)Sphere->owner->s.number); + + gi.CreateEffect(&Sphere->s, + FX_WEAPON_SPHEREGLOWBALLS, + CEF_OWNERS_ORIGIN, + NULL, + "s", + -1); + + + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&Sphere->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", Sphere->velocity); + + return(Sphere); +} + + +void SphereExplodeThink(edict_t *self) +{ + edict_t *ent=NULL; + + while(ent=findradius(ent, self->s.origin, self->dmg_radius)) + { + if (ent->takedamage && ent != self->owner && ent->fire_timestamp < self->fire_timestamp) + { + T_Damage(ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, self->dmg, 0, 0, MOD_SPHERE); + ent->fire_timestamp = self->fire_timestamp; + gi.CreateEffect(&ent->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", vec3_origin); + } + } + + self->count--; + self->dmg_radius += SPHERE_GROW_SPEED; + self->nextthink = level.time + 0.1; + + if (self->count < 0) + G_SetToFree(self); +} + + +// **************************************************************************** +// SphereOfAnnihilationTouch +// **************************************************************************** + +static void SphereOfAnnihilationTouch(edict_t *self, edict_t *Other, cplane_t *Plane, csurface_t *surface) +{ + edict_t *explosion; + + // has the target got reflection turned on ? + if(EntReflecting(Other, true, true) && self->reflect_debounce_time) + { + Create_rand_relect_vect(self->velocity, self->velocity); + Vec3ScaleAssign(SPHERE_FLY_SPEED/2, self->velocity); + SphereReflect(self, Other, self->velocity); + return; + } + + if(surface && (surface->flags & SURF_SKY)) + { + SkyFly(self); + return; + } + + explosion = G_Spawn(); + VectorCopy(self->s.origin, explosion->s.origin); + explosion->solid = SOLID_NOT; + explosion->dmg_radius = SPHERE_GROW_START; + explosion->count = self->count + SPHERE_GROW_MIN_TIME; + explosion->fire_timestamp = level.time; + explosion->think = SphereExplodeThink; + explosion->owner = self->owner; + explosion->classname = "sphere_damager"; + explosion->dmg = self->dmg; + + gi.linkentity(explosion); + + AlertMonsters (self, self->owner, 3, false); + // Back off the origin for the damage a bit. We are a point and this will + // help fix hitting base of a stair and not hurting a guy on next step up. + VectorMA(self->s.origin, -8.0, self->movedir, self->s.origin); + + gi.CreateEffect(&self->s, FX_WEAPON_SPHEREPLAYEREXPLODE, CEF_OWNERS_ORIGIN, NULL, + "db", self->movedir, (byte)(self->count)); + + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/SphereImpact.wav"),2,ATTN_NORM,0); + + G_SetToFree(self); + + // Do damage directly to the thing you hit. This is mainly for big creatures, like the trial beast. + // The sphere will not damage the other after this initial impact. + if (Other && Other->takedamage) + { + T_Damage(Other, self, self->owner, self->velocity, self->s.origin, vec3_origin, self->dmg, 0, 0, MOD_SPHERE); + Other->fire_timestamp = level.time; + gi.CreateEffect(&Other->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", vec3_origin); + } + + SphereExplodeThink(explosion); +} + +// guts of create sphere +void create_sphere(edict_t *Sphere) +{ + Sphere->svflags |= SVF_ALWAYS_SEND; + Sphere->s.effects |= EF_ALWAYS_ADD_EFFECTS|EF_MARCUS_FLAG1; + Sphere->classname="Spell_SphereOfAnnihilation"; + Sphere->clipmask=MASK_SHOT; + Sphere->movetype = MOVETYPE_FLYMISSILE; + Sphere->nextthink=level.time+0.1; + +} + +// **************************************************************************** +// SpellCastSphereOfAnnihilation +// **************************************************************************** + +void SpellCastSphereOfAnnihilation(edict_t *Caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir, + float Value,qboolean *ReleaseFlagsPtr) +{ + edict_t *Sphere; + int flags; + + // Spawn the sphere of annihilation as an invisible entity (i.e. modelindex=0). + + Sphere=G_Spawn(); + + if(Caster->client) + { + VectorCopy(Caster->s.origin, Sphere->s.origin); + Sphere->s.origin[0] += AimDir[0]*20.0; + Sphere->s.origin[1] += AimDir[1]*20.0; + Sphere->s.origin[2] += Caster->viewheight-5.0; + } + else + VectorCopy(StartPos, Sphere->s.origin); + + VectorCopy(AimAngles,Sphere->s.angles); + + Sphere->avelocity[YAW]=100.0; + Sphere->avelocity[ROLL]=100.0; + + // NOTE: 'edict_t'->combattarget is used as a pointer to a 'qboolean' which flags + // whether or not I have been released. Would like a dedicated value in the 'edict_t' but this + // is unlikely to happen, sooooo... + + + Sphere->combattarget=(char *)ReleaseFlagsPtr; + + Sphere->count = 0; + Sphere->solid = SOLID_NOT; + Sphere->dmg = 0; + Sphere->s.scale = SPHERE_INIT_SCALE; + Sphere->owner = Caster; + Sphere->enemy = Caster->enemy; + create_sphere(Sphere); + Sphere->reflect_debounce_time = MAX_REFLECT; + + if (Caster->client && Caster->client->playerinfo.powerup_timer > level.time) + { + Sphere->think=SphereOfAnnihilationGrowThinkPower; + } + else + { + if (Caster->client) + Sphere->think=SphereOfAnnihilationGrowThink; + else // The celestial watcher can also cast a sphere, but a different kind of one. + Sphere->think=SphereWatcherGrowThink; + } + + gi.linkentity(Sphere); + + if(!Caster->client) + flags = 0; + else + flags = CEF_OWNERS_ORIGIN; + + gi.CreateEffect(&Sphere->s, + FX_WEAPON_SPHERE, + flags, + StartPos, + "s", + (short)Caster->s.number); + + if(!Caster->client) + flags = CEF_FLAG6; + else + flags = CEF_OWNERS_ORIGIN; + + gi.CreateEffect(&Sphere->s, + FX_WEAPON_SPHEREGLOWBALLS, + flags, + StartPos, + "s", + (short)Caster->s.number); + + Sphere->s.sound = gi.soundindex("weapons/SphereGrow.wav"); + Sphere->s.sound_data = (255 & ENT_VOL_MASK) | ATTN_NORM; +} + + + + +////////////////////////////////// +// For Celestial Watcher +////////////////////////////////// +#define SPHERE_WATCHER_DAMAGE_MIN 50 +#define SPHERE_WATCHER_DAMAGE_RANGE 150 +#define SPHERE_WATCHER_EXPLOSION_RADIUS_MIN 50.0 +#define SPHERE_WATCHER_EXPLOSION_RADIUS_MAX 200.0 + +// **************************************************************************** +// SphereWatcherFlyThink +// **************************************************************************** + +void SphereWatcherFlyThink(edict_t *Self) +{ + Self->count++; + + if(Self->count > 20) + { + // End the circling... + G_SetToFree(Self); + } + else + { + Self->nextthink=level.time+0.2; + } +} + + +static void SphereWatcherGrowThink(edict_t *Self) +{ + vec3_t Forward, Up, endpos; + trace_t trace; + + + if (Self->owner->client) + AngleVectors(Self->owner->client->aimangles,Forward,NULL,Up); + else + AngleVectors(Self->owner->s.angles,Forward,NULL,Up); + + // NOTE: 'edict_t'->combattarget is used as a pointer to a 'qboolean' which flags + // whether or not I have been released. Would like a dedicated value in the 'edict_t' but this + // is unlikely to happen, sooooo... + + // if we have released, or we are dead, or a chicken, release the sphere + if(*(qboolean *)Self->combattarget && !(Self->owner->deadflag & (DEAD_DYING|DEAD_DEAD))) + { + + Self->count+=irand(1,2); + + if((Self->count>10)&&(Self->s.scalecount>20) + { + Self->s.scale-=0.01; + } + else + { + Self->s.scale+=0.1; + } + + if(Self->count>25) + { + Self->count&=3; + } + + } + + Self->nextthink=level.time+0.1; + } + else + { + vec3_t angles; + // My caster has released me, so I am now a missile and I will fly like the wind. + + Self->svflags &= ~SVF_NOCLIENT; + + Self->s.effects&=~EF_MARCUS_FLAG1; + + VectorCopy(Self->owner->movedir,Self->movedir); + + //Check ahead first to see if it's going to hit anything at this angle + VectorCopy(Self->owner->s.angles, angles); + AngleVectors(angles, Forward, NULL, NULL); + VectorMA(Self->s.origin, SPHERE_FLY_SPEED, Forward, endpos); + gi.trace(Self->s.origin, vec3_origin, vec3_origin, endpos, Self->owner, MASK_MONSTERSOLID,&trace); + if(trace.ent && ok_to_autotarget(Self->owner, trace.ent)) + {//already going to hit a valid target at this angle- so don't autotarget + VectorScale(Forward, SPHERE_FLY_SPEED, Self->velocity); + } + else + {//autotarget current enemy + GetAimVelocity(Self->owner->enemy, Self->s.origin, SPHERE_FLY_SPEED, Self->s.angles, Self->velocity); + } + VectorNormalize2(Self->velocity, Self->movedir); + + Self->movetype=MOVETYPE_FLYMISSILE; + Self->solid=SOLID_BBOX; + Self->health=0; + Self->count=0; + Self->dmg= SPHERE_WATCHER_DAMAGE_MIN + + (SPHERE_WATCHER_DAMAGE_RANGE*((Self->s.scale-SPHERE_INIT_SCALE)/SPHERE_SCALE_RANGE)); + Self->dmg_radius = + SPHERE_WATCHER_EXPLOSION_RADIUS_MIN + + (SPHERE_WATCHER_EXPLOSION_RADIUS_MAX - SPHERE_WATCHER_EXPLOSION_RADIUS_MIN) * + (Self->s.scale-SPHERE_INIT_SCALE)/SPHERE_SCALE_RANGE; + Self->touch=SphereWatcherTouch; + Self->think=SphereWatcherFlyThink; + Self->nextthink=level.time+0.1; + + VectorSet(Self->mins, -SPHERE_RADIUS, -SPHERE_RADIUS, -SPHERE_RADIUS); + VectorSet(Self->maxs, SPHERE_RADIUS, SPHERE_RADIUS, SPHERE_RADIUS); + + Self->s.sound = 0; + gi.sound(Self,CHAN_WEAPON,gi.soundindex("weapons/SphereFire.wav"),1,ATTN_NORM,0); + + gi.trace(Self->s.origin, vec3_origin, vec3_origin, Self->s.origin, Self->owner, MASK_PLAYERSOLID,&trace); + if (trace.startsolid) + { + SphereWatcherTouch(Self, trace.ent, &trace.plane, trace.surface); + return; + } + } +} + + + +edict_t *SphereWatcherReflect(edict_t *self, edict_t *other, vec3_t vel) +{ + edict_t *Sphere; + Sphere = G_Spawn(); + create_sphere(Sphere); + Sphere->owner = other; + Sphere->enemy = self->enemy; + Sphere->reflect_debounce_time = self->reflect_debounce_time -1; + + Sphere->count=self->count; + Sphere->solid=self->solid; + Sphere->dmg=self->dmg; + Sphere->dmg_radius=self->dmg_radius; + Sphere->s.scale=self->s.scale; + + VectorCopy(vel, Sphere->velocity); + + Sphere->touch=SphereWatcherTouch; + Sphere->think=SphereWatcherFlyThink; + Sphere->nextthink=level.time+0.1; + + VectorCopy(self->mins, Sphere->mins); + VectorCopy(self->maxs, Sphere->maxs); + + VectorCopy(self->s.origin, Sphere->s.origin); + G_LinkMissile(Sphere); + + gi.CreateEffect(&Sphere->s, + FX_WEAPON_SPHERE, + CEF_OWNERS_ORIGIN, + NULL, + "s", + (short)Sphere->owner->s.number); + + gi.CreateEffect(&Sphere->s, + FX_WEAPON_SPHEREGLOWBALLS, + CEF_OWNERS_ORIGIN, + NULL, + "s", + -1); + + + // kill the existing missile, since its a pain in the ass to modify it so the physics won't screw it. + G_SetToFree(self); + + // Do a nasty looking blast at the impact point + gi.CreateEffect(&Sphere->s, FX_LIGHTNING_HIT, CEF_OWNERS_ORIGIN, NULL, "t", Sphere->velocity); + + return(Sphere); +} + + + +static void SphereWatcherTouch(edict_t *self, edict_t *Other, cplane_t *Plane, csurface_t *surface) +{ + int makeScorch; + + // has the target got reflection turned on ? + if(EntReflecting(Other, true, true) && self->reflect_debounce_time) + { + Create_rand_relect_vect(self->velocity, self->velocity); + Vec3ScaleAssign(SPHERE_FLY_SPEED/2, self->velocity); + SphereWatcherReflect(self, Other, self->velocity); + return; + } + + + if(surface && (surface->flags & SURF_SKY)) + { + SkyFly(self); + return; + } + + AlertMonsters (self, self->owner, 3, false); + if(Other->takedamage) + { + T_Damage(Other, self, self->owner, self->movedir, self->s.origin, Plane->normal, self->dmg, self->dmg, DAMAGE_SPELL,MOD_SPHERE); + } + else + { + // Back off the origin for the damage a bit. We are a point and this will + // help fix hitting base of a stair and not hurting a guy on next step up. + VectorMA(self->s.origin, -8.0, self->movedir, self->s.origin); + } + + T_DamageRadius(self, self->owner, self, self->dmg_radius, self->dmg, self->dmg / 8, DAMAGE_ATTACKER_KNOCKBACK,MOD_SPHERE); + makeScorch = 0; + if(IsDecalApplicable(self, Other, self->s.origin, surface, Plane, NULL)) + { + makeScorch = CEF_FLAG6; + } + gi.CreateEffect(&self->s, FX_WEAPON_SPHEREEXPLODE, CEF_OWNERS_ORIGIN | makeScorch, NULL, + "db", self->movedir, (byte)(self->s.scale * 7.5)); + + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/SphereImpact.wav"),2,ATTN_NORM,0); + + G_SetToFree(self); +} diff --git a/Toolkit/Programming/GameCode/game/spl_teleport.c b/Toolkit/Programming/GameCode/game/spl_teleport.c new file mode 100644 index 0000000..726eaa2 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_teleport.c @@ -0,0 +1,242 @@ +// +// spl_teleport.c +// +// Heretic II +// Copyright 1998 Raven Software +// +// Written by Jake Simpson + +#include "g_local.h" +#include "fx.h" +#include "Angles.h" +#include "Utilities.h" +#include "random.h" +#include "vector.h" +#include "g_teleport.h" +#include "p_main2.h" +#include "g_playstats.h" + +extern void SelectSpawnPoint (edict_t *ent,vec3_t origin, vec3_t angles); +extern void AlertMonsters (edict_t *self, edict_t *enemy, float lifetime, qboolean ignore_shadows); + +// PLAYER ONLY!!! +// make the guy actually teleport from one place to another +// called from ANIMACTOR +void Perform_Teleport(edict_t *self) +{ + int i; + + //Get the player off the rope + self->client->playerinfo.flags |= PLAYER_FLAG_RELEASEROPE; + + //physically move the player, bearing in mind thats what a teleport is + VectorCopy (self->client->tele_dest, self->client->playerinfo.origin); + VectorCopy (self->client->tele_dest, self->s.origin); + + // set angles + for (i=0 ; i<3 ; i++) + self->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(self->client->tele_angles[i] - self->client->resp.cmd_angles[i]); + + self->s.angles[PITCH] = 0; + self->s.angles[YAW] = self->client->tele_angles[YAW]; + self->s.angles[ROLL] = 0; + VectorCopy (self->client->tele_angles, self->client->ps.viewangles); + VectorCopy (self->client->tele_angles, self->client->v_angle); + + // reset the cvar Farclip dist, incase it was modified by a trigger - there should be no teleport + // destinations or spawn points anywhere where the far clip has been modified. + gi.cvar_set("r_farclipdist", FAR_CLIP_DIST); + + // unlink to make sure it can't possibly interfere with KillBox - we don't want to collide with ourselves + gi.unlinkentity (self); + + // kill anything at the destination + KillBox (self); + + // re link us + gi.linkentity (self); + + // draw the teleport splash at the destination + gi.CreateEffect(&self->s, FX_PLAYER_TELEPORT_IN, CEF_BROADCAST|CEF_OWNERS_ORIGIN | ((byte)self->client->tele_type << 5), NULL, "" ); + + // restart the loop and tell us next time we aren't de-materialising + self->client->tele_count = TELE_TIME; + self->client->tele_dest[0] = self->client->tele_dest[1] = self->client->tele_dest[2] = -1; + + AlertMonsters (self, self, 2, true); +} + +// PLAYER ONLY!!! +// Done teleporting, clean up after ourselves +// called from ANIMACTOR +void CleanUpTeleport(edict_t *self) +{ + self->client->tele_dest[0] = self->client->tele_dest[1] = self->client->tele_dest[2] = 0; + self->client->tele_count = 0; + self->flags &= ~FL_LOCKMOVE; + self->client->playerinfo.flags &=~PLAYER_FLAG_TELEPORT; + self->client->ps.pmove.pm_flags &= ~PMF_LOCKMOVE; + self->s.color.a = 255; + self->client->shrine_framenum = level.time - 1;; +} + +// Setup the teleporter - from the player hitting a teleport pad +// We could send the teleport type over the flags instead of as a parameter byte +void teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) +{ + vec3_t dest_v, dest_v_angles; + int rand_targ, i; + edict_t *dest = NULL; + + // if we aren't a player, forget it + if (!other->client) + return; + + // if we are already teleporting, forget it + + if ((other->client->playerinfo.flags & (PLAYER_FLAG_TELEPORT | PLAYER_FLAG_MORPHING)) || (other->deadflag & (DEAD_DYING|DEAD_DEAD))) + return; + + // if we are in deathmatch, and this teleporter is so flagged, give us a random destination + if (deathmatch->value && (self->spawnflags & 2)) + { + // figure out a destination point + SelectSpawnPoint(other,dest_v, dest_v_angles); + // dest coors to teleport to + VectorCopy(dest_v,other->client->tele_dest); + // angles we should start at + VectorCopy(dest_v_angles,other->client->tele_angles); + } + // we do have a specific destination in mind + else + { + // setup in player info the dest entity of the teleport + + // do we have multiple destinations ? + if (self->style) + { + rand_targ = irand(1,self->style); + for (i = 0; itarget); + if (!dest) + { +#ifdef _DEVEL + gi.dprintf ("Couldn't find multiple teleport destination %d\n",rand_targ); +#endif + return; + } + } + } + // no - just the one + else + { + dest = G_Find (dest, FOFS(targetname), self->target); + if (!dest) + { +#ifdef _DEVEL + gi.dprintf ("Couldn't find teleport destination %s\n",self->target); +#endif + return; + } + } + // dest coors to teleport to + VectorCopy(dest->last_org,other->client->tele_dest); + // angles we should start at + VectorCopy(dest->s.angles,other->client->tele_angles); + } + + + // setup other teleporter information that the character will require + // when the teleport is actually performed in AnimUpdateFrame + + // set the player as teleporting + + other->client->playerinfo.flags |= PLAYER_FLAG_TELEPORT; + + other->client->ps.pmove.pm_flags |= PMF_LOCKMOVE; + + // time taken over dematerialisation + other->client->tele_count = TELE_TIME_OUT; + + // save out what kind of solid ability we are + other->client->old_solid = other->solid; + + // make us invunerable for a couple of seconds + other->client->shrine_framenum = level.time + 10; + + // tell us how we triggered the teleport + other->client->tele_type = 0; + + // clear the velocity and hold them in place briefly + VectorClear (other->velocity); + other->client->ps.pmove.pm_time = 50; + // make the player still + other->flags |= FL_LOCKMOVE; + // allow the player to fade out + other->s.color.a = 255; + other->s.color.r = 255; + other->s.color.g = 255; + other->s.color.b = 255; + + // draw the teleport splash at the teleport source + gi.CreateEffect(&other->s, FX_PLAYER_TELEPORT_OUT, CEF_OWNERS_ORIGIN | ((byte)other->client->tele_type << 5), NULL, "" ); + // do the teleport sound + gi.sound(other,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); + +} + +// Spawn the Spell teleport effect - from the player +// We could send the teleport type over the flags instead of as a parameter byte +void SpellCastTeleport(edict_t *caster,vec3_t StartPos,vec3_t AimAngles,vec3_t AimDir,float Value) +{ + + vec3_t dest, dest_angles; + + // if we are already teleporting, forget it + if ((caster->client->playerinfo.flags & (PLAYER_FLAG_TELEPORT | PLAYER_FLAG_MORPHING)) || (caster->deadflag & (DEAD_DYING|DEAD_DEAD))) + return; + + // setup other teleporter information that the character will require + // when the teleport is actually performed in AnimUpdateFrame + + // set the player as teleporting + caster->client->playerinfo.flags |= PLAYER_FLAG_TELEPORT; + + caster->client->ps.pmove.pm_flags |= PMF_LOCKMOVE; + + // figure out a destination point + SelectSpawnPoint(caster,dest, dest_angles); + + // dest coors to teleport to + VectorCopy(dest,caster->client->tele_dest); + // angles we should start at + VectorCopy(dest_angles,caster->client->tele_angles); + // time taken over dematerialisation + caster->client->tele_count = TELE_TIME_OUT; + + // tell us how we triggered the teleport + caster->client->tele_type = 1; + + // save out what kind of solid ability we are + caster->client->old_solid = caster->solid; + + // make us invunerable for a couple of seconds + caster->client->shrine_framenum = level.time + 10; + + // clear the velocity and hold them in place briefly + VectorClear (caster->velocity); + caster->client->ps.pmove.pm_time = 50; + // make the player still + caster->flags |= FL_LOCKMOVE; + // allow the player to fade out + caster->s.color.a = 255; + caster->s.color.r = 255; + caster->s.color.g = 255; + caster->s.color.b = 255; + + // draw the teleport splash at the teleport source + gi.CreateEffect(&caster->s, FX_PLAYER_TELEPORT_OUT, CEF_OWNERS_ORIGIN | ((byte)caster->client->tele_type << 5), NULL, "" ); + // do the teleport sound + gi.sound(caster,CHAN_WEAPON,gi.soundindex("weapons/teleport.wav"),1,ATTN_NORM,0); +} diff --git a/Toolkit/Programming/GameCode/game/spl_wall.c b/Toolkit/Programming/GameCode/game/spl_wall.c new file mode 100644 index 0000000..3158be2 --- /dev/null +++ b/Toolkit/Programming/GameCode/game/spl_wall.c @@ -0,0 +1,534 @@ +// +// Heretic II +// Copyright 1998 Raven Software +// + +#include "g_local.h" +#include "fx.h" +#include "vector.h" +#include "angles.h" +#include "matrix.h" +#include "g_volume_effect.h" +#include "Utilities.h" +#include "g_ClassStatics.h" +#include "g_Physics.h" +#include "g_volume_effect.h" +#include "g_playstats.h" + + +#define FIREWALL_DOT_MIN 0.25 + +// **************************************************************************** +// FireBlast +// Unpowered +// **************************************************************************** + +void FireBlastBlocked(edict_t *self, trace_t *trace); +void FireBlastStartThink(edict_t *self); + + +// **************************************************************************** +// SpellCastBlast +// **************************************************************************** + +edict_t *CreateFireBlast(vec3_t startpos, vec3_t angles, edict_t *owner, int health, float timestamp) +{ + edict_t *wall; + + wall = G_Spawn(); + + VectorSet(wall->mins, -FIREBLAST_PROJ_RADIUS, -FIREBLAST_PROJ_RADIUS, -FIREBLAST_PROJ_RADIUS); + VectorSet(wall->maxs, FIREBLAST_PROJ_RADIUS, FIREBLAST_PROJ_RADIUS, FIREBLAST_PROJ_RADIUS); + + VectorCopy(startpos, wall->s.origin); + VectorCopy(angles, wall->s.angles); + AngleVectors(angles, wall->movedir, NULL, NULL); + VectorScale(wall->movedir, FIREBLAST_SPEED, wall->velocity); + + wall->mass = 250; + wall->elasticity = ELASTICITY_NONE; + wall->friction = 0; + wall->gravity = 0; + + wall->s.effects |= EF_ALWAYS_ADD_EFFECTS; + wall->svflags |= SVF_ALWAYS_SEND|SVF_DO_NO_IMPACT_DMG; + wall->movetype = PHYSICSTYPE_FLY; + wall->isBlocked = FireBlastBlocked; + + wall->classname = "Spell_FireBlast"; + wall->solid = SOLID_BBOX; + wall->clipmask = MASK_DRIP; + wall->owner = owner; + wall->think = FireBlastStartThink; + wall->nextthink = level.time + 0.1; + wall->dmg_radius = FIREBLAST_RADIUS; + wall->dmg = FIREBLAST_DAMAGE; + + wall->health = health; // Can bounce 3 times + + wall->fire_timestamp = timestamp; // This marks the wall with a more-or-less unique value so the wall + // doesn't damage twice. + + gi.linkentity(wall); + + gi.CreateEffect(&wall->s, FX_WEAPON_FIREBURST, CEF_OWNERS_ORIGIN, NULL, "ff", angles[YAW], angles[PITCH]); + + return wall; +} + + +// This called when missile touches anything (world or edict) +void FireBlastBlocked(edict_t *self, trace_t *trace) +{ + edict_t *newwall; + float dot, speed, factor; + vec3_t surfvect, surfvel, testpos, newang; + trace_t newtrace; + + assert(trace); + + // If we haven't damaged what we are hitting yet, damage it now. Mainly for the Trial Beast. + if (trace->ent && trace->ent->takedamage && self->fire_timestamp > trace->ent->fire_timestamp) + { + // if we have reflection on, then no damage + if(!EntReflecting(trace->ent, true, true)) + { + if(trace->ent != self->owner) // No damage to casting player + { + T_Damage(trace->ent, self, self->owner, self->movedir, self->s.origin, vec3_origin, + self->dmg, self->dmg, DAMAGE_FIRE | DAMAGE_FIRE_LINGER, MOD_FIREWALL); + gi.CreateEffect(&(trace->ent->s), FX_FLAREUP, CEF_OWNERS_ORIGIN, NULL, ""); + + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/FirewallDamage.wav"),1,ATTN_NORM,0); + + trace->ent->fire_timestamp = self->fire_timestamp; // Mark so the fire doesn't damage an ent twice. + } + } + } + + if (self->health > 0 && !(trace->contents & CONTENTS_WATER) && + (trace->plane.normal[2] > FIREWALL_DOT_MIN || trace->plane.normal[2] < -FIREWALL_DOT_MIN)) + dot = DotProduct(self->movedir, trace->plane.normal); + speed = VectorLength(self->velocity); + if (dot < 0 && dot > -0.67) // slide on all but the most extreme angles. + { + VectorMA(self->movedir, -dot, trace->plane.normal, surfvel); // Vel then holds the velocity negated by the impact. + factor = VectorNormalize2(surfvel, surfvect); // Yes, there is the tiniest chance this could be a zero vect, + if (factor > 0) + { + VectorMA(self->s.origin, 16.0, surfvect, testpos); // test distance + + gi.trace(self->s.origin, self->mins, self->maxs, testpos, self, MASK_SHOT, &newtrace); + if (newtrace.fraction > 0.99) + { // If this is successful, then we can make another fireblast moving in the new direction. + vectoangles(surfvect, newang); + newwall = CreateFireBlast(self->s.origin, newang, self->owner, self->health-1, level.time); + } + } + } + + // Well, whatever happened, free the current blast. + VectorSet(self->velocity, 0.0, 0.0, 0.0); + + self->s.effects |= EF_ALTCLIENTFX; // Indicate to the wall that it's time to die + G_SetToFree(self); +} + + +// **************************************************************************** +// FireBlast think +// **************************************************************************** + +void FireBlastThink(edict_t *self) +{ // Check in the area and try to damage anything in the immediate area + edict_t *ent=NULL; + vec3_t min, max; + + // Set up the checking volume + VectorSet(min, -self->dmg_radius, -self->dmg_radius, -FIREBLAST_VRADIUS); + VectorAdd(self->s.origin, min, min); + VectorSet(max, self->dmg_radius, self->dmg_radius, FIREBLAST_VRADIUS); + VectorAdd(self->s.origin, max, max); + + // find all the entities in the volume + while(ent = findinbounds(ent, min, max)) + { +// if ((!(ent->svflags & SVF_MONSTER) && !(ent->client && deathmatch->value)) || (ent->svflags & SVF_DEADMONSTER)) + if(!ent->takedamage) + { // Anything that takes damage now. + continue; + } + + if (self->fire_timestamp <= ent->fire_timestamp) + continue; + + // if we have reflection on, then no damage + if(EntReflecting(ent, true, true)) + continue; + + if(ent != self->owner) // No damage to casting player + { + T_Damage(ent, self, self->owner, self->movedir, self->s.origin, vec3_origin, + self->dmg, self->dmg, DAMAGE_FIRE | DAMAGE_FIRE_LINGER, MOD_FIREWALL); + gi.CreateEffect(&ent->s, FX_FLAREUP, CEF_OWNERS_ORIGIN, NULL, ""); + + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/FirewallDamage.wav"),1,ATTN_NORM,0); + + ent->fire_timestamp = self->fire_timestamp; // Mark so the fire doesn't damage an ent twice. + } + } + + self->nextthink = level.time + 0.1; + self->dmg_radius += FIREBLAST_DRADIUS*0.1; + self->dmg -= 3; + if (self->dmg < FIREBLAST_DAMAGE_MIN) + self->dmg = FIREBLAST_DAMAGE_MIN; +} + + +void FireBlastStartThink(edict_t *self) +{ + self->svflags |= SVF_NOCLIENT; // Allow transmission to client + + FireBlastThink(self); + self->think = FireBlastThink; + self->nextthink = level.time + 0.1; +} + + +void CastFireBlast(edict_t *caster, vec3_t startpos, vec3_t aimangles) +{ + edict_t *wall; + vec3_t newpos, fwd; + trace_t trace; + + wall = G_Spawn(); + + AngleVectors(aimangles, fwd, NULL, NULL); + VectorMA(startpos, FIREBLAST_RADIUS*0.5, fwd, newpos); + wall = CreateFireBlast(newpos, aimangles, caster, 3, level.time); // Bounce 3 times + + // Check to see if this is a legit spawn. + gi.trace(caster->s.origin, wall->mins, wall->maxs, wall->s.origin, caster, MASK_SOLID, &trace); + if (trace.startsolid || trace.fraction < .99) + { + if (trace.startsolid) + VectorCopy(caster->s.origin, wall->s.origin); + else + VectorCopy(trace.endpos, wall->s.origin); + + FireBlastBlocked(wall, &trace); + return; + } + + FireBlastThink(wall); +} + + + + + + +// **************************************************************************** +// FireWall +// Powered up +// **************************************************************************** + +void WallMissileBlocked(edict_t *self, trace_t *trace); +void WallMissileStartThink(edict_t *self); + +edict_t *CreateFireWall(vec3_t startpos, vec3_t angles, edict_t *owner, int health, float timestamp, float sidespeed) +{ + edict_t *wall; + vec3_t right; + int flags=0; + + wall = G_Spawn(); + + VectorSet(wall->mins, -FIREWAVE_PROJ_RADIUS, -FIREWAVE_PROJ_RADIUS, -FIREWAVE_PROJ_RADIUS); + VectorSet(wall->maxs, FIREWAVE_PROJ_RADIUS, FIREWAVE_PROJ_RADIUS, FIREWAVE_PROJ_RADIUS); + + VectorCopy(startpos, wall->s.origin); + VectorCopy(angles, wall->s.angles); + AngleVectors(angles, wall->movedir, right, NULL); + + if (deathmatch->value) + { + flags |= CEF_FLAG8; + VectorScale(wall->movedir, FIREWAVE_DM_SPEED, wall->velocity); // Goes faster in deathmatch + } + else + { + VectorScale(wall->movedir, FIREWAVE_SPEED, wall->velocity); + } + VectorMA(wall->velocity, sidespeed, right, wall->velocity); + + if (sidespeed < 0) + flags |= CEF_FLAG6; + else if (sidespeed > 0) + flags |= CEF_FLAG7; + + wall->mass = 250; + wall->elasticity = ELASTICITY_NONE; + wall->friction = 0; + wall->gravity = 0; + + wall->s.effects |= EF_ALWAYS_ADD_EFFECTS; + wall->svflags |= SVF_ALWAYS_SEND; + wall->movetype = PHYSICSTYPE_FLY; + wall->isBlocked = WallMissileBlocked; + + wall->classname = "Spell_FireWall"; + wall->solid = SOLID_BBOX; + wall->clipmask = MASK_DRIP; + wall->owner = owner; + wall->think = WallMissileStartThink; + wall->nextthink = level.time + 0.1; + wall->dmg = FIREWAVE_DAMAGE; + wall->dmg_radius = FIREWAVE_RADIUS; + + wall->health = health; // Can bounce 3 times + + wall->fire_timestamp = timestamp; // Mark the wall so it can't damage something twice. + + gi.linkentity(wall); + + gi.CreateEffect(&wall->s, FX_WEAPON_FIREWAVE, CEF_OWNERS_ORIGIN | flags, startpos, "ff", angles[YAW], angles[PITCH]); + + return wall; +} + + +// **************************************************************************** +// WallMissile touch +// **************************************************************************** + +void WallMissileWormThink(edict_t *self) +{ + T_DamageRadius(self, self->owner, self->owner, 64.0, + FIREWAVE_WORM_DAMAGE, FIREWAVE_WORM_DAMAGE, DAMAGE_FIRE, MOD_FIREWALL); + + G_SetToFree(self); +} + + +#define FIREWORM_LIFETIME 1.0 + + +// This called when missile touches anything (world or edict) +void WallMissileBlocked(edict_t *self, trace_t *trace) +{ + edict_t *newwall; + float dot, speed, factor; + vec3_t surfvect, surfvel, testpos, newang; + trace_t newtrace; + edict_t *worm; + + assert(trace); + + // If we haven't damaged what we are hitting yet, damage it now. Mainly for the Trial Beast. + if (trace->ent && trace->ent->takedamage && self->fire_timestamp > trace->ent->fire_timestamp) + { + // if we have reflection on, then no damage + if(!EntReflecting(trace->ent, true, true)) + { + if(trace->ent != self->owner) // No damage to casting player + { + T_Damage(trace->ent, self, self->owner, self->movedir, self->s.origin, vec3_origin, + self->dmg, self->dmg, DAMAGE_FIRE | DAMAGE_FIRE_LINGER, MOD_FIREWALL); + gi.CreateEffect(&(trace->ent->s), FX_FLAREUP, CEF_OWNERS_ORIGIN, NULL, ""); + + trace->ent->fire_timestamp = self->fire_timestamp; + + gi.CreateEffect(NULL, FX_WEAPON_FIREWAVEWORM, 0, trace->ent->s.origin, "t", self->movedir); + + worm = G_Spawn(); + VectorCopy(trace->ent->s.origin, worm->s.origin); + worm->think = WallMissileWormThink; + worm->nextthink = level.time + FIREWORM_LIFETIME; + worm->solid = SOLID_NOT; + worm->clipmask = MASK_DRIP; + worm->owner = self->owner; + gi.linkentity(worm); + + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/FirewallDamage.wav"),1,ATTN_NORM,0); + } + } + } + + if (self->health > 0 && !(trace->contents & CONTENTS_WATER) && + (trace->plane.normal[2] > FIREWALL_DOT_MIN || trace->plane.normal[2] < -FIREWALL_DOT_MIN)) + dot = DotProduct(self->movedir, trace->plane.normal); + speed = VectorLength(self->velocity); + if (dot < 0 && dot > -0.67) // slide on all but the most extreme angles. + { + VectorMA(self->movedir, -dot, trace->plane.normal, surfvel); // Vel then holds the velocity negated by the impact. + factor = VectorNormalize2(surfvel, surfvect); // Yes, there is the tiniest chance this could be a zero vect, + if (factor > 0) + { + VectorMA(self->s.origin, 16.0, surfvect, testpos); // test distance + + gi.trace(self->s.origin, self->mins, self->maxs, testpos, self, MASK_SOLID, &newtrace); + if (newtrace.fraction > 0.99) + { // If this is successful, then we can make another fireblast moving in the new direction. + vectoangles(surfvect, newang); + newwall = CreateFireWall(self->s.origin, newang, self->owner, self->health-1, level.time, 0); + } + } + } + + // Well, whatever happened, free the current blast. + VectorSet(self->velocity, 0.0, 0.0, 0.0); + + self->s.effects |= EF_ALTCLIENTFX; // Indicate to the wall that it's time to die + G_SetToFree(self); +} + +// **************************************************************************** +// WallMissile think +// **************************************************************************** + +void WallMissileThink(edict_t *self) +{ // Check in the area and try to damage anything in the immediate area + edict_t *ent=NULL, *worm; + vec3_t min, max; + + // Set up the checking volume + VectorSet(min, -self->dmg_radius, -self->dmg_radius, -FIREWAVE_DOWN); + VectorAdd(self->s.origin, min, min); + VectorSet(max, self->dmg_radius, self->dmg_radius, FIREWAVE_UP); + VectorAdd(self->s.origin, max, max); + + // find all the entities in the volume + while(ent = findinbounds(ent, min, max)) + { +// if ((!(ent->svflags & SVF_MONSTER) && !(ent->client && deathmatch->value)) || (ent->svflags & SVF_DEADMONSTER)) + if(!ent->takedamage) + { // Anything that takes damage now. + continue; + } + + if (ent->fire_timestamp >= self->fire_timestamp) + continue; + + // if we have reflection on, then no damage + if(EntReflecting(ent, true, true)) + continue; + + if(ent != self->owner) // No damage to casting player + { + T_Damage(ent, self, self->owner, self->movedir, self->s.origin, vec3_origin, + self->dmg, self->dmg, DAMAGE_FIRE | DAMAGE_FIRE_LINGER, MOD_FIREWALL); + gi.CreateEffect(&ent->s, FX_FLAREUP, CEF_OWNERS_ORIGIN, NULL, ""); + + ent->fire_timestamp = self->fire_timestamp; + + gi.CreateEffect(NULL, FX_WEAPON_FIREWAVEWORM, 0, ent->s.origin, "t", self->movedir); + + worm = G_Spawn(); + VectorCopy(ent->s.origin, worm->s.origin); + worm->think = WallMissileWormThink; + worm->nextthink = level.time + FIREWORM_LIFETIME; + worm->solid = SOLID_NOT; + worm->clipmask = MASK_DRIP; + worm->owner = self->owner; + gi.linkentity(worm); + + gi.sound(self,CHAN_WEAPON,gi.soundindex("weapons/FirewallDamage.wav"),1,ATTN_NORM,0); + } + } + + self->nextthink = level.time + 0.1; + self->dmg_radius += .1*FIREWAVE_DRADIUS; + self->dmg -= 3; + if (self->dmg < FIREWAVE_DAMAGE_MIN) + self->dmg = FIREWAVE_DAMAGE_MIN; +} + + +void WallMissileStartThink(edict_t *self) +{ + self->svflags |= SVF_NOCLIENT; // Allow transmission to client + + WallMissileThink(self); + self->think = WallMissileThink; + self->nextthink = level.time + 0.1; +} + + +void CastFireWall(edict_t *caster, vec3_t startpos, vec3_t aimangles) +{ // Big wall is powered up + edict_t *wall; + vec3_t fwd, right, spawnpos; + trace_t trace; + + AngleVectors(aimangles, fwd, right, NULL); + + // Spawn wall to left + VectorMA(startpos, -FIREWAVE_RADIUS, right, spawnpos); + wall = CreateFireWall(spawnpos, aimangles, caster, 3, level.time, -FIREWAVE_DRADIUS); + + // Check to see if this is a legit spawn. + gi.trace(caster->s.origin, wall->mins, wall->maxs, wall->s.origin, caster, MASK_SOLID, &trace); + if (trace.startsolid || trace.fraction < .99) + { + if (trace.startsolid) + VectorCopy(caster->s.origin, wall->s.origin); + else + VectorCopy(trace.endpos, wall->s.origin); + + WallMissileBlocked(wall, &trace); + goto rightwall; + } + + WallMissileThink(wall); + +rightwall: + // Spawn wall to right + VectorMA(startpos, FIREWAVE_RADIUS, right, spawnpos); + wall = CreateFireWall(spawnpos, aimangles, caster, 3, level.time, FIREWAVE_DRADIUS); + + // Check to see if this is a legit spawn. + gi.trace(caster->s.origin, wall->mins, wall->maxs, wall->s.origin, caster, MASK_SOLID, &trace); + if (trace.startsolid || trace.fraction < .99) + { + if (trace.startsolid) + VectorCopy(caster->s.origin, wall->s.origin); + else + VectorCopy(trace.endpos, wall->s.origin); + + WallMissileBlocked(wall, &trace); + return; + } + + WallMissileThink(wall); +} + + + + +// **************************************************************************** +// The Firewall spell is cast. +// **************************************************************************** + + +void SpellCastWall(edict_t *caster, vec3_t startpos, vec3_t aimangles, vec3_t unused, float value) +{ + vec3_t castpos; + + VectorCopy(startpos, castpos); + + if (caster->client->playerinfo.powerup_timer <= level.time) + { // Not powered up. + castpos[2] += 16; // Aim higher than powered up version. + CastFireBlast(caster, castpos, aimangles); + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/FirewallCast.wav"), 1, ATTN_NORM, 0); + } + else + { // Powered up, cast big wall o' doom. + CastFireWall(caster, castpos, aimangles); + gi.sound(caster, CHAN_WEAPON, gi.soundindex("weapons/FirewallPowerCast.wav"), 1, ATTN_NORM, 0); + } +} + +// end diff --git a/Toolkit/Programming/GameCode/heretic2mods.dsw b/Toolkit/Programming/GameCode/heretic2mods.dsw new file mode 100644 index 0000000..b2496de --- /dev/null +++ b/Toolkit/Programming/GameCode/heretic2mods.dsw @@ -0,0 +1,41 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Client Effects"=".\Client Effects\Client Effects.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "game"=.\game\game.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Toolkit/Programming/GameCode/heretic2mods.ncb b/Toolkit/Programming/GameCode/heretic2mods.ncb new file mode 100644 index 0000000..3cb7f90 Binary files /dev/null and b/Toolkit/Programming/GameCode/heretic2mods.ncb differ diff --git a/Toolkit/Programming/GameCode/heretic2mods.opt b/Toolkit/Programming/GameCode/heretic2mods.opt new file mode 100644 index 0000000..2db3bdd Binary files /dev/null and b/Toolkit/Programming/GameCode/heretic2mods.opt differ diff --git a/Toolkit/Programming/GameCode/qcommon/Matrix.h b/Toolkit/Programming/GameCode/qcommon/Matrix.h new file mode 100644 index 0000000..17b13f8 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/Matrix.h @@ -0,0 +1,20 @@ +#include "H2Common.h" +#include "q_Typedef.h" + +H2COMMON_API void CreateRollMatrix(matrix3_t, vec_t); +H2COMMON_API void CreateYawMatrix(matrix3_t, vec_t); +H2COMMON_API void CreatePitchMatrix(matrix3_t, vec_t); + +H2COMMON_API void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); + +H2COMMON_API void Matrix3MultByMatrix3(matrix3_t A, matrix3_t B, matrix3_t C); +H2COMMON_API void Matrix3MultByVec3(matrix3_t A, vec3_t B, vec3_t C); +H2COMMON_API void Matrix3FromAngles(vec3_t angles, matrix3_t rotationMatrix); +H2COMMON_API void IMatrix3FromAngles(vec3_t angles, matrix3_t rotationMatrix); +H2COMMON_API void Matrixs3FromDirAndUp(vec3_t direction, vec3_t up, matrix3_t toLocal, matrix3_t fromLocal); +H2COMMON_API double Matricies3FromDirAndUp(vec3_t direction, vec3_t up, matrix3_t toWorld, matrix3_t partialToLocal); +H2COMMON_API void RotatePointAboutLocalOrigin(matrix3_t rotation, vec3_t origin, vec3_t point); +H2COMMON_API void TransformPoint(matrix3_t rotation, vec3_t origin, vec3_t newOrigin, vec3_t point); + +#define HACK_PITCH_FOR_REFS // eliminates a problem with ref points when the player is bent backwards; + // placed in the header to avoid inconsistencies between projects \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/Message.c b/Toolkit/Programming/GameCode/qcommon/Message.c new file mode 100644 index 0000000..b9b3447 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/Message.c @@ -0,0 +1,220 @@ +// +// Message.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#include "Message.h" +#include "SinglyLinkedList.h" + +void QueueMessage(MsgQueue_t *this, void *msg) +{ + GenericUnion4_t temp; + + temp.t_void_p = msg; + SLList_Push(&this->msgs, temp); +} + +#ifdef _GAME_DLL +#include "g_local.h" +size_t SetParms(SinglyLinkedList_t *this, char *format, va_list marker, qboolean entsAsNames) +#else +size_t SetParms(SinglyLinkedList_t *this, char *format, va_list marker) +#endif +{ + qboolean append = false; + GenericUnion4_t parm; + char current; + int count = 0; + size_t bytesParsed = 0; + + SLList_Front(this); + + while(current = format[count]) + { + switch(current) + { + case 'b': + parm.t_byte = va_arg(marker, byte); + bytesParsed += sizeof(byte); + break; + case 's': + parm.t_short = va_arg(marker, short); + bytesParsed += sizeof(short); + break; + case 'i': + parm.t_int = va_arg(marker, int); + bytesParsed += sizeof(int); + break; + case 'f': + parm.t_float = va_arg(marker, double); + bytesParsed += sizeof(double); + break; + case 'e': // a pointer is a pointer is a pointer +// parm.t_edict_p = va_arg(marker, edict_t*); +// break; + +#ifdef _GAME_DLL // this is pretty nasty, this may be an indication that something + // needs to be rethought currently this is only used in the + // ICScript_Advance + + // It does keep the code all in one place, which is nice + + if(entsAsNames) + { + int j = 0; + edict_t *ent = NULL; + char entityName[64]; + + do + { + entityName[j] = *(marker + j); + }while(*(marker + j++)); + + marker += j; + + ent = G_Find (ent, FOFS(targetname), entityName); + +#ifdef _DEBUG + if(ent) + { + edict_t *ent2 = NULL; + + ent2 = G_Find (ent, FOFS(targetname), entityName); + + assert(!ent2); // each entityName should be unique!!! + } +#endif + parm.t_void_p = ent; + break; + } +#endif + case 'v': // this better be not be a local variable or this will be bunk when + // the message is received and parsed +// parm.t_float_p = va_arg(marker, float*); +// break; + case 'g': // g for generic + parm.t_void_p = va_arg(marker, void*); + bytesParsed += sizeof(void*); + break; + case 'c': + parm.t_RGBA = va_arg(marker, paletteRGBA_t); + bytesParsed += sizeof(paletteRGBA_t); + break; + default: + assert(0); + } + + if(append) + { + SLList_InsertAfter(this, parm); + SLList_Increment(this); + } + else + { + SLList_ReplaceCurrent(this, parm); + + if(SLList_AtLast(this)) + { + append = true; + } + else + { + SLList_Increment(this); + } + } + + ++count; + } + + return bytesParsed; +} + +int GetParms(SinglyLinkedList_t *this, char *format, va_list marker) +{ + qboolean append = false; + char current; + int count = 0; + byte *b; + short *s; + int *i; + float *f, *v; +// edict_t **e; + void **g; + paletteRGBA_t *c; + + assert(format); + + if(!format) + { + Sys_Error("GetParms: null format string"); + return 0; + } + + SLList_Front(this); + + assert(!SLList_AtEnd(this)); + + if(SLList_AtEnd(this)) + { + Sys_Error("Getthis: empty parameter list"); + return 0; + } + + while(current = format[count]) + { + switch(current) + { + + case 'b': + b = va_arg(marker, byte*); + + *b = SLList_PostIncrement(this).t_byte; + break; + case 's': + s = va_arg(marker, short*); + + *s = SLList_PostIncrement(this).t_short; + break; + case 'i': + i = va_arg(marker, int*); + + *i = SLList_PostIncrement(this).t_int; + break; + case 'f': + f = va_arg(marker, float*); + + *f = SLList_PostIncrement(this).t_float; + break; + case 'v': + v = va_arg(marker, float*); + + v = SLList_PostIncrement(this).t_float_p; + break; + case 'e': // a pointer is a pointer is a pointer +// e = va_arg(marker, edict_t**); + +// *e = SLList_PostIncrement(this).t_edict_p; +// break; + case 'g': + g = va_arg(marker, void**); + + *g = SLList_PostIncrement(this).t_void_p; + break; + case 'c': + c = va_arg(marker, paletteRGBA_t*); + + *c = SLList_PostIncrement(this).t_RGBA; + break; + default: + assert(0); + return 0; + } + + ++count; + } + + return count; +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/Message.h b/Toolkit/Programming/GameCode/qcommon/Message.h new file mode 100644 index 0000000..d6764dd --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/Message.h @@ -0,0 +1,20 @@ +#ifndef MESSAGE_H +#define MESSAGE_H + +#include "SinglyLinkedList.h" + +typedef struct MsgQueue_s +{ + SinglyLinkedList_t msgs; +} MsgQueue_t; + +#ifdef _GAME_DLL +size_t SetParms(SinglyLinkedList_t *this_ptr, char *format, va_list marker, qboolean entsAsNames); +#else +size_t SetParms(SinglyLinkedList_t *this_ptr, char *format, va_list marker); +#endif + +int GetParms(SinglyLinkedList_t *this_ptr, char *format, va_list marker); +void QueueMessage(MsgQueue_t *this_ptr, void *msg); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/Vector.h b/Toolkit/Programming/GameCode/qcommon/Vector.h new file mode 100644 index 0000000..553c1af --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/Vector.h @@ -0,0 +1,346 @@ +#ifndef VECTOR_H +#define VECTOR_H + +#include +#include + +#include "H2Common.h" +#include "q_Typedef.h" +#include "angles.h" +#include "q_shared.h" + +// angle indexes +#define PITCH 0 // up / down +#define YAW 1 // left / right +#define ROLL 2 // fall over + +#define FLOAT_ZERO_EPSILON 0.0005f + +#ifdef __cplusplus +extern "C" +{ +#endif +H2COMMON_API void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); +H2COMMON_API void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ); +H2COMMON_API void PerpendicularVector( vec3_t dst, const vec3_t src ); +H2COMMON_API void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +H2COMMON_API void RealAngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); + +H2COMMON_API void DirFromAngles(vec3_t angles, vec3_t direction); +H2COMMON_API void DirAndUpFromAngles(vec3_t angles, vec3_t direction, vec3_t up); +H2COMMON_API void AnglesFromDir(vec3_t direction, vec3_t angles); +H2COMMON_API void AnglesFromDirI(vec3_t direction, vec3_t angles); +H2COMMON_API void vectoangles(vec3_t in, vec3_t out); +H2COMMON_API void AnglesFromDirAndUp(vec3_t direction, vec3_t up, vec3_t angles); +H2COMMON_API int VectorCompare (vec3_t v1, vec3_t v2); +H2COMMON_API vec_t VectorNormalize (vec3_t v); // returns vector length +H2COMMON_API float Vec3Normalize(vec3_t v1); +H2COMMON_API vec_t VectorNormalize2 (vec3_t v, vec3_t out); +H2COMMON_API void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc); +H2COMMON_API void VectorAverage (vec3_t veca, vec3_t vecb, vec3_t vecc); +H2COMMON_API void VectorGetOffsetOrigin(vec3_t off, vec3_t org, vec_t degree, vec3_t out); +H2COMMON_API vec_t VectorSeparation(vec3_t, vec3_t); +H2COMMON_API void VectorRandomCopy(vec3_t, vec3_t, float); +H2COMMON_API void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +H2COMMON_API vec_t VectorLength (vec3_t v); +H2COMMON_API vec_t VectorLengthSquared (vec3_t v); +H2COMMON_API void VectorRandomAdd (vec3_t veca, vec3_t vecb, vec3_t out); +H2COMMON_API void VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out); +H2COMMON_API void VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out); +H2COMMON_API float vhlen (vec3_t p1, vec3_t p2); +H2COMMON_API void Create_rand_relect_vect(vec3_t in, vec3_t out); +H2COMMON_API qboolean Vec3IsZeroEpsilon(vec3_t in); + +#define INLINE_VEC_FUNCS // placed in the header to avoid inconsistencies between projects + +#ifndef INLINE_VEC_FUNCS + +H2COMMON_API void VectorAbs(const vec3_t in, vec3_t out); +H2COMMON_API void VectorRound(vec3_t v); +H2COMMON_API vec_t DotProduct (const vec3_t v1, const vec3_t v2); +H2COMMON_API void VectorDec(vec3_t v); +H2COMMON_API void VectorInc(vec3_t v); +H2COMMON_API void VectorClear (vec3_t in); +H2COMMON_API void VectorSet (vec3_t in, vec_t x, vec_t y, vec_t z); +H2COMMON_API void VectorCopy (vec3_t in, vec3_t out); +H2COMMON_API void VectorInverse (vec3_t v); +H2COMMON_API void VectorNegate (vec3_t in, vec3_t out); +H2COMMON_API void VectorScale (vec3_t in, vec_t scale, vec3_t out); +H2COMMON_API void VectorRadiansToDegrees (vec3_t in, vec3_t out); +H2COMMON_API void VectorDegreesToRadians (vec3_t in, vec3_t out); +H2COMMON_API void VectorScaleByVector(vec3_t, vec3_t, vec3_t); + +H2COMMON_API void Vec3SubtractAssign(vec3_t value, vec3_t subFrom); +H2COMMON_API void Vec3AddAssign(vec3_t value, vec3_t addTo); +H2COMMON_API void Vec3MultAssign(vec3_t value, vec3_t multBy); +H2COMMON_API void Vec3ScaleAssign(vec_t value, vec3_t scaleBy); +H2COMMON_API qboolean FloatIsZeroEpsilon(float f); +H2COMMON_API qboolean FloatIsZero(float f, float epsilon); +H2COMMON_API qboolean Vec3EqualsEpsilon(vec3_t v1, vec3_t v2); +H2COMMON_API qboolean Vec3IsZero(vec3_t v1); +H2COMMON_API qboolean Vec3NotZero(vec3_t vec); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#else // INLINE_VEC_FUNCS + +#ifdef __cplusplus +} +#endif // __cplusplus + +__inline vec_t DotProduct (const vec3_t v1, const vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +__inline int VectorCompare (vec3_t v1, vec3_t v2) +{ + if ((v1[0] != v2[0]) || (v1[1] != v2[1]) || (v1[2] != v2[2])) + return(false); + + return(true); +} + +__inline void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc) +{ + assert(vecc != vec3_origin); + + vecc[0] = veca[0] + scale*vecb[0]; + vecc[1] = veca[1] + scale*vecb[1]; + vecc[2] = veca[2] + scale*vecb[2]; +} + +__inline vec_t VectorLength(vec3_t v) +{ + float length; + + length = sqrt(DotProduct(v, v)); + + return length; +} + +__inline vec_t VectorLengthSquared(vec3_t v) +{ + float length; + + length = DotProduct(v, v); + + return length; +} + +__inline void VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out) +{ + assert(out != vec3_origin); + + out[0] = veca[0]-vecb[0]; + out[1] = veca[1]-vecb[1]; + out[2] = veca[2]-vecb[2]; +} + +__inline vec_t VectorSeparationSquared(vec3_t va, vec3_t vb) +{ + vec3_t work; + vec_t result; + + VectorSubtract(va, vb, work); + result = DotProduct(work, work); + return(result); +} + +__inline void VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out) +{ + assert(out != vec3_origin); + + out[0] = veca[0] + vecb[0]; + out[1] = veca[1] + vecb[1]; + out[2] = veca[2] + vecb[2]; +} + +__inline void VectorAbs(const vec3_t in, vec3_t out) +{ + assert(out != vec3_origin); + + out[0] = (float)Q_fabs(in[0]); + out[1] = (float)Q_fabs(in[1]); + out[2] = (float)Q_fabs(in[2]); +} + +__inline void VectorRound(vec3_t v) +{ + assert(v != vec3_origin); + + v[0] = (float)floor(v[0] + 0.5); + v[1] = (float)floor(v[1] + 0.5); + v[2] = (float)floor(v[2] + 0.5); +} + +__inline void VectorInc(vec3_t v) +{ + assert(v != vec3_origin); + + v[0] += 1.0; + v[1] += 1.0; + v[2] += 1.0; +} + +__inline void VectorDec(vec3_t v) +{ + assert(v != vec3_origin); + + v[0] -= 1.0; + v[1] -= 1.0; + v[2] -= 1.0; +} + +_inline void VectorClear (vec3_t in) +{ + assert(in != vec3_origin); + + in[0] = 0; + in[1] = 0; + in[2] = 0; +} + +_inline void VectorSet (vec3_t in, vec_t x, vec_t y, vec_t z) +{ + assert(in != vec3_origin); + + in[0] = x; + in[1] = y; + in[2] = z; +} + +_inline void VectorCopy(vec3_t in, vec3_t out) +{ + assert(out != vec3_origin); + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +_inline void VectorInverse (vec3_t v) +{ + assert(v != vec3_origin); + + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +_inline void VectorNegate (vec3_t in, vec3_t out) +{ + assert(out != vec3_origin); + + out[0] = -in[0]; + out[1] = -in[1]; + out[2] = -in[2]; +} + +_inline void VectorScale (vec3_t in, vec_t scale, vec3_t out) +{ + assert(out != vec3_origin); + + out[0] = in[0] * scale; + out[1] = in[1] * scale; + out[2] = in[2] * scale; +} + +_inline void VectorRadiansToDegrees (vec3_t in, vec3_t out) +{ + assert(out != vec3_origin); + + out[0] = in[0] * RAD_TO_ANGLE; + out[1] = in[1] * RAD_TO_ANGLE; + out[2] = in[2] * RAD_TO_ANGLE; +} + +_inline void VectorDegreesToRadians (vec3_t in, vec3_t out) +{ + assert(out != vec3_origin); + + out[0] = in[0] * ANGLE_TO_RAD; + out[1] = in[1] * ANGLE_TO_RAD; + out[2] = in[2] * ANGLE_TO_RAD; +} + +_inline void VectorScaleByVector (vec3_t in, vec3_t scale, vec3_t out) +{ + assert(out != vec3_origin); + + out[0] = in[0] * scale[0]; + out[1] = in[1] * scale[1]; + out[2] = in[2] * scale[2]; +} + +_inline void Vec3SubtractAssign(vec3_t value, vec3_t subFrom) +{ + assert(subFrom != vec3_origin); + + subFrom[0] -= value[0]; + subFrom[1] -= value[1]; + subFrom[2] -= value[2]; +} + +_inline void Vec3AddAssign(vec3_t value, vec3_t addTo) +{ + assert(addTo != vec3_origin); + + addTo[0] += value[0]; + addTo[1] += value[1]; + addTo[2] += value[2]; +} + +_inline void Vec3MultAssign(vec3_t value, vec3_t multBy) +{ + assert(multBy != vec3_origin); + + multBy[0] *= value[0]; + multBy[1] *= value[1]; + multBy[2] *= value[2]; +} + +_inline void Vec3ScaleAssign(vec_t value, vec3_t scaleBy) +{ + assert(scaleBy != vec3_origin); + + scaleBy[0] *= value; + scaleBy[1] *= value; + scaleBy[2] *= value; +} + +_inline qboolean FloatIsZeroEpsilon(float f) +{ + return (Q_fabs(f) < FLOAT_ZERO_EPSILON); +} + +_inline qboolean FloatIsZero(float f, float epsilon) +{ + return (Q_fabs(f) < epsilon); +} + +_inline qboolean Vec3EqualsEpsilon(vec3_t v1, vec3_t v2) +{ + if(!FloatIsZeroEpsilon(v1[0] - v2[0]) || !FloatIsZeroEpsilon(v1[1] - v2[1]) || !FloatIsZeroEpsilon(v1[2] - v2[2])) + { + return false; + } + + return true; +} + +_inline qboolean Vec3IsZero(vec3_t vec) +{ + return !( vec[0] != 0.0 || vec[1] != 0.0 || vec[2] != 0.0 ); +} + +_inline qboolean Vec3NotZero(vec3_t vec) +{ + return ( vec[0] != 0.0 || vec[1] != 0.0 || vec[2] != 0.0 ); +} + +#endif + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/angles.h b/Toolkit/Programming/GameCode/qcommon/angles.h new file mode 100644 index 0000000..dc65d53 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/angles.h @@ -0,0 +1,54 @@ +// Angles in radians + +#define ANGLE_0 0.0F +#define ANGLE_1 0.017453292F +#define ANGLE_5 0.087266462F +#define ANGLE_10 0.174532925F +#define ANGLE_15 0.261799387F +#define ANGLE_20 0.392699081F +#define ANGLE_30 0.523598775F +#define ANGLE_45 0.785398163F +#define ANGLE_60 1.047197551F +#define ANGLE_72 1.256637061F +#define ANGLE_90 1.570796327F +#define ANGLE_120 2.094395102F +#define ANGLE_135 2.35619449F +#define ANGLE_144 2.513274123F +#define ANGLE_180 3.141592653F +#define ANGLE_225 3.926990817F +#define ANGLE_270 4.71238898F +#define ANGLE_315 5.497787144F +#define ANGLE_360 6.283185307F + +// Angles in degrees + +#define DEGREE_0 0.0F +#define DEGREE_180 180.0F +#define DEGREE_45 (DEGREE_180 / 4.0F) +#define DEGREE_90 (DEGREE_180 / 2.0F) +#define DEGREE_135 (DEGREE_90 + DEGREE_45) +#define DEGREE_270 (DEGREE_180 + DEGREE_90) +#define DEGREE_360 (DEGREE_180 * 2.0F) + +#define DEGREE_225 (DEGREE_180 + DEGREE_45) +#define DEGREE_315 (DEGREE_270 + DEGREE_45) + +#define DEGREE_30 (DEGREE_180 / 6.0F) +#define DEGREE_60 (DEGREE_180 / 3.0F) +#define DEGREE_120 (DEGREE_360 / 3.0F) + +#define DEGREE_1 (DEGREE_180 / 180.0F) +#define DEGREE_5 (DEGREE_180 / 36.0F) +#define DEGREE_10 (DEGREE_180 / 18.0F) +#define DEGREE_15 (DEGREE_180 / 12.0F) +#define DEGREE_20 (DEGREE_180 / 8.0F) + +// Conversion routines + +#define ANGLE_TO_RAD ANGLE_1 +#define RAD_TO_ANGLE (180.0F / ANGLE_180) + +#define SHORT_TO_ANGLE (360.0/65536) + + +#pragma warning(disable : 4305) // 'initializing' : truncation from 'const double ' to 'float ' diff --git a/Toolkit/Programming/GameCode/qcommon/anorms.h b/Toolkit/Programming/GameCode/qcommon/anorms.h new file mode 100644 index 0000000..f6d982c --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/anorms.h @@ -0,0 +1,162 @@ +{-0.525731, 0.000000, 0.850651}, +{-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, +{-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, +{0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, +{-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, +{0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, +{0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, +{0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, +{-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, +{-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, +{-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, +{-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, +{-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, +{-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, +{-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, +{-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, +{-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, +{0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, +{0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, +{0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, +{0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, +{0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, +{0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, +{0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, +{0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, +{0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, +{0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, +{0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, +{0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, +{0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, +{0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, +{0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, +{0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, +{0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, +{0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, +{0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, +{0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, +{0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, +{0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, +{-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, +{0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, +{-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, +{-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, +{0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, +{-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, +{-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, +{-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, +{0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, +{0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, +{0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, +{0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, +{0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, +{0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, +{0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, +{0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, +{0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, +{0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, +{-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, +{-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, +{-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, +{-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, +{-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, +{-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, +{-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, +{-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, +{-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, +{-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, +{0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, +{0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, +{0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, +{0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, +{-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, +{-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, +{-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, +{-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, +{-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, +{-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, +{-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, +{-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, +{-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, +{-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, +{-0.688191, -0.587785, -0.425325}, diff --git a/Toolkit/Programming/GameCode/qcommon/arrayedlist.h b/Toolkit/Programming/GameCode/qcommon/arrayedlist.h new file mode 100644 index 0000000..f9ac8af --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/arrayedlist.h @@ -0,0 +1,32 @@ +#include + +typedef struct ArrayedListNode_s +{ + int data; + int next; + int inUse; +} ArrayedListNode_t; + +#define ARRAYEDLISTNODE_NULL -1 + +_inline int GetFreeNode(ArrayedListNode_t *nodeArray, int max) +{ + int i; + + for(i = 0; i < max; ++i) + { + if(!nodeArray[i].inUse) + { + nodeArray[i].inUse = 1; + return i; + } + } + + assert(0); + return -1; +} + +_inline void FreeNode(ArrayedListNode_t *nodeArray, int index) +{ + nodeArray[index].inUse = 0; +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/cl_strings.h b/Toolkit/Programming/GameCode/qcommon/cl_strings.h new file mode 100644 index 0000000..d812409 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/cl_strings.h @@ -0,0 +1,318 @@ + +// Top 2 bits are used for level of message +#define MESSAGE_MASK 0x1fff + +typedef enum +{ + GM_CS_HEALTH = 3, + GM_CS_MANA , + GM_CS_SILVER , + GM_CS_REFLECT , + GM_CS_POWERUP , + GM_CS_GOLD , + GM_CS_BLADE , + GM_CS_GHOST , + GM_CS_SPEED , + GM_S_MANA , + GM_S_HEALTH , + GM_S_SILVER , + GM_S_LIGHT , + GM_S_POWERUP , + GM_S_BLADE , + GM_S_GHOST , + GM_S_REFLECT , + GM_S_LUNGS , + GM_S_GOLD , + GM_S_SPEED , + + GM_HELLSTAFF = 27, + GM_FORCEBLAST , + GM_STORMBOW , + GM_SPHERE , + GM_PHOENIX , + GM_IRONDOOM , + GM_FIREWALL , + GM_TOME , + GM_RING , + GM_SHIELD , + GM_TELEPORT , + GM_MORPH , + GM_METEOR , + GM_OFFMANAS , + GM_OFFMANAB , + GM_DEFMANAS , + GM_DEFMANAB , + GM_COMBMANAS , + GM_COMBMANAB , + GM_STORMARROWS , + GM_PHOENARROWS , + GM_HELLORB , + GM_HEALTHVIAL , + GM_HEALTHPOTION , + GM_F_TOWNKEY , + GM_F_COG , + GM_F_SHIELD , + GM_F_POTION , + GM_F_CONT , + GM_F_CONTFULL , + GM_F_CRYSTAL , + GM_F_CANYONKEY , + GM_F_AMULET , + GM_F_SPEAR , + GM_F_GEM , + GM_F_CARTWHEEL , + GM_F_UNREFORE , + GM_F_REFORE , + GM_F_DUNGEONKEY , + GM_F_CLOUDKEY , + GM_F_HIGHKEY , + GM_F_SYMBOL , + GM_F_TOME , + GM_F_TAVERNKEY , + + GM_NOHELLORBS = 74, + GM_NOFORCE , + GM_NOSTORMBOW , + GM_NOSPHERE , + GM_NOPHOENIX , + GM_NOIRONDOOM , + GM_NOFIREWALL , + GM_NOTOME , + GM_NORING , + GM_NOSHIELD , + GM_NOTELEPORT , + GM_NOMORPH , + GM_NOMETEOR , + GM_NEED_TOWNKEY , + GM_NEED_COG , + GM_NEED_SHIELD , + GM_NEED_POTION , + GM_NEED_CONT , + GM_NEED_CONTFULL , + GM_NEED_CRYSTAL , + GM_NEED_CANYONKEY , + GM_NEED_AMULET , + GM_NEED_SPEAR , + GM_NEED_GEM , + GM_NEED_CARTWHEEL , + GM_NEED_UNREFORE , + GM_NEED_REFORE , + GM_NEED_DUNGEONKEY , + GM_NEED_CLOUDKEY , + GM_NEED_HIGHKEY , + GM_NEED_SYMBOL , + GM_NEED_TOME , + GM_NEED_TAVERNKEY , + + GM_NOTUSABLE = 110, + GM_NOCHEATS , + GM_NOITEM , + GM_NOMANA , + GM_NOAMMO , + GM_SEQCOMPLETE , + GM_TOGO_1 , + GM_TOGO_2 , + GM_TOGO_3 , + GM_TOGO_4 , + GM_TOGO_5 , + GM_TOGO_6 , + GM_TOGO_7 , + GM_TOGO_8 , + GM_TOGO_9 , + GM_TOGO_10 , + GM_NEWOBJ , + + GM_KILLED_SELF = 128, + GM_DIED , + GM_WASKILLED , + GM_ENTERED , + GM_TIMELIMIT , + GM_FRAGLIMIT , + GM_EXIT , + GM_DISCON , + GM_WASKICKED , + GM_WASBANNED , + GM_KICKED , + GM_BANNED , + GM_TIMEDOUT , + GM_OVERFLOW , + GM_COOPTIMEOUT , + GM_COOPWAITCIN , + + GM_OBIT_STAFF = 147, + GM_OBIT_STAFF1 , + GM_OBIT_STAFF2 , + GM_OBIT_FIREBALL , + GM_OBIT_FIREBALL1 , + GM_OBIT_FIREBALL2 , + GM_OBIT_MMISSILE , + GM_OBIT_MMISSILE1 , + GM_OBIT_MMISSILE2 , + GM_OBIT_SPHERE , + GM_OBIT_SPHERE1 , + GM_OBIT_SPHERE2 , + GM_OBIT_SPHERE_SPL , + GM_OBIT_SPHERE_SPL1 , + GM_OBIT_SPHERE_SPL2 , + GM_OBIT_IRONDOOM , + GM_OBIT_IRONDOOM1 , + GM_OBIT_IRONDOOM2 , + GM_OBIT_FIREWALL , + GM_OBIT_FIREWALL1 , + GM_OBIT_FIREWALL2 , + GM_OBIT_STORM , + GM_OBIT_STORM1 , + GM_OBIT_STORM2 , + GM_OBIT_PHOENIX , + GM_OBIT_PHOENIX1 , + GM_OBIT_PHOENIX2 , + GM_OBIT_PHOENIX_SPL , + GM_OBIT_PHOENIX_SPL1 , + GM_OBIT_PHOENIX_SPL2 , + GM_OBIT_HELLSTAFF , + GM_OBIT_HELLSTAFF1 , + GM_OBIT_HELLSTAFF2 , + + GM_OBIT_P_STAFF = 183, + GM_OBIT_P_STAFF1 , + GM_OBIT_P_STAFF2 , + GM_OBIT_P_FIREBALL , + GM_OBIT_P_FIREBALL1 , + GM_OBIT_P_FIREBALL2 , + GM_OBIT_P_MMISSILE , + GM_OBIT_P_MMISSILE1 , + GM_OBIT_P_MMISSILE2 , + GM_OBIT_P_SPHERE , + GM_OBIT_P_SPHERE1 , + GM_OBIT_P_SPHERE2 , + GM_OBIT_P_SPHERE_SPL , + GM_OBIT_P_SPHERE_SPL1 , + GM_OBIT_P_SPHERE_SPL2 , + GM_OBIT_P_IRONDOOM , + GM_OBIT_P_IRONDOOM1 , + GM_OBIT_P_IRONDOOM2 , + GM_OBIT_P_FIREWALL , + GM_OBIT_P_FIREWALL1 , + GM_OBIT_P_FIREWALL2 , + GM_OBIT_P_STORM , + GM_OBIT_P_STORM1 , + GM_OBIT_P_STORM2 , + GM_OBIT_P_PHOENIX , + GM_OBIT_P_PHOENIX1 , + GM_OBIT_P_PHOENIX2 , + GM_OBIT_P_PHOENIX_SPL , + GM_OBIT_P_PHOENIX_SPL1 , + GM_OBIT_P_PHOENIX_SPL2 , + GM_OBIT_P_HELLSTAFF , + GM_OBIT_P_HELLSTAFF1 , + GM_OBIT_P_HELLSTAFF2 , + + GM_OBIT_UNKNOWN = 219, + GM_OBIT_UNKNOWN1 , + GM_OBIT_UNKNOWN2 , + GM_OBIT_KILLEDSELF , + GM_OBIT_KILLEDSELF1 , + GM_OBIT_KILLEDSELF2 , + GM_OBIT_KICKED , + GM_OBIT_KICKED1 , + GM_OBIT_KICKED2 , + GM_OBIT_METEORS , + GM_OBIT_METEORS1 , + GM_OBIT_METEORS2 , + GM_OBIT_ROR , + GM_OBIT_ROR1 , + GM_OBIT_ROR2 , + GM_OBIT_SHIELD , + GM_OBIT_SHIELD1 , + GM_OBIT_SHIELD2 , + GM_OBIT_CHICKEN , + GM_OBIT_CHICKEN1 , + GM_OBIT_CHICKEN2 , + GM_OBIT_TELEFRAG , + GM_OBIT_TELEFRAG1 , + GM_OBIT_TELEFRAG2 , + GM_OBIT_WATER , + GM_OBIT_WATER1 , + GM_OBIT_WATER2 , + GM_OBIT_SLIME , + GM_OBIT_SLIME1 , + GM_OBIT_SLIME2 , + GM_OBIT_LAVA , + GM_OBIT_LAVA1 , + GM_OBIT_LAVA2 , + GM_OBIT_CRUSH , + GM_OBIT_CRUSH1 , + GM_OBIT_CRUSH2 , + GM_OBIT_FALLING , + GM_OBIT_FALLING1 , + GM_OBIT_FALLING2 , + GM_OBIT_SUICIDE , + GM_OBIT_SUICIDE1 , + GM_OBIT_SUICIDE2 , + GM_OBIT_BARREL , + GM_OBIT_BARREL1 , + GM_OBIT_BARREL2 , + GM_OBIT_EXIT , + GM_OBIT_EXIT1 , + GM_OBIT_EXIT2 , + GM_OBIT_DIED , + GM_OBIT_DIED1 , + GM_OBIT_DIED2 , + GM_OBIT_BLEED , + GM_OBIT_BLEED1 , + GM_OBIT_BLEED2 , + GM_OBIT_SPEAR , + GM_OBIT_SPEAR1 , + GM_OBIT_SPEAR2 , + GM_OBIT_BURNT , + GM_OBIT_BURNT1 , + GM_OBIT_BURNT2 , + GM_OBIT_EXPL , + GM_OBIT_EXPL1 , + GM_OBIT_EXPL2 , + + GM_SIR_NATE_HIT_AGAIN0 = 285, + GM_SIR_NATE_HIT_AGAIN1, + GM_SIR_NATE_HIT_AGAIN2, + GM_SIR_NATE_HIT_AGAIN3, + GM_SIR_NATE_HIT_AGAIN4, + GM_SIR_NATE_HIT_AGAIN5, + GM_SIR_NATE_HIT_AGAIN6, + GM_SIR_NATE_HIT_AGAIN7, + GM_SIR_NATE_HIT_AGAIN8, + GM_SIR_NATE_HIT_AGAIN9, + GM_SIR_NATE_FAILURE, + GM_SIR_NATE_SUCCESS, + GM_SIR_NATE_FINISH, + GM_SIR_NATE_INSTRUCTIONS0, + GM_SIR_NATE_INSTRUCTIONS1, + GM_SIR_NATE_INSTRUCTIONS2, + GM_SIR_NATE_INSTRUCTIONS3, + GM_SIR_NATE_GREETING, + GM_SIR_NATE_GET_STARTED, + GM_SIR_NATE_END, + + GM_SHUTUP = 306, + GM_NONAMECHANGE , + GM_NOKILL , + GM_CH_SERVERS , + GM_CH_SAVECFG , + GM_CH_SOUND , + + GM_M_KELLCAVES = 313, + GM_M_DARKMIRE , + GM_M_KATLITK , + GM_M_MINES , + GM_M_DUNGEON , + GM_M_CLOUD , + + // Always keep these last to test alignment + GM_HELP1 = 320, + GM_HELP2 +} GameMsg_t; + + + + + + diff --git a/Toolkit/Programming/GameCode/qcommon/compfmod.h b/Toolkit/Programming/GameCode/qcommon/compfmod.h new file mode 100644 index 0000000..f51d384 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/compfmod.h @@ -0,0 +1,8 @@ +#ifndef COMPFMOD_H +#define COMPFMOD_H + +#if 0 +#define COMP_FMOD +#endif + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/effectflags.h b/Toolkit/Programming/GameCode/qcommon/effectflags.h new file mode 100644 index 0000000..caac9ff --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/effectflags.h @@ -0,0 +1,104 @@ +#ifndef EFFECTFLAGS_H +#define EFFECTFLAGS_H + +// ************************************************************************************************ +// EF_XXX +// ------ +// Effects (held by 'entity_state_t'->effects) are things that are handled on the client side +// (lights, particles, frame animations) and happen constantly on the given entity. An entity that +// has effects will be sent to the client even if it has a zero index model. +// ************************************************************************************************ + +#define EF_ROTATE 0x00000001 // Rotate the entity's model (used for bonus items). +#define EF_CL_PHYS_ALWAYS_BOUNCE 0x00000002 +#define EF_JOINTED 0x00000004 +#define EF_SWAPFRAME 0x00000008 +#define EF_DISABLE_ALL_CFX 0x00000010 // All effects linked to this entity will longer be + // rendered, but will continue to think. + +#define EF_PLAYER 0x00000020 // Safe flag, never changes. Is a player/client. + +#define EF_NODRAW_ALWAYS_SEND 0x00000040 // Prevents invisible (i.e. modelindex=0) entities + // from being culled by the server when it builds + // frames to + // send to the client. +#define EF_MARCUS_FLAG1 0x00000080 // FIXME: Remove when convenient. +#define EF_CAMERA_NO_CLIP 0x00000100 // Client-side camera's LOS won't clip against any + // entities that have this flag set. +#define EF_CAMERA_ONLY 0x00000200 // Client-side camera LOS traces will clip against any + // entities that have this flag set, but other traces won't. +#define EF_ALTCLIENTFX 0x00000400 // A message flag to send to the client effects, for + // user's purpose. +#define EF_ALWAYS_ADD_EFFECTS 0x00000800 // Any effects attached to the entity will always be + // added to the view + // This overrides EF_DISABLE_*_CFX +#define EF_LIGHT_ENABLED 0x00001000 // Tells the client effects that corvus' personal + // torch is activated. +#define EF_CHICKEN 0x00002000 // The flag that tells the system that the player is + // a chicken, and not corvus. +#define EF_ANIM_ALL 0x00004000 // Automatically cycle through all frames at 2hz +#define EF_ANIM_ALLFAST 0x00008000 // Automatically cycle through all frames at 10hz +#define EF_DISABLE_EXTRA_FX 0x00010000 // Remove effects that are not owned by an entity + // with this flag, but need this info. This should be + // set when something dies and needs the effects to + // reflect this. +#define EF_MACE_ROTATE 0x00020000 // make the mace ball model rotate around its axes - save network traffic +#define EF_CLIENT_DEAD 0x00040000 // this client on the server is dead. Easiest way to get this flag to CFX. +#define EF_POWERUP_ENABLED 0x00080000 // Tells the client effects that corvus powerup is enabled + + +// ************************************************************************************************ +// CEF_XXX +// ------- +// Flags specified when a client-effect is created; don't even think about expanding this beyond 1 +// byte! This is 'cos only the frist byte is sent across the net (and only a flag is actually set). +// ************************************************************************************************ + +#define CEF_OWNERS_ORIGIN 0x00000001 // Use the owner's origin only, with no additional + // displacment. +#define CEF_BROADCAST 0x00000002 // sent to all client's +#define CEF_ENTNUM16 0x00000004 // index is a short +#define CEF_MULTICAST 0x00000008 // places the effect into the world buffer + // instead of the owner's buffer (no effect + // on independent effects), resulting in the + // effect being more reliably sent at the + // expense of an extra byte or two +#define CEF_DONT_LINK 0x00000010 // used to stop cleint effects from being linked to their + // owner's movement + // In this case, CEF_OWNERS_ORIGIN causes the owner's origin + // to be used for initialization only +#define CEF_FLAG6 0x00000020 // +#define CEF_FLAG7 0x00000040 // +#define CEF_FLAG8 0x00000080 // + +// Client-effect Flags relevant only in the Client Effects DLL. + +#define CEF_VIEWSTATUSCHANGED 0x00020000 // If this flag is set, do not think when the CEF_CULLED flag is set. +#define CEF_USE_VELOCITY2 0x00040000 // Sprite lines. Read and apply the velocity2 and acceleration2 fields of the line +#define CEF_USE_SCALE2 0x00080000 // Sprite lines. Read and apply the scale2 value to the endpoint +#define CEF_AUTO_ORIGIN 0x00100000 // Sprite lines. Read just the origin of the line to the centerpoint after any movement + +#define CEF_PULSE_ALPHA 0x00200000 // Particle/fx d_alpha: when hits 1.0 alpha, reverse and start fading out. +#define CEF_ABSOLUTE_PARTS 0x00400000 // Particle origins represent absolute positions. +#define CEF_ADDITIVE_PARTS 0x00800000 // Particles are additively transparent (temporary) + +#define CEF_DROPPED 0x01000000 // entity was dropped from the view due to an excessive number of entites in the view +#define CEF_NOMOVE 0x02000000 // velocity and acceleration are not applied to origin in update + // acceleration is not applied to velocity in update + // allows vel and accel to be used for something else + // for static entities +#define CEF_CULLED 0x04000000 // Culled from view this frame (set or unset) in AddEffectsToView(). +#define CEF_CLIP_TO_WORLD 0x08000000 // Turns on collision detection with the world. Additionally, the + // entity needs to have a message handler in order to recieve MSG_COLLISION. +#define CEF_CLIP_TO_ENTITIES 0x10000000 // Turn on collision detection with server entities (not client only + // entities) requires CEF_CLIP_TO_WORLD to be turned on as well. + // NOTE: This only clip against entities in the current frame, not + // all entities in the world +#define CEF_DISAPPEARED 0x20000000 // Alpha faded out, or scaled to nothing needs to be turned off if entity + // later scales up or fades back in. +#define CEF_CHECK_OWNER 0x40000000 // if we are owned, then check to see if our owner has been server culled before it gets to the client +#define CEF_NO_DRAW 0x80000000 // Doesn't get added to the render list. + +#define CEF_CLIP_TO_ALL (CEF_CLIP_TO_WORLD|CEF_CLIP_TO_ENTITIES) + +#endif // EFFECTFLAGS_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/fx.h b/Toolkit/Programming/GameCode/qcommon/fx.h new file mode 100644 index 0000000..8938747 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/fx.h @@ -0,0 +1,267 @@ +#include "EffectFlags.h" + +// ************************************************************************************************ +// FX_XXX +// ------ +// Id's for all the client-effects types. +// ************************************************************************************************ + +typedef enum FX_Types_e +{ // NOTE We currently have 126 client effects, we cannot exceed 32768 - ha !! Like we'll ever reach that ! + FX_REMOVE_EFFECTS=0, // special fx type for removing client fx + FX_TEST, + FX_EXPLOSION1, + FX_EXPLOSION2, + FX_SPLASH, + FX_GIB_TRAIL, + FX_BLOOD, + FX_BLOOD_TRAIL, + FX_LINKEDBLOOD, + FX_SPARKS, + FX_PLAYER_TELEPORT_IN, //10 + FX_PICKUP_HEALTH, + FX_PICKUP_WEAPON, + FX_PICKUP_DEFENSE, + FX_PICKUP_PUZZLE, + FX_PICKUP_AMMO, + FX_WEAPON_FLYINGFIST, + FX_WEAPON_FLYINGFISTEXPLODE, + FX_SPELL_BLUERING, + FX_SPELL_METEORBARRIER, // there is a reason for this - we create 4 different persistant effects + FX_SPELL_METEORBARRIER1, //20 + FX_SPELL_METEORBARRIER2, + FX_SPELL_METEORBARRIER3, + FX_SPELL_METEORBARRIER_TRAVEL, + FX_SPELL_METEORBARRIEREXPLODE, + FX_SPELL_LIGHTNINGSHIELD, + FX_WEAPON_SPHERE, + FX_WEAPON_SPHEREGLOWBALLS, + FX_WEAPON_SPHEREEXPLODE, + FX_WEAPON_SPHEREPOWER, + FX_WEAPON_SPHEREPLAYEREXPLODE, //30 + FX_WEAPON_MAGICMISSILE, + FX_WEAPON_MAGICMISSILEEXPLODE, + FX_WEAPON_BLAST, + FX_WEAPON_REDRAINMISSILE, + FX_WEAPON_REDRAIN, + FX_WEAPON_REDRAINGLOW, + FX_WEAPON_MACEBALL, + FX_WEAPON_MACEBALLBOUNCE, + FX_WEAPON_MACEBALLEXPLODE, + FX_WEAPON_PHOENIXMISSILE, //40 + FX_WEAPON_PHOENIXEXPLODE, + FX_SPELL_MORPHMISSILE, + FX_SPELL_MORPHMISSILE_INITIAL, + FX_SPELL_MORPHEXPLODE, + FX_WEAPON_FIREWAVE, + FX_WEAPON_FIREWAVEWORM, + FX_WEAPON_FIREBURST, + FX_WEAPON_RIPPEREXPLODE, + FX_WATER_ENTRYSPLASH, + FX_WATER_RIPPLES, //50 + FX_WATER_WAKE, + FX_BUBBLER, + FX_SCORCHMARK, + FX_DEBRIS, + FX_FLESH_DEBRIS, + FX_SHADOW, + FX_ANIMATE, + FX_FOUNTAIN, + FX_WATERFALLBASE, + FX_DRIPPER, //60 + FX_MIST, + FX_PLAGUEMIST, + FX_PLAGUEMISTEXPLODE, + FX_SPELLHANDS, + FX_LENSFLARE, + FX_STAFF, + FX_SPOO, + FX_HALO, + FX_REMOTE_CAMERA, + FX_WEAPON_HELLBOLT, //70 + FX_WEAPON_HELLBOLTEXPLODE, + FX_WEAPON_HELLSTAFF_POWER, + FX_WEAPON_HELLSTAFF_POWER_BURN, + FX_SPELL_CHANGE, + FX_STAFF_CREATE, + FX_STAFF_CREATEPOOF, + FX_STAFF_REMOVE, + FX_DUST_PUFF, + FX_FIRE, + FX_SOUND, //80 + FX_PICKUP, + FX_HITPUFF, + FX_DUST, + FX_ENVSMOKE, + FX_SPOO_SPLAT, + FX_BODYPART, + FX_PLAYER_TELEPORT_OUT, + FX_PLAYER_PERSISTANT, + FX_PLAYER_TORCH, + FX_TOME_OF_POWER, //90 + FX_FIRE_ON_ENTITY, + FX_FLAREUP, + FX_SHRINE_PLAYER, + FX_SHRINE_MANA, + FX_SHRINE_LUNGS, + FX_SHRINE_LIGHT, + FX_SHRINE_REFLECT, + FX_SHRINE_ARMOR, + FX_SHRINE_HEALTH, + FX_SHRINE_STAFF, //100 + FX_SHRINE_GHOST, + FX_SHRINE_SPEED, + FX_SHRINE_POWERUP, + FX_ROPE, + FX_FIREHANDS, //105 + FX_SHRINE_BALL, + FX_SHRINE_BALL_EXPLODE, + FX_OGLE_HITPUFF, + FX_HP_MISSILE, + FX_I_EFFECTS, + FX_CHICKEN_EXPLODE, + FX_FLAMETHROWER, + FX_TELEPORT_PAD, + FX_QUAKE, + FX_LIGHTNING, + FX_POWER_LIGHTNING, + FX_BUBBLE, + + FX_TPORTSMOKE, + FX_WATER_PARTICLES, + FX_M_EFFECTS, + FX_HP_STAFF, + FX_WATER_BUBBLE, + FX_MAGIC_PORTAL, + + FX_TB_EFFECTS, + + FX_TEST_BBOX, + FX_THROWWEAPON, + FX_SSITHRA_ARROW, + FX_PE_SPELL, + FX_LIGHTNING_HIT, + + FX_FOOTSTEP, + FX_FALLSHORT, + + FX_WEAPON_STAFF_STRIKE, + FX_ARMOR_HIT, + + FX_BARREL_EXPLODE, + FX_CWATCHER, + FX_CORPSE_REMOVE, + FX_SHOW_LEADER, + + NUM_FX, + + // not spawnable in the Game DLL, + + FX_PUFF +} FX_Type_t; + +// ************************************************************************************************ +// FX_ANIM_XXX +// ----------- +// Id's for static object animations as client effects +// ************************************************************************************************ + +enum +{ + FX_ANIM_BANNER=0, + FX_ANIM_CANDELABRUM, + FX_ANIM_CHANDELIER2, + FX_ANIM_FLAME, + FX_ANIM_FIRE, + FX_ANIM_BANNERONPOLE, + FX_ANIM_FLAGONPOLE, + FX_ANIM_COCOON, + FX_ANIM_LABPARTSCONTAINER, + FX_ANIM_LABTRAY, + FX_ANIM_EYEBALLJAR, + FX_ANIM_HANGING_OGLE, + NUM_FX_ANIM +}; + +// ************************************************************************************************ +// MaterialID_t +// ------------ +// Id's for all the material types that we care about in the world (e.g. different materials yield +// different debris chunks when an FX_DEBRI is created). +// ************************************************************************************************ + +typedef enum MaterialID_e +{ + MAT_STONE, // 0 + MAT_GREYSTONE, // 1 + MAT_CLOTH, // 2 + MAT_METAL, // 3 + MAT_FLESH, // 4 + MAT_POTTERY, // 5 + MAT_GLASS, // 6 + MAT_LEAF, // 7 + MAT_WOOD, // 8 + MAT_BROWNSTONE, // 9 + MAT_NONE, // 10 + MAT_INSECT, // 11 + NUM_MAT +} MaterialID_t; + +//These are used in the same field as MAT_ for client effects, +//if MAT_ goes up to 16 or higher, change these! +#define SIF_FLAG_MASK 15 +#define SIF_INWATER 16 +#define SIF_INLAVA 32 +#define SIF_INMUCK 64 + +// ************************************************************************************************ +// SPELLHANDS_XXX +// -------------- +// ************************************************************************************************ + +enum +{ + SPELLHANDS_RED=0, + SPELLHANDS_BLUE, + SPELLHANDS_INDIGO, + NUM_SPELLHANDS +}; + +#define SPELLHANDS_SHIFT 16 +#define SPELLHANDS_MASK_COLOUR 0x00ff0000 +#define SPELLHANDS_MASK_REFPTS 0x0000ffff + +// ************************************************************************************************ +// All this crap below is to be pulled out at some point REAL soon. +// ************************************************************************************************ + +#define SERVER_SENT 1 +#define SERVER_DELETED 2 + +enum +{ + SPLASH_UNKNOWN = 0, + SPLASH_SPARKS, + SPLASH_BLUE_WATER, + SPLASH_BROWN_WATER, + SPLASH_SLIME, + SPLASH_LAVA, + SPLASH_BLOOD, + NUM_SPLASHES +}; + +// Player Muzzle Flashes +enum +{ + PF_BLASTER = 0, + PF_HYPERBLASTER, + PF_LOGIN, + PF_LOGOUT, + PF_RESPAWN, +}; + +// Mosnter Muzzle Flashes +enum +{ + MF_ACTOR_MACHINEGUN_1 +}; diff --git a/Toolkit/Programming/GameCode/qcommon/genericunions.h b/Toolkit/Programming/GameCode/qcommon/genericunions.h new file mode 100644 index 0000000..9a6ae41 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/genericunions.h @@ -0,0 +1,36 @@ +#ifndef GENERICUNIONS_H +#define GENERICUNIONS_H + +#include "q_shared.h" + +// don't add anything to this union which is greater than 4 bytes in size +typedef union GenericUnion4_u +{ + byte t_byte; + short t_short; + int t_int; + unsigned int t_uint; + float t_float; + float *t_float_p; + struct edict_s *t_edict_p; + void *t_void_p; + paletteRGBA_t t_RGBA; +} GenericUnion4_t; + +// don't add anything to this union which is greater than 8 bytes in size +typedef union GenericUnion8_u +{ + GenericUnion4_t u4; + long t_long; + unsigned long t_ulong; + double t_double; +} GenericUnion8_t; + +// don't add anything to this union which is greater than 8 bytes in size +typedef union GenericUnion12_u +{ + GenericUnion8_t u8; + vec3_t t_vec3; +} GenericUnion12_t; + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/h2common.h b/Toolkit/Programming/GameCode/qcommon/h2common.h new file mode 100644 index 0000000..14e0f04 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/h2common.h @@ -0,0 +1,14 @@ +#ifndef H2COMMON_H +#define H2COMMON_H + +#ifdef H2COMMON_STATIC +#define H2COMMON_API +#else +#ifdef H2COMMON +#define H2COMMON_API __declspec(dllexport) +#else +#define H2COMMON_API __declspec(dllimport) +#endif +#endif + +#endif diff --git a/Toolkit/Programming/GameCode/qcommon/items.h b/Toolkit/Programming/GameCode/qcommon/items.h new file mode 100644 index 0000000..42a4282 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/items.h @@ -0,0 +1,25 @@ +typedef enum +{ + ITEM_TOWNKEY, + ITEM_COG, + ITEM_SHIELD, + ITEM_POTION, + ITEM_CONT, + ITEM_SLUMCONT, + ITEM_CRYSTAL, + ITEM_CANKEY, + ITEM_AMULET, + ITEM_SPEAR, + ITEM_GEM, + ITEM_WHEEL, + ITEM_ORE, + ITEM_REF_ORE, + ITEM_DUNKEY, + ITEM_CLOUDKEY, + ITEM_HIVEKEY, + ITEM_HPSYM, + ITEM_TOME, + ITEM_TAVERNKEY, + ITEM_TOTAL +} Items_t; + diff --git a/Toolkit/Programming/GameCode/qcommon/levelmaps.h b/Toolkit/Programming/GameCode/qcommon/levelmaps.h new file mode 100644 index 0000000..a5ee0ab --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/levelmaps.h @@ -0,0 +1,51 @@ +#pragma once + +// Level progression map only needs to work on the dmireswamp, kellcaves, canyon, oglemine1, and oglemine2. +// The other levels should simply highlight a city on the map. + +// 1st unit +// SSdocks, SSwarehouse, SStown, SSpalace. +// The player will acquire the hellstaff, the array, and the ring of repulsion. + +// 2nd unit +// Dmireswamp. +// No new weapon. + +// 3rd unit +// Andhealer, Andplaza, Andacademic, Andslums. +// The player will acquire the Red Rain Bow, Polymorph, Sphere of Annihilation. + +// 4th unit +// Kellcaves, Canyon. +// The player will acquire the Phoenix Bow. + +// 5th unit +// Hive1, Hive2, Gauntlet, Hivetrialpit, Hivepriestess. +// The player will acquire the Meteor Barrier, the Firewall, and the Mace Ball. + +// 6th unit +// Oglemine1, Oglemine2, Dungeon. +// The player will acquire the Teleport Spell. + +// 7th unit +// Cloudhub, Cloudlabs, Cloudquarters, Cloudsanctum. +// All weapons have been acquired at this point. + +#define LMI_PROGRESS 1 +#define LMI_DRAW 2 +#define LMI_NODRAW 4 + +typedef struct level_map_info_s +{ + int hub; + int flags; + char *world_map; + char *city_map; + short message; + short pad; + int x, y; + int count; + int *dot_coords; +} level_map_info_t; + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/motion.h b/Toolkit/Programming/GameCode/qcommon/motion.h new file mode 100644 index 0000000..a6c84b2 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/motion.h @@ -0,0 +1,9 @@ +#include "H2Common.h" +#include "q_typedef.h" + +H2COMMON_API float GetTimeToReachDistance(float, float, float); +H2COMMON_API float GetDistanceOverTime(float, float, float); +H2COMMON_API void GetPositionOverTime(vec3_t, vec3_t, vec3_t, float, vec3_t); +H2COMMON_API void GetVelocityOverTime(vec3_t velocity, vec3_t accel, float time, vec3_t output); + +// end \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/netmsg read.c b/Toolkit/Programming/GameCode/qcommon/netmsg read.c new file mode 100644 index 0000000..d909d9b --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/netmsg read.c @@ -0,0 +1,361 @@ +#include "qcommon.h" +#include "assert.h" +#include "vector.h" + +// +// reading functions +// + +void MSG_BeginReading (sizebuf_t *msg) +{ + msg->readcount = 0; +} + +// returns -1 if no more characters are available +int MSG_ReadChar (sizebuf_t *msg_read) +{ + int c; + + if (msg_read->readcount+1 > msg_read->cursize) + c = -1; + else + c = (signed char)msg_read->data[msg_read->readcount]; + msg_read->readcount++; + + return c; +} + +int MSG_ReadByte (sizebuf_t *msg_read) +{ + int c; + + if (msg_read->readcount+1 > msg_read->cursize) + c = -1; + else + c = (unsigned char)msg_read->data[msg_read->readcount]; + msg_read->readcount++; + + return c; +} + +int MSG_ReadShort (sizebuf_t *msg_read) +{ + int c; + + if (msg_read->readcount+2 > msg_read->cursize) + c = -1; + else + c = (short)(msg_read->data[msg_read->readcount] + + (msg_read->data[msg_read->readcount+1]<<8)); + + msg_read->readcount += 2; + + return c; +} + +int MSG_ReadLong (sizebuf_t *msg_read) +{ + int c; + + if (msg_read->readcount+4 > msg_read->cursize) + c = -1; + else + c = msg_read->data[msg_read->readcount] + + (msg_read->data[msg_read->readcount+1]<<8) + + (msg_read->data[msg_read->readcount+2]<<16) + + (msg_read->data[msg_read->readcount+3]<<24); + + msg_read->readcount += 4; + + return c; +} + +float MSG_ReadFloat (sizebuf_t *msg_read) +{ + union + { + byte b[4]; + float f; + int l; + } dat; + + if (msg_read->readcount+4 > msg_read->cursize) + { + assert(0); + dat.f = -1; + } + else + { + dat.b[0] = msg_read->data[msg_read->readcount]; + dat.b[1] = msg_read->data[msg_read->readcount+1]; + dat.b[2] = msg_read->data[msg_read->readcount+2]; + dat.b[3] = msg_read->data[msg_read->readcount+3]; + } + msg_read->readcount += 4; + + dat.l = LittleLong (dat.l); + + return dat.f; +} + +char *MSG_ReadString (sizebuf_t *msg_read) +{ + static char string[2048]; + int l,c; + + l = 0; + do + { + c = MSG_ReadChar (msg_read); + if (c == -1 || c == 0) + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +char *MSG_ReadStringLine (sizebuf_t *msg_read) +{ + static char string[2048]; + int l,c; + + l = 0; + do + { + c = MSG_ReadChar (msg_read); + if (c == -1 || c == 0 || c == '\n') + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +float MSG_ReadCoord (sizebuf_t *msg_read) +{ + return MSG_ReadShort(msg_read) * (1.0/8); +} + +void MSG_ReadPos (sizebuf_t *msg_read, vec3_t pos) +{ + if(msg_read->readcount+6 > msg_read->cursize) + { + assert(0); + } + + pos[0] = MSG_ReadShort(msg_read) * (1.0/8); + pos[1] = MSG_ReadShort(msg_read) * (1.0/8); + pos[2] = MSG_ReadShort(msg_read) * (1.0/8); +} + +float MSG_ReadAngle (sizebuf_t *msg_read) +{ + return MSG_ReadChar(msg_read) * (360.0/256); +} + +float MSG_ReadAngle16 (sizebuf_t *msg_read) +{ + return SHORT2ANGLE(MSG_ReadShort(msg_read)); +} + +void MSG_ReadDeltaUsercmd (sizebuf_t *msg_read, usercmd_t *from, usercmd_t *move) +{ + int bits; + + memcpy (move, from, sizeof(*move)); + + // Read delta bits. + + bits=MSG_ReadShort(msg_read); + + // Read angles. + + if (bits & CM_ANGLE1) + move->angles[0] = MSG_ReadShort (msg_read); + if (bits & CM_ANGLE2) + move->angles[1] = MSG_ReadShort (msg_read); + if (bits & CM_ANGLE3) + move->angles[2] = MSG_ReadShort (msg_read); + + // Read aimangles. + + if (bits & CM_AIMANGLE1) + move->aimangles[0] = MSG_ReadShort (msg_read); + if (bits & CM_AIMANGLE2) + move->aimangles[1] = MSG_ReadShort (msg_read); + if (bits & CM_AIMANGLE3) + move->aimangles[2] = MSG_ReadShort (msg_read); + + // Read camera vieworigin. + + if (bits & CM_CAMERAVIEWORIGIN1) + move->camera_vieworigin[0] = MSG_ReadShort (msg_read); + if (bits & CM_CAMERAVIEWORIGIN2) + move->camera_vieworigin[1] = MSG_ReadShort (msg_read); + if (bits & CM_CAMERAVIEWORIGIN3) + move->camera_vieworigin[2] = MSG_ReadShort (msg_read); + + // Read camera viewangles. + + if (bits & CM_CAMERAVIEWANGLES1) + move->camera_viewangles[0] = MSG_ReadShort (msg_read); + if (bits & CM_CAMERAVIEWANGLES2) + move->camera_viewangles[1] = MSG_ReadShort (msg_read); + if (bits & CM_CAMERAVIEWANGLES3) + move->camera_viewangles[2] = MSG_ReadShort (msg_read); + + // Read movement. + + if (bits & CM_FORWARD) + move->forwardmove = MSG_ReadShort (msg_read); + if (bits & CM_SIDE) + move->sidemove = MSG_ReadShort (msg_read); + if (bits & CM_UP) + move->upmove = MSG_ReadShort (msg_read); + + // Read buttons. + + if (bits & CM_BUTTONS) + move->buttons = MSG_ReadShort (msg_read); + + // Read time to run command. + + move->msec = MSG_ReadByte (msg_read); + + // Read lightlevel. + + move->lightlevel = MSG_ReadByte (msg_read); +} + + +void MSG_ReadData (sizebuf_t *msg_read, void *data, int len) +{ + int i; + + for (i=0 ; i= NUMVERTEXNORMALS) + { + assert(0); + Com_Error (ERR_DROP, "MSF_ReadDir: out of range"); + } + VectorCopy (bytedirs[b], dir); +} + +void MSG_ReadDirMag (sizebuf_t *sb, vec3_t dir) +{ + int b; + + // Read in index into vector table + b = MSG_ReadByte (sb); + if (b >= NUMVERTEXNORMALS) + { + assert(0); + Com_Error (ERR_DROP, "MSF_ReadDirMag: out of range"); + } + VectorCopy (bytedirs[b], dir); + + // Scale by magnitude + b = MSG_ReadByte (sb); + Vec3ScaleAssign(10.0 * b, dir); +} + +void MSG_ReadShortYawPitch(sizebuf_t *sb, vec3_t dir) +{ + vec3_t angles; + + if(sb->readcount+4 > sb->cursize) + { + assert(0); + } + + angles[0] = MSG_ReadShort(sb) * (1.0/8); + angles[1] = MSG_ReadShort(sb) * (1.0/8); + angles[2] = 0; + + angles[YAW] = angles[YAW] * ANGLE_TO_RAD; + angles[PITCH] = angles[PITCH] * ANGLE_TO_RAD; + DirFromAngles(angles, dir); +} + +void MSG_ReadYawPitch(sizebuf_t *sb, vec3_t dir) +{ + int yb, pb; + float yaw, pitch; + vec3_t angles; + + yb = MSG_ReadByte(sb); + pb = MSG_ReadByte(sb); + + // Convert to signed degrees + yaw = (yb * (360.0 / 255.0)) - 180.0; + pitch = (pb * (180.0 / 255.0)) - 90.0; + + // Convert to radians + angles[YAW] = yaw * ANGLE_TO_RAD; + angles[PITCH] = pitch * ANGLE_TO_RAD; + DirFromAngles(angles, dir); +} + +void MSG_ReadEffects(sizebuf_t *msg_read, EffectsBuffer_t *fxBuf) +{ + size_t bufTypeSize; + + fxBuf->numEffects = MSG_ReadByte(msg_read); + + assert(fxBuf->numEffects >= 0); + + if(fxBuf->numEffects < 0) + { + Com_Error (ERR_DROP, "MSG_ReadEffects: number of effects < 0"); + return; + } + + if(fxBuf->numEffects == 0) + { + return; + } + + if(fxBuf->numEffects & 0x80) + { + fxBuf->numEffects &= ~0x80; + bufTypeSize = sizeof(short); + fxBuf->bufSize = MSG_ReadShort(msg_read); + } + else + { + bufTypeSize = sizeof(byte); + fxBuf->bufSize = MSG_ReadByte(msg_read); + } + + assert(fxBuf->bufSize > 0); + + if(fxBuf->numEffects <= 0) + { + Com_Error (ERR_DROP, "MSG_ReadEffects: bufSize not > 0"); + return; + } + + MSG_ReadData(msg_read, fxBuf->buf, fxBuf->bufSize); +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/p_actions2.h b/Toolkit/Programming/GameCode/qcommon/p_actions2.h new file mode 100644 index 0000000..e05e898 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_actions2.h @@ -0,0 +1,169 @@ +// +// p_actions2.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef _P_ACTIONS2_H_ +#define _P_ACTIONS2_H_ + +#include "p_types.h" +#include "p_anims2.h" + +#define SOUND_SWIM_FORWARD 0 +#define SOUND_SWIM_BACK 1 +#define SOUND_SWIM_SIDE 2 +#define SOUND_SWIM_UNDER 3 + +void PlayerActionHandFXStart(playerinfo_t *playerinfo, float value); +void PlayerActionHandFXEnd(playerinfo_t *playerinfo, float value); + +void PlayerActionSpellBegin(playerinfo_t *playerinfo, float value); +void PlayerActionSpellEnd(playerinfo_t *playerinfo, float value); + +void PlayerActionSpellChange(playerinfo_t *playerinfo, float value); +void PlayerActionWeaponChange(playerinfo_t *playerinfo, float value); +void PlayerActionArrowChange(playerinfo_t *playerinfo, float value); + +void PlayerActionSwordAttack(playerinfo_t *playerinfo, float value); +void PlayerActionSpellFireball(playerinfo_t *playerinfo, float value); +void PlayerActionSpellBlast(playerinfo_t *playerinfo, float value); +void PlayerActionSpellArray(playerinfo_t *playerinfo, float value); +void PlayerActionSpellSphereCreate(playerinfo_t *playerinfo, float value); +void PlayerActionSpellSphereCharge(playerinfo_t *playerinfo, float value); +void PlayerActionSpellSphereRelease(playerinfo_t *playerinfo, float value); +void PlayerActionSpellBigBall(playerinfo_t *playerinfo, float value); +void PlayerActionSpellFirewall(playerinfo_t *playerinfo, float value); +void PlayerActionRedRainBowAttack(playerinfo_t *playerinfo, float value); +void PlayerActionPhoenixBowAttack(playerinfo_t *playerinfo, float value); +void PlayerActionHellstaffAttack(playerinfo_t *playerinfo, float value); +void PlayerActionSpellDefensive(playerinfo_t *playerinfo, float value); + +void PlayerActionSwordTrailStart(playerinfo_t *playerinfo, float value); +void PlayerActionSwordTrailEnd(playerinfo_t *playerinfo, float value); +void PlayerActionRedRainBowTrailStart(playerinfo_t *playerinfo, float value); +void PlayerActionPhoenixBowTrailStart(playerinfo_t *playerinfo, float value); +void PlayerActionBowTrailEnd(playerinfo_t *playerinfo, float value); +void PlayerActionStartStaffGlow(playerinfo_t *playerinfo, float value); +void PlayerActionEndStaffGlow(playerinfo_t *playerinfo, float value); + +qboolean PlayerActionCheckVault(playerinfo_t *playerinfo, float value); +void PlayerActionSwimIdleSound(playerinfo_t *playerinfo, float value); +void PlayerActionSwimSound(playerinfo_t *playerinfo, float value); +//void PlayerActionSwimBackSound(playerinfo_t *playerinfo, float value); +void PlayerActionClimbWallSound(playerinfo_t *playerinfo, float value); +void PlayerActionClimbFinishSound(playerinfo_t *playerinfo, float value); + +void PlayerActionBreath(playerinfo_t *playerinfo, float value); +void PlayerActionFireBow(playerinfo_t *playerinfo, float value); +void PlayerActionFootstep(playerinfo_t *playerinfo, float value); +void PlayerActionSwim(playerinfo_t *playerinfo, float value); +void PlayerActionPullup(playerinfo_t *playerinfo, float value); +void PlayerActionSkidSmoke(playerinfo_t *playerinfo, float value); +void PlayerActionCheckGrab(playerinfo_t *playerinfo, float value); +void PlayerActionCheckFallingGrab(playerinfo_t *playerinfo, float value); +qboolean PlayerActionCheckJumpGrab(playerinfo_t *playerinfo, float value); +void PlayerActionSplashFeet(playerinfo_t *playerinfo, float value); +void PlayerActionBowSound(playerinfo_t *playerinfo, float value); +void PlayerActionIdleSound(playerinfo_t *playerinfo, float value); +void PlayerActionPushButton(playerinfo_t *playerinfo, float value); +void PlayerActionPushLever(playerinfo_t *playerinfo, float value); +void PlayerActionVaultSound(playerinfo_t *playerinfo, float value); +void PlayerActionBowReadySound(playerinfo_t *playerinfo, float value); +void PlayerActionTakePuzzle(playerinfo_t *playerinfo, float value); +void PlayerActionMoveItem(playerinfo_t *playerinfo, float value); + +qboolean PlayerActionCheckPuzzleGrab(playerinfo_t *playerinfo); +qboolean PlayerActionCheckPushPull(playerinfo_t *playerinfo); +qboolean PlayerActionCheckPushButton(playerinfo_t *playerinfo); +qboolean PlayerActionCheckPushLever(playerinfo_t *playerinfo); +qboolean PlayerActionCheckRopeGrab(playerinfo_t *playerinfo, float v_adjust); + +qboolean PlayerActionUsePuzzle(playerinfo_t *playerinfo); + +void PlayerMoveFunc(playerinfo_t *playerinfo, float fwd, float right, float up); +void PlayerClimbingMoveFunc(playerinfo_t *playerinfo, float fwd, float right, float up); +void PlayerMoveUpperFunc(playerinfo_t *playerinfo, float fwd, float right, float up); +void PlayerMoveForce(playerinfo_t *playerinfo, float fwd, float right, float height); +void PlayerMoveALittle(playerinfo_t *playerinfo, float fwd, float right, float up); +void PlayerPullupHeight(playerinfo_t *playerinfo, float height, float var2, float var3); + +void PlayerActionFlipForward(playerinfo_t *playerinfo, float value); +void PlayerActionJump(playerinfo_t *playerinfo, float value); +void PlayerActionJumpBack(playerinfo_t *playerinfo, float value); +void PlayerActionPushAway(playerinfo_t *playerinfo, float value); +void PlayerActionShrineEffect(playerinfo_t *playerinfo, float value); + +void PlayerActionStrafe(playerinfo_t *playerinfo, float value); + +void PlayerActionCheckWalkStrafe(playerinfo_t *playerinfo); +void PlayerActionCheckWalkUnStrafe(playerinfo_t *playerinfo); +void PlayerActionCheckWalkBStrafe(playerinfo_t *playerinfo); //FIXME: remove +void PlayerActionCheckWalkBUnStrafe(playerinfo_t *playerinfo); + +void PlayerActionCheckRunStrafe(playerinfo_t *playerinfo); +void PlayerActionCheckRunUnStrafe(playerinfo_t *playerinfo); + +void PlayerActionCheckDoubleJump( playerinfo_t *playerinfo ); +void PlayerMoveAdd(playerinfo_t *playerinfo); +void PlayerActionFlip(playerinfo_t *playerinfo, float value); +void PlayerActionTurn180(playerinfo_t *playerinfo); +void PlayerActionCheckCreepForward( playerinfo_t *playerinfo ); +void PlayerActionCheckCreepBack( playerinfo_t *playerinfo ); +void PlayerActionCheckVaultKick ( playerinfo_t *playerinfo ); + +void PlayerActionDrownFloatUp( playerinfo_t *playerinfo ); + +void PlayerJumpMoveForce(playerinfo_t *playerinfo, float fwd, float right, float up); +void PlayerActionCheckDive( playerinfo_t *playerinfo ); + +void PlayerActionCheckBowRefire( playerinfo_t *playerinfo ); +void PlayerActionCheckRopeMove( playerinfo_t *playerinfo, float foo ); + +void PlayerActionSetCrouchHeight( playerinfo_t *playerinfo ); +void PlayerActionCheckUncrouchToFinishSeq(playerinfo_t *playerinfo); +void PlayerActionCheckStrafe ( playerinfo_t *playerinfo ); + +void PlayerJumpNudge(playerinfo_t *playerinfo, float fwd, float right, float up); +void PlayerActionCheckHitGround(playerinfo_t *playerinfo); +void PlayerSetDeathLoop1(playerinfo_t *playerinfo); + +void PlayerActionCheckBranchWalking ( playerinfo_t *playerinfo ); +void PlayerActionCheckBranchRunningStrafe ( playerinfo_t *playerinfo ); + +H2COMMON_API void PlayerReleaseRope(playerinfo_t *playerinfo); +H2COMMON_API void KnockDownPlayer(playerinfo_t *playerinfo); +H2COMMON_API void PlayFly(playerinfo_t *playerinfo, float dist); +H2COMMON_API void PlaySlap(playerinfo_t *playerinfo, float dist); +H2COMMON_API void PlayScratch(playerinfo_t *playerinfo, float dist); +H2COMMON_API void PlaySigh(playerinfo_t *playerinfo, float dist); +H2COMMON_API void SpawnDustPuff(playerinfo_t *playerinfo, float dist); + +qboolean PlayerActionCheckCreepMoveBack( playerinfo_t *playerinfo ); +qboolean PlayerActionCheckCreepMoveForward( playerinfo_t *playerinfo ); + +void PlayerSwimMoveFunc(playerinfo_t *playerinfo, float fwd, float right, float up); + +void PlayerActionClimbStartSound(playerinfo_t *playerinfo, float value); +void PlayerPlaySlide(playerinfo_t *playerinfo); + +// JWEIER NEW ACTIONS +void PlayerActionCheckCreep( playerinfo_t *playerinfo ); +void PlayerActionCheckCreepUnStrafe( playerinfo_t *playerinfo ); + +void PlayerActionCheckCreepBack( playerinfo_t *playerinfo ); +void PlayerActionCheckCreepBackUnStrafe( playerinfo_t *playerinfo ); + +void PlayerActionCheckWalk( playerinfo_t *playerinfo ); +void PlayerActionCheckWalkUnStrafe( playerinfo_t *playerinfo ); + +void PlayerActionCheckWalkBack( playerinfo_t *playerinfo ); +void PlayerActionCheckWalkBackUnStrafe(playerinfo_t *playerinfo); + +void PlayerActionCheckRun( playerinfo_t *playerinfo ); +// JWEIER NEW ACTIONS END + +extern H2COMMON_API void PlayerInterruptAction(playerinfo_t *playerinfo); + +#endif //_P_ACTIONS2_H_ diff --git a/Toolkit/Programming/GameCode/qcommon/p_anim_branch2.h b/Toolkit/Programming/GameCode/qcommon/p_anim_branch2.h new file mode 100644 index 0000000..c6ca8c7 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_anim_branch2.h @@ -0,0 +1,43 @@ +// +// p_anim_branch2.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef _P_ANIM_BRANCH2_H_ +#define _P_ANIM_BRANCH2_H_ + +//Chicken Branch +int ChickenBranchLwrStanding(playerinfo_t *playerinfo); +int ChickenBranchidle(playerinfo_t *playerinfo); + +//Player Lower Branch +int BranchLwrStanding(playerinfo_t *playerinfo); +int BranchLwrStandingRun(playerinfo_t *playerinfo); +int BranchLwrRunning(playerinfo_t *playerinfo); +int BranchLwrWalking(playerinfo_t *playerinfo); +int BranchLwrShortstep(playerinfo_t *playerinfo); +int BranchLwrBackspring(playerinfo_t *playerinfo); +int BranchLwrCrouching(playerinfo_t *playerinfo); +int BranchLwrJumping(playerinfo_t *playerinfo); +int BranchLwrSliding(playerinfo_t *playerinfo); +int BranchLwrSurfaceSwim(playerinfo_t *playerinfo); +int BranchLwrUnderwaterSwim(playerinfo_t *playerinfo); +int BranchLwrHanging(playerinfo_t *playerinfo); +int BranchLwrClimbing(playerinfo_t *playerinfo); +int BranchLwrKnockDown(playerinfo_t *playerinfo); +int BranchLwrRunningStrafe(playerinfo_t *playerinfo); + +//Player Upper Branch +int BranchUprReady(playerinfo_t *playerinfo); +int BranchUprRdySpell(playerinfo_t *playerinfo); +int BranchUprRdyStaff(playerinfo_t *playerinfo); +int BranchUprRdyBow(playerinfo_t *playerinfo); +int BranchCheckAmmo(playerinfo_t *playerinfo); +int BranchCheckHellAmmo(playerinfo_t *playerinfo); +int BranchCheckMana(playerinfo_t *playerinfo); + + +H2COMMON_API qboolean BranchCheckDismemberAction(playerinfo_t *playerinfo, int weapon); +#endif // _P_ANIM_BRANCH2_H_ diff --git a/Toolkit/Programming/GameCode/qcommon/p_anim_data2.h b/Toolkit/Programming/GameCode/qcommon/p_anim_data2.h new file mode 100644 index 0000000..7b3bfeb --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_anim_data2.h @@ -0,0 +1,344 @@ +// +// p_anim_data2.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef _P_ANIM_DATA2_H_ +#define _P_ANIM_DATA2_H_ + +#include "p_anims2.h" + +typedef struct seqctrl_s +{ + int command; + int continueseq; + int ceaseseq; + int (*branchfunc)(playerinfo_t *playerinfo); +} seqctrl_t; + +enum weaponloc_e +{ + WPLOC_NONE, + WPLOC_BOTH, + WPLOC_HAND, + WPLOC_BACK +}; + +enum footsteptype_e +{ + STEP_NONE, + STEP_CREEP, + STEP_WALK, + STEP_RUN, + STEP_ROLL, + + STEP_OFFSET, + STEP_CREEP2, + STEP_WALK2, + STEP_RUN2, + STEP_ROLL2, + + STEP_MAX +}; + +extern char *SeqName[ASEQ_MAX]; +extern int PlayerAnimWeaponSwitchSeq[WEAPON_READY_MAX][WEAPON_READY_MAX]; +extern seqctrl_t SeqCtrl[ASEQ_MAX]; +extern H2COMMON_API paceldata_t PlayerSeqData[ASEQ_MAX]; +extern seqctrl_t ChickenCtrl[ASEQ_MAX]; +extern H2COMMON_API paceldata_t PlayerChickenData[ASEQ_MAX]; + +extern panimmove_t + player_move_nothing, + player_move_stand, + player_move_vaulthigh, + player_move_grabstartwall, + player_move_grabstartwall, + player_move_grabhold, + player_move_grabmoveleft, + player_move_grabmoveright, + player_move_pullupwall, + player_move_pullupwall, + player_move_spellfireball, + player_move_spellarray, + player_move_spellspherestart, + player_move_spellspherecharge, + player_move_spellspherefire1, + player_move_spellspherefire2, + player_move_spellspherefire3, + player_move_spellspherefire4, + player_move_spellfirewall, + player_move_spellripper, + player_move_spellbigball, + player_move_spellblast, + player_move_bowready, + player_move_rrbowdrawarrow, + player_move_phbowdrawarrow, + player_move_bowholdarrow, + player_move_rrbowfire, + player_move_phbowfire, + player_move_bowholdready, + player_move_bowunready, + player_move_hellready, // Ready hellstaff + player_move_hellfire1, // Fire hellstaff + player_move_hellfire2, // Fire hellstaff + player_move_hellunready, // Release hellstaff + player_move_spelldefensive, + player_move_spellchange, + player_move_staffatkstand1, + player_move_staffatkstand2, + player_move_staffatkspin, // Spin attack + player_move_staffatkspin2, // Spin attack + player_move_jumpflipback, // Backflip + player_move_jumpfliphandspringgo, // Handspring Start + player_move_jumpfliphandspring, // Handspring + player_move_staffatkstep2, + player_move_staffatkstep, + player_move_drawsword, + player_move_drawhell, + player_move_drawbow, + player_move_stowsword, + player_move_sword2hell, + player_move_sword2bow, + player_move_stowhell, + player_move_hell2sword, + player_move_hell2bow, + player_move_stowbow, + player_move_bow2sword, + player_move_bow2hell, + player_move_bow2bow, + player_move_pushbuttongo, + player_move_pushleverleft, + player_move_pushleverright, + player_move_takepuzzlepiece, + player_move_pivotleftgo, // Pivot to the left start anims + player_move_pivotleft, // Pivot to the left continue anims + player_move_pivotleftend, // Pivot to the left end + player_move_pivotrightgo, // Pivot to the right start anims + player_move_pivotright, // Pivot to the right continue anims + player_move_pivotrightend, // Pivot to the right end + player_move_turn180, + player_move_runstart, + player_move_run, + player_move_runstop, + player_move_walkstart, + player_move_walk, + player_move_walkstop, + player_move_creepforward, + player_move_creepforward_end, + + player_move_walkback, + + player_move_creepback, + player_move_creepback_end, + + player_move_crouchdown, + player_move_crouch, + player_move_crouchup, + player_move_crouchpivotleft, + player_move_crouchpivotright, + + player_move_strafeleft, + player_move_strafeleft_end, + + player_move_straferight, + player_move_straferight_end, + + player_move_standjumpstart, + player_move_standjumpfwdstart, + player_move_walkjumpfwdstart, + player_move_runjumpfwdstart, + player_move_jumpfwd, + player_move_jumpup, + player_move_jumpuploop, + player_move_jumpback, + player_move_jumpflipleft, + player_move_jumpflipright, + player_move_jumpflipback, + player_move_rolldivefwdwalk, + player_move_rolldivefwdrun, + player_move_rollfromfflip, + player_move_dash_forward, + player_move_dash_back, + player_move_polevault1walk, + player_move_polevault1run, + player_move_polevault2, + player_move_land1, + player_move_land3, + player_move_slide, + player_move_fall, + player_move_fallarmsup, + player_move_fallwalkstart, + player_move_fallwalkloop, + player_move_painstand, + player_move_painstand, + player_move_vaultwall, + player_move_sswimgo, + player_move_sswimidle, + player_move_sswimfwdgo, + player_move_sswimfwd, + player_move_sswimfwdstop, + player_move_sswimbackgo, + player_move_sswimback, + player_move_sswimbackstop, + player_move_sswim_left_go, + player_move_sswim_right_go, + player_move_sswim_left, + player_move_sswim_right, + player_move_sswim_left_stop, + player_move_sswim_right_stop, + player_move_swimstart, + player_move_grabstart, + player_move_grabloop, + player_move_pullup, + player_move_pulluphalfwall, + player_move_tumbleon1, + player_move_tumbleon2, + player_move_lstair4, + player_move_lstair8, + player_move_lstair12, + player_move_lstair16, + player_move_rstair4, + player_move_rstair8, + player_move_rstair12, + player_move_rstair16, + player_move_standreadystart, + player_move_standready, + player_move_standreadyend, + player_move_standlookleft, + player_move_standlookright, + player_move_paina, + player_move_painb, + player_move_pest1, + player_move_pest2, + player_move_fallleft, + player_move_fallright, + player_move_fallleftend, + player_move_fallrightend, + player_move_death1, + player_move_uswimfwd_go, + player_move_uswimfwd, + player_move_uswimfwd_end, + player_move_dive1, + player_move_swimgo, + player_move_swimidle, + player_move_uswimbackgo, + player_move_uswimback, + player_move_uswimbackstop, + player_move_uswim_left_go, + player_move_uswim_right_go, + player_move_uswim_left, + player_move_uswim_right, + player_move_uswim_left_stop, + player_move_uswim_right_stop, + player_move_slide_forward, + player_move_slide_backward, + player_move_resurface, + player_move_roll_l, + player_move_roll_r, + player_move_idle_under, + player_move_roll_b, + player_move_climb_on, + player_move_climb_up_start_r, + player_move_climb_up_start_l, + player_move_climb_up_r, + player_move_climb_up_l, + player_move_climb_down_start_r, + player_move_climb_down_start_l, + player_move_climb_down_r, + player_move_climb_down_l, + player_move_climb_off, + player_move_climb_hold_r, + player_move_climb_hold_l, + player_move_climb_settle_r, + player_move_climb_settle_l, + player_move_climb_idle_r, + player_move_climb_idle_l, + player_move_knockdown, + player_move_knockdown_getup, + player_move_knockdown_evade, + player_move_shrine, + player_move_pushpull_ready, + player_move_pushpull_stand, + player_move_push_go, + player_move_push, + player_move_push_end_l, + player_move_push_end_r, + player_move_takepuzzleunderwater, + player_move_pull_go, + player_move_pull, + player_move_pull_end, + player_move_drown, + player_move_forward_flip_l_go, + player_move_forward_flip_r_go, + player_move_forward_flip_l, + player_move_forward_flip_r, + + player_move_walk_strafe_left, + player_move_walk_strafe_right, + + player_move_run_strafe_left, + player_move_run_strafe_right, + + player_move_standjumpbackstart, + player_move_walkjumpbackstart, + player_move_runjumpbackstart, + player_move_jumpback, + player_move_jumpbackflip, + + player_move_standjumpleftstart, + player_move_walkjumpleftstart, + player_move_runjumpleftstart, + player_move_jumpleft, + player_move_jumpleftflip, + + player_move_standjumprightstart, + player_move_walkjumprightstart, + player_move_runjumprightstart, + player_move_jumpright, + player_move_jumprightflip, + + player_move_dash_back, + player_move_dash_forward, + + player_move_drown_idle, + + player_move_turn180, + + player_move_dash_left_go, + player_move_dash_left, + player_move_dash_right_go, + player_move_dash_right, + + player_move_walkb_strafe_left, + player_move_walkb_strafe_right, + + player_move_overhang, + player_move_death_b, + player_move_death_fly_forward_go, + player_move_death_fly_forward_loop, + player_move_death_fly_forward_end, + player_move_death_choke, + + player_move_idle_lookback, + player_move_idle_scratch_ass, + player_move_idle_wipe_brow, + + player_move_creepb_strafe_left, + player_move_creepb_strafe_right, + player_move_creep_strafe_left, + player_move_creep_strafe_right, + + player_move_crouch_creep_forward, + player_move_crouch_creep_back, + player_move_crouch_creep_left, + player_move_crouch_creep_right, + + player_move_swim_fast_go, + player_move_swim_fast, + player_move_staffatkback; + +#endif // _P_ANIM_DATA2_H_ + diff --git a/Toolkit/Programming/GameCode/qcommon/p_animactor.h b/Toolkit/Programming/GameCode/qcommon/p_animactor.h new file mode 100644 index 0000000..8ce5249 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_animactor.h @@ -0,0 +1,17 @@ +// +// p_animactor.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef _P_ANIMACTOR_H_ +#define _P_ANIMACTOR_H_ + +#include "p_types.h" + +extern H2COMMON_API void TurnOffPlayerEffects(playerinfo_t *playerinfo); +extern H2COMMON_API void AnimUpdateFrame(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerFallingDamage(playerinfo_t *playerinfo); + +#endif // _P_ANIMACTOR_H_ diff --git a/Toolkit/Programming/GameCode/qcommon/p_anims2.h b/Toolkit/Programming/GameCode/qcommon/p_anims2.h new file mode 100644 index 0000000..55aeae8 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_anims2.h @@ -0,0 +1,321 @@ +// +// p_anims2.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef _P_ANIMS2_H_ +#define _P_ANIMS2_H_ + +#include "p_types.h" + +extern H2COMMON_API void PlayerBasicAnimReset(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerAnimReset(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerAnimSetLowerSeq(playerinfo_t *playerinfo, int seq); +extern H2COMMON_API void PlayerAnimSetUpperSeq(playerinfo_t *playerinfo, int seq); +extern H2COMMON_API void PlayerAnimUpperIdle(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerAnimLowerIdle(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerAnimUpperUpdate(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerAnimLowerUpdate(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerAnimSetVault(playerinfo_t *playerinfo, int seq); +extern H2COMMON_API void PlayerPlayPain(playerinfo_t *playerinfo, int type); + +extern int PlayerAnimWeaponSwitch(playerinfo_t *playerinfo); + + +// ************************************************************************************************ +// seq_cmd_e +// --------- +// ************************************************************************************************ + +enum seq_cmd_e +{ + ACMD_NONE, + ACMDU_ATTACK, + ACMDU_SWITCHWPN, + ACMDU_DEFSPELL, + ACMDL_ACTION, + ACMDL_JUMP, + ACMDL_CROUCH, + ACMDL_CREEP_F, + ACMDL_WALK_F, + ACMDL_RUN_F, + ACMDL_FWD, + ACMDL_CREEP_B, + ACMDL_WALK_B, + ACMDL_RUN_B, + ACMDL_BACK, + ACMDL_STRAFE_L, + ACMDL_STRAFE_R, + ACMDL_ROTATE_L, + ACMDL_ROTATE_R, + ACMDL_QUICKTURN, + ACMD_MAX // NOTENOTE This is currently assumed to be 19 by the cmd array in gclient_t in g_local.h. + // DO NOT CHANGE THIS without mirroring this change in gclient_t. +}; + +// ************************************************************************************************ +// seq_anim_e +// --------- +// ************************************************************************************************ + +enum seq_anim_e +{ + ASEQ_NONE, + ASEQ_WSWORD_STD1, + ASEQ_WSWORD_STD2, + ASEQ_WSWORD_STEP2, + ASEQ_WSWORD_STEP, + ASEQ_WSWORD_ROUND_BACK, + ASEQ_WFIREBALL, + ASEQ_WARRAY, + ASEQ_WSPHERE_GO, + ASEQ_WSPHERE_HOLD, + ASEQ_WSPHERE_FIRE1, + ASEQ_WSPHERE_FIRE2, + ASEQ_WSPHERE_FIRE3, + ASEQ_WSPHERE_FIRE4, + ASEQ_WFIREWALL, + ASEQ_WRIPPER, + ASEQ_WBIGBALL, + ASEQ_WBLAST, + ASEQ_WRRBOW_GO, + ASEQ_WRRBOW_DRAW, + ASEQ_WRRBOW_HOLD, + ASEQ_WRRBOW_FIRE, + ASEQ_WRRBOW_READY, + ASEQ_WRRBOW_END, + ASEQ_WPHBOW_GO, + ASEQ_WPHBOW_DRAW, + ASEQ_WPHBOW_HOLD, + ASEQ_WPHBOW_FIRE, + ASEQ_WPHBOW_READY, + ASEQ_WPHBOW_END, + ASEQ_WHELL_GO, + ASEQ_WHELL_FIRE1, + ASEQ_WHELL_FIRE2, + ASEQ_WHELL_END, + ASEQ_SPELL_DEF, + ASEQ_HAND2HAND, + ASEQ_HAND2SWD, + ASEQ_HAND2HELL, + ASEQ_HAND2BOW, + ASEQ_SWD2HAND, + ASEQ_SWD2HELL, + ASEQ_SWD2BOW, + ASEQ_HELL2HAND, + ASEQ_HELL2SWD, + ASEQ_HELL2BOW, + ASEQ_BOW2HAND, + ASEQ_BOW2SWD, + ASEQ_BOW2HELL, + ASEQ_BOW2BOW, + ASEQ_PUSHBUTTON_GO, + ASEQ_PUSHLEVERLEFT, + ASEQ_PUSHLEVERRIGHT, + ASEQ_LOWER_BASE, + ASEQ_STAND, + ASEQ_PIVOTL_GO, + ASEQ_PIVOTL, + ASEQ_PIVOTL_END, + ASEQ_PIVOTR_GO, + ASEQ_PIVOTR, + ASEQ_PIVOTR_END, + ASEQ_TURN180, + ASEQ_RUNF_GO, + ASEQ_RUNF, + ASEQ_RUNF_END, + ASEQ_WALKF_GO, + ASEQ_WALKF, + ASEQ_WALKF_END, + ASEQ_CREEPF, + ASEQ_CREEPF_END, + ASEQ_WALKB, + ASEQ_CREEPB, + ASEQ_CREEPB_END, + ASEQ_CROUCH_GO, + ASEQ_CROUCH, + ASEQ_CROUCH_END, + ASEQ_CROUCH_PIVOTL, + ASEQ_CROUCH_PIVOTR, + ASEQ_STRAFEL, + ASEQ_STRAFEL_END, + ASEQ_STRAFER, + ASEQ_STRAFER_END, + ASEQ_JUMPSTD_GO, + ASEQ_JUMPFWD_SGO, + ASEQ_JUMPFWD_WGO, + ASEQ_JUMPFWD_RGO, + ASEQ_JUMPFWD, + ASEQ_JUMPUP, + ASEQ_JUMPUP_LOOP, + ASEQ_JUMPFLIPL, + ASEQ_JUMPFLIPR, + ASEQ_JUMPSPRINGBGO, + ASEQ_JUMPSPRINGB, + ASEQ_JUMPFLIPB, + ASEQ_ROLLDIVEF_W, + ASEQ_ROLLDIVEF_R, + ASEQ_ROLL_FROM_FFLIP, + ASEQ_POLEVAULT1_W, + ASEQ_POLEVAULT1_R, + ASEQ_POLEVAULT2, + ASEQ_LANDLIGHT, + ASEQ_LANDHEAVY, + ASEQ_FALLWALK_GO, + ASEQ_FALLRUN_GO, + ASEQ_FALL, + ASEQ_FALLARMSUP, + ASEQ_VAULT_LOW, + ASEQ_VAULT_HIGH, + ASEQ_PULLUP_WALL, + ASEQ_SSWIM_IDLE, + ASEQ_SSWIMF_GO, + ASEQ_SSWIMF, + ASEQ_SSWIMF_END, + ASEQ_SSWIMB_GO, + ASEQ_SSWIMB, + ASEQ_SSWIMB_END, + ASEQ_SSWIML_GO, + ASEQ_SSWIMR_GO, + ASEQ_SSWIML, + ASEQ_SSWIMR, + ASEQ_SSWIML_END, + ASEQ_SSWIMR_END, + ASEQ_WSWORD_SPIN, + ASEQ_WSWORD_SPIN2, + ASEQ_PULLUP_HALFWALL, + ASEQ_TUMBLEON1, + ASEQ_TUMBLEON2, + ASEQ_LSTAIR4, + ASEQ_LSTAIR8, + ASEQ_LSTAIR12, + ASEQ_LSTAIR16, + ASEQ_RSTAIR4, + ASEQ_RSTAIR8, + ASEQ_RSTAIR12, + ASEQ_RSTAIR16, + ASEQ_IDLE_READY_GO, + ASEQ_IDLE_READY, + ASEQ_IDLE_READY_END, + ASEQ_IDLE_LOOKL, + ASEQ_IDLE_LOOKR, + ASEQ_PAIN_A, + ASEQ_PAIN_B, + ASEQ_IDLE_FLY1, + ASEQ_IDLE_FLY2, + ASEQ_FALLL, + ASEQ_FALLR, + ASEQ_FALLL_END, + ASEQ_FALLR_END, + ASEQ_DEATH_A, + ASEQ_USWIMF_GO, + ASEQ_USWIMF, + ASEQ_USWIMF_END, + ASEQ_DIVE, + ASEQ_USWIMB_GO, + ASEQ_USWIMB, + ASEQ_USWIMB_END, + ASEQ_USWIML_GO, + ASEQ_USWIMR_GO, + ASEQ_USWIML, + ASEQ_USWIMR, + ASEQ_USWIML_END, + ASEQ_USWIMR_END, + ASEQ_SLIDE_FORWARD, + ASEQ_SLIDE_BACKWARD, + ASEQ_SSWIM_RESURFACE, + ASEQ_ROLL_L, + ASEQ_ROLL_R, + ASEQ_USWIM_IDLE, + ASEQ_ROLL_B, + ASEQ_CLIMB_ON, + ASEQ_CLIMB_UP_START_R, + ASEQ_CLIMB_UP_START_L, + ASEQ_CLIMB_UP_R, + ASEQ_CLIMB_UP_L, + ASEQ_CLIMB_DOWN_START_R, + ASEQ_CLIMB_DOWN_START_L, + ASEQ_CLIMB_DOWN_R, + ASEQ_CLIMB_DOWN_L, + ASEQ_CLIMB_OFF, + ASEQ_CLIMB_HOLD_R, + ASEQ_CLIMB_HOLD_L, + ASEQ_CLIMB_SETTLE_R, + ASEQ_CLIMB_SETTLE_L, + ASEQ_KNOCKDOWN, + ASEQ_KNOCKDOWN_GETUP, + ASEQ_KNOCKDOWN_EVADE, + ASEQ_SHRINE, + ASEQ_TAKEPUZZLEPIECE, + ASEQ_TAKEPUZZLEUNDERWATER, + ASEQ_DROWN, + ASEQ_FORWARD_FLIP_L_GO, + ASEQ_FORWARD_FLIP_R_GO, + ASEQ_FORWARD_FLIP_L, + ASEQ_FORWARD_FLIP_R, + ASEQ_CSTRAFE_LEFT, + ASEQ_CSTRAFE_RIGHT, + ASEQ_WSTRAFE_LEFT, + ASEQ_WSTRAFE_RIGHT, + ASEQ_RSTRAFE_LEFT, + ASEQ_RSTRAFE_RIGHT, + ASEQ_JUMPBACK_SGO, + ASEQ_JUMPBACK_WGO, + ASEQ_JUMPBACK_RGO, + ASEQ_JUMPBACK, + ASEQ_JUMPFLIPBACK, + ASEQ_JUMPLEFT_SGO, + ASEQ_JUMPLEFT_WGO, + ASEQ_JUMPLEFT_RGO, + ASEQ_JUMPLEFT, + ASEQ_JUMPFLIPLEFT, + ASEQ_JUMPRIGHT_SGO, + ASEQ_JUMPRIGHT_WGO, + ASEQ_JUMPRIGHT_RGO, + ASEQ_JUMPRIGHT, + ASEQ_JUMPFLIPRIGHT, + ASEQ_DROWN_IDLE, + ASEQ_DASH_LEFT_GO, + ASEQ_DASH_LEFT, + ASEQ_DASH_RIGHT_GO, + ASEQ_DASH_RIGHT, + ASEQ_CSTRAFEB_LEFT, + ASEQ_CSTRAFEB_RIGHT, + ASEQ_WSTRAFEB_LEFT, + ASEQ_WSTRAFEB_RIGHT, + ASEQ_OVERHANG, + ASEQ_DEATH_B, + ASEQ_DEATH_FLY1_GO, + ASEQ_DEATH_FLY1_LOOP, + ASEQ_DEATH_FLY1_END, + ASEQ_DEATH_CHOKE, + ASEQ_IDLE_LOOKBACK, + ASEQ_IDLE_SCRATCH_ASS, + ASEQ_IDLE_WIPE_BROW, + ASEQ_CROUCH_WALK_F, + ASEQ_CROUCH_WALK_B, + ASEQ_CROUCH_WALK_L, + ASEQ_CROUCH_WALK_R, + ASEQ_SSWIM_FAST_GO, + ASEQ_SSWIM_FAST, + ASEQ_MAX +}; + +// ************************************************************************************************ +// seq_data2_t +// ----------- +// ************************************************************************************************ + +typedef struct seq_data2_s +{ + char nosplit; + int viewheight; + int collideseq; + int waterseq; +} seq_data2_t; + +extern seq_data2_t PlayerSeqData2[ASEQ_MAX]; + +#endif // _P_ANIMS2_H_ diff --git a/Toolkit/Programming/GameCode/qcommon/p_chicken.h b/Toolkit/Programming/GameCode/qcommon/p_chicken.h new file mode 100644 index 0000000..bb4a623 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_chicken.h @@ -0,0 +1,79 @@ +#ifndef _P_CHICKEN_H_ +#define _P_CHICKEN_H_ + +#include "p_types.h" + +typedef enum SoundID_e +{ + SND_BITEHIT1, + SND_BITEMISS1, + SND_BITEMISS2, + + SND_SCRATCH, + + SND_HISS, + + SND_PAIN1, + SND_PAIN2, + + SND_CHATTER1, + SND_CHATTER2, + SND_CHATTER3, + + SND_CHEW1, + SND_CHEW2, + SND_CHEW3, + + SND_SWALLOW, + + SND_DIE, + SND_GIB, + NUM_SOUNDS +} SoundID_t; + +extern panimmove_t chicken_move_stand1; +extern panimmove_t chicken_move_walk; +extern panimmove_t chicken_move_run; +extern panimmove_t chicken_move_cluck; +extern panimmove_t chicken_move_attack; +extern panimmove_t chicken_move_eat; +extern panimmove_t chicken_move_jump; + +//Dummy anim to catch sequence leaks +extern panimmove_t chickenp_move_dummy; + +extern panimmove_t chickenp_move_stand; +extern panimmove_t chickenp_move_stand1; +extern panimmove_t chickenp_move_stand2; +extern panimmove_t chickenp_move_walk; +extern panimmove_t chickenp_move_run; +extern panimmove_t chickenp_move_back; +extern panimmove_t chickenp_move_runb; +extern panimmove_t chickenp_move_bite; +extern panimmove_t chickenp_move_strafel; +extern panimmove_t chickenp_move_strafer; +extern panimmove_t chickenp_move_jump; +extern panimmove_t chickenp_move_wjump; +extern panimmove_t chickenp_move_wjumpb; +extern panimmove_t chickenp_move_rjump; +extern panimmove_t chickenp_move_rjumpb; +extern panimmove_t chickenp_move_jump_loop; +extern panimmove_t chickenp_move_attack; +extern panimmove_t chickenp_move_jump_flap; +extern panimmove_t chickenp_move_runattack; +extern panimmove_t chickenp_move_swim_idle; +extern panimmove_t chickenp_move_swim; + +void PlayerChickenBite(playerinfo_t *playerinfo); +void PlayerChickenSqueal(playerinfo_t *playerinfo); +int PlayerChickenJump(playerinfo_t *playerinfo); + +void PlayerChickenFlap ( playerinfo_t *playerinfo ); +void PlayerChickenCheckFlap ( playerinfo_t *playerinfo ); + +void ChickenAssert(playerinfo_t *playerinfo); +void PlayerChickenCluck(playerinfo_t *playerinfo, float force); + +void ChickenStepSound(playerinfo_t *playerinfo, float value); + +#endif // _P_CHICKEN_H_ \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/p_ctrl2.h b/Toolkit/Programming/GameCode/qcommon/p_ctrl2.h new file mode 100644 index 0000000..ff2e6f0 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_ctrl2.h @@ -0,0 +1,15 @@ +// +// p_ctrl2.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef _P_CTRL2_H_ +#define _P_CTRL2_H_ + +#include "p_actions2.h" + +extern H2COMMON_API void PlayerIntLand(playerinfo_t *playerinfo_t, float landspeed); + +#endif //_P_CTRL2_H_ diff --git a/Toolkit/Programming/GameCode/qcommon/p_dll.c b/Toolkit/Programming/GameCode/qcommon/p_dll.c new file mode 100644 index 0000000..41c9836 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_dll.c @@ -0,0 +1,73 @@ +// +// ce_Message.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN + +#include + +#include "qcommon.h" +#include "g_local.h" + +void Sys_LoadGameDll(const char *name, HINSTANCE *hinst, DWORD *chkSum); +void Sys_UnloadGameDll (const char *name, HINSTANCE *hinst); + +void (*P_Init)(); +void (*P_Shutdown)(); + +static HINSTANCE player_library = NULL; // Handle to player DLL + +void P_Freelib() +{ + if(!player_library) + { + return; + } + + P_Shutdown(); + +#if _GAME_DLL + gi.Sys_UnloadGameDll("Player", &player_library); +#else + Sys_UnloadGameDll("Player", &player_library); +#endif +} + +void P_Load(char *name) +{ + DWORD chkSum; + + P_Freelib(); + +#if _GAME_DLL + Com_Printf("------- Loading %s -------\n", name); + gi.Sys_LoadGameDll(name, &player_library, &chkSum); +#else + Com_ColourPrintf(P_HEADER, "------- Loading %s -------\n", name); + Sys_LoadGameDll(name, &player_library, &chkSum); +#endif + + if((P_Init = (void *)GetProcAddress(player_library, "P_Init")) == 0) + { + Sys_Error ("GetProcAddress failed on P_Init for library %s", name); + } + + if((P_Shutdown = (void *)GetProcAddress(player_library, "P_Shutdown")) == 0) + { + Sys_Error("GetProcAddress failed on P_Shutdown for library %s", name); + } + + P_Init(); // this may not be the best place to call this; remains to be seen -JKH + +#if _GAME_DLL + Com_Printf("------------------------------------\n"); +#else + Com_ColourPrintf(P_HEADER, "------------------------------------\n"); +#endif +} + diff --git a/Toolkit/Programming/GameCode/qcommon/p_main2.h b/Toolkit/Programming/GameCode/qcommon/p_main2.h new file mode 100644 index 0000000..686b7e9 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_main2.h @@ -0,0 +1,67 @@ +// +// p_main2.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef _P_MAIN2_H_ +#define _P_MAIN2_H_ + +#include "h2common.h" +#include "p_types.h" + +#define PLAYER_FLAG_NONE 0x00000000 +#define PLAYER_FLAG_FALLING 0x00000001 +#define PLAYER_FLAG_IDLE 0x00000002 +#define PLAYER_FLAG_FALLBREAK 0x00000004 +#define PLAYER_FLAG_BOWDRAWN 0x00000008 +#define PLAYER_FLAG_TURNLOCK 0x00000010 +#define PLAYER_FLAG_TURNDAMP 0x00000020 +#define PLAYER_FLAG_SURFSWIM 0x00000040 +#define PLAYER_FLAG_UNDERWATER 0x00000080 +//#define PLAYER_FLAG_COLLISION 0x00000100 //Move out of lower segment +//#define PLAYER_FLAG_DIVE 0x00000200 //Move out of lower segment +//#define PLAYER_FLAG_SLIDE 0x00000400 //Move out of lower segment +#define PLAYER_FLAG_RESIZED 0x00000100 +#define PLAYER_FLAG_ONROPE 0x00000200 +#define PLAYER_FLAG_STAND 0x00000400 +//#define PLAYER_FLAG_KNOCKDOWN 0x00002000 //Move out of lower segment +#define PLAYER_FLAG_TURN180 0x00000800 +//#define PLAYER_FLAG_RELEASEROPE 0x00008000 //Move out of lower segment + +// We MASK out the low two bytes every time an animation is set. +#define PLAYER_FLAG_ANIMMASK 0x0000FFFF +#define PLAYER_FLAG_PERSMASK 0xFFFF0000 + +// The two high bytes are persistent. +#define PLAYER_FLAG_TELEPORT 0x00010000 +#define PLAYER_FLAG_MORPHING 0x00020000 +#define PLAYER_FLAG_LOCKMOVE_WAS_SET 0x00040000 +#define PLAYER_FLAG_USE_ENT_POS 0x00080000 +#define PLAYER_FLAG_BLEED 0x00100000 // player is bleeding +#define PLAYER_FLAG_NO_LARM 0x00200000 // player lost left arm +#define PLAYER_FLAG_NO_RARM 0x00400000 // player lost right arm +#define PLAYER_FLAG_ALTFIRE 0x00800000 // This alternates every time a weapon fires, so they don't cut out. +#define PLAYER_FLAG_COLLISION 0x01000000 +#define PLAYER_FLAG_DIVE 0x02000000 +#define PLAYER_FLAG_SLIDE 0x04000000 +#define PLAYER_FLAG_KNOCKDOWN 0x08000000 +#define PLAYER_FLAG_RELEASEROPE 0x10000000 + +//#define PLAYER_FLAG_RESIZED 0x01000000 //Move out of upper segment + +#define PLAYER_FLAG_WATER (PLAYER_FLAG_UNDERWATER | PLAYER_FLAG_SURFSWIM) + +extern H2COMMON_API void PlayerInit(playerinfo_t *playerinfo, int complete_reset); +extern H2COMMON_API void PlayerClearEffects(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerUpdate(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerUpdateCmdFlags(playerinfo_t *playerinfo); +extern H2COMMON_API void PlayerUpdateModelAttributes(playerinfo_t *playerinfo); +extern void PlayerSetHandFX(playerinfo_t *playerinfo, int handfxtype, int lifetime); + +//Information for creep fall checking +#define CREEP_MAXFALL 18 +#define CREEP_STEPDIST 30 + +#endif // _P_MAIN2_H_ diff --git a/Toolkit/Programming/GameCode/qcommon/p_types.h b/Toolkit/Programming/GameCode/qcommon/p_types.h new file mode 100644 index 0000000..4f7b580 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_types.h @@ -0,0 +1,722 @@ +// +// p_types.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef _P_TYPES_H_ +#define _P_TYPES_H_ + +#include "q_shared.h" +#include "q_clientserver.h" +#include "g_itemstats.h" + +// Forward define 'playerinfo_t' for use in 'panimframe_t' and 'panimmove_t'. + +typedef struct playerinfo_s playerinfo_t; + +// ************************************************************************************************ +// panimframe_t +// ------------ +// ************************************************************************************************ + +typedef struct +{ + int framenum; + void (*movefunc)(playerinfo_t *playerinfo,float var1,float var2,float var3); + float var1,var2,var3; + void (*actionfunc)(playerinfo_t *playerinfo,float var4); + float var4; + void (*thinkfunc)(playerinfo_t *playerinfo); +} panimframe_t; + +// ************************************************************************************************ +// panimmove_t +// ----------- +// ************************************************************************************************ + +typedef struct +{ + int numframes; + panimframe_t *frame; + void (*endfunc)(playerinfo_t *playerinfo); +} panimmove_t; + +// ************************************************************************************************ +// paceldata_t +// ----------- +// ************************************************************************************************ + +typedef struct +{ + panimmove_t *move; + void (*animfunc)(playerinfo_t *playerinfo, int animcell); + short fly; + short lockmove; + int playerflags; +} paceldata_t; + +// ************************************************************************************************ +// pacelsizes_t +// ------------ +// ************************************************************************************************ + +typedef struct +{ + vec3_t boundbox[2]; + int altmove; + float viewheight; + float waterheight; +} pacelsizes_t; + +// ************************************************************************************************ +// gitem_armour_t +// -------------- +// ************************************************************************************************ + +typedef struct +{ + float max_armor; + float normal_protection; + float spell_protection; +} gitem_armor_t; + +// ************************************************************************************************ +// weaponready_e +// ------------- +// Indicates what actual weapon model the player has readied. +// ************************************************************************************************ + +enum weaponready_e +{ + WEAPON_READY_NONE, + WEAPON_READY_HANDS, + WEAPON_READY_STAFFSTUB, + WEAPON_READY_SWORDSTAFF, + WEAPON_READY_HELLSTAFF, + WEAPON_READY_BOW, + WEAPON_READY_MAX +}; + +// ************************************************************************************************ +// armortype_e +// ----------- +// Indicates what actual armor the player is wearing. +// ************************************************************************************************ + +enum armortype_e +{ + ARMOR_TYPE_NONE, + ARMOR_TYPE_SILVER, + ARMOR_TYPE_GOLD +}; + +// ************************************************************************************************ +// bowtype_e +// ----------- +// Indicates what actual bow the player has currently on his back. +// ************************************************************************************************ + +enum bowtype_e +{ + BOW_TYPE_NONE, + BOW_TYPE_REDRAIN, + BOW_TYPE_PHOENIX +}; + +// ************************************************************************************************ +// stafftype_e +// ----------- +// Indicates what powerup level of the staff the player has. +// ************************************************************************************************ + +enum stafftype_e +{ + STAFF_LEVEL_NONE, + STAFF_LEVEL_BASIC, + STAFF_LEVEL_POWER1, + STAFF_LEVEL_POWER2, + STAFF_LEVEL_MAX +}; + +// ************************************************************************************************ +// helltype_e +// ----------- +// Indicates what powerup level of the staff the player has. +// ************************************************************************************************ + +enum helltype_e +{ + HELL_TYPE_NONE, + HELL_TYPE_BASIC, + HELL_TYPE_POWER +}; + +// ************************************************************************************************ +// ammo_t +// ------ +// ************************************************************************************************ + +typedef enum +{ + MODEL_HEALTH1, + MODEL_HEALTH2, + AMMO_BULLETS, + AMMO_SHELLS, + AMMO_ROCKETS, + AMMO_GRENADES, + AMMO_CELLS, + AMMO_SLUGS +} ammo_t; + +#define PICKUP_MIN 0, 0, 0 +#define PICKUP_MAX 0, 0, 0 + +// ************************************************************************************************ +// PNOISE_XXX +// ---------- +// Noise types for 'PlayerNoise'. +// ************************************************************************************************ + +#define PNOISE_SELF 0 +#define PNOISE_WEAPON 1 +#define PNOISE_IMPACT 2 + +// ************************************************************************************************ +// skintype_e +// ----------- +// Indicates what skin Corvus has. On the model, there is actually a pain skin in between each of these +// ************************************************************************************************ + +enum skincooptype_e +{ + SKIN_TYPE_COOP_CORVUS, + SKIN_TYPE_COOP_NUBIAN, + SKIN_TYPE_COOP_ROGUE, + SKIN_TYPE_COOP_BRIGAND, + SKIN_NUM_COOP_TYPES +}; + +enum skindeathmatchtype_e +{ + SKIN_TYPE_DM_VALKYRIE, + SKIN_TYPE_DM_SPIDER, + SKIN_TYPE_DM_THIEFKING, + SKIN_TYPE_DM_RONIN, + SKIN_TYPE_DM_SOULTAKER, + SKIN_TYPE_DM_PATCHWORK, + SKIN_TYPE_DM_DEMON, + SKIN_TYPE_DM_MVP, + SKIN_NUM_DM_TYPES +}; + +// For code clarity +#define PLAGUE_NUM_LEVELS 3 +#define DAMAGE_NUM_LEVELS 2 + +#define SKIN_DM_OFFSET (PLAGUE_NUM_LEVELS * DAMAGE_NUM_LEVELS * SKIN_NUM_COOP_TYPES) +#define REFLECTION_SKIN (SKIN_DM_OFFSET + (DAMAGE_NUM_LEVELS * SKIN_NUM_DM_TYPES)) + + +// ************************************************************************************************ +// IT_XXX +// ------ +// Held in 'gitem_t'->flags. +// ************************************************************************************************ + +#define IT_WEAPON 1 // use makes active weapon +#define IT_AMMO 2 +#define IT_ARMOR 4 +#define IT_STAY_COOP 8 +#define IT_PUZZLE 16 +#define IT_DEFENSE 32 + +// ************************************************************************************************ +// gitem_t +// ------- +// ************************************************************************************************ + +typedef struct gitem_s +{ + // Spawning name. + + char *classname; + char *pickup_name; + + short msg_pickup; // pickup + short msg_nouse; // can`t use + + // Access function pointers. + + qboolean (*pickup)(struct edict_s *ent, struct edict_s *other); + void (*use)(playerinfo_t *playerinfo, struct gitem_s *item); + void (*drop)(struct edict_s *ent, struct gitem_s *item); + void (*weaponthink)(struct edict_s *WeaponOwner,char *Format,...); + + char *pickup_sound; + char *world_model; + int world_model_flags; + + vec3_t mins; // Bounding box + vec3_t maxs; // Bounding box + + int playeranimseq; // The ASEQ_ player sequence that should be engaged when this item is used. + int altanimseq; // Powerup animation sequence + + int MaxActive; // Maximum allowable active uses of items of this type by a single + // player, at any instant in time. -1 indicates no limit. + + // Client side information. + + int count_width; // Number of digits to display by icon. + + int quantity; // For ammo, how much. For weapons, how much is used per shot. + char *ammo; // For weapons + int flags; // IT_XXX. + + void *info; + int tag; + + char *icon; +} gitem_t; + +extern H2COMMON_API gitem_t *p_itemlist; +extern H2COMMON_API int p_num_items; + +#define ITEM_INDEX(x) GetItemIndex(x) + +extern H2COMMON_API int GetItemIndex(gitem_t* x); +extern H2COMMON_API gitem_t *GetItemByIndex(int index); +extern H2COMMON_API gitem_t *FindItemByClassname(char *classname); +extern H2COMMON_API gitem_t *FindItem(char *pickupname); +extern H2COMMON_API void InitItems(void); + +// ************************************************************************************************ +// inventory_t +// ----------- +// Holds the players inventory. +// ************************************************************************************************ + +typedef struct inventory_s +{ + int Items[MAX_ITEMS]; // No held of each item type. + float Timer[MAX_ITEMS]; // Timer (if this item requires one). +} inventory_t; + +// ************************************************************************************************ +// client_persistant_t +// ------------------- +// Client data that stays across multiple level loads. +// ************************************************************************************************ + +typedef struct +{ + // ******************************************************************************************** + // User info. + // ******************************************************************************************** + + char userinfo[MAX_INFO_STRING]; + char netname[16]; + char sounddir[MAX_QPATH]; + int autoweapon; + + // A loadgame will leave valid entities that just don't have a connection yet. + + qboolean connected; + + // ******************************************************************************************** + // Values that are saved from and restored to 'edict_t's when changing levels. + // ******************************************************************************************** + + // Health. + + int health; + int max_health; + + short mission_num1; + short mission_num2; + + // Visible model attributes. + + int weaponready; + byte armortype; // Current armour Corvus is wearing. + byte bowtype; // Current bow and what kind (when it is on Corvus' back too). + byte stafflevel; // Current powerup level for the staff. + byte helltype; // Current skin on the hellstaff. + byte handfxtype; // Current spell effect Corvus has attached to his refpoints. + short skintype; // Skin index that reflects plague stages and alternate skins + unsigned int altparts; // Missing hands, heads etc. + + // Inventory. + + inventory_t inventory; + inventory_t old_inventory; + int selected_item; + + // Ammo capacities. + + int max_offmana; + int max_defmana; + int max_redarrow; + int max_phoenarr; + int max_hellstaff; + + // Offenses and defenses. + + gitem_t *weapon,*lastweapon, + *defence,*lastdefence, + *newweapon; + + // For calculating total unit score in co-op games. + int score; + +} client_persistant_t; + +// ************************************************************************************************ +// FL_XXX +// ------ +// Held in 'edict_t'->flags. +// ************************************************************************************************ + +#define FL_FLY 0x00000001 +#define FL_SWIM 0x00000002 // implied immunity to drowining +#define FL_SUSPENDED 0x00000004 +#define FL_INWATER 0x00000008 +#define FL_GODMODE 0x00000010 +#define FL_NOTARGET 0x00000020 +#define FL_IMMUNE_SLIME 0x00000040 +#define FL_IMMUNE_LAVA 0x00000080 +#define FL_PARTIALGROUND 0x00000100 // not all corners are valid +#define FL_INLAVA 0x00000200 // INWATER is set when in lava, but this is a modifier so we know when we leave +#define FL_TEAMSLAVE 0x00000400 // not the first on the team +#define FL_NO_KNOCKBACK 0x00000800 +#define FL_INSLIME 0x00001000 // INWATER is set when in muck, but this is a modifier so we know when we leave +#define FL_LOCKMOVE 0x00002000 // Move updates should not process, actor can only move explicitly +#define FL_DONTANIMATE 0x00004000 // stop animating +#define FL_AVERAGE_CHICKEN 0x00008000 // Currently a chicken. +#define FL_AMPHIBIAN 0x00010000 // Does not drown on land or in water, but is damaged by muck and lava +#define FL_SUPER_CHICKEN 0x00020000 // Ah yeah... +#define FL_RESPAWN 0x80000000 // used for item respawning + +#define FL_CHICKEN (FL_AVERAGE_CHICKEN | FL_SUPER_CHICKEN) + +// ************************************************************************************************ +// movetype_t +// ---------- +// 'edict_t'->movetype values. +// ************************************************************************************************ + +typedef enum physicsType_e +{ + // new system + PHYSICSTYPE_NONE, // MOVETYPE_NONE 0 + PHYSICSTYPE_STATIC, + PHYSICSTYPE_NOCLIP, // MOVETYPE_NOCLIP 2 + PHYSICSTYPE_FLY, // MOVETYPE_FLY 3 + PHYSICSTYPE_STEP, // MOVETYPE_WALK, MOVETYPE_STEP, MOVETYPE_TOSS, MOVETYPE_BOUNCE + PHYSICSTYPE_PUSH, // MOVETYPE_PUSH 5 + PHYSICSTYPE_STOP, // MOVETYPE_STOP 6 + MOVETYPE_FLYMISSILE, // MOVETYPE_FYMISSILE (extra size to monsters) + PHYSICSTYPE_SCRIPT_ANGULAR, // MOVETYPE_SCRIPT_ANGULAR 8 + NUM_PHYSICSTYPES, + + MOVETYPE_NONE, // never moves + MOVETYPE_NOCLIP, // origin and angles change with no interaction + MOVETYPE_PUSH, // no clip to world, push on box contact + MOVETYPE_STOP, // no clip to world, stops on box contact + MOVETYPE_WALK, // gravity + MOVETYPE_STEP, // gravity, special edge handling + MOVETYPE_FLY, + MOVETYPE_TOSS, // gravity + MOVETYPE_BOUNCE, + + MOVETYPE_SCRIPT_ANGULAR, // moves with the rotation of another entity +} physicsType_t; + +// ************************************************************************************************ +// DEAD_XXX +// -------- +// Held in 'edict_t'->deadflag. +// ************************************************************************************************ + +typedef enum deadState_e +{ + DEAD_NO=0, + DEAD_DYING, + DEAD_DEAD, + NUM_DEADSTATE +} deadState_t; + +// ************************************************************************************************ +// HANDFX_XXX +// ---------- +// Hand effects, glowing for spells. Can be used for staff and bow, or others that are used by the +// upper torso half and toggle. +// ************************************************************************************************ + +typedef enum handfx_e +{ + HANDFX_NONE=0, + HANDFX_FIREBALL, + HANDFX_MISSILE, + HANDFX_SPHERE, + HANDFX_MACEBALL, + HANDFX_FIREWALL, + HANDFX_REDRAIN, + HANDFX_POWERREDRAIN, + HANDFX_PHOENIX, + HANDFX_POWERPHOENIX, + HANDFX_STAFF1, + HANDFX_STAFF2, + HANDFX_STAFF3, + HANDFX_MAX, +} handfx_t; + +// ************************************************************************************************ +// playerinfo_t +// ------------ +// This is the information needed by the player animation system on both the client and server. +// ************************************************************************************************ + +typedef struct playerinfo_s +{ + // ******************************************************************************************** + // Inputs only. + // ******************************************************************************************** + + // Client side function callbacks (approximating functionality of server function callbacks). + + void (*CL_Sound)(vec3_t origin,int channel,char *soundname,float fvol,int attenuation,float timeofs); + void (*CL_Trace)(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,int brushmask,int flags,trace_t *trace); + void (*CL_CreateEffect)(void); + void (*CL_RemoveEffects)(void); + + // Server (game) function callbacks (approximating functionality of client-side function callbacks). + + void (*G_Sound)(edict_t *entity,int channel,int sound_num,float volume,float attenuation,float timeofs); + void (*G_Trace)(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,edict_t *passent,int contentmask,trace_t *trace); + void (*G_CreateEffect)(entity_state_t *state,int type,int flags,vec3_t origin,char *format,...); + void (*G_RemoveEffects)(entity_state_t *state,int type); + + // Server (game) function callbacks that have no client side equivalent. + + int (*G_SoundIndex)(char *name); + void (*G_SoundRemove)(char *name); + void (*G_UseTargets)(edict_t *ent,edict_t *activator); + entity_state_t *(*G_GetEntityStatePtr)(edict_t *entity); + int (*G_BranchLwrClimbing)(playerinfo_t *playerinfo); + qboolean (*G_PlayerActionCheckRopeGrab)(playerinfo_t *playerinfo, float stomp_org); + void (*G_PlayerClimbingMoveFunc)(playerinfo_t *playerinfo, float height, float var2, float var3); + qboolean (*G_PlayerActionCheckPuzzleGrab)(playerinfo_t *playerinfo); + void (*G_PlayerActionTakePuzzle)(playerinfo_t *playerinfo); + qboolean (*G_PlayerActionUsePuzzle)(playerinfo_t *playerinfo); + qboolean (*G_PlayerActionCheckPushPull_Ent)(edict_t *ent); + void (*G_PlayerActionMoveItem)(playerinfo_t *playerinfo,float distance); + qboolean (*G_PlayerActionCheckPushButton)(playerinfo_t *playerinfo); + void (*G_PlayerActionCheckHitGround)(playerinfo_t *playerinfo); + void (*G_PlayerActionPushButton)(playerinfo_t *playerinfo); + qboolean (*G_PlayerActionCheckPushLever)(playerinfo_t *playerinfo); + void (*G_PlayerActionPushLever)(playerinfo_t *playerinfo); + qboolean (*G_HandleTeleport)(playerinfo_t *playerinfo); + void (*G_PlayerActionShrineEffect)(playerinfo_t *playerinfo); + void (*G_PlayerActionChickenBite)(playerinfo_t *playerinfo); + void (*G_PlayerFallingDamage)(playerinfo_t *playerinfo,float delta); + void (*G_PlayerSpellShieldAttack)(playerinfo_t *playerinfo); + void (*G_PlayerSpellStopShieldAttack)(playerinfo_t *playerinfo); + void (*G_PlayerVaultKick)(playerinfo_t *playerinfo); + void (*G_PlayerActionCheckRopeMove)(playerinfo_t *playerinfo); + void (*G_gamemsg_centerprintf)(edict_t *ent, short msg); + void (*G_levelmsg_centerprintf)(edict_t *ent, short msg); + void (*G_WeapNext)(edict_t *ent); + void (*G_UseItem)(edict_t *ent, char *s); + + // Common client & server (game) function callbacks. + + int (*PointContents)(vec3_t point); + void (*SetJointAngles)(playerinfo_t *playerinfo); + void (*ResetJointAngles)(playerinfo_t *playerinfo); + void (*PlayerActionSwordAttack)(playerinfo_t *playerinfo,int value); + void (*PlayerActionSpellFireball)(playerinfo_t *playerinfo); + void (*PlayerActionSpellBlast)(playerinfo_t *playerinfo); + void (*PlayerActionSpellArray)(playerinfo_t *playerinfo,int value); + void (*PlayerActionSpellSphereCreate)(playerinfo_t *playerinfo,qboolean *Charging); + void (*PlayerActionSpellFirewall)(playerinfo_t *playerinfo); + void (*PlayerActionSpellBigBall)(playerinfo_t *playerinfo); + void (*PlayerActionRedRainBowAttack)(playerinfo_t *playerinfo); + void (*PlayerActionPhoenixBowAttack)(playerinfo_t *playerinfo); + void (*PlayerActionHellstaffAttack)(playerinfo_t *playerinfo); + void (*PlayerActionSpellDefensive)(playerinfo_t *playerinfo); + qboolean (*G_EntIsAButton)(edict_t *ent); + int (*irand)(playerinfo_t *playerinfo,int mn,int mx); + + // Indicates whether this playerinfo_t is held on the client or server. + + qboolean isclient; + + // This is client only and records the highest level time the anim has run... we use this to + // prevent multiple sounds etc. Logic is basically if(!ishistory) playsound... + + float Highestleveltime; + qboolean ishistory; + + // Pointer to the associated player's edict_t. + + void *self; + + // Game .dll variables. + + float leveltime; + + // Server variables. + + float sv_gravity; + float sv_cinematicfreeze; // Not used on client. + float sv_jumpcinematic; // Jumping through cinematic. Not used on client. + + // From edict_t. + + float ideal_yaw; + void *groundentity; + + // From pmove_t. + + csurface_t *GroundSurface; + cplane_t GroundPlane; + int GroundContents; + + // Pointer to entity_state_t of player's enemy edict. + + entity_state_t *enemystate; + + // Spell / weapon aiming direction (from g_client_t). + + vec3_t aimangles; + + // Deathmatch flags. + + int dmflags; + + // ******************************************************************************************** + // Inputs & outputs. + // ******************************************************************************************** + + // Data that must be maintatined over the duration of a level. + + client_persistant_t pers; + + // Last usercmd_t. + + usercmd_t pcmd; + + // Status of controller buttons. + + int buttons; + int oldbuttons; + int latched_buttons; + int remember_buttons; + + // Weapons & defenses. + + qboolean autoaim; // Set on client from a flag. + int switchtoweapon; + int weap_ammo_index; + int def_ammo_index; // Not used on client. + int weaponcharge; + float defensive_debounce; // Used on client? Defensive spell delay. + byte meteor_count; + + // Visible model attributes. + + byte plaguelevel; // Current plague level: 0=none, 2=max. + + // Shrine stuff. Used by the player to determine the time for the torch to be lit, reflection + // to work and invisibilty to work (xxx_timer). + + float light_timer; // Not used on client. + float reflect_timer; // FIXME not transmitted yet. + float ghost_timer; // FIXME not transmitted yet. + float powerup_timer; // FIXME not transmitted yet. + float lungs_timer; // Not used on client. + float shield_timer; // FIXME not transmitted yet. + float armor_count; // Not used on client. + float speed_timer; // FIXME not transmitted yet. + + float cinematic_starttime; // Not used on client. Time cinematic started. + float cin_shield_timer; // What the shield timer was set at the beginning of the cinematic + int c_mode; // Show cinematics is on + + // Movement & animation. + + int flags; + float fwdvel,sidevel,upvel; + float turncmd; + float waterheight; + vec3_t LastWatersplashPos; // Not used on client. + vec3_t oldvelocity; + qboolean chargingspell; + + // From edict_t. + + vec3_t origin; + vec3_t angles; + vec3_t velocity; + vec3_t mins,maxs; + void *enemy; // Not used on client. + void *target; // Not used on client. + void *target_ent; // Not used on client. + void *targetEnt; // FIXME - always 0 on client, but checked by client. + float nextthink; // Not used on client. + float viewheight; + float knockbacktime; // FIXME Used on client, but not transmitted yet? --Pat + int watertype; + int waterlevel; + int deadflag; + int movetype; + int edictflags; + + // From entity_state_t. + + int frame,swapFrame; + int effects; + int renderfx; + int skinnum; + fmnodeinfo_t fmnodeinfo[MAX_FM_MESH_NODES]; + + // From pmove_state_t. + + int pm_flags,pm_w_flags; + + // ******************************************************************************************** + // Outputs only. + // ******************************************************************************************** + + // From playerstate_t. + + vec3_t offsetangles; + + // Torso angle twisting stuff which is derived entirely from various inputs to the animation + // system. + + qboolean headjointonly; + vec3_t targetjointangles; + qboolean showscores; // Set layout stat. + qboolean showpuzzleinventory; // Set layout stat. + + // ******************************************************************************************** + // Internal state info. + // ******************************************************************************************** + + int seqcmd[20]; + panimmove_t *uppermove,*lowermove; + int uppermove_index,lowermove_index; + panimframe_t *upperframeptr,*lowerframeptr; + int upperframe,lowerframe; + qboolean upperidle,loweridle; + int upperseq,lowerseq; + float idletime; + vec3_t grabloc; + float grabangle; +} playerinfo_t; + +#endif // _P_TYPES_H_ \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/p_weapon2.h b/Toolkit/Programming/GameCode/qcommon/p_weapon2.h new file mode 100644 index 0000000..f6cd887 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/p_weapon2.h @@ -0,0 +1,28 @@ +// +// p_weapon2.h +// +// Heretic II +// Copyright 1998 Raven Software +// + +#ifndef P_WEAPON2_H +#define P_WEAPON2_H + +#include "p_types.h" + +// ************************************************************************************************ +// Weapon_XXX +// ---------- +// Applicable to all player-weapon types. +// ************************************************************************************************ + +H2COMMON_API void Weapon_Ready(playerinfo_t *playerinfo,gitem_t *Weapon); +H2COMMON_API void Weapon_EquipSpell(playerinfo_t *playerinfo,gitem_t *Weapon); +H2COMMON_API void Weapon_EquipSwordStaff(playerinfo_t *playerinfo,gitem_t *Weapon); +H2COMMON_API void Weapon_EquipHellStaff(playerinfo_t *playerinfo,gitem_t *Weapon); +H2COMMON_API void Weapon_EquipBow(playerinfo_t *playerinfo,gitem_t *Weapon); +H2COMMON_API void Weapon_EquipArmor(playerinfo_t *playerinfo, gitem_t *Weapon); +H2COMMON_API int Weapon_CurrentShotsLeft(playerinfo_t *playerinfo); +H2COMMON_API int Defence_CurrentShotsLeft(playerinfo_t *playerinfo, int intent); + +#endif // P_WEAPON_H diff --git a/Toolkit/Programming/GameCode/qcommon/placement.h b/Toolkit/Programming/GameCode/qcommon/placement.h new file mode 100644 index 0000000..f874111 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/placement.h @@ -0,0 +1,13 @@ +#ifndef PLACEMENT_H +#define PLACEMENT_H + +typedef float vec3_t[3]; + +typedef struct Placement_s +{ + vec3_t origin; + vec3_t direction; + vec3_t up; +} Placement_t; + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/primitivedisplayhack.h b/Toolkit/Programming/GameCode/qcommon/primitivedisplayhack.h new file mode 100644 index 0000000..e687ea6 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/primitivedisplayhack.h @@ -0,0 +1,53 @@ +#ifndef PRIMITIVEDISPLAYHACK_H +#define PRIMITIVEDISPLAYHACK_H + +// ********************************************************************************** +// +// Develoment Display Aids +// +// DO NOT use these for production code. These are only usuable as development aids +// in single player mode. These will not work in multiplayer. Some are also not valid +// in the render DLL (AddServerParticle). +// +// ********************************************************************************** + +#if 0 +#define NONCLIENT_PRIMITIVE_DISPLAY_HACK +#endif + +#ifdef NONCLIENT_PRIMITIVE_DISPLAY_HACK + +#include "q_ClientServer.h" +#include "q_Surface.h" + +extern H2COMMON_API int *r_numparticles; +extern H2COMMON_API struct particle_s *r_particles; + +H2COMMON_API void AddServerParticle(vec3_t org, paletteRGBA_t color, float scale, int type); + +// WARNING!!!! don't call this from any server or game code; only valid on the client!!!! +H2COMMON_API int (*GetPoly)(struct mnode_s *node, vec3_t start, vec3_t end, Surface_t *surface); + +#if 1 +#define BBOX_DISPLAY_HACK +#endif + +#ifdef BBOX_DISPLAY_HACK +typedef struct BBoxDisplayInfo_s +{ + qboolean display; + float *mins; + float *maxs; +} BBoxDisplayInfo_t; + +extern H2COMMON_API BBoxDisplayInfo_t entBBoxs[MAX_EDICTS]; + +H2COMMON_API void InitBBoxDisplayInfo(int entNum, float *mins, float *maxs); +H2COMMON_API void EnableBBoxDisplay(int entNum); +H2COMMON_API void DisableBBoxDisplay(int entNum); + +#endif // BBOX_DISPLAY_HACK + +#endif // NONCLIENT_PRIMITIVE_DISPLAY_HACK + +#endif // PRIMITIVEDISPLAYHACK_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/q_clientserver.h b/Toolkit/Programming/GameCode/qcommon/q_clientserver.h new file mode 100644 index 0000000..c70d80b --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/q_clientserver.h @@ -0,0 +1,30 @@ +#ifndef Q_CLIENTSERVER_H +#define Q_CLIENTSERVER_H + +// +// per-level limits +// +#define MAX_CLIENTS 32 // absolute limit +#define MAX_EDICTS 1024 // must change protocol to increase more +#define MAX_LIGHTSTYLES 256 +#define MAX_MODELS 256 // these are sent over the net as bytes +#define MAX_SOUNDS 768 // so they cannot be blindly increased +#define MAX_IMAGES 256 +#define MAX_ITEMS 256 + +#define MAX_NETWORKABLE_EDICTS MAX_EDICTS + +#define G_MAX_ENTITIES "1024" // string to go into a convar + +// destination class for gi.multicast() +typedef enum +{ +MULTICAST_ALL, +MULTICAST_PHS, +MULTICAST_PVS, +MULTICAST_ALL_R, +MULTICAST_PHS_R, +MULTICAST_PVS_R +} multicast_t; + +#endif // Q_CLIENTSERVER_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/q_physics.h b/Toolkit/Programming/GameCode/qcommon/q_physics.h new file mode 100644 index 0000000..46f0646 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/q_physics.h @@ -0,0 +1,71 @@ +#ifndef Q_PHYSICS_H +#define Q_PHYSICS_H + +#include "H2Common.h" +#include "q_Typedef.h" +#include "q_Shared.h" // for trace_t + +#define ELASTICITY_NONE 0.0f +#define ELASTICITY_SLIDE 1.0001f +#define ELASTICITY_ENTITY_BOUNCE 1.1f +#define ELASTICITY_BOUNCE 1.5f +#define ELASTICITY_REFLECT 2.0f +#define ELASTICITY_MACEBALL 2.0f + +#define GROUND_NORMAL 0.7f + +#define GRAVITY 675.0f +#define GRAVITY_STRING "675.0" // to set cvars with + +#define FRICTION 1600.0f +#define FRICTION_STRING "1600.0" // to set cvars with + +#define STOP_EPSILON 0.1 + +#define MAX_VELOCITY 2000 +#define MAX_VELOCITY_STRING "2000" + +#define PHYSICS_Z_FUDGE 0.5 +#define CHECK_BELOW_DIST 0.5 +#define Z_VEL_NOT_ONGROUND 100 + +typedef struct FormMove_s +{ + vec3_t mins, maxs; + float *start; + float *end; + void *passEntity; + int clipMask; + trace_t trace; + int waterLevel; + int waterType; + float stepHeight; + float dropHeight; + int processFlags; // filled in prior to passing in the FormMove + // to a high level physics call + int resultFlags; // will eventually be filled in by phsyics +} FormMove_t; + +//************************************************************************ +// +// Physics Process Flags +// +//************************************************************************ + +#define PPF_INFO_GRAB 0x00000001 // indicates the funtion is being only for informational purposes + // The entities position will not be modified and it will not be linked + // This currently only works with DiscreteMove_Step + +//************************************************************************ +// +// Physics Result Flags +// +//************************************************************************ + +#define PRF_COLLISION 0x00000001 // indicates there was a collision +#define PRF_EXPANSION_BLOCKED 0x00000002 // indicates an expansion was blocked + +H2COMMON_API void BounceVelocity(vec3_t in, vec3_t normal, vec3_t out, float elasticity); +H2COMMON_API qboolean BoundVelocity(float *vel); + +#endif // Q_PHYSICS_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/q_sprite.h b/Toolkit/Programming/GameCode/qcommon/q_sprite.h new file mode 100644 index 0000000..ce3a384 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/q_sprite.h @@ -0,0 +1,15 @@ +#ifndef Q_SPRITE_H +#define Q_SPRITE_H + +typedef enum SpriteType_s +{ + SPRITE_EDICT = -1, // Comes from the server. Note this is a bit hacky, because the spritetype is unioned with the RootJoint (-1) + SPRITE_STANDARD, // standard square sprite + SPRITE_DYNAMIC, // sprite with 4 variable verts (x,y scale and s,t); texture must be square + SPRITE_VARIABLE, // sprite with n variable verts (x,y scale and s,t); texture must be square + SPRITE_LINE, // Long linear semi-oriented sprite with two verts (xyz start and end) and a width + NUM_SPRITE_TYPES, +}; + + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/q_surface.h b/Toolkit/Programming/GameCode/qcommon/q_surface.h new file mode 100644 index 0000000..bfb002a --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/q_surface.h @@ -0,0 +1,24 @@ +#ifndef Q_SURFACE_H +#define Q_SURFACE_H + +#include "q_shared.h" + +#define MAX_POLY_VERTS 6 + +typedef struct Poly_s +{ + float fraction; + int numverts; + int flags; + float (*verts)[7]; +} Poly_t; + +typedef struct Surface_s +{ + cplane_t *plane; + vec3_t normal; + vec3_t point; // point of intersection with line segment used to find the surface + Poly_t poly; +} Surface_t; + +#endif // Q_SURFACE_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/q_typedef.h b/Toolkit/Programming/GameCode/qcommon/q_typedef.h new file mode 100644 index 0000000..7dfa676 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/q_typedef.h @@ -0,0 +1,39 @@ +#ifndef Q_TYPEDEF_H +#define Q_TYPEDEF_H + +typedef float vec_t; +typedef vec_t vec2_t[2]; +typedef vec_t vec3_t[3]; +typedef double vec3d_t[3]; +typedef vec_t vec5_t[5]; + +typedef float matrix3_t[3][3]; +typedef float matrix3d_t[3][3]; + +typedef int fixed4_t; +typedef int fixed8_t; +typedef int fixed16_t; + +typedef unsigned char byte; +#ifndef __cplusplus +typedef enum {false, true} qboolean; +#else +typedef int qboolean; +#endif + +typedef struct edict_s edict_t; + +typedef struct paletteRGBA_s +{ + union + { + struct + { + byte r,g,b,a; + }; + unsigned c; + byte c_array[4]; + }; +} paletteRGBA_t; + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/qcommon.h b/Toolkit/Programming/GameCode/qcommon/qcommon.h new file mode 100644 index 0000000..9ed90d2 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/qcommon.h @@ -0,0 +1,932 @@ +#ifndef QCOMMON_H +#define QCOMMON_H + +// qcommon.h -- definitions common between client and server, but not game.dll + +#include "../game/q_shared.h" + + +#define VERSION_MAJOR "1" +#define VERSION_MINOR "00" +#define VERSION_LOCAL "01" +#define VERSION_DATE "1117" +#define VERSION_ITERATION "01" + +#define VERSIONDISP (VERSION_MAJOR"."VERSION_MINOR) +#define VERSIONFULL (VERSION_MAJOR"."VERSION_MINOR"."VERSION_LOCAL"."VERSION_DATE"."VERSION_ITERATION) + +#ifdef _HERETIC2_ +#define GAME_DECLSPEC __declspec(dllexport) +#else +#define GAME_DECLSPEC __declspec(dllimport) +#endif + + +#ifdef WIN32 + +#ifdef NDEBUG +#define BUILDSTRING "RELEASE" +#else +#define BUILDSTRING "DEBUG" +#endif + +#ifdef _M_IX86 +#define CPUSTRING "x86" +#endif + +#endif + +//============================================================================ + +typedef struct sizebuf_s +{ + qboolean allowoverflow; // if false, do a Com_Error + qboolean overflowed; // set to true if the buffer size failed + byte *data; + int maxsize; + int cursize; + int readcount; +} sizebuf_t; + +void SZ_Init (sizebuf_t *buf, byte *data, int length); +void SZ_Clear (sizebuf_t *buf); +void *SZ_GetSpace (sizebuf_t *buf, int length); +void SZ_Write (sizebuf_t *buf, void *data, int length); +void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf + +//============================================================================ + +struct usercmd_s; +struct entity_state_s; + +unsigned char GetB(unsigned char * buf, int i); +void SetB(unsigned char * buf, int i); + +void MSG_WriteChar (sizebuf_t *sb, int c); +void MSG_WriteByte (sizebuf_t *sb, int c); +void MSG_WriteShort (sizebuf_t *sb, int c); +void MSG_WriteLong (sizebuf_t *sb, int c); +void MSG_WriteFloat (sizebuf_t *sb, float f); +void MSG_WriteString (sizebuf_t *sb, char *s); +void MSG_WriteCoord (sizebuf_t *sb, float f); +void MSG_WritePos (sizebuf_t *sb, vec3_t pos); +void MSG_WriteAngle (sizebuf_t *sb, float f); +void MSG_WriteAngle16 (sizebuf_t *sb, float f); +void MSG_WriteDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd); +//void MSG_WriteEntityHeaderBits(sizebuf_t *msg, __int64 bits); +void MSG_WriteEntityHeaderBits(sizebuf_t *msg, unsigned char *bf, unsigned char *bfNonZero); +void MSG_WriteDeltaEntity (struct entity_state_s *from, struct entity_state_s *to + , sizebuf_t *msg, qboolean force); +void MSG_WriteDir (sizebuf_t *sb, vec3_t vector); +void MSG_WriteDirMag (sizebuf_t *sb, vec3_t dir); +void MSG_WriteYawPitch (sizebuf_t *sb, vec3_t vector); +void MSG_WriteShortYawPitch (sizebuf_t *sb, vec3_t vector); + +void MSG_BeginReading (sizebuf_t *sb); + +int MSG_ReadChar (sizebuf_t *sb); +int MSG_ReadByte (sizebuf_t *sb); +int MSG_ReadShort (sizebuf_t *sb); +int MSG_ReadLong (sizebuf_t *sb); +float MSG_ReadFloat (sizebuf_t *sb); +char *MSG_ReadString (sizebuf_t *sb); +char *MSG_ReadStringLine (sizebuf_t *sb); + +float MSG_ReadCoord (sizebuf_t *sb); +void MSG_ReadPos (sizebuf_t *sb, vec3_t pos); +float MSG_ReadAngle (sizebuf_t *sb); +float MSG_ReadAngle16 (sizebuf_t *sb); +void MSG_ReadDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd); + +void MSG_ReadDir (sizebuf_t *sb, vec3_t vector); +void MSG_ReadDirMag (sizebuf_t *sb, vec3_t dir); +void MSG_ReadYawPitch (sizebuf_t *sb, vec3_t vector); +void MSG_ReadShortYawPitch (sizebuf_t *sb, vec3_t vector); + +void MSG_ReadData (sizebuf_t *sb, void *buffer, int size); +void MSG_ReadJoints(sizebuf_t *msg_read, entity_state_t *ent); +void MSG_ReadEffects(sizebuf_t *msg_read, EffectsBuffer_t *fxBuf); + +//============================================================================ + +extern qboolean bigendien; + +//============================================================================ + + +int COM_Argc (void); +char *COM_Argv (int arg); // range and null checked +void COM_ClearArgv (int arg); +int COM_CheckParm (char *parm); +void COM_AddParm (char *parm); + +void COM_Init (void); +void COM_InitArgv (int argc, char **argv); + +char *CopyString (char *in); + +//============================================================================ + +void Info_Print (char *s); + + +/* crc.h */ + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); +int CRC_Block (byte *start, int count); + + + + +/* +============================================================== + +PROTOCOL + +============================================================== +*/ + +// protocol.h -- communications protocols + +#define PROTOCOL_VERSION 32 + +//========================================= + +#define PORT_MASTER 28900 +#define PORT_CLIENT 28901 +#define PORT_SERVER 28910 +#define PORT_GAMESPY 28911 // port that gamespy will communicate to our server on +#define PORT_GAMESPYMASTER 27900 // port we communicate to gamespy's master server + +//========================================= + +#define UPDATE_BACKUP 16 // copies of entity_state_t to keep buffered + // must be power of two +#define UPDATE_MASK (UPDATE_BACKUP-1) + +#define MAX_PACKET_ENTITIES 64 + + +//================== +// the svc_strings[] array in cl_parse.c should mirror this +//================== + +// +// server to client +// +enum svc_ops_e +{ + svc_bad, + + svc_layout, + svc_inventory, + svc_client_effect, + + // the rest are private to the client and server + svc_nop, + svc_disconnect, + svc_reconnect, + svc_sound, // + svc_print, // [byte] id [string] null terminated string + svc_gamemsg_print, // [short] id (top 3 bits flags) + svc_stufftext, // [string] stuffed into client's console buffer, should be \n terminated + svc_serverdata, // [long] protocol ... + svc_configstring, // [short] [string] + svc_spawnbaseline, + svc_centerprint, // [string] to put in center of the screen + svc_gamemsg_centerprint, // line number of [string] in strings.txt file + svc_gamemsgvar_centerprint, // line number of [string] in strings.txt file, along with var to insert + svc_levelmsg_centerprint, // line number of [string] in strings.txt file + svc_captionprint, // line number of [string] in strings.txt file + svc_obituary, // line number of [string] in strings.txt file + svc_download, // [short] size [size bytes] + svc_playerinfo, // variable + svc_packetentities, // [...] + svc_deltapacketentities, // [...] + svc_frame, + svc_removeentities, + svc_changeCDtrack, + svc_framenum, //only sent on world spawn, before client effects get through, so we can ensure client time is right + svc_demo_client_effect, //only used to send down persistant effects at the start of a demo + svc_special_client_effect, //almost the same as svc_client_effect, except its got an extra size short at the top. + svc_gamemsgdual_centerprint, //send down two message numbers, to combine into one text string +}; + +//============================================== + +// +// client to server +// +enum clc_ops_e +{ + clc_bad, + clc_nop, + clc_move, // [[usercmd_t] + clc_userinfo, // [[userinfo string] + clc_stringcmd, // [string] message + clc_startdemo // start a demo - please send me all persistant effects +}; + +//============================================== + +// player_state_t communication delta flags. + +#define PLAYER_DEL_BYTES (14) +#define PLAYER_DELNZ_BYTES (2) + +#define PS_VIEWANGLES (0) +#define PS_FRAMEINFO1 (1) // (1,0)=sent one, upper=lower (1,1)=sent both, (0,0)=sent neither +#define PS_FRAMEINFO2 (2) +#define PS_M_ORIGIN_XY (3) +#define PS_M_ORIGIN_Z (4) +#define PS_M_VELOCITY_XY (5) +#define PS_M_VELOCITY_Z (6) +#define PS_FWDVEL (7) + +#define PS_LOWERSEQ (8) +#define PS_LOWERMOVE_INDEX (9) +#define PS_AUTOTARGETENTITY (10) +#define PS_GROUNDPLANE_INFO1 (11) // (0,0) = zaxis, (1,0)=(0,0,0),(1,1)=all three sent +#define PS_GROUNDPLANE_INFO2 (12) +#define PS_IDLETIME (13) +#define PS_UPPERSEQ (14) +#define PS_UPPERMOVE_INDEX (15) + +#define PS_M_TYPE (16) +#define PS_M_TIME (17) +#define PS_M_FLAGS (18) +#define PS_W_FLAGS (19) +#define PS_M_GRAVITY (20) +#define PS_M_DELTA_ANGLES (21) +#define PS_REMOTE_VIEWANGLES (22) +#define PS_REMOTE_VIEWORIGIN (23) + +#define PS_REMOTE_ID (24) +#define PS_VIEWHEIGHT (25) +#define PS_OFFSETANGLES (26) +#define PS_FOV (27) +#define PS_RDFLAGS (28) +#define PS_FOG_DENSITY (29) +#define PS_MAP_PERCENTAGE (30) +#define PS_MISSION1 (31) + +#define PS_MISSION2 (32) +#define PS_MINSMAXS (33) +#define PS_INVENTORY (34) +#define PS_GROUNDBITS_NNGE (35) +#define PS_GROUNDBITS_GC (36) +#define PS_GROUNDBITS_SURFFLAGS (37) +#define PS_WATERLEVEL (38) +#define PS_WATERTYPE (39) + +#define PS_WATERHEIGHT (40) +#define PS_GRABLOC0 (41) +#define PS_GRABLOC1 (42) +#define PS_GRABLOC2 (43) +#define PS_GRABANGLE (44) +#define PS_SIDEVEL (45) +#define PS_UPVEL (46) +#define PS_FLAGS (47) + +#define PS_EDICTFLAGS (48) +#define PS_UPPERIDLE (49) +#define PS_LOWERIDLE (50) +#define PS_WEAPON (51) +#define PS_DEFENSE (52) +#define PS_LASTWEAPON (53) +#define PS_LASTDEFENSE (54) +#define PS_WEAPONREADY (55) + +#define PS_SWITCHTOWEAPON (56) +#define PS_NEWWEAPON (57) +#define PS_WEAP_AMMO_INDEX (58) +#define PS_DEF_AMMO_INDEX (59) +#define PS_ARMORTYPE (60) +#define PS_BOWTYPE (61) +#define PS_STAFFLEVEL (62) +#define PS_HELLTYPE (63) + +#define PS_HANDFXTYPE (64) +#define PS_PLAGUELEVEL (65) +#define PS_SKINTYPE (66) +#define PS_ALTPARTS (67) +#define PS_WEAPONCHARGE (68) +#define PS_DEADFLAG (69) +#define PS_IDEAL_YAW (70) +#define PS_DMFLAGS (71) + +#define PS_OLDVELOCITY_Z (72) +#define PS_STAT_BIT_0 (73) // 1st of a contiguous block. +#define PS_STAT_BIT_31 (74+31) // Rest of the block. +#define PS_CINEMATIC (106) +#define PS_PIV (107) +#define PS_METEORCOUNT (108) + +//============================================== + +// user_cmd_t communication delta flags. + +// ms and light allways sent, the others are optional + +#define CM_ANGLE1 (1<<0) +#define CM_ANGLE2 (1<<1) +#define CM_ANGLE3 (1<<2) +#define CM_AIMANGLE1 (1<<3) +#define CM_AIMANGLE2 (1<<4) +#define CM_AIMANGLE3 (1<<5) +#define CM_CAMERAVIEWORIGIN1 (1<<6) +#define CM_CAMERAVIEWORIGIN2 (1<<7) +#define CM_CAMERAVIEWORIGIN3 (1<<8) +#define CM_CAMERAVIEWANGLES1 (1<<9) +#define CM_CAMERAVIEWANGLES2 (1<<10) +#define CM_CAMERAVIEWANGLES3 (1<<11) +#define CM_FORWARD (1<<12) +#define CM_SIDE (1<<13) +#define CM_UP (1<<14) +#define CM_BUTTONS (1<<15) + +//============================================== + +// a sound without an ent or pos will be a local only sound +#define SND_VOLUME (1<<0) // a byte +#define SND_ATTENUATION (1<<1) // a byte +#define SND_POS (1<<2) // three coordinates +#define SND_ENT (1<<3) // a short 0-2: channel, 3-12: entity +#define SND_OFFSET (1<<4) // a byte, msec offset from frame start + +#define DEFAULT_SOUND_PACKET_VOLUME 1.0 +#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 + +//============================================== + +// entity_state_t communication delta flags + +#define ENT_DEL_BYTES (4) +#define ENT_DELNZ_BYTES (1) + +#define U_FRAME8 (0) +#define U_FRAME16 (1) +#define U_ORIGIN12 (2) +#define U_ORIGIN3 (3) +#define U_ANGLE1 (4) +#define U_ANGLE2 (5) +#define U_ANGLE3 (6) +#define U_SWAPFRAME (7) + +#define U_EFFECTS8 (8) +#define U_EFFECTS16 (9) +#define U_RENDERFX8 (10) +#define U_RENDERFX16 (11) +#define U_CLIENT_EFFECTS (12) +#define U_FM_INFO (13) +#define U_REMOVE (14) +#define U_ENT_FREED (15) + +#define U_COLOR_R (16) +#define U_COLOR_G (17) +#define U_COLOR_B (18) +#define U_COLOR_A (19) +#define U_SKIN8 (20) +#define U_SKIN16 (21) +#define U_MODEL (22) +#define U_SCALE (23) + +#define U_SOUND (24) +#define U_SOLID (25) +#define U_JOINTED (26) +#define U_ABSLIGHT (27) +#define U_OLDORIGIN (28) +#define U_USAGE_COUNT (29) +#define U_NUMBER16 (30) +#define U_BMODEL (31) + +#define U_FM_HIGH (1<<7) // Means more then the first 7 updates + +#define U_FM_FRAME (1<<0) // Individual bits for each update +#define U_FM_FRAME16 (1<<1) +#define U_FM_COLOR_R (1<<2) +#define U_FM_COLOR_G (1<<3) +#define U_FM_COLOR_B (1<<4) +#define U_FM_COLOR_A (1<<5) +#define U_FM_FLAGS (1<<6) +#define U_FM_SKIN (1<<7) + +/* +============================================================== + +CMD + +Command text buffering and command execution + +============================================================== +*/ + +/* + +Any number of commands can be added in a frame, from several different sources. +Most commands come from either keybindings or console line input, but remote +servers can also send across commands and entire text files can be execed. + +The + command line options are also added to the command buffer. + +The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute (); + +*/ + +#define EXEC_NOW 0 // don't return until completed +#define EXEC_INSERT 1 // insert at current position, but don't run yet +#define EXEC_APPEND 2 // add to end of the command buffer + +void Cbuf_Init (void); +// allocates an initial text buffer that will grow as needed + +void Cbuf_AddText (char *text); +// as new commands are generated from the console or keybindings, +// the text is added to the end of the command buffer. + +void Cbuf_InsertText (char *text); +// when a command wants to issue other commands immediately, the text is +// inserted at the beginning of the buffer, before any remaining unexecuted +// commands. + +void Cbuf_ExecuteText (int exec_when, char *text); +// this can be used in place of either Cbuf_AddText or Cbuf_InsertText + +void Cbuf_AddEarlyCommands (qboolean clear); +// adds all the +set commands from the command line + +qboolean Cbuf_AddLateCommands (void); +// adds all the remaining + commands from the command line +// Returns true if any late commands were added, which +// will keep the demoloop from immediately starting + +void Cbuf_Execute (void); +// Pulls off \n terminated lines of text from the command buffer and sends +// them through Cmd_ExecuteString. Stops when the buffer is empty. +// Normally called once per frame, but may be explicitly invoked. +// Do not call inside a command function! + +void Cbuf_CopyToDefer (void); +void Cbuf_InsertFromDefer (void); +// These two functions are used to defer any pending commands while a map +// is being loaded + +//=========================================================================== + +/* + +Command execution takes a null terminated string, breaks it into tokens, +then searches for a command or variable that matches the first token. + +*/ + +typedef void (*xcommand_t) (void); + +void Cmd_Init (void); + +void Cmd_AddCommand (char *cmd_name, xcommand_t function); +// called by the init functions of other parts of the program to +// register commands and functions to call for them. +// The cmd_name is referenced later, so it should not be in temp memory +// if function is NULL, the command will be forwarded to the server +// as a clc_stringcmd instead of executed locally +void Cmd_RemoveCommand (char *cmd_name); + +qboolean Cmd_Exists (char *cmd_name); +// used by the cvar code to check for cvar / command name overlap + +char *Cmd_CompleteCommand (char *partial); +// attempts to match a partial command for automatic command line completion +// returns NULL if nothing fits + +char *Cmd_CompleteCommandNext (char *partial, char *last); +// similar to above, but returns the next value after last + +int Cmd_Argc (void); +char *Cmd_Argv (int arg); +char *Cmd_Args (void); +// The functions that execute commands get their parameters with these +// functions. Cmd_Argv () will return an empty string, not a NULL +// if arg > argc, so string operations are allways safe. + +void Cmd_TokenizeString (char *text, qboolean macroExpand); +// Takes a null terminated string. Does not need to be /n terminated. +// breaks the string up into arg tokens. + +void Cmd_ExecuteString (char *text); +// Parses a single line of text into arguments and tries to execute it +// as if it was typed at the console + +void Cmd_ForwardToServer (void); +// adds the current command line as a clc_stringcmd to the client message. +// things like godmode, noclip, etc, are commands directed to the server, +// so when they are typed in at the console, they will need to be forwarded. + + +/* +============================================================== + +CVAR + +============================================================== +*/ + +/* + +cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly +in C code. + +The user can access cvars from the console in three ways: +r_draworder prints the current value +r_draworder 0 sets the current value to 0 +set r_draworder 0 as above, but creates the cvar if not present +Cvars are restricted from having the same names as commands to keep this +interface from being ambiguous. +*/ + +extern cvar_t *cvar_vars; + +float ClampCvar( float min, float max, float value ); + +cvar_t *Cvar_Get (char *var_name, char *value, int flags); +// creates the variable if it doesn't exist, or returns the existing one +// if it exists, the value will not be changed, but flags will be ORed in +// that allows variables to be unarchived without needing bitflags + +cvar_t *Cvar_Set (char *var_name, char *value); +// will create the variable if it doesn't exist + +cvar_t *Cvar_ForceSet (char *var_name, char *value); +// will set the variable even if NOSET or LATCH + +cvar_t *Cvar_FullSet (char *var_name, char *value, int flags); + +void Cvar_SetValue (char *var_name, float value); +// expands value to a string and calls Cvar_Set + +float Cvar_VariableValue (char *var_name); +// returns 0 if not defined or non numeric + +char *Cvar_VariableString (char *var_name); +// returns an empty string if not defined + +char *Cvar_CompleteVariable (char *partial); +// attempts to match a partial variable name for command line completion +// returns NULL if nothing fits + +char *Cvar_CompleteVariableNext(char *partial, char *last); +// similar to above, except that it goes to next match if any + +void Cvar_GetLatchedVars (void); +// any CVAR_LATCHED variables that have been set will now take effect + +qboolean Cvar_Command (void); +// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known +// command. Returns true if the command was a variable reference that +// was handled. (print or change) + +void Cvar_WriteVariables (char *path); +// appends lines containing "set variable value" for all variables +// with the archive flag set to true. + +void Cvar_Init (void); + +char *Cvar_Userinfo (void); +// returns an info string containing all the CVAR_USERINFO cvars + +char *Cvar_Serverinfo (void); +// returns an info string containing all the CVAR_SERVERINFO cvars + +extern qboolean userinfo_modified; +// this is set each time a CVAR_USERINFO variable is changed +// so that the client knows to send it to the server + +// Screen flash set +void Activate_Screen_Flash(int color); + +// Screen flash unset +void Deactivate_Screen_Flash(void); + +// return screen flash value +int Is_Screen_Flashing(void); + +// set up a screen shaking +void Activate_Screen_Shake(float intensity, float duration, float current_time, int flags); +// reset screen shakings +void Reset_Screen_Shake(void); + +qboolean Get_Crosshair(vec3_t origin, byte *type); + +// called by the camera code to determine our camera offset +void Perform_Screen_Shake(vec3_t, float current_time); + +/* +============================================================== + +NET + +============================================================== +*/ + +// net.h -- quake's interface to the networking layer + +#define PORT_ANY -1 + +// FIXME: this really shouldn't have to be changed to 2000 but some maps (SSTOWN4) were causing it to crash +//#define MAX_MSGLEN 1400 // max length of a message +#define MAX_MSGLEN 2500 // max length of a message +#define PACKET_HEADER 10 // two ints and a short + +typedef enum {NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX} netadrtype_t; + +typedef enum {NS_CLIENT, NS_SERVER, NS_GAMESPY} netsrc_t; + +extern int gamespy_port; + +typedef struct +{ + netadrtype_t type; + + byte ip[4]; + byte ipx[10]; + + unsigned short port; +} netadr_t; + +void NET_Init (void); +void NET_Shutdown (void); +void NET_TotalShutdown (void); + +void NET_Config (qboolean multiplayer); + +qboolean NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message); +void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to); + +qboolean NET_CompareAdr (netadr_t a, netadr_t b); +qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b); +qboolean NET_IsLocalAddress (netadr_t adr); +char *NET_AdrToString (netadr_t a); +qboolean NET_StringToAdr (char *s, netadr_t *a); + +//============================================================================ + +#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG) + +#define MAX_LATENT 32 + +typedef struct +{ + qboolean fatal_error; + + netsrc_t sock; + + int dropped; // between last packet and previous + + int last_received; // for timeouts + int last_sent; // for retransmits + + netadr_t remote_address; + int qport; // qport value to write when transmitting + +// sequencing variables + int incoming_sequence; + int incoming_acknowledged; + int incoming_reliable_acknowledged; // single bit + + int incoming_reliable_sequence; // single bit, maintained local + + int outgoing_sequence; + int reliable_sequence; // single bit + int last_reliable_sequence; // sequence number of last send + +// reliable staging and holding areas + sizebuf_t message; // writing buffer to send to server + byte message_buf[MAX_MSGLEN-16]; // leave space for header + +// message is copied to this buffer when it is first transfered + int reliable_length; + byte reliable_buf[MAX_MSGLEN-16]; // unacked reliable message +} netchan_t; + +extern netadr_t net_from; +extern sizebuf_t net_message; +extern byte net_message_buffer[MAX_MSGLEN]; + + +void Netchan_Init (void); +void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport); + +qboolean Netchan_NeedReliable (netchan_t *chan); +int Netchan_Transmit (netchan_t *chan, int length, byte *data); +void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data); +void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...); +qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg); + +qboolean Netchan_CanReliable (netchan_t *chan); + + +/* +============================================================== + +CMODEL + +============================================================== +*/ + + +#include "../qcommon/qfiles.h" + +cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum); +cmodel_t *CM_InlineModel (char *name); // *1, *2, etc + +int CM_NumClusters (void); +int CM_NumInlineModels (void); +char *CM_EntityString (void); + +// creates a clipping hull for an arbitrary box +int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs); + + +// returns an ORed contents mask +int CM_PointContents (vec3_t p, int headnode); +int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles); + +void CM_BoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask, trace_t *return_trace); +void CM_TransformedBoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask, + vec3_t origin, vec3_t angles, trace_t *return_trace); + +byte *CM_ClusterPVS (int cluster); +byte *CM_ClusterPHS (int cluster); + +int CM_PointLeafnum (vec3_t p); + +// call with topnode set to the headnode, returns with topnode +// set to the first node that splits the box +int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, + int listsize, int *topnode); + +int CM_LeafContents (int leafnum); +int CM_LeafCluster (int leafnum); +int CM_LeafArea (int leafnum); + +void CM_SetAreaPortalState (int portalnum, qboolean open); +qboolean CM_AreasConnected (int area1, int area2); + +int CM_WriteAreaBits (byte *buffer, int area); +qboolean CM_HeadnodeVisible (int headnode, byte *visbits); + +void CM_WritePortalState (FILE *f); +void CM_ReadPortalState (FILE *f); + +/* +============================================================== + +PLAYER MOVEMENT CODE + +Common between server and client so prediction matches + +============================================================== +*/ + +void Pmove(pmove_t *pmove, qboolean server); + +/* +============================================================== + +FILESYSTEM + +============================================================== +*/ + +void FS_InitFilesystem (void); +char *FS_GetPath (char *name); +void FS_SetGamedir (char *dir); +char *FS_Gamedir (void); +char *FS_Userdir (void); +char *FS_NextPath (char *prevpath); +void FS_ExecAutoexec (void); + +int FS_FOpenFile (char *filename, FILE **file); +void FS_FCloseFile (FILE *f); +// note: this can't be called from another DLL, due to MS libc issues + +int FS_LoadFile (char *path, void **buffer); +// a null buffer will just return the file length without loading +// a -1 length is not present + +void FS_Read (void *buffer, int len, FILE *f); +// properly handles partial reads + +void FS_FreeFile (void *buffer); + +void FS_CreatePath (char *path); + +/* +============================================================== + +MISC + +============================================================== +*/ + +#define CFX_CULLING_DIST 1000.0f + +#define ERR_FATAL 0 // exit the entire game with a popup window +#define ERR_DROP 1 // print to console and disconnect from game +#define ERR_QUIT 2 // not an error, just a normal exit + +#define EXEC_NOW 0 // don't return until completed +#define EXEC_INSERT 1 // insert at current position, but don't run yet +#define EXEC_APPEND 2 // add to end of the command buffer + +#define PRINT_ALL 0 +#define PRINT_DEVELOPER 1 // only print when "developer 1" + +void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush)); +void Com_EndRedirect (void); +void Com_Printf (char *fmt, ...); +void Com_DPrintf (char *fmt, ...); +void Com_Error (int code, char *fmt, ...); +void Com_Quit (void); +int Com_ServerState (void); +void Com_SetServerState (int state); + +unsigned Com_BlockChecksum (void *buffer, int length); +byte COM_BlockSequenceCheckByte (byte *base, int length, int sequence); + +extern cvar_t *developer; +extern cvar_t *dedicated; +extern cvar_t *host_speeds; +extern cvar_t *log_stats; +extern cvar_t *player_dll; + +extern FILE *log_stats_file; + +// host_speeds times +#ifdef _DEVEL +extern __int64 time_before_game; +extern __int64 time_after_game; +extern __int64 time_before_ref; +extern __int64 time_after_ref; +#endif // _DEVEL + +void Z_Free (void *ptr); +void *Z_Malloc (int size); // returns 0 filled memory +void *Z_TagMalloc (int size, int tag); +void Z_FreeTags (int tag); + +void Qcommon_Init (int argc, char **argv); +void Qcommon_Frame (int msec); + +#define NUMVERTEXNORMALS 162 +extern vec3_t bytedirs[NUMVERTEXNORMALS]; + +/* +============================================================== + +NON-PORTABLE SYSTEM SERVICES + +============================================================== +*/ + +void Sys_Init (void); + +void Sys_AppActivate (void); + +void Sys_UnloadGame (void); +void *Sys_GetGameAPI (void *parms); +// loads the game dll and calls the api init function + +char *Sys_ConsoleInput (void); +void Sys_ConsoleOutput (char *string); +void Sys_SendKeyEvents (void); +void Sys_Error (char *error, ...); +void Sys_Quit (void); +char *Sys_GetClipboardData( void ); +void Sys_CopyProtect (void); + +/* +============================================================== + +CLIENT / SERVER SYSTEMS + +============================================================== +*/ + +void CL_Init (void); +void CL_Drop (void); +void CL_Shutdown (void); +void CL_Frame (int msec); +void SCR_BeginLoadingPlaque (void); + +void SV_Init (void); +void SV_Shutdown (char *finalmsg, qboolean reconnect); +void SV_Frame (int msec); + +#endif // QCOMMON_H \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/qfiles.h b/Toolkit/Programming/GameCode/qcommon/qfiles.h new file mode 100644 index 0000000..04d06ae --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/qfiles.h @@ -0,0 +1,582 @@ + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +/* +======================================================================== + +The .pak files are just a linear collapse of a directory tree + +======================================================================== +*/ + +#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') + +typedef struct +{ + char name[56]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} dpackheader_t; + +#define MAX_FILES_IN_PACK 6144 + + +/* +======================================================================== + +PCX files are used for as many images as possible + +======================================================================== +*/ + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + +/* +======================================================================== + +.MD2 compressed triangle model file format + +======================================================================== +*/ +#define IDCOMPRESSEDALIASHEADER (('2'<<24)+('C'<<16)+('D'<<8)+'I') + +/* +======================================================================== + +.MD2 compressed triangle model file format + +======================================================================== +*/ +#define IDJOINTEDALIASHEADER (('2'<<24)+('J'<<16)+('D'<<8)+'I') + +/* +======================================================================== + +.MD2 triangle model file format + +======================================================================== +*/ + +#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I') +#define ALIAS_VERSION 8 + +#define MAX_TRIANGLES 4096 +#define MAX_VERTS 2048 +#define MAX_FRAMES 512 +#define MAX_MD2SKINS 64 +#define MAX_SKINNAME 64 + +typedef struct +{ + short s; + short t; +} dstvert_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} dtriangle_t; + +typedef struct +{ + union + { + struct + { + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; + }; + + int vert; + }; +} dtrivertx_t; + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + dtrivertx_t verts[1]; // variable sized +} daliasframe_t; + + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +typedef struct +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + + int ofs_skins; // each skin is a MAX_SKINNAME string + int ofs_st; // byte offset from start for stverts + int ofs_tris; // offset for dtriangles + int ofs_frames; // offset for first frame + int ofs_glcmds; + int ofs_end; // end of file + +} dmdl_t; + +// compressed model +typedef struct dcompmdl_s +{ + dmdl_t header; + short CompressedFrameSize; + short UniqueVerts; + short *remap; + float *translate; // then add this + float *scale; // multiply byte verts by this + char *mat; + char *frames; + char *base; + float *ctranslate; + float *cscale; + char data[1]; +} dcompmdl_t; + +typedef struct +{ + dcompmdl_t compModInfo; + int rootCluster; + int skeletalType; + struct ModelSkeleton_s *skeletons; +} JointedModel_t; + +/* +======================================================================== + +.BK file format + +======================================================================== +*/ + +#define IDBOOKHEADER (('K'<<24)+('O'<<16)+('O'<<8)+'B') +#define BOOK_VERSION 2 + +typedef struct bookframe_s +{ + int x; + int y; + int w; + int h; + char name[MAX_SKINNAME]; // name of gfx file +} bookframe_t; + +typedef struct bookheader_s +{ + unsigned int ident; + unsigned int version; + int num_segments; + int total_w; + int total_h; +} bookheader_t; + +typedef struct book_s +{ + bookheader_t bheader; + bookframe_t bframes[MAX_MD2SKINS]; +} book_t; + +/* +======================================================================== + +.SP2 sprite file format + +======================================================================== +*/ + +#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDS2" +#define SPRITE_VERSION 2 + +typedef struct +{ + int width, height; + int origin_x, origin_y; // raster coordinates inside pic + char name[MAX_SKINNAME]; // name of pcx file +} dsprframe_t; + +typedef struct { + int ident; + int version; + int numframes; + dsprframe_t frames[1]; // variable sized +} dsprite_t; + +/* +============================================================================== + + .M8 texture file format + +============================================================================== +*/ + +typedef struct palette_s +{ + union + { + struct + { + byte r,g,b; + }; + }; +} palette_t; + +#define MIP_VERSION 2 +#define PAL_SIZE 256 +#define MIPLEVELS 16 + +typedef struct miptex_s +{ + int version; + char name[32]; + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + palette_t palette[PAL_SIZE]; + int flags; + int contents; + int value; +} miptex_t; + + + +#define MIP32_VERSION 4 + +typedef struct miptex32_s +{ + int version; + char name[128]; + char altname[128]; // texture substitution + char animname[128]; // next frame in animation chain + char damagename[128]; // image that should be shown when damaged + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; + int flags; + int contents; + int value; + float scale_x, scale_y; + int mip_scale; + + // detail texturing info + char dt_name[128]; // detailed texture name + float dt_scale_x, dt_scale_y; + float dt_u, dt_v; + float dt_alpha; + int dt_src_blend_mode, dt_dst_blend_mode; + + int unused[20]; // future expansion to maintain compatibility with h2 +} miptex32_t; + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +#define BSPVERSION 38 + + +// upper design bounds +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +//#define MAX_MAP_BRUSHES 8192 // Quake 2 original +#define MAX_MAP_BRUSHES 10240 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_ENTSTRING 0x40000 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_AREAS 256 +#define MAX_MAP_AREAPORTALS 1024 +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x180000 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_VERTEXES 2 +#define LUMP_VISIBILITY 3 +#define LUMP_NODES 4 +#define LUMP_TEXINFO 5 +#define LUMP_FACES 6 +#define LUMP_LIGHTING 7 +#define LUMP_LEAFS 8 +#define LUMP_LEAFFACES 9 +#define LUMP_LEAFBRUSHES 10 +#define LUMP_EDGES 11 +#define LUMP_SURFEDGES 12 +#define LUMP_MODELS 13 +#define LUMP_BRUSHES 14 +#define LUMP_BRUSHSIDES 15 +#define LUMP_POP 16 +#define LUMP_AREAS 17 +#define LUMP_AREAPORTALS 18 +#define HEADER_LUMPS 19 + +typedef struct +{ + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces + // without walking the bsp tree +} dmodel_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +// planes (x&~1) and (x&~1)+1 are allways opposites + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// These definitions also need to be in q_shared.h! + +// ************************************************************************************************ +// CONTENTS_XXX +// ------------ +// Contents flags. +// ************************************************************************************************ + +// Lower bits are stronger, and will eat weaker brushes completely. + +#define CONTENTS_SOLID 0x00000001 // An eye is never valid in a solid. +#define CONTENTS_WINDOW 0x00000002 // Translucent, but not watery. +#define CONTENTS_AUX 0x00000004 +#define CONTENTS_LAVA 0x00000008 +#define CONTENTS_SLIME 0x00000010 +#define CONTENTS_WATER 0x00000020 +#define CONTENTS_MIST 0x00000040 +#define LAST_VISIBLE_CONTENTS CONTENTS_MIST + +// Remaining contents are non-visible, and don't eat brushes. + +#define CONTENTS_AREAPORTAL 0x00008000 +#define CONTENTS_PLAYERCLIP 0x00010000 +#define CONTENTS_MONSTERCLIP 0x00020000 + +// Currents can be added to any other contents, and may be mixed. + +#define CONTENTS_CURRENT_0 0x00040000 +#define CONTENTS_CURRENT_90 0x00080000 +#define CONTENTS_CURRENT_180 0x00100000 +#define CONTENTS_CURRENT_270 0x00200000 +#define CONTENTS_CURRENT_UP 0x00400000 +#define CONTENTS_CURRENT_DOWN 0x00800000 +#define CONTENTS_ORIGIN 0x01000000 // Removed before bsping an entity. +#define CONTENTS_MONSTER 0x02000000 // Should never be on a brush, only in game. +#define CONTENTS_DEADMONSTER 0x04000000 +#define CONTENTS_DETAIL 0x08000000 // Brushes to be added after vis leaves. +#define CONTENTS_TRANSLUCENT 0x10000000 // Auto set if any surface has transparency. +#define CONTENTS_LADDER 0x20000000 +#define CONTENTS_CAMERANOBLOCK 0x40000000 // Camera LOS ignores any brushes with this flag. + +typedef struct +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int flags; // miptex flags + overrides + int value; // light emission, etc + char texture[32]; // texture name (textures/*.wal) + int nexttexinfo; // for animations, -1 = end of chain +} texinfo_t; + + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +typedef struct +{ + int contents; // OR of all brushes (not needed?) + + short cluster; + short area; + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + +typedef struct +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the visibility lump consists of a header with a count, then +// byte offsets for the PVS and PHS of each cluster, then the raw +// compressed bit vectors +#define DVIS_PVS 0 +#define DVIS_PHS 1 +typedef struct +{ + int numclusters; + int bitofs[8][2]; // bitofs[numclusters][2] +} dvis_t; + +// each area has a list of portals that lead into other areas +// when portals are closed, other areas may not be visible or +// hearable even if the vis info says that it should be +typedef struct +{ + int portalnum; + int otherarea; +} dareaportal_t; + +typedef struct +{ + int numareaportals; + int firstareaportal; +} darea_t; diff --git a/Toolkit/Programming/GameCode/qcommon/random.h b/Toolkit/Programming/GameCode/qcommon/random.h new file mode 100644 index 0000000..a775b88 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/random.h @@ -0,0 +1,11 @@ +#ifndef RANDOM_H +#define RANDOM_H + +// Required protos for random functions + +#include "H2Common.h" + +H2COMMON_API float flrand(float, float); +H2COMMON_API int irand(int, int); + +#endif diff --git a/Toolkit/Programming/GameCode/qcommon/reference.h b/Toolkit/Programming/GameCode/qcommon/reference.h new file mode 100644 index 0000000..0d9bbe3 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/reference.h @@ -0,0 +1,103 @@ +#ifndef REFERENCE_H +#define REFERENCE_H + +#include "Placement.h" + +#define MAX_REFPOINTS 16 +#define REF_MINCULLTIME 1.0 + +typedef struct Reference_s +{ + int activecount; + Placement_t placement; +} Reference_t; + +typedef struct LERPedReferences_s +{ + int refType; + int *jointIDs; + float lastUpdate; + Reference_t references[MAX_REFPOINTS]; + Reference_t oldReferences[MAX_REFPOINTS]; +} LERPedReferences_t; + +// Reference Types +enum { + REF_NULL = -1, + REF_CORVUS,//0 + REF_INSECT,//1 + REF_PRIESTESS,//2 + REF_MORK,//3 + NUM_REFERENCED//4 +}; + +// Corvus Reference Points +enum { + CORVUS_LEFTHAND,//0 + CORVUS_RIGHTHAND, + CORVUS_LEFTFOOT, + CORVUS_RIGHTFOOT, + CORVUS_STAFF, + CORVUS_BLADE, + CORVUS_HELL_HEAD, + NUM_REFERENCES_CORVUS//7 +}; + +// Tchekrik Reference Points +enum { + INSECT_STAFF,//0 + INSECT_SWORD, + INSECT_SPEAR, + INSECT_RIGHTFOOT, + INSECT_LEFTFOOT, + NUM_REFERENCES_INSECT//5 +}; + +// High Priestess Reference Points +enum { + PRIESTESS_BACK,//0 + PRIESTESS_STAFF, + PRIESTESS_LHAND, + PRIESTESS_RHAND, + PRIESTESS_RFOOT, + PRIESTESS_LFOOT, + NUM_REFERENCES_PRIESTESS//6 +}; + +// Morcalavin Reference Points +enum +{ + MORK_STAFFREF,//0 + MORK_RFOOTREF,//1 + MORK_LFOOTREF,//2 + MORK_RHANDREF,//3 + MORK_LHANDREF,//4 + MORK_LEYEREF,//5 + MORK_REYEREF,//6 + NUM_REFERENCES_MORK//7 +}; + +#define CORVUS_LIMBS_MASK ((1 << CORVUS_LEFTHAND) | (1 << CORVUS_RIGHTHAND) | (1 << CORVUS_LEFTFOOT) | (1 << CORVUS_RIGHTFOOT)) +#define CORVUS_WEAPON_MASK ((1 << CORVUS_STAFF) | (1 << CORVUS_BLADE) | (1 << CORVUS_HELL_HEAD)) +#define CORVUS_MASK (CORVUS_LIMBS_MASK | CORVUS_WEAPON_MASK) + +#define INSECT_MASK ((1 << INSECT_STAFF) | (1 << INSECT_SWORD) | (1 << INSECT_SPEAR) | (1 << INSECT_RIGHTFOOT) | (1 << INSECT_LEFTFOOT)) + +#define PRIESTESS_MASK ((1 << PRIESTESS_BACK) | (1 << PRIESTESS_STAFF) | (1 << PRIESTESS_LHAND) | (1 << PRIESTESS_RHAND) | (1 << PRIESTESS_RFOOT) | (1 << PRIESTESS_LFOOT)) + +#define MORK_MASK ((1 << MORK_STAFFREF) | (1 << MORK_RFOOTREF) | (1 << MORK_LFOOTREF) | (1 << MORK_RHANDREF) | (1 << MORK_LHANDREF) | (1 << MORK_LEYEREF) | (1 << MORK_REYEREF)) + +extern char *referenceRootNames[]; +extern int referenceRootNameOffsets[]; +extern int numReferences[]; + +void EnableRefPoints(LERPedReferences_t *refInfo, int mask); +void DisableRefPoints(LERPedReferences_t *refInfo, int mask); + +void InitReferenceMngr(); +void ReleaseReferenceMngr(); + +LERPedReferences_t *LERPedReferences_new(int init_refType); +void LERPedReferences_delete(LERPedReferences_t *toDelete); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/resourcemanager.h b/Toolkit/Programming/GameCode/qcommon/resourcemanager.h new file mode 100644 index 0000000..9c4776e --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/resourcemanager.h @@ -0,0 +1,27 @@ +// +// ResourceManager.h +// +// Copyright 1998 Raven Software +// + +#include "H2Common.h" +#include // needed here for size_t + +typedef struct ResourceManager_s +{ + size_t resSize; + unsigned int resPerBlock; + unsigned int nodeSize; + struct ResMngr_Block_s *blockList; + char **free; +#ifndef NDEBUG + unsigned numResourcesAllocated; +#endif +} ResourceManager_t; + +extern H2COMMON_API void ResMngr_Con(ResourceManager_t *resource, size_t init_resSize, unsigned int init_resPerBlock); +extern H2COMMON_API void ResMngr_Des(ResourceManager_t *resource); +extern H2COMMON_API void *ResMngr_AllocateResource(ResourceManager_t *resource, size_t size); +extern H2COMMON_API void ResMngr_DeallocateResource(ResourceManager_t *resource, void *toDeallocate, size_t size); + + diff --git a/Toolkit/Programming/GameCode/qcommon/singlylinkedlist.h b/Toolkit/Programming/GameCode/qcommon/singlylinkedlist.h new file mode 100644 index 0000000..8773918 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/singlylinkedlist.h @@ -0,0 +1,35 @@ +// +// SinglyLinkedList.h +// +// Copyright 1998 Raven Software +// + +#ifndef SINGLYLINKEDLIST_H +#define SINGLYLINKEDLIST_H + +#include "H2Common.h" +#include "GenericUnions.h" + +typedef struct SinglyLinkedList_s +{ + struct SinglyLinkedListNode_s *rearSentinel; + struct SinglyLinkedListNode_s *front; + struct SinglyLinkedListNode_s *current; +} SinglyLinkedList_t; + +H2COMMON_API void SLList_DefaultCon(SinglyLinkedList_t *this_ptr); +H2COMMON_API void SLList_Des(SinglyLinkedList_t *this_ptr); +H2COMMON_API qboolean SLList_AtEnd(SinglyLinkedList_t *this_ptr); +H2COMMON_API qboolean SLList_AtLast(SinglyLinkedList_t *this_ptr); +H2COMMON_API qboolean SLList_IsEmpty(SinglyLinkedList_t *this_ptr); +H2COMMON_API const GenericUnion4_t SLList_Increment(SinglyLinkedList_t *this_ptr); +H2COMMON_API const GenericUnion4_t SLList_PostIncrement(SinglyLinkedList_t *this_ptr); +H2COMMON_API GenericUnion4_t SLList_Front(SinglyLinkedList_t *this_ptr); +H2COMMON_API GenericUnion4_t SLList_ReplaceCurrent(SinglyLinkedList_t *this_ptr, const GenericUnion4_t toReplace); +H2COMMON_API void SLList_PushEmpty(SinglyLinkedList_t *this_ptr); +H2COMMON_API void SLList_Push(SinglyLinkedList_t *this_ptr, const GenericUnion4_t toInsert); +H2COMMON_API GenericUnion4_t SLList_Pop(SinglyLinkedList_t *this_ptr); +H2COMMON_API void SLList_Chop(SinglyLinkedList_t *this_ptr); +H2COMMON_API void SLList_InsertAfter(SinglyLinkedList_t *this_ptr, const GenericUnion4_t toInsert); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/skeletons.c b/Toolkit/Programming/GameCode/qcommon/skeletons.c new file mode 100644 index 0000000..8c7b990 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/skeletons.c @@ -0,0 +1,214 @@ +// +// Skeletons.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#include "Skeletons.h" +#include "ArrayedList.h" + +char *skeletonRootNames[] = +{ + "RAVEN_ROOT", + "BOX_ROOT", + "BEETLE_ROOT", + "ELFLORD_ROOT", + "PLAGUELF_ROOT", + "ELF_BACKROOT", +}; + +int skeletonRNameOffsets[] = +{ + 0, // RAVEN + 1, // BOX + 2, // BEETLE + 3, // ELFLORD + 4, // PLAGUE ELF + 5, // CORVUS +}; + +char *skeletonJointNames[] = +{ + "RAVEN_LOWERBACK", // 0 + "RAVEN_UPPERBACK", + "RAVEN_NECK", + "BOX_CENTER", // 3 + "BEETLE_NECK", // 4 + "BEETLE_HEAD", + "PLAGUELF_BACKB", // 6 + "PLAGUELF_BACKC", + "PLAGUELF_NECK", + "ELF_BACKB", // 9 + "ELF_BACKC", + "ELF_NECKB", +}; + +int skeletonNameOffsets[] = +{ + 0, // RAVEN + 3, // BOX + 4, // BEETLE + -1, // ELFLORD + 6, // PLAGUE ELF + 9, // CORVUS +}; + +char *skeletonEffectorNames[] = +{ + "BEETLE_EYES", // 0 + "CORVUS_EYES", // 1 +}; + +int skeletonENameOffsets[] = +{ + -1, // RAVEN + -1, // BOX + 0, // BEETLE + -1, // ELFLORD + 1, // PLAGUE ELF +}; + +int numJointsInSkeleton[] = +{ + NUM_JOINTS_RAVEN, + NUM_JOINTS_BOX, + NUM_JOINTS_BEETLE, + NUM_JOINTS_ELFLORD, + NUM_JOINTS_PLAGUE_ELF, + NUM_JOINTS_CORVUS, +}; + +int numNodesInSkeleton[] = +{ + 2, // RAVEN + 0, // BOX + 1, // BEETLE + -1, // ELFLORD + 2, // PLAGUE ELF + 2, // CORVUS +}; + +void CreateRavenSkel(void *skeletalJoints, size_t jointSize, struct ArrayedListNode_s *jointNodes, int root); +void CreateBoxSkel(void *skeletalJoints, size_t jointSize, struct ArrayedListNode_s *jointNodes, int root); +void CreateBeetleSkel(void *skeletalJoints, size_t jointSize, ArrayedListNode_t *jointNodes, int rootIndex); +void CreateElfLordSkel(void *skeletalJoints, size_t jointSize, ArrayedListNode_t *jointNodes, int rootIndex); +void CreatePlagueElfSkel(void *skeletalJoints, size_t jointSize, ArrayedListNode_t *jointNodes, int rootIndex); + +CreateSkeleton_t SkeletonCreators[NUM_SKELETONS] = +{ + CreateRavenSkel, + CreateBoxSkel, + CreateBeetleSkel, + CreateElfLordSkel, + CreatePlagueElfSkel, + CreatePlagueElfSkel, // Corvus has the same structure as the Plague Elf +}; + +void CreateRavenSkel(void *skeletalJoints, size_t jointSize, ArrayedListNode_t *jointNodes, int rootIndex) +{ + char *root; + int *children; + int nodeIndex; + + root = (char *)skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + RAVEN_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + RAVEN_UPPERBACK * jointSize); + *children = nodeIndex; + + jointNodes[nodeIndex].data = rootIndex + RAVEN_HEAD; + jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + RAVEN_LOWERBACK * jointSize); + *children = nodeIndex; + + jointNodes[nodeIndex].data = rootIndex + RAVEN_UPPERBACK; + jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; +} + +void CreateBoxSkel(void *skeletalJoints, size_t jointSize, ArrayedListNode_t *jointNodes, int rootIndex) +{ + char *root; + int *children; + + root = (char *)skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + RAVEN_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; +} + +void CreateBeetleSkel(void *skeletalJoints, size_t jointSize, ArrayedListNode_t *jointNodes, int rootIndex) +{ + char *root; + int *children; + int nodeIndex; + + root = (char *)skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + BEETLE_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + BEETLE_NECK * jointSize); + *children = nodeIndex; + + jointNodes[nodeIndex].data = rootIndex + BEETLE_HEAD; + jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; +} + +void CreateElfLordSkel(void *skeletalJoints, size_t jointSize, ArrayedListNode_t *jointNodes, int rootIndex) +{ + char *root; + int *children; + int nodeIndex; + + root = (char *)skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + BEETLE_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + BEETLE_NECK * jointSize); + *children = nodeIndex; + + jointNodes[nodeIndex].data = rootIndex + BEETLE_HEAD; + jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; +} + +void CreatePlagueElfSkel(void *skeletalJoints, size_t jointSize, ArrayedListNode_t *jointNodes, int rootIndex) +{ + char *root; + int *children; + int nodeIndex; + + root = (char *)skeletalJoints + rootIndex * jointSize; + + children = (int *)(root + PLAGUE_ELF_HEAD * jointSize); + *children = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + PLAGUE_ELF_UPPERBACK * jointSize); + *children = nodeIndex; + + jointNodes[nodeIndex].data = rootIndex + PLAGUE_ELF_HEAD; + jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; + + nodeIndex = GetFreeNode(jointNodes, MAX_ARRAYED_JOINT_NODES); + + children = (int *)(root + PLAGUE_ELF_LOWERBACK * jointSize); + *children = nodeIndex; + + jointNodes[nodeIndex].data = rootIndex + PLAGUE_ELF_UPPERBACK; + jointNodes[nodeIndex].next = ARRAYEDLISTNODE_NULL; +} \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/skeletons.h b/Toolkit/Programming/GameCode/qcommon/skeletons.h new file mode 100644 index 0000000..4cc8b49 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/skeletons.h @@ -0,0 +1,83 @@ +#include // for size_t + +#define JN_YAW_CHANGED 0x00000001 +#define JN_PITCH_CHANGED 0x00000002 +#define JN_ROLL_CHANGED 0x00000004 + +// Skeleton types +enum { + SKEL_NULL = -1, + SKEL_RAVEN = 0, + SKEL_BOX, + SKEL_BEETLE, + SKEL_ELFLORD, + SKEL_PLAGUE_ELF, + SKEL_CORVUS, + NUM_SKELETONS +}; + +// Raven Skeletal joints +enum { + RAVEN_LOWERBACK = 0, + RAVEN_UPPERBACK, + RAVEN_HEAD, + NUM_JOINTS_RAVEN +}; + +// Box Skeletal joints +enum { + BOX_CENTER = 0, + NUM_JOINTS_BOX +}; + +// Beetle Skeletal joints +enum { + BEETLE_NECK = 0, + BEETLE_HEAD, + NUM_JOINTS_BEETLE +}; + +// Elflord Skeletal joints +enum { + ELFLORD_, + ELFLORD__, + NUM_JOINTS_ELFLORD +}; + +// Plague Elf Skeletal joints +enum { + PLAGUE_ELF_LOWERBACK, + PLAGUE_ELF_UPPERBACK, + PLAGUE_ELF_HEAD, + NUM_JOINTS_PLAGUE_ELF +}; + +// Corvus Skeletal joints +enum { + CORVUS_LOWERBACK, + CORVUS_UPPERBACK, + CORVUS_HEAD, + NUM_JOINTS_CORVUS +}; + +#define NO_SWAP_FRAME -1 +#define NULL_ROOT_JOINT -1 + +#define MAX_ARRAYED_SKELETAL_JOINTS 255 // has max of 65,535 (if this remains at 255, net code can be changed to reflect) +#define MAX_ARRAYED_JOINT_NODES (MAX_ARRAYED_SKELETAL_JOINTS - 1) + +#define MAX_JOINTS_PER_SKELETON 8 // arbitrary small number +#define MAX_JOINT_NODES_PER_SKELETON (MAX_JOINTS_PER_SKELETON - 1) + +extern char *skeletonRootNames[]; +extern int skeletonRNameOffsets[]; +extern char *skeletonJointNames[]; +extern int skeletonNameOffsets[]; +extern int numJointsInSkeleton[]; +extern char *skeletonEffectorNames[]; +extern int skeletonENameOffsets[]; +extern int numNodesInSkeleton[]; + +typedef void (*CreateSkeleton_t)(void *skeletalJoints, size_t jointSize, struct ArrayedListNode_s *jointNodes, int rootIndex); + +extern CreateSkeleton_t SkeletonCreators[NUM_SKELETONS]; \ No newline at end of file diff --git a/Toolkit/Programming/GameCode/qcommon/timing.h b/Toolkit/Programming/GameCode/qcommon/timing.h new file mode 100644 index 0000000..d226dc3 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/timing.h @@ -0,0 +1,10 @@ +#include "H2Common.h" + +H2COMMON_API void TIMING_ResetCount(); +H2COMMON_API int TIMING_GetAverage(); +H2COMMON_API void TIMING_Start(); +H2COMMON_API int TIMING_End(); +H2COMMON_API __int64 TIMING_GetTime(); +H2COMMON_API __int64 TIMING_ReturnTotal(); + +// end diff --git a/Toolkit/Programming/GameCode/qcommon/tokens.h b/Toolkit/Programming/GameCode/qcommon/tokens.h new file mode 100644 index 0000000..522e411 --- /dev/null +++ b/Toolkit/Programming/GameCode/qcommon/tokens.h @@ -0,0 +1,16 @@ +// tokens for config strings +// sounds +#define TOKEN_S_AMBIENT 254 +#define TOKEN_S_CINEMATICS 253 +#define TOKEN_S_CORVUS 252 +#define TOKEN_S_MISC 251 +#define TOKEN_S_MONSTERS 250 +#define TOKEN_S_WEAPONS 249 +#define TOKEN_S_PLAYER 248 +#define TOKEN_S_ITEMS 247 + +//models +#define TOKEN_M_MODELS 254 +#define TOKEN_M_MONSTERS 253 +#define TOKEN_M_OBJECTS 252 + diff --git a/Toolkit/Programming/Tools/MakeQDT/makeqdt.c b/Toolkit/Programming/Tools/MakeQDT/makeqdt.c new file mode 100644 index 0000000..c5d8dc6 --- /dev/null +++ b/Toolkit/Programming/Tools/MakeQDT/makeqdt.c @@ -0,0 +1,826 @@ +#include +#include +#include +#include +#include +#include + +FILE *FH; + +#define MAX_FILES 500 + +typedef enum project_e { + PROJECT_QUAKE2, + PROJECT_WOLF, + PROJECT_HERETIC2, + PROJECT_MAX +} project_t; + +char FileList[MAX_FILES][256],FileSubList[MAX_FILES][256]; +char StartSequenceList[MAX_FILES][256]; +int NumFiles = 0; +int NumSubFiles = 0; +int NumRemainingFiles; +char Path[256],FileName[256]; + +BOOL NoModelGen; +BOOL GenWeaponCode; +int StartWeaponIndex; + +char CodeName[256] = "frame"; + +char SaveCommands[100][256]; +int NumCommands = 0; + +int NumFrames = 0; +int NumSequences = 0; +DWORD TotalSize = 0; + +int TotalFrames = 0; +char FrameList[MAX_FILES+50][256]; + + +char ProjectMainDir[PROJECT_MAX][16] = +{ + "QUAKE2\\", + "WOLF\\", + "HERETIC2\\" +}; +char ProjectBaseDir[PROJECT_MAX][16] = +{ + "BASEQ2\\", + "BASEW\\", + "BASE\\" +}; +int ActiveProject = PROJECT_HERETIC2; +int UseMd2Model = 0; + + +void RemoveFiles(char *Pat) +{ + char temp[256]; + int counter; + + for(counter=0;counter= Position;c2--) + strcpy(FileSubList[c2+1],FileSubList[c2]); + + strcpy(FileSubList[Position],FileList[counter]); + Pos = strchr(FileSubList[Position],'.'); + if (Pos) *Pos = 0; + } + else + { + strcpy(FileSubList[NumSubFiles],FileList[counter]); + Pos = strchr(FileSubList[NumSubFiles],'.'); + if (Pos) *Pos = 0; + } + + NumSubFiles++; + NumRemainingFiles--; + FileList[counter][0] = 0; + } + } +} + +void CreateExtSubList(char *Pat, BOOL Reset) +{ + int Length,counter,c2,Position; + char *Pos; + + if (Reset) + { + NumSubFiles = 0; + } + Length = strlen(Pat); + for(counter=0;counter= Position;c2--) + strcpy(FileSubList[c2+1],FileSubList[c2]); + + strcpy(FileSubList[Position],FileList[counter]); + + } + else + strcpy(FileSubList[NumSubFiles],FileList[counter]); + + NumSubFiles++; + NumRemainingFiles--; + FileList[counter][0] = 0; + } + } +} + +void DoDirectory(void) +{ + WIN32_FIND_DATA filedata; + HANDLE handle; + BOOL retval; + char temp[256]; + int counter; + + sprintf(temp,"%s*.*",Path); + + handle = FindFirstFile(temp,&filedata); + retval = TRUE; + + while (handle != INVALID_HANDLE_VALUE && retval) + { + if (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + // Ignore directories until later + } + else + { + strcpy(temp,filedata.cFileName); + strlwr(temp); + if (strstr(temp,".tri") || + strstr(temp,".hrc") || + strstr(temp,".asc") || + strstr(temp,".htr") || + strstr(temp,".lbm") || + strstr(temp,".tga") || + strstr(temp,".pcx")) + { + strcpy(FileList[NumFiles],filedata.cFileName); +// Pos = strchr(FileList[NumFiles],'.'); +// if (Pos) *Pos = 0; + + for(counter=0;counter= NumFiles) + { + NumFiles++; + TotalSize += filedata.nFileSizeLow; + } + } + } + + retval = FindNextFile(handle,&filedata); + } + + if (handle != INVALID_HANDLE_VALUE) + FindClose(handle); + + NumRemainingFiles = NumFiles; +} + +void CreateFrames(void) +{ + int counter,c2,Length; + char temp[256]; + + for(counter=0;counter= %d)\n",NumSequences); + fprintf(FH," self.cnt = 0;\n"); + fprintf(FH,"};\n"); + +} + +void ReadOldQDT(char *Name) +{ + FILE *FH; + char temp[256]; + int start; + + FH = fopen(Name,"r"); + if (!FH) return; + + while(!feof(FH)) + { + fgets(temp,sizeof(temp),FH); + if (feof(FH)) continue; + + temp[strlen(temp)-1] = 0; // get rid of the lf + + start = 0; + while (temp[start] != 0 && temp[start] < 33) + start++; + + if (temp[start] != '$') continue; + + if (_strnicmp(&temp[start],"$fm_frame",9) == 0) break; + if (_strnicmp(&temp[start],"$frame",6) == 0) break; + + if (_strnicmp(&temp[start],"$fm_skin",8) == 0) continue; + if (_strnicmp(&temp[start],"$skin",5) == 0) continue; + if (_strnicmp(&temp[start],"$fm_base",8) == 0) continue; + if (_strnicmp(&temp[start],"$fm_stbase",10) == 0) continue; + if (_strnicmp(&temp[start],"$base",5) == 0) continue; + if (_strnicmp(&temp[start],"$fm_cd",6) == 0) continue; + if (_strnicmp(&temp[start],"$cd",3) == 0) continue; + + strcpy(SaveCommands[NumCommands],temp); + NumCommands++; + } + + fclose(FH); +} + +int FindCommand(char *Which) +{ + int counter,start,length; + + length = 0; + while(Which[length] != 0 && Which[length] > 32) + length++; + + for(counter=0;counter\n" + +int main(int argc, char **argv) +{ + char Buffer[MAX_PATH],*FilePtr,*Pos,BaseName[64],temp[MAX_PATH],CDPath[MAX_PATH], NewFile[MAX_PATH],STBaseName[64]; + int counter,Position; + + GetTempPath(sizeof(Buffer),Buffer); + + NoModelGen = GenWeaponCode = FALSE; + StartWeaponIndex = 1; + + printf("makeqdt V1.2 (%s %s) by RJ!\n\n",__DATE__,__TIME__); + if (argc < 2) + { + printf(COMMAND_LINE); + return 0; + } + + counter = 1; + while(counter < argc) + { + if (strcmpi(argv[counter],"-q2") == 0) + ActiveProject = PROJECT_QUAKE2; + else if (strcmpi(argv[counter],"-wolf") == 0) + ActiveProject = PROJECT_WOLF; + else if (strcmpi(argv[counter],"-ht2") == 0) + ActiveProject = PROJECT_HERETIC2; + else if (strcmpi(argv[counter],"-md2") == 0) + UseMd2Model = TRUE; + else if (strcmpi(argv[counter],"-fm") == 0) + UseMd2Model = FALSE; + else if (strcmpi(argv[counter],"-nogen") == 0) + NoModelGen = TRUE; + else if (strcmpi(argv[counter],"-weapon") == 0) + GenWeaponCode = TRUE; + else if (strcmpi(argv[counter],"-index") == 0) + { + counter++; + if (counter < argc) StartWeaponIndex = atoi(argv[counter]); + } + else if (strcmpi(argv[counter],"-name") == 0) + { + counter++; + if (counter < argc) strcpy(CodeName,argv[counter]); + } + else + { + strcpy(temp,argv[counter]); + DefaultExtension(temp,".qdt"); + GetFullPathName(temp,sizeof(Buffer),Buffer,&FilePtr); + strcpy(NewFile,Buffer); + strlwr(NewFile); + if (strstr(NewFile,ProjectBaseDir[ActiveProject])) + { + *(strstr(NewFile,ProjectBaseDir[ActiveProject])+6) = 0; + strcat(NewFile,"scripts\\"); + strcat(NewFile,temp); + } + } + + counter++; + } + + if (Buffer[0] == 0) + { + printf(COMMAND_LINE); + return 0; + } + + strcpy(FileName,FilePtr); + *FilePtr = 0; + strcpy(Path,Buffer); + *FilePtr = FileName[0]; + + printf("Path: %s\n",Path); + printf("QDT: %s\n",FileName); + + DoDirectory(); + + FH = fopen(NewFile,"r"); + if (FH) + { + fclose(FH); + printf("File exists: %s\n",FileName); + printf("Do you want to delete this? (Y/N) "); + counter = getche(); + printf("\n"); + if (counter != 'y' && counter != 'Y') + return 0; + printf("\n"); + ReadOldQDT(NewFile); + } + + FH = fopen(NewFile,"w"); + if (!FH) + { + printf("Could not create %s\n",Buffer); + return 0; + } + + *(FilePtr-1) = 0; + strcpy(temp, Buffer); + _strlwr(temp); + if (strstr(temp,"models")) + { + strcpy(CDPath, strstr(temp,"models")+7); + } + else + strcpy(CDPath, temp); + + if (UseMd2Model) + { + fprintf(FH,"$cd %s\n",CDPath); + Position = FindCommand("$origin"); + } + else + { + fprintf(FH,"$fm_cd %s\n",CDPath); + Position = FindCommand("$fm_origin"); + } + + if (Position >= 0) + { + fprintf(FH,"%s\n",SaveCommands[Position]); + SaveCommands[Position][0] = 0; + } + else + { + if (UseMd2Model) + { + fprintf(FH,"$origin 0 0 0\n"); + } + else + { + fprintf(FH,"$fm_origin 0 0 0\n"); + } + } + + RemoveFiles("bin"); + RemoveFiles("!"); + CreateSubList("base"); + if (!NumSubFiles) + { + fclose(FH); + printf("No base* file!\n"); + return 1; + } + else if (NumSubFiles > 1) + { + fclose(FH); + printf("More than one base* files!\n"); + return 1; + } + strcpy(BaseName,FileSubList[0]); + + CreateSubList("stbase"); + STBaseName[0]=0; + if (NumSubFiles > 1) + { + printf("More than one STbase* files!\n"); + } + else if (NumSubFiles) + { + strcpy(STBaseName,FileSubList[0]); + } + + CreateExtSubList("pcx", TRUE); + CreateExtSubList("tga", FALSE); + if (!NumSubFiles) + { + fclose(FH); + printf("No .pcx or .tga files!\n"); + return 2; + } + + temp[0] = 0; //find the first skin for the base cmd + for(counter=0;counter= 0) + { + fprintf(FH,"%s\n",SaveCommands[Position]); + SaveCommands[Position][0] = 0; + } + else + { + if (UseMd2Model) + { + fprintf(FH,"$scale 1\n"); + } + else + { + fprintf(FH,"$fm_scale 1\n"); + } + } + for(counter=0;counter +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=makeqdt - 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 "makeqdt.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 "makeqdt.mak" CFG="makeqdt - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "makeqdt - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "makeqdt - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName ""$/Q2 Utilities/MakeQDT", SPBAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "makeqdt - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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:console /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 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "makeqdt - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# 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:console /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 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "makeqdt - Win32 Release" +# Name "makeqdt - Win32 Debug" +# Begin Source File + +SOURCE=.\makeqdt.c +# End Source File +# End Target +# End Project diff --git a/Toolkit/Programming/Tools/MakeQDT/makeqdt.dsw b/Toolkit/Programming/Tools/MakeQDT/makeqdt.dsw new file mode 100644 index 0000000..14611d2 --- /dev/null +++ b/Toolkit/Programming/Tools/MakeQDT/makeqdt.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "makeqdt"=.\makeqdt.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/MakeQDT", SPBAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/MakeQDT", SPBAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Toolkit/Programming/Tools/bsp/bsp.dsp b/Toolkit/Programming/Tools/bsp/bsp.dsp new file mode 100644 index 0000000..ae087d3 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/bsp.dsp @@ -0,0 +1,97 @@ +# Microsoft Developer Studio Project File - Name="bsp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=bsp - Win32 Release +!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 "bsp.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 "bsp.mak" CFG="bsp - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bsp - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "bsp - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName ""$/Wolf/Final/Utilities/bsp", SODAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bsp - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /O2 /I "..\common" /I "..\ref_gl" /I "..\..\qdata" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_TOOL" /YX /FD /c +# 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:console /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib 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:console /map /debug /machine:I386 + +!ELSEIF "$(CFG)" == "bsp - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Gm /Zi /Od /I "..\common" /I "..\ref_gl" /D "_TOOL" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /YX /FD /c +# 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:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib 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:console /map /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "bsp - Win32 Release" +# Name "bsp - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Toolkit/Programming/Tools/bsp/bsp.dsw b/Toolkit/Programming/Tools/bsp/bsp.dsw new file mode 100644 index 0000000..c1e3bcb --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/bsp.dsw @@ -0,0 +1,113 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "bsp"=.\bsp.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/bsp", SODAAAAA + . + end source code control +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bspinfo3 + End Project Dependency + Begin Project Dependency + Project_Dep_Name qbsp3 + End Project Dependency + Begin Project Dependency + Project_Dep_Name qrad3 + End Project Dependency + Begin Project Dependency + Project_Dep_Name qvis3 + End Project Dependency +}}} + +############################################################################### + +Project: "bspinfo3"=.\bspinfo3\bspinfo3.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/bsp/bspinfo3", DPDAAAAA + .\bspinfo3 + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "qbsp3"=.\qbsp3\qbsp3.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/bsp/qbsp3", YODAAAAA + .\qbsp3 + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "qrad3"=.\qrad3\qrad3.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/bsp/qrad3", ZODAAAAA + .\qrad3 + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "qvis3"=.\qvis3\qvis3.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/bsp/qvis3", APDAAAAA + .\qvis3 + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/bsp", SODAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Toolkit/Programming/Tools/bsp/bsp.ncb b/Toolkit/Programming/Tools/bsp/bsp.ncb new file mode 100644 index 0000000..0b89083 Binary files /dev/null and b/Toolkit/Programming/Tools/bsp/bsp.ncb differ diff --git a/Toolkit/Programming/Tools/bsp/bsp.opt b/Toolkit/Programming/Tools/bsp/bsp.opt new file mode 100644 index 0000000..d13af1e Binary files /dev/null and b/Toolkit/Programming/Tools/bsp/bsp.opt differ diff --git a/Toolkit/Programming/Tools/bsp/bspinfo3/bspinfo3.c b/Toolkit/Programming/Tools/bsp/bspinfo3/bspinfo3.c new file mode 100644 index 0000000..563f5d4 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/bspinfo3/bspinfo3.c @@ -0,0 +1,35 @@ + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" + +void main (int argc, char **argv) +{ + int i; + char source[1024]; + int size; + FILE *f; + + if (argc == 1) + Error ("usage: bspinfo bspfile [bspfiles]"); + + for (i=1 ; i +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=bspinfo3 - Win32 Release +!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 "bspinfo3.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 "bspinfo3.mak" CFG="bspinfo3 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bspinfo3 - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "bspinfo3 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName ""$/Wolf/Final/Utilities/bsp/bspinfo3", DPDAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bspinfo3 - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Zi /O2 /I "..\..\common" /I "..\..\ref_gl" /I "..\..\qdata" /I "..\..\qcommon" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_TOOL" /FR /YX /FD /c +# 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:console /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib 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:console /map /debug /machine:I386 + +!ELSEIF "$(CFG)" == "bspinfo3 - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Gm /Zi /Od /I "..\..\common" /I "..\..\ref_gl" /I "../../qcommon" /D "_DEBUG" /D "_TOOL" /D "WIN32" /D "_CONSOLE" /FR /YX /FD /c +# 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:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib 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:console /map /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "bspinfo3 - Win32 Release" +# Name "bspinfo3 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\..\common\bspfile.c +# End Source File +# Begin Source File + +SOURCE=.\bspinfo3.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\cmdlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\mathlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\scriplib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\scriplib.h +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=..\..\common\bspfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\cmdlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\mathlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\qcommon\q_typedef.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\qfiles.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Toolkit/Programming/Tools/bsp/bspinfo3/bspinfo3.dsw b/Toolkit/Programming/Tools/bsp/bspinfo3/bspinfo3.dsw new file mode 100644 index 0000000..8f08a63 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/bspinfo3/bspinfo3.dsw @@ -0,0 +1,33 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "bspinfo3"=.\bspinfo3.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/bsp/bspinfo3", DPDAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/brushbsp.c b/Toolkit/Programming/Tools/bsp/qbsp3/brushbsp.c new file mode 100644 index 0000000..89149e3 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/brushbsp.c @@ -0,0 +1,1321 @@ + +#include "qbsp.h" + + +int c_nodes; +int c_nonvis; +int c_active_brushes; + +// if a brush just barely pokes onto the other side, +// let it slide by without chopping +#define PLANESIDE_EPSILON 0.001 +//0.1 + +#define PSIDE_FRONT 1 +#define PSIDE_BACK 2 +#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK) +#define PSIDE_FACING 4 + + +void FindBrushInTree (node_t *node, int brushnum) +{ + bspbrush_t *b; + + if (node->planenum == PLANENUM_LEAF) + { + for (b=node->brushlist ; b ; b=b->next) + if (b->original->brushnum == brushnum) + printf ("here\n"); + return; + } + FindBrushInTree (node->children[0], brushnum); + FindBrushInTree (node->children[1], brushnum); +} + +//================================================== + +/* +================ +DrawBrushList +================ +*/ +void DrawBrushList (bspbrush_t *brush, node_t *node) +{ +#ifdef _USEOPENGL + int i; + side_t *s; + + GLS_BeginScene (); + for ( ; brush ; brush=brush->next) + { + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + if (!s->winding) + continue; + if (s->texinfo == TEXINFO_NODE) + GLS_Winding (s->winding, 1); + else if (!s->visible) + GLS_Winding (s->winding, 2); + else + GLS_Winding (s->winding, 0); + } + } + GLS_EndScene (); +#endif +} + +/* +================ +WriteBrushList +================ +*/ +void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis) +{ + int i; + side_t *s; + FILE *f; + + qprintf ("writing %s\n", name); + f = SafeOpenWrite (name); + + for ( ; brush ; brush=brush->next) + { + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + if (!s->winding) + continue; + if (onlyvis && !s->visible) + continue; + OutputWinding (brush->sides[i].winding, f); + } + } + + fclose (f); +} + +void PrintBrush (bspbrush_t *brush) +{ + int i; + + printf ("brush: %p\n", brush); + for (i=0;inumsides ; i++) + { + pw(brush->sides[i].winding); + printf ("\n"); + } +} + +/* +================== +BoundBrush + +Sets the mins/maxs based on the windings +================== +*/ +void BoundBrush (bspbrush_t *brush) +{ + int i, j; + winding_t *w; + + ClearBounds (brush->mins, brush->maxs); + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + AddPointToBounds (w->p[j], brush->mins, brush->maxs); + } +} + +/* +================== +CreateBrushWindings + +================== +*/ +void CreateBrushWindings (bspbrush_t *brush) +{ + int i, j; + winding_t *w; + side_t *side; + plane_t *plane; + + for (i=0 ; inumsides ; i++) + { + side = &brush->sides[i]; + plane = &mapplanes[side->planenum]; + w = BaseWindingForPlane (plane->normal, plane->dist); + for (j=0 ; jnumsides && w; j++) + { + if (i == j) + continue; + if (brush->sides[j].bevel) + continue; + plane = &mapplanes[brush->sides[j].planenum^1]; + ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); + } + + side->winding = w; + } + + BoundBrush (brush); +} + +/* +================== +BrushFromBounds + +Creates a new axial brush +================== +*/ +bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs) +{ + bspbrush_t *b; + int i; + vec3_t normal; + vec_t dist; + + b = AllocBrush (6); + b->numsides = 6; + for (i=0 ; i<3 ; i++) + { + VectorClear (normal); + normal[i] = 1; + dist = maxs[i]; + b->sides[i].planenum = FindFloatPlane (normal, dist); + + normal[i] = -1; + dist = -mins[i]; + b->sides[3+i].planenum = FindFloatPlane (normal, dist); + } + + CreateBrushWindings (b); + + return b; +} + +/* +================== +BrushVolume + +================== +*/ +vec_t BrushVolume (bspbrush_t *brush) +{ + int i; + winding_t *w; + vec3_t corner; + vec_t d, area, volume; + plane_t *plane; + + if (!brush) + return 0; + + // grab the first valid point as the corner + + w = NULL; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (w) + break; + } + if (!w) + return 0; + VectorCopy (w->p[0], corner); + + // make tetrahedrons to all other faces + + volume = 0; + for ( ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + plane = &mapplanes[brush->sides[i].planenum]; + d = -(DotProduct (corner, plane->normal) - plane->dist); + area = WindingArea (w); + volume += d*area; + } + + volume /= 3; + return volume; +} + +/* +================ +CountBrushList +================ +*/ +int CountBrushList (bspbrush_t *brushes) +{ + int c; + + c = 0; + for ( ; brushes ; brushes = brushes->next) + c++; + return c; +} + +/* +================ +AllocTree +================ +*/ +tree_t *AllocTree (void) +{ + tree_t *tree; + + tree = malloc(sizeof(*tree)); + if (tree == NULL) + Error("AllocTree MALLOC failed! Could not allocate %s bytes.", sizeof(*tree)); + + memset (tree, 0, sizeof(*tree)); + ClearBounds (tree->mins, tree->maxs); + + return tree; +} + +/* +================ +AllocNode +================ +*/ +node_t *AllocNode (void) +{ + node_t *node; + + node = malloc(sizeof(*node)); + if (node == NULL) + Error("AllocNode MALLOC failed! Could not allocate %s bytes.", sizeof(*node)); + + memset (node, 0, sizeof(*node)); + + return node; +} + + +/* +================ +AllocBrush +================ +*/ +bspbrush_t *AllocBrush (int numsides) +{ + bspbrush_t *bb; + int c; + + c = (int)&(((bspbrush_t *)0)->sides[numsides]); + bb = malloc(c); + if (bb == NULL) + Error("AllocBrush MALLOC failed! Could not allocate %s bytes.", sizeof(c)); + + memset (bb, 0, c); + if (numthreads == 1) + c_active_brushes++; + return bb; +} + +/* +================ +FreeBrush +================ +*/ +void FreeBrush (bspbrush_t *brushes) +{ + int i; + + for (i=0 ; inumsides ; i++) + if (brushes->sides[i].winding) + FreeWinding(brushes->sides[i].winding); + free (brushes); + if (numthreads == 1) + c_active_brushes--; +} + + +/* +================ +FreeBrushList +================ +*/ +void FreeBrushList (bspbrush_t *brushes) +{ + bspbrush_t *next; + + for ( ; brushes ; brushes = next) + { + next = brushes->next; + + FreeBrush (brushes); + } +} + +/* +================== +CopyBrush + +Duplicates the brush, the sides, and the windings +================== +*/ +bspbrush_t *CopyBrush (bspbrush_t *brush) +{ + bspbrush_t *newbrush; + int size; + int i; + + size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]); + + newbrush = AllocBrush (brush->numsides); + memcpy (newbrush, brush, size); + + for (i=0 ; inumsides ; i++) + { + if (brush->sides[i].winding) + newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding); + } + + return newbrush; +} + + +/* +================== +PointInLeaf + +================== +*/ +node_t *PointInLeaf (node_t *node, vec3_t point) +{ + vec_t d; + plane_t *plane; + + while (node->planenum != PLANENUM_LEAF) + { + plane = &mapplanes[node->planenum]; + d = DotProduct (point, plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return node; +} + +//======================================================== + +/* +============== +BoxOnPlaneSide + +Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH +============== +*/ +int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane) +{ + int side; + int i; + vec3_t corners[2]; + vec_t dist1, dist2; + + // axial planes are easy + if (plane->type < 3) + { + side = 0; + if (maxs[plane->type] > plane->dist+PLANESIDE_EPSILON) + side |= PSIDE_FRONT; + if (mins[plane->type] < plane->dist-PLANESIDE_EPSILON) + side |= PSIDE_BACK; + return side; + } + + // create the proper leading and trailing verts for the box + + for (i=0 ; i<3 ; i++) + { + if (plane->normal[i] < 0) + { + corners[0][i] = mins[i]; + corners[1][i] = maxs[i]; + } + else + { + corners[1][i] = mins[i]; + corners[0][i] = maxs[i]; + } + } + + dist1 = DotProduct (plane->normal, corners[0]) - plane->dist; + dist2 = DotProduct (plane->normal, corners[1]) - plane->dist; + side = 0; + if (dist1 >= PLANESIDE_EPSILON) + side = PSIDE_FRONT; + if (dist2 < PLANESIDE_EPSILON) + side |= PSIDE_BACK; + + return side; +} + +/* +============ +QuickTestBrushToPlanenum + +============ +*/ +int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits) +{ + int i, num; + plane_t *plane; + int s; + + *numsplits = 0; + + // if the brush actually uses the planenum, + // we can tell the side for sure + for (i=0 ; inumsides ; i++) + { + num = brush->sides[i].planenum; + if (num >= 0x10000) + Error ("bad planenum"); + if (num == planenum) + return PSIDE_BACK|PSIDE_FACING; + if (num == (planenum ^ 1) ) + return PSIDE_FRONT|PSIDE_FACING; + } + + // box on plane side + plane = &mapplanes[planenum]; + s = BoxOnPlaneSide (brush->mins, brush->maxs, plane); + + // if both sides, count the visible faces split + if (s == PSIDE_BOTH) + { + *numsplits += 3; + } + + return s; +} + +/* +============ +TestBrushToPlanenum + +============ +*/ +int TestBrushToPlanenum (bspbrush_t *brush, int planenum, + int *numsplits, qboolean *hintsplit, int *epsilonbrush) +{ + int i, j, num; + plane_t *plane; + int s; + winding_t *w; + vec_t d, d_front, d_back; + int front, back; + + *numsplits = 0; + *hintsplit = false; + + // if the brush actually uses the planenum, + // we can tell the side for sure + for (i=0 ; inumsides ; i++) + { + num = brush->sides[i].planenum; + if (num >= 0x10000) + Error ("bad planenum"); + if (num == planenum) + return PSIDE_BACK|PSIDE_FACING; + if (num == (planenum ^ 1) ) + return PSIDE_FRONT|PSIDE_FACING; + } + + // box on plane side + plane = &mapplanes[planenum]; + s = BoxOnPlaneSide (brush->mins, brush->maxs, plane); + + if (s != PSIDE_BOTH) + return s; + +// if both sides, count the visible faces split + d_front = d_back = 0; + + for (i=0 ; inumsides ; i++) + { + if (brush->sides[i].texinfo == TEXINFO_NODE) + continue; // on node, don't worry about splits + if (!brush->sides[i].visible) + continue; // we don't care about non-visible + w = brush->sides[i].winding; + if (!w) + continue; + front = back = 0; + for (j=0 ; jnumpoints; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > d_front) + d_front = d; + if (d < d_back) + d_back = d; + + if (d > 0.1) // PLANESIDE_EPSILON) + front = 1; + if (d < -0.1) // PLANESIDE_EPSILON) + back = 1; + } + if (front && back) + { + if ( !(brush->sides[i].surf & SURF_SKIP) ) + { + (*numsplits)++; + if (brush->sides[i].surf & SURF_HINT) + *hintsplit = true; + } + } + } + + if ( (d_front > 0.0 && d_front < 1.0) + || (d_back < 0.0 && d_back > -1.0) ) + (*epsilonbrush)++; + +#if 0 + if (*numsplits == 0) + { // didn't really need to be split + if (front) + s = PSIDE_FRONT; + else if (back) + s = PSIDE_BACK; + else + s = 0; + } +#endif + + return s; +} + +//======================================================== + +/* +================ +WindingIsTiny + +Returns true if the winding would be crunched out of +existance by the vertex snapping. +================ +*/ +#define EDGE_LENGTH 0.2 +qboolean WindingIsTiny (winding_t *w) +{ +#if 0 + if (WindingArea (w) < 1) + return true; + return false; +#else + int i, j; + vec_t len; + vec3_t delta; + int edges; + + edges = 0; + for (i=0 ; inumpoints ; i++) + { + j = i == w->numpoints - 1 ? 0 : i+1; + VectorSubtract (w->p[j], w->p[i], delta); + len = VectorLength (delta); + if (len > EDGE_LENGTH) + { + if (++edges == 3) + return false; + } + } + return true; +#endif +} + +/* +================ +WindingIsHuge + +Returns true if the winding still has one of the points +from basewinding for plane +================ +*/ +qboolean WindingIsHuge (winding_t *w) +{ + int i, j; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + if (w->p[i][j] < -8000 || w->p[i][j] > 8000) + return true; + } + return false; +} + +//============================================================ + +/* +================ +Leafnode +================ +*/ +void LeafNode (node_t *node, bspbrush_t *brushes) +{ + bspbrush_t *b; + int i; + + node->planenum = PLANENUM_LEAF; + node->contents = 0; + + for (b=brushes ; b ; b=b->next) + { + // if the brush is solid and all of its sides are on nodes, + // it eats everything + if (b->original->contents & CONTENTS_SOLID) + { + for (i=0 ; inumsides ; i++) + if (b->sides[i].texinfo != TEXINFO_NODE) + break; + if (i == b->numsides) + { + node->contents = CONTENTS_SOLID; + break; + } + } + node->contents |= b->original->contents; + } + + node->brushlist = brushes; +} + + +//============================================================ + +void CheckPlaneAgainstParents (int pnum, node_t *node) +{ + node_t *p; + + for (p=node->parent ; p ; p=p->parent) + { + if (p->planenum == pnum) + Error ("Tried parent"); + } +} + +qboolean CheckPlaneAgainstVolume (int pnum, node_t *node) +{ + bspbrush_t *front, *back; + qboolean good; + + SplitBrush (node->volume, pnum, &front, &back); + + good = (front && back); + + if (front) + FreeBrush (front); + if (back) + FreeBrush (back); + + return good; +} + +/* +================ +SelectSplitSide + +Using a hueristic, choses one of the sides out of the brushlist +to partition the brushes with. +Returns NULL if there are no valid planes to split with.. +================ +*/ +side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node) +{ + int value, bestvalue; + bspbrush_t *brush, *test; + side_t *side, *bestside; + int i, j, pass, numpasses; + int pnum; + int s; + int front, back, both, facing, splits; + int bsplits; + int bestsplits; + int epsilonbrush; + qboolean hintsplit; + + bestside = NULL; + bestvalue = -99999; + bestsplits = 0; + + // the search order goes: visible-structural, visible-detail, + // nonvisible-structural, nonvisible-detail. + // If any valid plane is available in a pass, no further + // passes will be tried. + numpasses = 4; + for (pass = 0 ; pass < numpasses ; pass++) + { + for (brush = brushes ; brush ; brush=brush->next) + { + if ( (pass & 1) && !(brush->original->contents & CONTENTS_DETAIL) ) + continue; + if ( !(pass & 1) && (brush->original->contents & CONTENTS_DETAIL) ) + continue; + for (i=0 ; inumsides ; i++) + { + side = brush->sides + i; + if (side->bevel) + continue; // never use a bevel as a spliter + if (!side->winding) + continue; // nothing visible, so it can't split + if (side->texinfo == TEXINFO_NODE) + continue; // allready a node splitter + if (side->tested) + continue; // we allready have metrics for this plane + if (side->surf & SURF_SKIP) + continue; // skip surfaces are never chosen + if ( side->visible ^ (pass<2) ) + continue; // only check visible faces on first pass + + pnum = side->planenum; + pnum &= ~1; // allways use positive facing plane + + CheckPlaneAgainstParents (pnum, node); + + if (!CheckPlaneAgainstVolume (pnum, node)) + continue; // would produce a tiny volume + + front = 0; + back = 0; + both = 0; + facing = 0; + splits = 0; + epsilonbrush = 0; + + for (test = brushes ; test ; test=test->next) + { + s = TestBrushToPlanenum (test, pnum, &bsplits, &hintsplit, &epsilonbrush); + + splits += bsplits; + if (bsplits && (s&PSIDE_FACING) ) + Error ("PSIDE_FACING with splits"); + + test->testside = s; + // if the brush shares this face, don't bother + // testing that facenum as a splitter again + if (s & PSIDE_FACING) + { + facing++; + for (j=0 ; jnumsides ; j++) + { + if ( (test->sides[j].planenum&~1) == pnum) + test->sides[j].tested = true; + } + } + if (s & PSIDE_FRONT) + front++; + if (s & PSIDE_BACK) + back++; + if (s == PSIDE_BOTH) + both++; + } + + // give a value estimate for using this plane + + value = 5*facing - 5*splits - abs(front-back); +// value = -5*splits; +// value = 5*facing - 5*splits; + if (mapplanes[pnum].type < 3) + value+=5; // axial is better + value -= epsilonbrush*1000; // avoid! + + // never split a hint side except with another hint + if (hintsplit && !(side->surf & SURF_HINT) ) + value = -9999999; + + // save off the side test so we don't need + // to recalculate it when we actually seperate + // the brushes + if (value > bestvalue) + { + bestvalue = value; + bestside = side; + bestsplits = splits; + for (test = brushes ; test ; test=test->next) + test->side = test->testside; + } + } + } + + // if we found a good plane, don't bother trying any + // other passes + if (bestside) + { + if (pass > 1) + { + if (numthreads == 1) + c_nonvis++; + } + if (pass > 0) + node->detail_seperator = true; // not needed for vis + break; + } + } + + // + // clear all the tested flags we set + // + for (brush = brushes ; brush ; brush=brush->next) + { + for (i=0 ; inumsides ; i++) + brush->sides[i].tested = false; + } + + return bestside; +} + + +/* +================== +BrushMostlyOnSide + +================== +*/ +int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane) +{ + int i, j; + winding_t *w; + vec_t d, max; + int side; + + max = 0; + side = PSIDE_FRONT; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > max) + { + max = d; + side = PSIDE_FRONT; + } + if (-d > max) + { + max = -d; + side = PSIDE_BACK; + } + } + } + return side; +} + +/* +================ +SplitBrush + +Generates two new brushes, leaving the original +unchanged +================ +*/ +void SplitBrush (bspbrush_t *brush, int planenum, + bspbrush_t **front, bspbrush_t **back) +{ + bspbrush_t *b[2]; + int i, j; + winding_t *w, *cw[2], *midwinding; + plane_t *plane, *plane2; + side_t *s, *cs; + float d, d_front, d_back; + + *front = *back = NULL; + plane = &mapplanes[planenum]; + + // check all points + d_front = d_back = 0; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > 0 && d > d_front) + d_front = d; + if (d < 0 && d < d_back) + d_back = d; + } + } + if (d_front < 0.1) // PLANESIDE_EPSILON) + { // only on back + *back = CopyBrush (brush); + return; + } + if (d_back > -0.1) // PLANESIDE_EPSILON) + { // only on front + *front = CopyBrush (brush); + return; + } + + // create a new winding from the split plane + + w = BaseWindingForPlane (plane->normal, plane->dist); + for (i=0 ; inumsides && w ; i++) + { + plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; + ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); + } + + if (!w || WindingIsTiny (w) ) + { // the brush isn't really split + int side; + + side = BrushMostlyOnSide (brush, plane); + if (side == PSIDE_FRONT) + *front = CopyBrush (brush); + if (side == PSIDE_BACK) + *back = CopyBrush (brush); + return; + } + + if (WindingIsHuge (w)) + { + qprintf ("WARNING: huge winding\n"); + } + + midwinding = w; + + // split it for real + + for (i=0 ; i<2 ; i++) + { + b[i] = AllocBrush (brush->numsides+1); + b[i]->original = brush->original; + } + + // split all the current windings + + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + w = s->winding; + if (!w) + continue; + ClipWindingEpsilon (w, plane->normal, plane->dist, + 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); + for (j=0 ; j<2 ; j++) + { + if (!cw[j]) + continue; +#if 0 + if (WindingIsTiny (cw[j])) + { + FreeWinding (cw[j]); + continue; + } +#endif + cs = &b[j]->sides[b[j]->numsides]; + b[j]->numsides++; + *cs = *s; +// cs->planenum = s->planenum; +// cs->texinfo = s->texinfo; +// cs->visible = s->visible; +// cs->original = s->original; + cs->winding = cw[j]; + cs->tested = false; + } + } + + + // see if we have valid polygons on both sides + + for (i=0 ; i<2 ; i++) + { + BoundBrush (b[i]); + for (j=0 ; j<3 ; j++) + { + if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096) + { + qprintf ("bogus brush after clip\n"); + break; + } + } + + if (b[i]->numsides < 3 || j < 3) + { + FreeBrush (b[i]); + b[i] = NULL; + } + } + + if ( !(b[0] && b[1]) ) + { + if (!b[0] && !b[1]) + qprintf ("split removed brush\n"); + else + qprintf ("split not on both sides\n"); + if (b[0]) + { + FreeBrush (b[0]); + *front = CopyBrush (brush); + } + if (b[1]) + { + FreeBrush (b[1]); + *back = CopyBrush (brush); + } + return; + } + + // add the midwinding to both sides + for (i=0 ; i<2 ; i++) + { + cs = &b[i]->sides[b[i]->numsides]; + b[i]->numsides++; + + cs->planenum = planenum^i^1; + cs->texinfo = TEXINFO_NODE; + cs->visible = false; + cs->tested = false; + if (i==0) + cs->winding = CopyWinding (midwinding); + else + cs->winding = midwinding; + } + +{ + vec_t v1; + int i; + + for (i=0 ; i<2 ; i++) + { + v1 = BrushVolume (b[i]); + if (v1 < 1.0) + { + FreeBrush (b[i]); + b[i] = NULL; +// qprintf ("tiny volume after clip\n"); + } + } +} + + *front = b[0]; + *back = b[1]; +} + +/* +================ +SplitBrushList +================ +*/ +void SplitBrushList (bspbrush_t *brushes, + node_t *node, bspbrush_t **front, bspbrush_t **back) +{ + bspbrush_t *brush, *newbrush, *newbrush2; + side_t *side; + int sides; + int i; + + *front = *back = NULL; + + for (brush = brushes ; brush ; brush=brush->next) + { + sides = brush->side; + + if (sides == PSIDE_BOTH) + { // split into two brushes + SplitBrush (brush, node->planenum, &newbrush, &newbrush2); + if (newbrush) + { + newbrush->next = *front; + *front = newbrush; + } + if (newbrush2) + { + newbrush2->next = *back; + *back = newbrush2; + } + continue; + } + + newbrush = CopyBrush (brush); + + // if the planenum is actualy a part of the brush + // find the plane and flag it as used so it won't be tried + // as a splitter again + if (sides & PSIDE_FACING) + { + for (i=0 ; inumsides ; i++) + { + side = newbrush->sides + i; + if ( (side->planenum& ~1) == node->planenum) + side->texinfo = TEXINFO_NODE; + } + } + + + if (sides & PSIDE_FRONT) + { + newbrush->next = *front; + *front = newbrush; + continue; + } + if (sides & PSIDE_BACK) + { + newbrush->next = *back; + *back = newbrush; + continue; + } + } +} + + +/* +================ +BuildTree_r +================ +*/ +node_t *BuildTree_r (node_t *node, bspbrush_t *brushes) +{ + node_t *newnode; + side_t *bestside; + int i; + bspbrush_t *children[2]; + + if (numthreads == 1) + c_nodes++; + +#ifdef _USEOPENGL + if (drawflag) + DrawBrushList (brushes, node); +#endif + // find the best plane to use as a splitter + bestside = SelectSplitSide (brushes, node); + if (!bestside) + { + // leaf node + node->side = NULL; + node->planenum = -1; + LeafNode (node, brushes); + return node; + } + + // this is a splitplane node + node->side = bestside; + node->planenum = bestside->planenum & ~1; // always use front facing + + SplitBrushList (brushes, node, &children[0], &children[1]); + FreeBrushList (brushes); + + // allocate children before recursing + for (i=0 ; i<2 ; i++) + { + newnode = AllocNode (); + newnode->parent = node; + node->children[i] = newnode; + } + + SplitBrush (node->volume, node->planenum, &node->children[0]->volume, + &node->children[1]->volume); + + // recursively process children + for (i=0 ; i<2 ; i++) + { + node->children[i] = BuildTree_r (node->children[i], children[i]); + } + + return node; +} + +//=========================================================== + +/* +================= +BrushBSP + +The incoming list will be freed before exiting +================= +*/ +tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs) +{ + node_t *node; + bspbrush_t *b; + int c_faces, c_nonvisfaces; + int c_brushes; + tree_t *tree; + int i; + vec_t volume; + + qprintf ("--- BrushBSP ---\n"); + + tree = AllocTree (); + + c_faces = 0; + c_nonvisfaces = 0; + c_brushes = 0; + for (b=brushlist ; b ; b=b->next) + { + c_brushes++; + + volume = BrushVolume (b); + if (volume < microvolume) + { + printf ("WARNING: entity %i, brush %i: microbrush\n", + b->original->entitynum, b->original->brushnum); + } + + for (i=0 ; inumsides ; i++) + { + if (b->sides[i].bevel) + continue; + if (!b->sides[i].winding) + continue; + if (b->sides[i].texinfo == TEXINFO_NODE) + continue; + if (b->sides[i].visible) + c_faces++; + else + c_nonvisfaces++; + } + + AddPointToBounds (b->mins, tree->mins, tree->maxs); + AddPointToBounds (b->maxs, tree->mins, tree->maxs); + } + + qprintf ("%5i brushes\n", c_brushes); + qprintf ("%5i visible faces\n", c_faces); + qprintf ("%5i nonvisible faces\n", c_nonvisfaces); + + c_nodes = 0; + c_nonvis = 0; + node = AllocNode (); + + node->volume = BrushFromBounds (mins, maxs); + + tree->headnode = node; + + node = BuildTree_r (node, brushlist); + qprintf ("%5i visible nodes\n", c_nodes/2 - c_nonvis); + qprintf ("%5i nonvis nodes\n", c_nonvis); + qprintf ("%5i leafs\n", (c_nodes+1)/2); +#if 0 +{ // debug code +static node_t *tnode; +vec3_t p; + +p[0] = -1469; +p[1] = -118; +p[2] = 119; +tnode = PointInLeaf (tree->headnode, p); +printf ("contents: %i\n", tnode->contents); +p[0] = 0; +} +#endif + return tree; +} + diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/csg.c b/Toolkit/Programming/Tools/bsp/qbsp3/csg.c new file mode 100644 index 0000000..a52b1d9 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/csg.c @@ -0,0 +1,614 @@ + +#include "qbsp.h" + +/* + +tag all brushes with original contents +brushes may contain multiple contents +there will be no brush overlap after csg phase + + + + +each side has a count of the other sides it splits + +the best split will be the one that minimizes the total split counts +of all remaining sides + +precalc side on plane table + +evaluate split side +{ +cost = 0 +for all sides + for all sides + get + if side splits side and splitside is on same child + cost++; +} + + + */ + +void SplitBrush2 (bspbrush_t *brush, int planenum, + bspbrush_t **front, bspbrush_t **back) +{ + SplitBrush (brush, planenum, front, back); +#if 0 + if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1) + (*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1 + if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1) + (*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1 +#endif +} + +/* +=============== +SubtractBrush + +Returns a list of brushes that remain after B is subtracted from A. +May by empty if A is contained inside B. + +The originals are undisturbed. +=============== +*/ +bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b) +{ // a - b = out (list) + int i; + bspbrush_t *front, *back; + bspbrush_t *out, *in; + + in = a; + out = NULL; + for (i=0 ; inumsides && in ; i++) + { + SplitBrush2 (in, b->sides[i].planenum, &front, &back); + if (in != a) + FreeBrush (in); + if (front) + { // add to list + front->next = out; + out = front; + } + in = back; + } + if (in) + FreeBrush (in); + else + { // didn't really intersect + FreeBrushList (out); + return a; + } + return out; +} + +/* +=============== +IntersectBrush + +Returns a single brush made up by the intersection of the +two provided brushes, or NULL if they are disjoint. + +The originals are undisturbed. +=============== +*/ +bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b) +{ + int i; + bspbrush_t *front, *back; + bspbrush_t *in; + + in = a; + for (i=0 ; inumsides && in ; i++) + { + SplitBrush2 (in, b->sides[i].planenum, &front, &back); + if (in != a) + FreeBrush (in); + if (front) + FreeBrush (front); + in = back; + } + + if (in == a) + return NULL; + + in->next = NULL; + return in; +} + + +/* +=============== +BrushesDisjoint + +Returns true if the two brushes definately do not intersect. +There will be false negatives for some non-axial combinations. +=============== +*/ +qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b) +{ + int i, j; + + // check bounding boxes + for (i=0 ; i<3 ; i++) + if (a->mins[i] >= b->maxs[i] + || a->maxs[i] <= b->mins[i]) + return true; // bounding boxes don't overlap + + // check for opposing planes + for (i=0 ; inumsides ; i++) + { + for (j=0 ; jnumsides ; j++) + { + if (a->sides[i].planenum == + (b->sides[j].planenum^1) ) + return true; // opposite planes, so not touching + } + } + + return false; // might intersect +} + +/* +=============== +IntersectionContents + +Returns a content word for the intersection of two brushes. +Some combinations will generate a combination (water + clip), +but most will be the stronger of the two contents. +=============== +*/ +int IntersectionContents (int c1, int c2) +{ + int out; + + out = c1 | c2; + + if (out & CONTENTS_SOLID) + out = CONTENTS_SOLID; + + return out; +} + + +int minplanenums[3]; +int maxplanenums[3]; + +/* +=============== +ClipBrushToBox + +Any planes shared with the box edge will be set to no texinfo +=============== +*/ +bspbrush_t *ClipBrushToBox (bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs) +{ + int i, j; + bspbrush_t *front, *back; + int p; + + for (j=0 ; j<2 ; j++) + { + if (brush->maxs[j] > clipmaxs[j]) + { + SplitBrush (brush, maxplanenums[j], &front, &back); + if (front) + FreeBrush (front); + brush = back; + if (!brush) + return NULL; + } + if (brush->mins[j] < clipmins[j]) + { + SplitBrush (brush, minplanenums[j], &front, &back); + if (back) + FreeBrush (back); + brush = front; + if (!brush) + return NULL; + } + } + + // remove any colinear faces + + for (i=0 ; inumsides ; i++) + { + p = brush->sides[i].planenum & ~1; + if (p == maxplanenums[0] || p == maxplanenums[1] + || p == minplanenums[0] || p == minplanenums[1]) + { + brush->sides[i].texinfo = TEXINFO_NODE; + brush->sides[i].visible = false; + } + } + return brush; +} + +/* +=============== +MakeBspBrushList +=============== +*/ +bspbrush_t *MakeBspBrushList (int startbrush, int endbrush, + vec3_t clipmins, vec3_t clipmaxs) +{ + mapbrush_t *mb; + bspbrush_t *brushlist, *newbrush; + int i, j; + int c_faces; + int c_brushes; + int numsides; + int vis; + vec3_t normal; + float dist; + + for (i=0 ; i<2 ; i++) + { + VectorClear (normal); + normal[i] = 1; + dist = clipmaxs[i]; + maxplanenums[i] = FindFloatPlane (normal, dist); + dist = clipmins[i]; + minplanenums[i] = FindFloatPlane (normal, dist); + } + + brushlist = NULL; + c_faces = 0; + c_brushes = 0; + + for (i=startbrush ; inumsides; + if (!numsides) + continue; + // make sure the brush has at least one face showing + vis = 0; + for (j=0 ; joriginal_sides[j].visible && mb->original_sides[j].winding) + vis++; +#if 0 + if (!vis) + continue; // no faces at all +#endif + // if the brush is outside the clip area, skip it + for (j=0 ; j<3 ; j++) + if (mb->mins[j] >= clipmaxs[j] + || mb->maxs[j] <= clipmins[j]) + break; + if (j != 3) + continue; + + // + // make a copy of the brush + // + newbrush = AllocBrush (mb->numsides); + newbrush->original = mb; + newbrush->numsides = mb->numsides; + memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t)); + for (j=0 ; jsides[j].winding) + newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding); + if (newbrush->sides[j].surf & SURF_HINT) + newbrush->sides[j].visible = true; // hints are always visible + } + VectorCopy (mb->mins, newbrush->mins); + VectorCopy (mb->maxs, newbrush->maxs); + + // + // carve off anything outside the clip box + // + newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs); + if (!newbrush) + continue; + + c_faces += vis; + c_brushes++; + + newbrush->next = brushlist; + brushlist = newbrush; + } + + return brushlist; +} + +/* +=============== +AddBspBrushListToTail +=============== +*/ +bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail) +{ + bspbrush_t *walk, *next; + + for (walk=list ; walk ; walk=next) + { // add to end of list + next = walk->next; + walk->next = NULL; + tail->next = walk; + tail = walk; + } + + return tail; +} + +/* +=========== +CullList + +Builds a new list that doesn't hold the given brush +=========== +*/ +bspbrush_t *CullList (bspbrush_t *list, bspbrush_t *skip1) +{ + bspbrush_t *newlist; + bspbrush_t *next; + + newlist = NULL; + + for ( ; list ; list = next) + { + next = list->next; + if (list == skip1) + { + FreeBrush (list); + continue; + } + list->next = newlist; + newlist = list; + } + return newlist; +} + + +/* +================== +WriteBrushMap +================== +*/ +void WriteBrushMap (char *name, bspbrush_t *list) +{ + FILE *f; + side_t *s; + int i; + winding_t *w; + + printf ("writing %s\n", name); + f = fopen (name, "wb"); + if (!f) + Error ("Can't write %s\b", name); + + fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); + + for ( ; list ; list=list->next ) + { + fprintf (f, "{\n"); + for (i=0,s=list->sides ; inumsides ; i++,s++) + { + w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist); + + fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); + + fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture); + FreeWinding (w); + } + fprintf (f, "}\n"); + } + fprintf (f, "}\n"); + + fclose (f); + +} + +/* +================== +BrushGE + +Returns true if b1 is allowed to bite b2 +================== +*/ +qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2) +{ + // detail brushes never bite structural brushes + if ( (b1->original->contents & CONTENTS_DETAIL) + && !(b2->original->contents & CONTENTS_DETAIL) ) + return false; + if (b1->original->contents & CONTENTS_SOLID) + return true; + return false; +} + +/* +================= +ChopBrushes + +Carves any intersecting solid brushes into the minimum number +of non-intersecting brushes. +================= +*/ +bspbrush_t *ChopBrushes (bspbrush_t *head) +{ + bspbrush_t *b1, *b2, *next; + bspbrush_t *tail; + bspbrush_t *keep; + bspbrush_t *sub, *sub2; + int c1, c2; + + qprintf ("---- ChopBrushes ----\n"); + qprintf ("original brushes: %i\n", CountBrushList (head)); + +#if 0 + if (startbrush == 0) + WriteBrushList ("before.gl", head, false); +#endif + keep = NULL; + +newlist: + // find tail + if (!head) + return NULL; + for (tail=head ; tail->next ; tail=tail->next) + ; + + for (b1=head ; b1 ; b1=next) + { + next = b1->next; + for (b2=b1->next ; b2 ; b2 = b2->next) + { + if (BrushesDisjoint (b1, b2)) + continue; + + sub = NULL; + sub2 = NULL; + c1 = 999999; + c2 = 999999; + + if ( BrushGE (b2, b1) ) + { + sub = SubtractBrush (b1, b2); + if (sub == b1) + continue; // didn't really intersect + if (!sub) + { // b1 is swallowed by b2 + head = CullList (b1, b1); + goto newlist; + } + c1 = CountBrushList (sub); + } + + if ( BrushGE (b1, b2) ) + { + sub2 = SubtractBrush (b2, b1); + if (sub2 == b2) + continue; // didn't really intersect + if (!sub2) + { // b2 is swallowed by b1 + FreeBrushList (sub); + head = CullList (b1, b2); + goto newlist; + } + c2 = CountBrushList (sub2); + } + + if (!sub && !sub2) + continue; // neither one can bite + + // only accept if it didn't fragment + // (commening this out allows full fragmentation) + if (c1 > 1 && c2 > 1) + { + if (sub2) + FreeBrushList (sub2); + if (sub) + FreeBrushList (sub); + continue; + } + + if (c1 < c2) + { + if (sub2) + FreeBrushList (sub2); + tail = AddBrushListToTail (sub, tail); + head = CullList (b1, b1); + goto newlist; + } + else + { + if (sub) + FreeBrushList (sub); + tail = AddBrushListToTail (sub2, tail); + head = CullList (b1, b2); + goto newlist; + } + } + + if (!b2) + { // b1 is no longer intersecting anything, so keep it + b1->next = keep; + keep = b1; + } + } + + qprintf ("output brushes: %i\n", CountBrushList (keep)); +#if 0 + { + WriteBrushList ("after.gl", keep, false); + WriteBrushMap ("after.map", keep); + } +#endif + return keep; +} + + +/* +================= +InitialBrushList +================= +*/ +bspbrush_t *InitialBrushList (bspbrush_t *list) +{ + bspbrush_t *b; + bspbrush_t *out, *newb; + int i; + + // only return brushes that have visible faces + out = NULL; + for (b=list ; b ; b=b->next) + { +#if 0 + for (i=0 ; inumsides ; i++) + if (b->sides[i].visible) + break; + if (i == b->numsides) + continue; +#endif + newb = CopyBrush (b); + newb->next = out; + out = newb; + + // clear visible, so it must be set by MarkVisibleFaces_r + // to be used in the optimized list + for (i=0 ; inumsides ; i++) + { + newb->sides[i].original = &b->sides[i]; +// newb->sides[i].visible = true; + b->sides[i].visible = false; + } + } + + return out; +} + +/* +================= +OptimizedBrushList +================= +*/ +bspbrush_t *OptimizedBrushList (bspbrush_t *list) +{ + bspbrush_t *b; + bspbrush_t *out, *newb; + int i; + + // only return brushes that have visible faces + out = NULL; + for (b=list ; b ; b=b->next) + { + for (i=0 ; inumsides ; i++) + if (b->sides[i].visible) + break; + if (i == b->numsides) + continue; + newb = CopyBrush (b); + newb->next = out; + out = newb; + } + +// WriteBrushList ("vis.gl", out, true); + + return out; +} diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/faces.c b/Toolkit/Programming/Tools/bsp/qbsp3/faces.c new file mode 100644 index 0000000..80a9e9b --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/faces.c @@ -0,0 +1,1060 @@ +// faces.c + +#include "qbsp.h" + +/* + + some faces will be removed before saving, but still form nodes: + + the insides of sky volumes + meeting planes of different water current volumes + +*/ + +// undefine for dumb linear searches +#define USE_HASHING + +#define INTEGRAL_EPSILON 0.01 +#define POINT_EPSILON 0.5 +#define OFF_EPSILON 0.5 + +int c_merge; +int c_subdivide; + +int c_totalverts; +int c_uniqueverts; +int c_degenerate; +int c_tjunctions; +int c_faceoverflows; +int c_facecollapse; +int c_badstartverts; + +#define MAX_SUPERVERTS 512 +int superverts[MAX_SUPERVERTS]; +int numsuperverts; + +face_t *edgefaces[MAX_MAP_EDGES][2]; +int firstmodeledge = 1; +int firstmodelface; + +int c_tryedges; + +vec3_t edge_dir; +vec3_t edge_start; +vec_t edge_len; + +int num_edge_verts; +int edge_verts[MAX_MAP_VERTS]; + + +float subdivide_size = 240; + + +face_t *NewFaceFromFace (face_t *f); + +//=========================================================================== + +typedef struct hashvert_s +{ + struct hashvert_s *next; + int num; +} hashvert_t; + + +#define HASH_SIZE 64 + + +int vertexchain[MAX_MAP_VERTS]; // the next vertex in a hash chain +int hashverts[HASH_SIZE*HASH_SIZE]; // a vertex number, or 0 for no verts + +face_t *edgefaces[MAX_MAP_EDGES][2]; + +//============================================================================ + + +unsigned HashVec (vec3_t vec) +{ + int x, y; + + x = (4096 + (int)(vec[0]+0.5)) >> 7; + y = (4096 + (int)(vec[1]+0.5)) >> 7; + + if ( x < 0 || x >= HASH_SIZE || y < 0 || y >= HASH_SIZE ) + Error ("HashVec: point outside valid range"); + + return y*HASH_SIZE + x; +} + +#ifdef USE_HASHING +/* +============= +GetVertex + +Uses hashing +============= +*/ +int GetVertexnum (vec3_t in) +{ + int h; + int i; + float *p; + vec3_t vert; + int vnum; + + c_totalverts++; + + for (i=0 ; i<3 ; i++) + { + if ( fabs(in[i] - Q_rint(in[i])) < INTEGRAL_EPSILON) + vert[i] = Q_rint(in[i]); + else + vert[i] = in[i]; + } + + h = HashVec (vert); + + for (vnum=hashverts[h] ; vnum ; vnum=vertexchain[vnum]) + { + p = dvertexes[vnum].point; + if ( fabs(p[0]-vert[0]) 4096) + Error ("GetVertexnum: outside +/- 4096"); + } + + // search for an existing vertex match + for (i=0, dv=dvertexes ; ipoint[j]; + if ( d > POINT_EPSILON || d < -POINT_EPSILON) + break; + } + if (j == 3) + return i; // a match + } + + // new point + if (numvertexes == MAX_MAP_VERTS) + Error ("MAX_MAP_VERTS"); + VectorCopy (v, dv->point); + numvertexes++; + c_uniqueverts++; + + return numvertexes-1; +} +#endif + + +/* +================== +FaceFromSuperverts + +The faces vertexes have beeb added to the superverts[] array, +and there may be more there than can be held in a face (MAXEDGES). + +If less, the faces vertexnums[] will be filled in, otherwise +face will reference a tree of split[] faces until all of the +vertexnums can be added. + +superverts[base] will become face->vertexnums[0], and the others +will be circularly filled in. +================== +*/ +void FaceFromSuperverts (node_t *node, face_t *f, int base) +{ + face_t *newf; + int remaining; + int i; + + remaining = numsuperverts; + while (remaining > MAXEDGES) + { // must split into two faces, because of vertex overload + c_faceoverflows++; + + newf = f->split[0] = NewFaceFromFace (f); + newf = f->split[0]; + newf->next = node->faces; + node->faces = newf; + + newf->numpoints = MAXEDGES; + for (i=0 ; ivertexnums[i] = superverts[(i+base)%numsuperverts]; + + f->split[1] = NewFaceFromFace (f); + f = f->split[1]; + f->next = node->faces; + node->faces = f; + + remaining -= (MAXEDGES-2); + base = (base+MAXEDGES-1)%numsuperverts; + } + + // copy the vertexes back to the face + f->numpoints = remaining; + for (i=0 ; ivertexnums[i] = superverts[(i+base)%numsuperverts]; +} + + +/* +================== +EmitFaceVertexes +================== +*/ +void EmitFaceVertexes (node_t *node, face_t *f) +{ + winding_t *w; + int i; + + if (f->merged || f->split[0] || f->split[1]) + return; + + w = f->w; + for (i=0 ; inumpoints ; i++) + { + if (noweld) + { // make every point unique + if (numvertexes == MAX_MAP_VERTS) + Error ("MAX_MAP_VERTS"); + superverts[i] = numvertexes; + VectorCopy (w->p[i], dvertexes[numvertexes].point); + numvertexes++; + c_uniqueverts++; + c_totalverts++; + } + else + superverts[i] = GetVertexnum (w->p[i]); + } + numsuperverts = w->numpoints; + + // this may fragment the face if > MAXEDGES + FaceFromSuperverts (node, f, 0); +} + +/* +================== +EmitVertexes_r +================== +*/ +void EmitVertexes_r (node_t *node) +{ + int i; + face_t *f; + + if (node->planenum == PLANENUM_LEAF) + return; + + for (f=node->faces ; f ; f=f->next) + { + EmitFaceVertexes (node, f); + } + + for (i=0 ; i<2 ; i++) + EmitVertexes_r (node->children[i]); +} + + +#ifdef USE_HASHING +/* +========== +FindEdgeVerts + +Uses the hash tables to cut down to a small number +========== +*/ +void FindEdgeVerts (vec3_t v1, vec3_t v2) +{ + int x1, x2, y1, y2, t; + int x, y; + int vnum; + +#if 0 +{ + int i; + num_edge_verts = numvertexes-1; + for (i=0 ; i> 7; + y1 = (4096 + (int)(v1[1]+0.5)) >> 7; + x2 = (4096 + (int)(v2[0]+0.5)) >> 7; + y2 = (4096 + (int)(v2[1]+0.5)) >> 7; + + if (x1 > x2) + { + t = x1; + x1 = x2; + x2 = t; + } + if (y1 > y2) + { + t = y1; + y1 = y2; + y2 = t; + } +#if 0 + x1--; + x2++; + y1--; + y2++; + if (x1 < 0) + x1 = 0; + if (x2 >= HASH_SIZE) + x2 = HASH_SIZE; + if (y1 < 0) + y1 = 0; + if (y2 >= HASH_SIZE) + y2 = HASH_SIZE; +#endif + num_edge_verts = 0; + for (x=x1 ; x <= x2 ; x++) + { + for (y=y1 ; y <= y2 ; y++) + { + for (vnum=hashverts[y*HASH_SIZE+x] ; vnum ; vnum=vertexchain[vnum]) + { + edge_verts[num_edge_verts++] = vnum; + } + } + } +} + +#else +/* +========== +FindEdgeVerts + +Forced a dumb check of everything +========== +*/ +void FindEdgeVerts (vec3_t v1, vec3_t v2) +{ + int i; + + num_edge_verts = numvertexes-1; + for (i=0 ; i= end) + continue; // off an end + VectorMA (edge_start, dist, edge_dir, exact); + VectorSubtract (p, exact, off); + error = VectorLength (off); + + if (fabs(error) > OFF_EPSILON) + continue; // not on the edge + + // break the edge + c_tjunctions++; + TestEdge (start, dist, p1, j, k+1); + TestEdge (dist, end, j, p2, k+1); + return; + } + + // the edge p1 to p2 is now free of tjunctions + if (numsuperverts >= MAX_SUPERVERTS) + Error ("MAX_SUPERVERTS"); + superverts[numsuperverts] = p1; + numsuperverts++; +} + +/* +================== +FixFaceEdges + +================== +*/ +void FixFaceEdges (node_t *node, face_t *f) +{ + int p1, p2; + int i; + vec3_t e2; + vec_t len; + int count[MAX_SUPERVERTS], start[MAX_SUPERVERTS]; + int base; + + if (f->merged || f->split[0] || f->split[1]) + return; + + numsuperverts = 0; + + for (i=0 ; inumpoints ; i++) + { + p1 = f->vertexnums[i]; + p2 = f->vertexnums[(i+1)%f->numpoints]; + + VectorCopy (dvertexes[p1].point, edge_start); + VectorCopy (dvertexes[p2].point, e2); + + FindEdgeVerts (edge_start, e2); + + VectorSubtract (e2, edge_start, edge_dir); + len = VectorNormalize (edge_dir, edge_dir); + + start[i] = numsuperverts; + TestEdge (0, len, p1, p2, 0); + + count[i] = numsuperverts - start[i]; + } + + if (numsuperverts < 3) + { // entire face collapsed + f->numpoints = 0; + c_facecollapse++; + return; + } + + // we want to pick a vertex that doesn't have tjunctions + // on either side, which can cause artifacts on trifans, + // especially underwater + for (i=0 ; inumpoints ; i++) + { + if (count[i] == 1 && count[(i+f->numpoints-1)%f->numpoints] == 1) + break; + } + if (i == f->numpoints) + { + f->badstartvert = true; + c_badstartverts++; + base = 0; + } + else + { // rotate the vertex order + base = start[i]; + } + + // this may fragment the face if > MAXEDGES + FaceFromSuperverts (node, f, base); +} + +/* +================== +FixEdges_r +================== +*/ +void FixEdges_r (node_t *node) +{ + int i; + face_t *f; + + if (node->planenum == PLANENUM_LEAF) + return; + + for (f=node->faces ; f ; f=f->next) + FixFaceEdges (node, f); + + for (i=0 ; i<2 ; i++) + FixEdges_r (node->children[i]); +} + +/* +=========== +FixTjuncs + +=========== +*/ +void FixTjuncs (node_t *headnode) +{ + // snap and merge all vertexes + qprintf ("---- snap verts ----\n"); + memset (hashverts, 0, sizeof(hashverts)); + c_totalverts = 0; + c_uniqueverts = 0; + c_faceoverflows = 0; + EmitVertexes_r (headnode); + qprintf ("%i unique from %i\n", c_uniqueverts, c_totalverts); + + // break edges on tjunctions + qprintf ("---- tjunc ----\n"); + c_tryedges = 0; + c_degenerate = 0; + c_facecollapse = 0; + c_tjunctions = 0; + if (!notjunc) + FixEdges_r (headnode); + qprintf ("%5i edges degenerated\n", c_degenerate); + qprintf ("%5i faces degenerated\n", c_facecollapse); + qprintf ("%5i edges added by tjunctions\n", c_tjunctions); + qprintf ("%5i faces added by tjunctions\n", c_faceoverflows); + qprintf ("%5i bad start verts\n", c_badstartverts); +} + + +//======================================================== + +int c_faces; + +face_t *AllocFace (void) +{ + face_t *f; + + f = malloc(sizeof(*f)); + if (f == NULL) + Error("AllocFace MALLOC failed! Could not allocate %s bytes.", sizeof(*f)); + + memset (f, 0, sizeof(*f)); + c_faces++; + + return f; +} + +face_t *NewFaceFromFace (face_t *f) +{ + face_t *newf; + + newf = AllocFace (); + *newf = *f; + newf->merged = NULL; + newf->split[0] = newf->split[1] = NULL; + newf->w = NULL; + return newf; +} + +void FreeFace (face_t *f) +{ + if (f->w) + FreeWinding (f->w); + free (f); + c_faces--; +} + +//======================================================== + +/* +================== +GetEdge + +Called by writebsp. +Don't allow four way edges +================== +*/ +int GetEdge2 (int v1, int v2, face_t *f) +{ + dedge_t *edge; + int i; + + c_tryedges++; + + if (!noshare) + { + for (i=firstmodeledge ; i < numedges ; i++) + { + edge = &dedges[i]; + if (v1 == edge->v[1] && v2 == edge->v[0] + && edgefaces[i][0]->contents == f->contents) + { + if (edgefaces[i][1]) + // printf ("WARNING: multiple backward edge\n"); + continue; + edgefaces[i][1] = f; + return -i; + } + #if 0 + if (v1 == edge->v[0] && v2 == edge->v[1]) + { + printf ("WARNING: multiple forward edge\n"); + return i; + } + #endif + } + } + +// emit an edge + if (numedges >= MAX_MAP_EDGES) + Error ("numedges == MAX_MAP_EDGES"); + edge = &dedges[numedges]; + numedges++; + edge->v[0] = v1; + edge->v[1] = v2; + edgefaces[numedges-1][0] = f; + + return numedges-1; +} + +/* +=========================================================================== + +FACE MERGING + +=========================================================================== +*/ + +#define CONTINUOUS_EPSILON 0.001 + +/* +============= +TryMergeWinding + +If two polygons share a common edge and the edges that meet at the +common points are both inside the other polygons, merge them + +Returns NULL if the faces couldn't be merged, or the new face. +The originals will NOT be freed. +============= +*/ +winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal) +{ + vec_t *p1, *p2, *p3, *p4, *back; + winding_t *newf; + int i, j, k, l; + vec3_t normal, delta; + vec_t dot; + qboolean keep1, keep2; + + + // + // find a common edge + // + p1 = p2 = NULL; // stop compiler warning + j = 0; // + + for (i=0 ; inumpoints ; i++) + { + p1 = f1->p[i]; + p2 = f1->p[(i+1)%f1->numpoints]; + for (j=0 ; jnumpoints ; j++) + { + p3 = f2->p[j]; + p4 = f2->p[(j+1)%f2->numpoints]; + for (k=0 ; k<3 ; k++) + { + if (fabs(p1[k] - p4[k]) > EQUAL_EPSILON) + break; + if (fabs(p2[k] - p3[k]) > EQUAL_EPSILON) + break; + } + if (k==3) + break; + } + if (j < f2->numpoints) + break; + } + + if (i == f1->numpoints) + return NULL; // no matching edges + + // + // check slope of connected lines + // if the slopes are colinear, the point can be removed + // + back = f1->p[(i+f1->numpoints-1)%f1->numpoints]; + VectorSubtract (p1, back, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->p[(j+2)%f2->numpoints]; + VectorSubtract (back, p1, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + back = f1->p[(i+2)%f1->numpoints]; + VectorSubtract (back, p2, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->p[(j+f2->numpoints-1)%f2->numpoints]; + VectorSubtract (back, p2, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + // + // build the new polygon + // + newf = AllocWinding (f1->numpoints + f2->numpoints); + + // copy first polygon + for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints) + { + if (k==(i+1)%f1->numpoints && !keep2) + continue; + + VectorCopy (f1->p[k], newf->p[newf->numpoints]); + newf->numpoints++; + } + + // copy second polygon + for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints) + { + if (l==(j+1)%f2->numpoints && !keep1) + continue; + VectorCopy (f2->p[l], newf->p[newf->numpoints]); + newf->numpoints++; + } + + return newf; +} + +/* +============= +TryMerge + +If two polygons share a common edge and the edges that meet at the +common points are both inside the other polygons, merge them + +Returns NULL if the faces couldn't be merged, or the new face. +The originals will NOT be freed. +============= +*/ +face_t *TryMerge (face_t *f1, face_t *f2, vec3_t planenormal) +{ + face_t *newf; + winding_t *nw; + + if (!f1->w || !f2->w) + return NULL; + if (f1->texinfo != f2->texinfo) + return NULL; + if (f1->planenum != f2->planenum) // on front and back sides + return NULL; + if (f1->contents != f2->contents) + return NULL; + + + nw = TryMergeWinding (f1->w, f2->w, planenormal); + if (!nw) + return NULL; + + c_merge++; + newf = NewFaceFromFace (f1); + newf->w = nw; + + f1->merged = newf; + f2->merged = newf; + + return newf; +} + +/* +=============== +MergeNodeFaces +=============== +*/ +void MergeNodeFaces (node_t *node) +{ + face_t *f1, *f2, *end; + face_t *merged; + plane_t *plane; + + plane = &mapplanes[node->planenum]; + merged = NULL; + + for (f1 = node->faces ; f1 ; f1 = f1->next) + { + if (f1->merged || f1->split[0] || f1->split[1]) + continue; + for (f2 = node->faces ; f2 != f1 ; f2=f2->next) + { + if (f2->merged || f2->split[0] || f2->split[1]) + continue; + merged = TryMerge (f1, f2, plane->normal); + if (!merged) + continue; + + // add merged to the end of the node face list + // so it will be checked against all the faces again + for (end = node->faces ; end->next ; end = end->next) + ; + merged->next = NULL; + end->next = merged; + break; + } + } +} + +//===================================================================== + +/* +=============== +SubdivideFace + +Chop up faces that are larger than we want in the surface cache +=============== +*/ +void SubdivideFace (node_t *node, face_t *f) +{ + float mins, maxs; + vec_t v; + int axis, i; + texinfo_t *tex; + vec3_t temp; + vec_t dist; + winding_t *w, *frontw, *backw; + + if (f->merged) + return; + +// special (non-surface cached) faces don't need subdivision + tex = &texinfo[f->texinfo]; + + if ( tex->flags & (SURF_WARP|SURF_SKY|SURF_TALL_WALL) ) + { + return; + } + + for (axis = 0 ; axis < 2 ; axis++) + { + while (1) + { + mins = 999999; + maxs = -999999; + + VectorCopy (tex->vecs[axis], temp); + w = f->w; + for (i=0 ; inumpoints ; i++) + { + v = DotProduct (w->p[i], temp); + if (v < mins) + mins = v; + if (v > maxs) + maxs = v; + } +#if 0 + if (maxs - mins <= 0) + Error ("zero extents"); +#endif + if (axis == 2) + { // allow double high walls + if (maxs - mins <= subdivide_size/* *2 */) + break; + } + else if (maxs - mins <= subdivide_size) + break; + + // split it + c_subdivide++; + + v = VectorNormalize (temp, temp); + + dist = (mins + subdivide_size - 16)/v; + + ClipWindingEpsilon (w, temp, dist, ON_EPSILON, &frontw, &backw); + if (!frontw || !backw) + Error ("SubdivideFace: didn't split the polygon"); + + f->split[0] = NewFaceFromFace (f); + f->split[0]->w = frontw; + f->split[0]->next = node->faces; + node->faces = f->split[0]; + + f->split[1] = NewFaceFromFace (f); + f->split[1]->w = backw; + f->split[1]->next = node->faces; + node->faces = f->split[1]; + + SubdivideFace (node, f->split[0]); + SubdivideFace (node, f->split[1]); + return; + } + } +} + +void SubdivideNodeFaces (node_t *node) +{ + face_t *f; + + for (f = node->faces ; f ; f=f->next) + { + SubdivideFace (node, f); + } +} + +//=========================================================================== + +int c_nodefaces; + + +/* +============ +FaceFromPortal + +============ +*/ +face_t *FaceFromPortal (portal_t *p, int pside) +{ + face_t *f; + side_t *side; + + side = p->side; + if (!side) + return NULL; // portal does not bridge different visible contents + + f = AllocFace (); + + f->texinfo = side->texinfo; + f->lighting.c = side->lighting.c; + f->planenum = (side->planenum & ~1) | pside; + f->portal = p; + + if ( (p->nodes[pside]->contents & CONTENTS_WINDOW) + && VisibleContents(p->nodes[!pside]->contents^p->nodes[pside]->contents) == CONTENTS_WINDOW ) + return NULL; // don't show insides of windows + + if (pside) + { + f->w = ReverseWinding(p->winding); + f->contents = p->nodes[1]->contents; + } + else + { + f->w = CopyWinding(p->winding); + f->contents = p->nodes[0]->contents; + } + return f; +} + + +/* +=============== +MakeFaces_r + +If a portal will make a visible face, +mark the side that originally created it + + solid / empty : solid + solid / water : solid + water / empty : water + water / water : none +=============== +*/ +void MakeFaces_r (node_t *node) +{ + portal_t *p; + int s; + + // recurse down to leafs + if (node->planenum != PLANENUM_LEAF) + { + MakeFaces_r (node->children[0]); + MakeFaces_r (node->children[1]); + + // merge together all visible faces on the node + if (!nomerge) + MergeNodeFaces (node); + if (!nosubdiv) + SubdivideNodeFaces (node); + + return; + } + + // solid leafs never have visible faces + if (node->contents & CONTENTS_SOLID) + return; + + // see which portals are valid + for (p=node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + + p->face[s] = FaceFromPortal (p, s); + if (p->face[s]) + { + c_nodefaces++; + p->face[s]->next = p->onnode->faces; + p->onnode->faces = p->face[s]; + } + } +} + +/* +============ +MakeFaces +============ +*/ +void MakeFaces (node_t *node) +{ + qprintf ("--- MakeFaces ---\n"); + c_merge = 0; + c_subdivide = 0; + c_nodefaces = 0; + + MakeFaces_r (node); + + qprintf ("%5i makefaces\n", c_nodefaces); + qprintf ("%5i merged\n", c_merge); + qprintf ("%5i subdivided\n", c_subdivide); +} diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/gldraw.c b/Toolkit/Programming/Tools/bsp/qbsp3/gldraw.c new file mode 100644 index 0000000..b68c17e --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/gldraw.c @@ -0,0 +1,211 @@ + +#include +#include +#include +#include + +#include "qbsp.h" + +// can't use the glvertex3fv functions, because the vec3_t fields +// could be either floats or doubles, depending on DOUBLEVEC_T + +qboolean drawflag; +vec3_t draw_mins, draw_maxs; + + +#define WIN_SIZE 512 + +void InitWindow (void) +{ + auxInitDisplayMode (AUX_SINGLE | AUX_RGB); + auxInitPosition (0, 0, WIN_SIZE, WIN_SIZE); + auxInitWindow ("qcsg"); +} + +void Draw_ClearWindow (void) +{ + static int init; + int w, h, g; + vec_t mx, my; + + if (!drawflag) + return; + + if (!init) + { + init = true; + InitWindow (); + } + + glClearColor (1,0.8,0.8,0); + glClear (GL_COLOR_BUFFER_BIT); + + w = (draw_maxs[0] - draw_mins[0]); + h = (draw_maxs[1] - draw_mins[1]); + + mx = draw_mins[0] + w/2; + my = draw_mins[1] + h/2; + + g = w > h ? w : h; + + glLoadIdentity (); + gluPerspective (90, 1, 2, 16384); + gluLookAt (mx, my, draw_maxs[2] + g/2, mx , my, draw_maxs[2], 0, 1, 0); + + glColor3f (0,0,0); +// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glDisable (GL_DEPTH_TEST); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +#if 0 + glColor4f (1,0,0,0.5); + glBegin (GL_POLYGON); + + glVertex3f (0, 500, 0); + glVertex3f (0, 900, 0); + glVertex3f (0, 900, 100); + glVertex3f (0, 500, 100); + + glEnd (); +#endif + + glFlush (); + +} + +void Draw_SetRed (void) +{ + if (!drawflag) + return; + + glColor3f (1,0,0); +} + +void Draw_SetGrey (void) +{ + if (!drawflag) + return; + + glColor3f (0.5,0.5,0.5); +} + +void Draw_SetBlack (void) +{ + if (!drawflag) + return; + + glColor3f (0,0,0); +} + +void DrawWinding (winding_t *w) +{ + int i; + + if (!drawflag) + return; + + glColor4f (0,0,0,0.5); + glBegin (GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glColor4f (0,1,0,0.3); + glBegin (GL_POLYGON); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glFlush (); +} + +void DrawAuxWinding (winding_t *w) +{ + int i; + + if (!drawflag) + return; + + glColor4f (0,0,0,0.5); + glBegin (GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glColor4f (1,0,0,0.3); + glBegin (GL_POLYGON); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glFlush (); +} + +//============================================================ + +#define GLSERV_PORT 25001 + +qboolean wins_init; +int draw_socket; + +void GLS_BeginScene (void) +{ + WSADATA winsockdata; + WORD wVersionRequested; + struct sockaddr_in address; + int r; + + if (!wins_init) + { + wins_init = true; + + wVersionRequested = MAKEWORD(1, 1); + + r = WSAStartup (MAKEWORD(1, 1), &winsockdata); + + if (r) + Error ("Winsock initialization failed."); + + } + + // connect a socket to the server + + draw_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (draw_socket == -1) + Error ("draw_socket failed"); + + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + address.sin_port = GLSERV_PORT; + r = connect (draw_socket, (struct sockaddr *)&address, sizeof(address)); + if (r == -1) + { + closesocket (draw_socket); + draw_socket = 0; + } +} + +void GLS_Winding (winding_t *w, int code) +{ + byte buf[1024]; + int i, j; + + if (!draw_socket) + return; + + ((int *)buf)[0] = w->numpoints; + ((int *)buf)[1] = code; + for (i=0 ; inumpoints ; i++) + for (j=0 ; j<3 ; j++) + ((float *)buf)[2+i*3+j] = w->p[i][j]; + + send (draw_socket, buf, w->numpoints*12+8, 0); +} + +void GLS_EndScene (void) +{ + closesocket (draw_socket); + draw_socket = 0; +} diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/glfile.c b/Toolkit/Programming/Tools/bsp/qbsp3/glfile.c new file mode 100644 index 0000000..3ef9718 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/glfile.c @@ -0,0 +1,128 @@ + +#include "qbsp.h" + +int c_glfaces; + +int PortalVisibleSides (portal_t *p) +{ + int fcon, bcon; + + if (!p->onnode) + return 0; // outside + + fcon = p->nodes[0]->contents; + bcon = p->nodes[1]->contents; + + // same contents never create a face + if (fcon == bcon) + return 0; + + // FIXME: is this correct now? + if (!fcon) + return 1; + if (!bcon) + return 2; + return 0; +} + +void OutputWinding (winding_t *w, FILE *glview) +{ + static int level = 128; + vec_t light; + int i; + + fprintf (glview, "%i\n", w->numpoints); + level+=28; + light = (level&255)/255.0; + for (i=0 ; inumpoints ; i++) + { + fprintf (glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n", + w->p[i][0], + w->p[i][1], + w->p[i][2], + light, + light, + light); + } + fprintf (glview, "\n"); +} + +/* +============= +OutputPortal +============= +*/ +void OutputPortal (portal_t *p, FILE *glview) +{ + winding_t *w; + int sides; + + sides = PortalVisibleSides (p); + if (!sides) + return; + + c_glfaces++; + + w = p->winding; + + if (sides == 2) // back side + w = ReverseWinding (w); + + OutputWinding (w, glview); + + if (sides == 2) + FreeWinding(w); +} + +/* +============= +WriteGLView_r +============= +*/ +void WriteGLView_r (node_t *node, FILE *glview) +{ + portal_t *p, *nextp; + + if (node->planenum != PLANENUM_LEAF) + { + WriteGLView_r (node->children[0], glview); + WriteGLView_r (node->children[1], glview); + return; + } + + // write all the portals + for (p=node->portals ; p ; p=nextp) + { + if (p->nodes[0] == node) + { + OutputPortal (p, glview); + nextp = p->next[0]; + } + else + nextp = p->next[1]; + } +} + +/* +============= +WriteGLView +============= +*/ +void WriteGLView (tree_t *tree, char *source) +{ + char name[1024]; + FILE *glview; + + c_glfaces = 0; + sprintf (name, "%s%s.gl",outbase, source); + printf ("Writing %s\n", name); + + glview = fopen (name, "w"); + if (!glview) + Error ("Couldn't open %s", name); + WriteGLView_r (tree->headnode, glview); + fclose (glview); + + printf ("%5i c_glfaces\n", c_glfaces); +} + diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/leakfile.c b/Toolkit/Programming/Tools/bsp/qbsp3/leakfile.c new file mode 100644 index 0000000..5d85db0 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/leakfile.c @@ -0,0 +1,79 @@ + +#include "qbsp.h" + +/* +============================================================================== + +LEAF FILE GENERATION + +Save out name.line for qe3 to read +============================================================================== +*/ + + +/* +============= +LeakFile + +Finds the shortest possible chain of portals +that leads from the outside leaf to a specifically +occupied leaf +============= +*/ +void LeakFile (tree_t *tree) +{ + vec3_t mid; + FILE *linefile; + char filename[1024]; + node_t *node; + int count; + + if (!tree->outside_node.occupied) + return; + + qprintf ("--- LeakFile ---\n"); + + // + // write the points to the file + // + sprintf (filename, "%s.lin", source); + linefile = fopen (filename, "w"); + if (!linefile) + Error ("Couldn't open %s\n", filename); + + count = 0; + node = &tree->outside_node; + while (node->occupied > 1) + { + int next; + portal_t *p, *nextportal; + node_t *nextnode; + int s; + + // find the best portal exit + next = node->occupied; + for (p=node->portals ; p ; p = p->next[!s]) + { + s = (p->nodes[0] == node); + if (p->nodes[s]->occupied + && p->nodes[s]->occupied < next) + { + nextportal = p; + nextnode = p->nodes[s]; + next = nextnode->occupied; + } + } + node = nextnode; + WindingCenter (nextportal->winding, mid); + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + count++; + } + // add the occupant center + GetVectorForKey (node->occupant, "origin", mid); + + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + qprintf ("%5i point linefile\n", count+1); + + fclose (linefile); +} + diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/map.c b/Toolkit/Programming/Tools/bsp/qbsp3/map.c new file mode 100644 index 0000000..0ad00b5 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/map.c @@ -0,0 +1,1352 @@ +// map.c + +#include "qbsp.h" + +#include + +extern qboolean onlyents; + +int nummapbrushes; +mapbrush_t mapbrushes[MAX_MAP_BRUSHES]; + +int nummapbrushsides; +side_t brushsides[MAX_MAP_SIDES]; +brush_texture_t side_brushtextures[MAX_MAP_SIDES]; + +int nummapplanes; +plane_t mapplanes[MAX_MAP_PLANES]; + +#define PLANE_HASHES 1024 +plane_t *planehash[PLANE_HASHES]; + +vec3_t map_mins, map_maxs; + +// undefine to make plane finding use linear sort +#define USE_HASHING + +void TestExpandBrushes (void); + +int c_boxbevels; +int c_edgebevels; + +int c_areaportals; + +int c_clipbrushes; + +/* +============================================================================= + +PLANE FINDING + +============================================================================= +*/ + + +void PrintBrushMsg(mapbrush_t *b, char *msg) +{ + if (b == NULL) + { + printf("%s\n", msg); + return; + } + + printf("BRUSH- %s: Entity#%i (%2.4f,%2.4f,%2.f)\n", + msg, b->entitynum, entities[b->entitynum].origin[0], entities[b->entitynum].origin[1], entities[b->entitynum].origin[2]); + printf(" Brush#%i min=(%2.4f,%2.4f,%2.4f) max=(%2.4f,%2.4f,%2.4f)\n", + b->brushnum, mapbrushes[b->brushnum].mins[0], mapbrushes[b->brushnum].mins[1], mapbrushes[b->brushnum].mins[2], + b->brushnum, mapbrushes[b->brushnum].maxs[0], mapbrushes[b->brushnum].maxs[1], mapbrushes[b->brushnum].maxs[2]); +} + + +/* +================= +PlaneTypeForNormal +================= +*/ +int PlaneTypeForNormal (vec3_t normal) +{ + vec_t ax, ay, az; + +// NOTE: should these have an epsilon around 1.0? + if (normal[0] == 1.0 || normal[0] == -1.0) + return PLANE_X; + if (normal[1] == 1.0 || normal[1] == -1.0) + return PLANE_Y; + if (normal[2] == 1.0 || normal[2] == -1.0) + return PLANE_Z; + + ax = fabs(normal[0]); + ay = fabs(normal[1]); + az = fabs(normal[2]); + + if (ax >= ay && ax >= az) + return PLANE_ANYX; + if (ay >= ax && ay >= az) + return PLANE_ANYY; + return PLANE_ANYZ; +} + +/* +================ +PlaneEqual +================ +*/ +#define NORMAL_EPSILON 0.00001 +#define DIST_EPSILON 0.01 +qboolean PlaneEqual (plane_t *p, vec3_t normal, vec_t dist) +{ +#if 1 + if ( + fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON + && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON + && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON + && fabs(p->dist - dist) < DIST_EPSILON ) + return true; +#else + if (p->normal[0] == normal[0] + && p->normal[1] == normal[1] + && p->normal[2] == normal[2] + && p->dist == dist) + return true; +#endif + return false; +} + +/* +================ +AddPlaneToHash +================ +*/ +void AddPlaneToHash (plane_t *p) +{ + int hash; + + hash = (int)fabs(p->dist) / 8; + hash &= (PLANE_HASHES-1); + + p->hash_chain = planehash[hash]; + planehash[hash] = p; +} + +/* +================ +CreateNewFloatPlane +================ +*/ +int CreateNewFloatPlane (vec3_t normal, vec_t dist) +{ + plane_t *p, temp; + + if (VectorLength(normal) < 0.5) + Error ("FloatPlane: bad normal"); + // create a new plane + if (nummapplanes+2 > MAX_MAP_PLANES) + Error ("MAX_MAP_PLANES"); + + p = &mapplanes[nummapplanes]; + VectorCopy (normal, p->normal); + p->dist = dist; + p->type = (p+1)->type = PlaneTypeForNormal (p->normal); + + VectorSubtract (vec3_origin, normal, (p+1)->normal); + (p+1)->dist = -dist; + + nummapplanes += 2; + + // allways put axial planes facing positive first + if (p->type < 3) + { + if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0) + { + // flip order + temp = *p; + *p = *(p+1); + *(p+1) = temp; + + AddPlaneToHash (p); + AddPlaneToHash (p+1); + return nummapplanes - 1; + } + } + + AddPlaneToHash (p); + AddPlaneToHash (p+1); + return nummapplanes - 2; +} + +/* +============== +SnapVector +============== +*/ +void SnapVector (vec3_t normal) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if ( fabs(normal[i] - 1) < NORMAL_EPSILON ) + { + VectorClear (normal); + normal[i] = 1; + break; + } + if ( fabs(normal[i] - -1) < NORMAL_EPSILON ) + { + VectorClear (normal); + normal[i] = -1; + break; + } + } +} + +/* +============== +SnapPlane +============== +*/ +void SnapPlane (vec3_t normal, vec_t *dist) +{ + SnapVector (normal); + + if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON) + *dist = Q_rint(*dist); +} + +/* +============= +FindFloatPlane + +============= +*/ +#ifndef USE_HASHING +int FindFloatPlane (vec3_t normal, vec_t dist) +{ + int i; + plane_t *p; + + SnapPlane (normal, &dist); + for (i=0, p=mapplanes ; ihash_chain) + { + if (PlaneEqual (p, normal, dist)) + return p-mapplanes; + } + } + + return CreateNewFloatPlane (normal, dist); +} +#endif + +/* +================ +PlaneFromPoints +================ +*/ +int PlaneFromPoints (int *p0, int *p1, int *p2) +{ + vec3_t t1, t2, normal; + vec_t dist; + + VectorSubtract (p0, p1, t1); + VectorSubtract (p2, p1, t2); + CrossProduct (t1, t2, normal); + if (VectorNormalize (normal, normal) < 0.5) + return (-1); + + dist = DotProduct (p0, normal); + + return FindFloatPlane (normal, dist); +} + + +//==================================================================== + + +/* +=========== +BrushContents +=========== +*/ +int BrushContents (mapbrush_t *b) +{ + int contents; + side_t *s; + int i; + int trans; + + s = &b->original_sides[0]; + contents = s->contents; + trans = texinfo[s->texinfo].flags; + for (i=1 ; inumsides ; i++, s++) + { + s = &b->original_sides[i]; + trans |= texinfo[s->texinfo].flags; + if (s->contents != contents) + { + PrintBrushMsg(b, "Mixed face contents"); + break; + } + } + + // if any side is translucent, mark the contents + // and change solid to window + if ( trans & (SURF_TRANS33|SURF_TRANS66) ) + { + contents |= CONTENTS_TRANSLUCENT; + if (contents & CONTENTS_SOLID) + { + contents &= ~CONTENTS_SOLID; + contents |= CONTENTS_WINDOW; + } + } + + if (trans & SURF_ALPHA_TEXTURE) + { + contents |= CONTENTS_TRANSLUCENT; + if (contents & CONTENTS_SOLID) + { + contents &= ~CONTENTS_SOLID; + contents |= CONTENTS_WINDOW; + } + } + + return contents; +} + + +//============================================================================ + +/* +================= +AddBrushBevels + +Adds any additional planes necessary to allow the brush to be expanded +against axial bounding boxes +================= +*/ +void AddBrushBevels (mapbrush_t *b) +{ + int axis, dir; + int i, j, k, l, order; + side_t sidetemp; + brush_texture_t tdtemp; + side_t *s, *s2; + vec3_t normal; + float dist; + winding_t *w, *w2; + vec3_t vec, vec2; + float d; + + // + // add the axial planes + // + order = 0; + for (axis=0 ; axis <3 ; axis++) + { + for (dir=-1 ; dir <= 1 ; dir+=2, order++) + { + // see if the plane is allready present + for (i=0, s=b->original_sides ; inumsides ; i++,s++) + { + if (mapplanes[s->planenum].normal[axis] == dir) + break; + } + + if (i == b->numsides) + { // add a new side + if (nummapbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + nummapbrushsides++; + b->numsides++; + VectorClear (normal); + normal[axis] = dir; + if (dir == 1) + dist = b->maxs[axis]; + else + dist = -b->mins[axis]; + s->planenum = FindFloatPlane (normal, dist); + s->texinfo = b->original_sides[0].texinfo; + s->contents = b->original_sides[0].contents; + s->bevel = true; + c_boxbevels++; + } + + // if the plane is not in it canonical order, swap it + if (i != order) + { + sidetemp = b->original_sides[order]; + b->original_sides[order] = b->original_sides[i]; + b->original_sides[i] = sidetemp; + + j = b->original_sides - brushsides; + tdtemp = side_brushtextures[j+order]; + side_brushtextures[j+order] = side_brushtextures[j+i]; + side_brushtextures[j+i] = tdtemp; + } + } + } + + // + // add the edge bevels + // + if (b->numsides == 6) + return; // pure axial + + // test the non-axial plane edges + for (i=6 ; inumsides ; i++) + { + s = b->original_sides + i; + w = s->winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + k = (j+1)%w->numpoints; + VectorSubtract (w->p[j], w->p[k], vec); + if (VectorNormalize (vec, vec) < 0.5) + continue; + SnapVector (vec); + for (k=0 ; k<3 ; k++) + if ( vec[k] == -1 || vec[k] == 1) + break; // axial + if (k != 3) + continue; // only test non-axial edges + + // try the six possible slanted axials from this edge + for (axis=0 ; axis <3 ; axis++) + { + for (dir=-1 ; dir <= 1 ; dir+=2) + { + // construct a plane + VectorClear (vec2); + vec2[axis] = dir; + CrossProduct (vec, vec2, normal); + if (VectorNormalize (normal, normal) < 0.5) + continue; + dist = DotProduct (w->p[j], normal); + + // if all the points on all the sides are + // behind this plane, it is a proper edge bevel + for (k=0 ; knumsides ; k++) + { + // if this plane has allready been used, skip it + if (PlaneEqual (&mapplanes[b->original_sides[k].planenum] + , normal, dist) ) + break; + + w2 = b->original_sides[k].winding; + if (!w2) + continue; + for (l=0 ; lnumpoints ; l++) + { + d = DotProduct (w2->p[l], normal) - dist; + if (d > 0.1) + break; // point in front + } + if (l != w2->numpoints) + break; + } + + if (k != b->numsides) + continue; // wasn't part of the outer hull + // add this plane + if (nummapbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + nummapbrushsides++; + s2 = &b->original_sides[b->numsides]; + s2->planenum = FindFloatPlane (normal, dist); + s2->texinfo = b->original_sides[0].texinfo; + s2->contents = b->original_sides[0].contents; + s2->bevel = true; + c_edgebevels++; + b->numsides++; + } + } + } + } +} + + +/* +================ +MakeBrushWindings + +makes basewindigs for sides and mins / maxs for the brush +================ +*/ +qboolean MakeBrushWindings (mapbrush_t *ob) +{ + int i, j; + winding_t *w; + side_t *side; + plane_t *plane; + + ClearBounds (ob->mins, ob->maxs); + + for (i=0 ; inumsides ; i++) + { + plane = &mapplanes[ob->original_sides[i].planenum]; + w = BaseWindingForPlane (plane->normal, plane->dist); + for (j=0 ; jnumsides && w; j++) + { + if (i == j) + continue; + if (ob->original_sides[j].bevel) + continue; + plane = &mapplanes[ob->original_sides[j].planenum^1]; + ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); + } + + side = &ob->original_sides[i]; + side->winding = w; + if (w) + { + side->visible = true; + for (j=0 ; jnumpoints ; j++) + AddPointToBounds (w->p[j], ob->mins, ob->maxs); + } + } + + for (i=0 ; i<3 ; i++) + { + if (ob->mins[0] < -4096 || ob->maxs[0] > 4096) + PrintBrushMsg(ob, "Bounds out of range"); + if (ob->mins[0] > 4096 || ob->maxs[0] < -4096) + PrintBrushMsg(ob, "No visible sides on brush"); + } + + return true; +} + + +/* +================= +ParseBrush +================= +*/ +void ParseBrush (entity_t *mapent) +{ + mapbrush_t *b; + int i,j, k; + int mt; + side_t *side, *s2; + int planenum; + brush_texture_t td; + int planepts[3][3]; + + if (nummapbrushes == MAX_MAP_BRUSHES) + Error ("nummapbrushes == MAX_MAP_BRUSHES"); + + b = &mapbrushes[nummapbrushes]; + b->original_sides = &brushsides[nummapbrushsides]; + b->entitynum = num_entities-1; + b->brushnum = nummapbrushes - mapent->firstbrush; + + do + { + if (!GetScriptToken (true)) + break; + if (!strcmp (token, "}") ) + break; + + if (nummapbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + side = &brushsides[nummapbrushsides]; + + // read the three point plane definition + for (i=0 ; i<3 ; i++) + { + if (i != 0) + GetScriptToken (true); + if (strcmp (token, "(") ) + Error ("parsing brush"); + + for (j=0 ; j<3 ; j++) + { + GetScriptToken (false); + planepts[i][j] = atoi(token); + } + + GetScriptToken (false); + if (strcmp (token, ")") ) + Error ("parsing brush"); + + } + + + // + // read the texturedef + // + GetScriptToken (false); + strcpy (td.name, token); + + GetScriptToken (false); + td.shift[0] = atoi(token); + GetScriptToken (false); + td.shift[1] = atoi(token); + GetScriptToken (false); + td.rotate = atoi(token); + GetScriptToken (false); + td.scale[0] = atof(token); + GetScriptToken (false); + td.scale[1] = atof(token); + + // find default flags and values + mt = FindMiptex (td.name); + td.flags = textureref[mt].flags; + td.value = textureref[mt].value; + side->contents = textureref[mt].contents; + side->surf = td.flags = textureref[mt].flags; + + if (ScriptTokenAvailable()) + { + GetScriptToken (false); + side->contents = atoi(token); + GetScriptToken (false); + side->surf = td.flags = atoi(token); + GetScriptToken (false); + td.value = atoi(token); + } + + if (ScriptTokenAvailable()) + { + GetScriptToken (false); + side->lighting.r = atof(token)*255.0; + GetScriptToken (false); + side->lighting.g = atof(token)*255.0; + GetScriptToken (false); + side->lighting.b = atof(token)*255.0; + GetScriptToken (false); + side->lighting.a = atof(token)*255.0; + } + + // translucent objects are automatically classified as detail + if (side->surf & (SURF_TRANS33|SURF_TRANS66) ) + side->contents |= CONTENTS_DETAIL; + if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) + side->contents |= CONTENTS_DETAIL; + if (fulldetail) + side->contents &= ~CONTENTS_DETAIL; + if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) + | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) ) + side->contents |= CONTENTS_SOLID; + + // hints and skips are never detail, and have no content + if (side->surf & (SURF_HINT|SURF_SKIP) ) + { + side->contents = 0; + side->surf &= ~CONTENTS_DETAIL; + } + + + // + // find the plane number + // + planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]); + if (planenum == -1) + { + PrintBrushMsg(b, "Plane with no normal"); + continue; + } + + // + // see if the plane has been used already + // + for (k=0 ; knumsides ; k++) + { + s2 = b->original_sides + k; + if (s2->planenum == planenum) + { + PrintBrushMsg(b, "Duplicate plane"); + break; + } + if ( s2->planenum == (planenum^1) ) + { + PrintBrushMsg(b, "Mirrored plane"); + break; + } + } + if (k != b->numsides) + continue; // duplicated + + // + // keep this side + // + + side = b->original_sides + b->numsides; + side->planenum = planenum; + side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum], + &td, vec3_origin); + + // save the td off in case there is an origin brush and we + // have to recalculate the texinfo + side_brushtextures[nummapbrushsides] = td; + + nummapbrushsides++; + b->numsides++; + } while (1); + + // get the content for the entire brush + b->contents = BrushContents (b); + + // allow detail brushes to be removed + if (nodetail && (b->contents & CONTENTS_DETAIL) ) + { + b->numsides = 0; + return; + } + + // allow water brushes to be removed + if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) + { + b->numsides = 0; + return; + } + + // create windings for sides and bounds for brush + MakeBrushWindings (b); + + // brushes that will not be visible at all will never be + // used as bsp splitters + if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) + { + c_clipbrushes++; + for (i=0 ; inumsides ; i++) + b->original_sides[i].texinfo = TEXINFO_NODE; + } + + // + // origin brushes are removed, but they set + // the rotation origin for the rest of the brushes + // in the entity. After the entire entity is parsed, + // the planenums and texinfos will be adjusted for + // the origin brush + // + if (b->contents & CONTENTS_ORIGIN) + { + char string[32]; + vec3_t origin; + + if (num_entities == 1) + { + PrintBrushMsg(b, "Origin brushes error."); + Error ("Origin brushes not allowed in world"); + return; + } + + VectorAdd (b->mins, b->maxs, origin); + VectorScale (origin, 0.5, origin); + + sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); + SetKeyValue (&entities[b->entitynum], "origin", string); + + VectorCopy (origin, entities[b->entitynum].origin); + + // don't keep this brush + b->numsides = 0; + + return; + } + + AddBrushBevels (b); + + nummapbrushes++; + mapent->numbrushes++; +} + +/* +================ +MoveBrushesToWorld + +Takes all of the brushes from the current entity and +adds them to the world's brush list. + +Used by func_group and func_areaportal +================ +*/ +void MoveBrushesToWorld (entity_t *mapent) +{ + int newbrushes; + int worldbrushes; + mapbrush_t *temp; + int i; + + // this is pretty gross, because the brushes are expected to be + // in linear order for each entity + + newbrushes = mapent->numbrushes; + worldbrushes = entities[0].numbrushes; + + temp = malloc(newbrushes*sizeof(mapbrush_t)); + if (temp == NULL) + Error("MoveBrushesToWorld MALLOC failed! Could not allocate %s bytes.", newbrushes*sizeof(mapbrush_t)); + + memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t)); + +#if 0 // let them keep their original brush numbers + for (i=0 ; inumbrushes = 0; +} + +/* +================ +ParseMapEntity +================ +*/ +qboolean ParseMapEntity (void) +{ + entity_t *mapent; + epair_t *e; + side_t *s; + int i, j; + int startbrush, startsides; + vec_t newdist; + mapbrush_t *b; + + if (!GetScriptToken (true)) + return false; + + if (strcmp (token, "{") ) + Error ("ParseEntity: { not found"); + + if (num_entities == MAX_MAP_ENTITIES) + Error ("num_entities == MAX_MAP_ENTITIES"); + + startbrush = nummapbrushes; + startsides = nummapbrushsides; + + mapent = &entities[num_entities]; + num_entities++; + memset (mapent, 0, sizeof(*mapent)); + mapent->firstbrush = nummapbrushes; + mapent->numbrushes = 0; +// mapent->portalareas[0] = -1; +// mapent->portalareas[1] = -1; + + do + { + if (!GetScriptToken (true)) + Error ("ParseEntity: EOF without closing brace"); + if (!strcmp (token, "}") ) + break; + if (!strcmp (token, "{") ) + ParseBrush (mapent); + else + { + e = ParseEpair (); + e->next = mapent->epairs; + mapent->epairs = e; + } + } while (1); + + GetVectorForKey (mapent, "origin", mapent->origin); + + // + // if there was an origin brush, offset all of the planes and texinfo + // + if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) + { + for (i=0 ; inumbrushes ; i++) + { + b = &mapbrushes[mapent->firstbrush + i]; + for (j=0 ; jnumsides ; j++) + { + s = &b->original_sides[j]; + newdist = mapplanes[s->planenum].dist - + DotProduct (mapplanes[s->planenum].normal, mapent->origin); + s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist); + s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum], + &side_brushtextures[s-brushsides], mapent->origin); + } + MakeBrushWindings (b); + } + } + + // group entities are just for editor convenience + // toss all brushes into the world entity + if (!strcmp ("func_group", ValueForKey (mapent, "classname"))) + { + MoveBrushesToWorld (mapent); + mapent->numbrushes = 0; + return true; + } + + // areaportal entities move their brushes, but don't eliminate + // the entity + if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) + { + char str[128]; + + if (mapent->numbrushes != 1) + Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1); + + b = &mapbrushes[nummapbrushes-1]; + b->contents = CONTENTS_AREAPORTAL; + c_areaportals++; + mapent->areaportalnum = c_areaportals; + // set the portal number as "style" + sprintf (str, "%i", c_areaportals); + SetKeyValue (mapent, "style", str); + MoveBrushesToWorld (mapent); + return true; + } + + return true; +} + +//=================================================================== + +static char *msgNames; +static int *msgNameOffsets; +static int numMsgs; + +#define MAX_MESSAGE_NAME_SIZE 64 + +void LoadMessageNames() +{ + int filesize; + char *buf; + int count = 0; + char path[1024]; + + sprintf(path, "%scinematics/messages.txt", gamedir); + + filesize = LoadFile(path, &buf); + + if(filesize) + { + int i; + int numRead; + char msg[MAX_MESSAGE_NAME_SIZE+1]; + + sscanf(buf + count, "%d%n", &numMsgs, &numRead); + count += numRead; + + msgNameOffsets = malloc(numMsgs * sizeof(int)); + if (msgNameOffsets == NULL) + Error("LoadMessageNames MALLOC failed! Could not allocate %s bytes.", numMsgs*sizeof(int)); + + for(i = 0; i < numMsgs; ++i) + { + assert(buf[count] == '\r'); + + ++count; + + assert(buf[count] == '\n'); + + ++count; + + msgNameOffsets[i] = count; + + sscanf(buf + count, "%s%n", msg, &numRead); + count += numRead; + } + + msgNames = buf; + } + else + { + msgNames = NULL; + } +} + +void FreeMessageNames() +{ + free(msgNames); + free(msgNameOffsets); +} + +_inline void WriteBuf(char *buf, int *count, void *toWrite, size_t size) +{ + memcpy(buf + *count, toWrite, size); + *count += size; +} + +#define ENT_NAME_MAX 128 + +void ProcessCinematicScript(char *name) +{ + int filesize; + char *buf; + char *buf2; + int count = 0; + int count2 = 0; + char path[1024]; + void *e = NULL; + +#if 1 + if(!msgNames) + { + assert(0); + return; + } + + sprintf(path, "%scinematics/%s.txt", gamedir, name); + + filesize = LoadFile(path, &buf); + + if(filesize) + { + buf2 = malloc(filesize+1); + if (buf2 == NULL) + Error("ProcessCinematicScript (1) MALLOC failed! Could not allocate %s bytes.", filesize+1); + + while(1) + { + int i, frame, msgID, numRead; + char msg[MAX_MESSAGE_NAME_SIZE+1]; + char entityName[ENT_NAME_MAX+1]; + + sscanf(buf + count, "%d %s %s%n", &frame, entityName, msg, &numRead); + count += numRead; + + WriteBuf(buf2, &count2, &frame, sizeof(int)); + + WriteBuf(buf2, &count2, entityName, strlen(entityName) + 1); + + msgID = -1; + + for(i = 0; i < numMsgs; ++i) + { + if(!strnicmp(msgNames + msgNameOffsets[i], msg, strlen(msg))) + { + msgID = i; + break; + } + } + + assert(msgID != -1); + + WriteBuf(buf2, &count2, &msgID, sizeof(int)); + + assert(buf[count] == '\t'); + + ++count; + + if((buf[count] != '\t') && (buf[count] != '\n')) + { + char format[17]; // should need more than 16 parms, +1 for null + int curFormat = 0; + char current; + byte *b; + short *s; + int *i; + float *f; + double *d; + char ent[ENT_NAME_MAX+1]; + + sscanf(buf + count, "%s%n", format, &numRead); + count += numRead; + + WriteBuf(buf2, &count2, &format, strlen(format) + 1); + + while(current = format[curFormat]) + { + switch(current) + { + case 'b': + sscanf(buf + count, "%b%n", &b, &numRead); + count += numRead; + + WriteBuf(buf2, &count2, &b, sizeof(byte)); + break; + case 's': + sscanf(buf + count, "%s%n", &s, &numRead); + count += numRead; + + WriteBuf(buf2, &count2, &s, sizeof(short)); + break; + case 'i': + sscanf(buf + count, "%d%n", &i, &numRead); + count += numRead; + + WriteBuf(buf2, &count2, &i, sizeof(int)); + break; + case 'f': + sscanf(buf + count, "%f%n", &f, &numRead); + count += numRead; + + *d = *f; + + WriteBuf(buf2, &count2, &d, sizeof(double)); + break; + case 'e': + assert(buf[count] == '\t'); + + ++count; + + if((buf[count] != '\t') && (buf[count] != '\n')) + { + sscanf(buf + count, "%s%n", ent, &numRead); + count += numRead; + } + else + { + ent[0] = '\0'; + } + + WriteBuf(buf2, &count2, &ent, strlen(ent) + 1); + break; + case 'c': // color is in hex + sscanf(buf + count, "%x%n", &i, &numRead); + count += numRead; + + WriteBuf(buf2, &count2, &i, sizeof(int)); + break; + default: + assert(0); + } + + ++curFormat; + } + } + else + { + char noFormat = '\0'; + + WriteBuf(buf2, &count2, &noFormat, sizeof(char)); + } + + while((buf[count] != '\n') && (buf[count] != EOF)) + { + assert(buf[count] == '\t' || buf[count] == '\r'); + + ++count; + } + + if(count == filesize - 1) + { + break; + } + + assert(count < filesize - 1); + } + + sprintf(path, "%scinematics/%s.ics", gamedir, name); // ingame cinematic script + + SaveFile (path, buf2, count); + free(buf2); + } + + free(buf); +#else + { + int i; + short s; + char *c; + char *entityName; + size_t size; + + buf2 = malloc(filesize+1); + if (buf2 == NULL) + Error("ProcessCinematicScript (2) MALLOC failed! Could not allocate %s bytes.", filesize+1); + + size = sizeof(int); + i = 10; // frame 10 + memcpy(buf2 + count, &i, size); + count += size; + + size = sizeof(char)*5; + entityName = "test"; + memcpy(buf2 + count, entityName, size); + count += size; + + size = sizeof(int); + i = 9; // MSG_DEATH + memcpy(buf2 + count, &i, size); + count += size; + + size = sizeof(char)*5; + c = "eeei"; // four parms + memcpy(buf2 + count, c, size); + count += size; + + size = sizeof(int); + i = 0; + memcpy(buf2 + count, &i, size); + count += size; + + size = sizeof(int); + i = 0; + memcpy(buf2 + count, &i, size); + count += size; + + size = sizeof(int); + i = 0; + memcpy(buf2 + count, &i, size); + count += size; + + size = sizeof(int); + i = 100; + memcpy(buf2 + count, &i, size); + count += size; + + sprintf(path, "%scinematics/%s.ics", gamedir, name); // ingame cinematic script + + SaveFile (path, buf2, count); + free(buf2); + } +#endif +} + +/* +================ +LoadMapFile +================ +*/ +void LoadMapFile (char *filename) +{ + int i; + + qprintf ("--- LoadMapFile ---\n"); + + LoadScriptFile (filename); + + nummapbrushsides = 0; + num_entities = 0; + + while (ParseMapEntity ()) + { + } + +#if 1 + for(i = 0; i < num_entities; ++i) + { + epair_t *e; + + e = entities[i].epairs; + + while(e) + { + if(stricmp(e->key, "cinematic") == 0) + { // found a cinematic script + ProcessCinematicScript(e->value); + break; + } + + e = e->next; + } + } +#else + ProcessCinematicScript("test"); +#endif + + ClearBounds (map_mins, map_maxs); + for (i=0 ; i 4096) + continue; // no valid points + AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs); + AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs); + } + + qprintf ("%5i brushes\n", nummapbrushes); + qprintf ("%5i clipbrushes\n", c_clipbrushes); + qprintf ("%5i total sides\n", nummapbrushsides); + qprintf ("%5i boxbevels\n", c_boxbevels); + qprintf ("%5i edgebevels\n", c_edgebevels); + qprintf ("%5i entities\n", num_entities); + qprintf ("%5i planes\n", nummapplanes); + qprintf ("%5i areaportals\n", c_areaportals); + qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2], + map_maxs[0],map_maxs[1],map_maxs[2]); + +// TestExpandBrushes (); +} + + +//==================================================================== + + +/* +================ +TestExpandBrushes + +Expands all the brush planes and saves a new map out +================ +*/ +void TestExpandBrushes (void) +{ + FILE *f; + side_t *s; + int i, j, bn; + winding_t *w; + char *name = "expanded.map"; + mapbrush_t *brush; + vec_t dist; + + printf ("writing %s\n", name); + f = fopen (name, "wb"); + if (!f) + Error ("Can't write %s\b", name); + + fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); + + for (bn=0 ; bnnumsides ; i++) + { + s = brush->original_sides + i; + dist = mapplanes[s->planenum].dist; + for (j=0 ; j<3 ; j++) + dist += fabs( 16 * mapplanes[s->planenum].normal[j] ); + + w = BaseWindingForPlane (mapplanes[s->planenum].normal, dist); + + fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); + + fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture); + FreeWinding (w); + } + fprintf (f, "}\n"); + } + fprintf (f, "}\n"); + + fclose (f); + + Error ("can't proceed after expanding brushes"); +} diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/nodraw.c b/Toolkit/Programming/Tools/bsp/qbsp3/nodraw.c new file mode 100644 index 0000000..28b9f49 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/nodraw.c @@ -0,0 +1,26 @@ + +#include "qbsp.h" + +vec3_t draw_mins, draw_maxs; +qboolean drawflag; + +void Draw_ClearWindow (void) +{ +} + +//============================================================ + +#define GLSERV_PORT 25001 + + +void GLS_BeginScene (void) +{ +} + +void GLS_Winding (winding_t *w, int code) +{ +} + +void GLS_EndScene (void) +{ +} diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/portals.c b/Toolkit/Programming/Tools/bsp/qbsp3/portals.c new file mode 100644 index 0000000..5a952f2 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/portals.c @@ -0,0 +1,1095 @@ + +#include "qbsp.h" + + +int c_active_portals; +int c_peak_portals; +int c_boundary; +int c_boundary_sides; + +/* +=========== +AllocPortal +=========== +*/ +portal_t *AllocPortal (void) +{ + portal_t *p; + + if (numthreads == 1) + c_active_portals++; + if (c_active_portals > c_peak_portals) + c_peak_portals = c_active_portals; + + p = malloc (sizeof(portal_t)); + if (p == NULL) + Error("AllocPortal MALLOC failed! Could not allocate %s bytes.", sizeof(portal_t)); + + memset (p, 0, sizeof(portal_t)); + + return p; +} + +void FreePortal (portal_t *p) +{ + if (p->winding) + FreeWinding (p->winding); + if (numthreads == 1) + c_active_portals--; + free (p); +} + +//============================================================== + +/* +============== +VisibleContents + +Returns the single content bit of the +strongest visible content present +============== +*/ +int VisibleContents (int contents) +{ + int i; + + for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1) + if (contents & i ) + return i; + + return 0; +} + + +/* +=============== +ClusterContents +=============== +*/ +int ClusterContents (node_t *node) +{ + int c1, c2, c; + + if (node->planenum == PLANENUM_LEAF) + return node->contents; + + c1 = ClusterContents(node->children[0]); + c2 = ClusterContents(node->children[1]); + c = c1|c2; + + // a cluster may include some solid detail areas, but + // still be seen into + if ( ! (c1&CONTENTS_SOLID) || ! (c2&CONTENTS_SOLID) ) + c &= ~CONTENTS_SOLID; + return c; +} + +/* +============= +Portal_VisFlood + +Returns true if the portal is empty or translucent, allowing +the PVS calculation to see through it. +The nodes on either side of the portal may actually be clusters, +not leafs, so all contents should be ored together +============= +*/ +qboolean Portal_VisFlood (portal_t *p) +{ + int c1, c2; + + if (!p->onnode) + return false; // to global outsideleaf + + c1 = ClusterContents(p->nodes[0]); + c2 = ClusterContents(p->nodes[1]); + + if (!VisibleContents (c1^c2)) + return true; + + if (c1 & (CONTENTS_TRANSLUCENT|CONTENTS_DETAIL)) + c1 = 0; + if (c2 & (CONTENTS_TRANSLUCENT|CONTENTS_DETAIL)) + c2 = 0; + + if ( (c1|c2) & CONTENTS_SOLID ) + return false; // can't see through solid + + if (! (c1 ^ c2)) + return true; // identical on both sides + + if (!VisibleContents (c1^c2)) + return true; + return false; +} + + +/* +=============== +Portal_EntityFlood + +The entity flood determines which areas are +"outside" on the map, which are then filled in. +Flowing from side s to side !s +=============== +*/ +qboolean Portal_EntityFlood (portal_t *p, int s) +{ + if (p->nodes[0]->planenum != PLANENUM_LEAF + || p->nodes[1]->planenum != PLANENUM_LEAF) + Error ("Portal_EntityFlood: not a leaf"); + + // can never cross to a solid + if ( (p->nodes[0]->contents & CONTENTS_SOLID) + || (p->nodes[1]->contents & CONTENTS_SOLID) ) + return false; + + // can flood through everything else + return true; +} + + +//============================================================================= + +int c_tinyportals; + +/* +============= +AddPortalToNodes +============= +*/ +void AddPortalToNodes (portal_t *p, node_t *front, node_t *back) +{ + if (p->nodes[0] || p->nodes[1]) + Error ("AddPortalToNode: allready included"); + + p->nodes[0] = front; + p->next[0] = front->portals; + front->portals = p; + + p->nodes[1] = back; + p->next[1] = back->portals; + back->portals = p; +} + + +/* +============= +RemovePortalFromNode +============= +*/ +void RemovePortalFromNode (portal_t *portal, node_t *l) +{ + portal_t **pp, *t; + +// remove reference to the current portal + pp = &l->portals; + while (1) + { + t = *pp; + if (!t) + Error ("RemovePortalFromNode: portal not in leaf"); + + if ( t == portal ) + break; + + if (t->nodes[0] == l) + pp = &t->next[0]; + else if (t->nodes[1] == l) + pp = &t->next[1]; + else + Error ("RemovePortalFromNode: portal not bounding leaf"); + } + + if (portal->nodes[0] == l) + { + *pp = portal->next[0]; + portal->nodes[0] = NULL; + } + else if (portal->nodes[1] == l) + { + *pp = portal->next[1]; + portal->nodes[1] = NULL; + } +} + +//============================================================================ + +void PrintPortal (portal_t *p) +{ + int i; + winding_t *w; + + w = p->winding; + for (i=0 ; inumpoints ; i++) + printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0] + , w->p[i][1], w->p[i][2]); +} + +/* +================ +MakeHeadnodePortals + +The created portals will face the global outside_node +================ +*/ +#define SIDESPACE 8 +void MakeHeadnodePortals (tree_t *tree) +{ + vec3_t bounds[2]; + int i, j, n; + portal_t *p, *portals[6]; + plane_t bplanes[6], *pl; + node_t *node; + + node = tree->headnode; + +// pad with some space so there will never be null volume leafs + for (i=0 ; i<3 ; i++) + { + bounds[0][i] = tree->mins[i] - SIDESPACE; + bounds[1][i] = tree->maxs[i] + SIDESPACE; + } + + tree->outside_node.planenum = PLANENUM_LEAF; + tree->outside_node.brushlist = NULL; + tree->outside_node.portals = NULL; + tree->outside_node.contents = 0; + + for (i=0 ; i<3 ; i++) + for (j=0 ; j<2 ; j++) + { + n = j*3 + i; + + p = AllocPortal (); + portals[n] = p; + + pl = &bplanes[n]; + memset (pl, 0, sizeof(*pl)); + if (j) + { + pl->normal[i] = -1; + pl->dist = -bounds[j][i]; + } + else + { + pl->normal[i] = 1; + pl->dist = bounds[j][i]; + } + p->plane = *pl; + p->winding = BaseWindingForPlane (pl->normal, pl->dist); + AddPortalToNodes (p, node, &tree->outside_node); + } + +// clip the basewindings by all the other planes + for (i=0 ; i<6 ; i++) + { + for (j=0 ; j<6 ; j++) + { + if (j == i) + continue; + ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON); + if (!portals[i]->winding) //it could get freed in chop + break; + } + } +} + +//=================================================== + + +/* +================ +BaseWindingForNode +================ +*/ +#define BASE_WINDING_EPSILON 0.001 +#define SPLIT_WINDING_EPSILON 0.001 + +winding_t *BaseWindingForNode (node_t *node) +{ + winding_t *w; + node_t *n; + plane_t *plane; + vec3_t normal; + vec_t dist; + + w = BaseWindingForPlane (mapplanes[node->planenum].normal + , mapplanes[node->planenum].dist); + + // clip by all the parents + for (n=node->parent ; n && w ; ) + { + plane = &mapplanes[n->planenum]; + + if (n->children[0] == node) + { // take front + ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON); + } + else + { // take back + VectorSubtract (vec3_origin, plane->normal, normal); + dist = -plane->dist; + ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON); + } + node = n; + n = n->parent; + } + + return w; +} + +//============================================================ + +qboolean WindingIsTiny (winding_t *w); + +/* +================== +MakeNodePortal + +create the new portal by taking the full plane winding for the cutting plane +and clipping it by all of parents of this node +================== +*/ +void MakeNodePortal (node_t *node) +{ + portal_t *new_portal, *p; + winding_t *w; + vec3_t normal; + float dist; + int side; + + w = BaseWindingForNode (node); + + // clip the portal by all the other portals in the node + for (p = node->portals ; p && w; p = p->next[side]) + { + if (p->nodes[0] == node) + { + side = 0; + VectorCopy (p->plane.normal, normal); + dist = p->plane.dist; + } + else if (p->nodes[1] == node) + { + side = 1; + VectorSubtract (vec3_origin, p->plane.normal, normal); + dist = -p->plane.dist; + } + else + Error ("CutNodePortals_r: mislinked portal"); + + ChopWindingInPlace (&w, normal, dist, 0.1); + } + + if (!w) + { + return; + } + + if (WindingIsTiny (w)) + { + c_tinyportals++; + FreeWinding (w); + return; + } + + + new_portal = AllocPortal (); + new_portal->plane = mapplanes[node->planenum]; + new_portal->onnode = node; + new_portal->winding = w; + AddPortalToNodes (new_portal, node->children[0], node->children[1]); +} + + +/* +============== +SplitNodePortals + +Move or split the portals that bound node so that the node's +children have portals instead of node. +============== +*/ +void SplitNodePortals (node_t *node) +{ + portal_t *p, *next_portal, *new_portal; + node_t *f, *b, *other_node; + int side; + plane_t *plane; + winding_t *frontwinding, *backwinding; + + plane = &mapplanes[node->planenum]; + f = node->children[0]; + b = node->children[1]; + + for (p = node->portals ; p ; p = next_portal) + { + if (p->nodes[0] == node) + side = 0; + else if (p->nodes[1] == node) + side = 1; + else + Error ("CutNodePortals_r: mislinked portal"); + next_portal = p->next[side]; + + other_node = p->nodes[!side]; + RemovePortalFromNode (p, p->nodes[0]); + RemovePortalFromNode (p, p->nodes[1]); + +// +// cut the portal into two portals, one on each side of the cut plane +// + ClipWindingEpsilon (p->winding, plane->normal, plane->dist, + SPLIT_WINDING_EPSILON, &frontwinding, &backwinding); + + if (frontwinding && WindingIsTiny(frontwinding)) + { + FreeWinding (frontwinding); + frontwinding = NULL; + c_tinyportals++; + } + + if (backwinding && WindingIsTiny(backwinding)) + { + FreeWinding (backwinding); + backwinding = NULL; + c_tinyportals++; + } + + if (!frontwinding && !backwinding) + { // tiny windings on both sides + continue; + } + + if (!frontwinding) + { + FreeWinding (backwinding); + if (side == 0) + AddPortalToNodes (p, b, other_node); + else + AddPortalToNodes (p, other_node, b); + continue; + } + if (!backwinding) + { + FreeWinding (frontwinding); + if (side == 0) + AddPortalToNodes (p, f, other_node); + else + AddPortalToNodes (p, other_node, f); + continue; + } + + // the winding is split + new_portal = AllocPortal (); + *new_portal = *p; + new_portal->winding = backwinding; + FreeWinding (p->winding); + p->winding = frontwinding; + + if (side == 0) + { + AddPortalToNodes (p, f, other_node); + AddPortalToNodes (new_portal, b, other_node); + } + else + { + AddPortalToNodes (p, other_node, f); + AddPortalToNodes (new_portal, other_node, b); + } + } + + node->portals = NULL; +} + + +/* +================ +CalcNodeBounds +================ +*/ +void CalcNodeBounds (node_t *node) +{ + portal_t *p; + int s; + int i; + + // calc mins/maxs for both leafs and nodes + ClearBounds (node->mins, node->maxs); + for (p = node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + for (i=0 ; iwinding->numpoints ; i++) + AddPointToBounds (p->winding->p[i], node->mins, node->maxs); + } +} + + +/* +================== +MakeTreePortals_r +================== +*/ +void MakeTreePortals_r (node_t *node) +{ + int i; + + CalcNodeBounds (node); + if (node->mins[0] >= node->maxs[0]) + { + printf ("WARNING: node without a volume\n"); + } + + for (i=0 ; i<3 ; i++) + { + if (node->mins[i] < -8000 || node->maxs[i] > 8000) + { + printf ("WARNING: node with unbounded volume\n"); + break; + } + } + if (node->planenum == PLANENUM_LEAF) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + MakeTreePortals_r (node->children[0]); + MakeTreePortals_r (node->children[1]); +} + +/* +================== +MakeTreePortals +================== +*/ +void MakeTreePortals (tree_t *tree) +{ + MakeHeadnodePortals (tree); + MakeTreePortals_r (tree->headnode); +} + +/* +========================================================= + +FLOOD ENTITIES + +========================================================= +*/ + +/* +============= +FloodPortals_r +============= +*/ +void FloodPortals_r (node_t *node, int dist) +{ + portal_t *p; + int s; + + node->occupied = dist; + + for (p=node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + + if (p->nodes[!s]->occupied) + continue; + + if (!Portal_EntityFlood (p, s)) + continue; + + FloodPortals_r (p->nodes[!s], dist+1); + } +} + +/* +============= +PlaceOccupant +============= +*/ +qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant) +{ + node_t *node; + vec_t d; + plane_t *plane; + + // find the leaf to start in + node = headnode; + while (node->planenum != PLANENUM_LEAF) + { + plane = &mapplanes[node->planenum]; + d = DotProduct (origin, plane->normal) - plane->dist; + if (d >= 0) + node = node->children[0]; + else + node = node->children[1]; + } + + if (node->contents == CONTENTS_SOLID) + return false; + node->occupant = occupant; + + FloodPortals_r (node, 1); + + return true; +} + +/* +============= +FloodEntities + +Marks all nodes that can be reached by entites +============= +*/ +qboolean FloodEntities (tree_t *tree) +{ + int i; + vec3_t origin; + char *cl; + qboolean inside; + node_t *headnode; + + headnode = tree->headnode; + qprintf ("--- FloodEntities ---\n"); + inside = false; + tree->outside_node.occupied = 0; + + for (i=1 ; ioutside_node.occupied) + { + qprintf ("entity reached from outside -- no filling\n"); + } + + return (qboolean)(inside && !tree->outside_node.occupied); +} + +/* +========================================================= + +FLOOD AREAS + +========================================================= +*/ + +int c_areas; + +/* +============= +FloodAreas_r +============= +*/ +void FloodAreas_r (node_t *node) +{ + portal_t *p; + int s; + bspbrush_t *b; + entity_t *e; + + if (node->contents == CONTENTS_AREAPORTAL) + { + // this node is part of an area portal + b = node->brushlist; + e = &entities[b->original->entitynum]; + + // if the current area has allready touched this + // portal, we are done + if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas) + return; + + // note the current area as bounding the portal + if (e->portalareas[1]) + { + printf ("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum); + return; + } + if (e->portalareas[0]) + e->portalareas[1] = c_areas; + else + e->portalareas[0] = c_areas; + + return; + } + + if (node->area) + return; // allready got it + node->area = c_areas; + + for (p=node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); +#if 0 + if (p->nodes[!s]->occupied) + continue; +#endif + if (!Portal_EntityFlood (p, s)) + continue; + + FloodAreas_r (p->nodes[!s]); + } +} + +/* +============= +FindAreas_r + +Just decend the tree, and for each node that hasn't had an +area set, flood fill out from there +============= +*/ +void FindAreas_r (node_t *node) +{ + if (node->planenum != PLANENUM_LEAF) + { + FindAreas_r (node->children[0]); + FindAreas_r (node->children[1]); + return; + } + + if (node->area) + return; // allready got it + + if (node->contents & CONTENTS_SOLID) + return; + + if (!node->occupied) + return; // not reachable by entities + + // area portals are allways only flooded into, never + // out of + if (node->contents == CONTENTS_AREAPORTAL) + return; + + c_areas++; + FloodAreas_r (node); +} + +/* +============= +SetAreaPortalAreas_r + +Just decend the tree, and for each node that hasn't had an +area set, flood fill out from there +============= +*/ +void SetAreaPortalAreas_r (node_t *node) +{ + bspbrush_t *b; + entity_t *e; + + if (node->planenum != PLANENUM_LEAF) + { + SetAreaPortalAreas_r (node->children[0]); + SetAreaPortalAreas_r (node->children[1]); + return; + } + + if (node->contents == CONTENTS_AREAPORTAL) + { + if (node->area) + return; // allready set + + b = node->brushlist; + e = &entities[b->original->entitynum]; + node->area = e->portalareas[0]; + if (!e->portalareas[1]) + { + printf ("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum); + return; + } + } +} + +/* +============= +EmitAreaPortals + +============= +*/ +void EmitAreaPortals (node_t *headnode) +{ + int i, j; + entity_t *e; + dareaportal_t *dp; + + if (c_areas > MAX_MAP_AREAS) + Error ("MAX_MAP_AREAS"); + numareas = c_areas+1; + numareaportals = 1; // leave 0 as an error + + for (i=1 ; i<=c_areas ; i++) + { + dareas[i].firstareaportal = numareaportals; + for (j=0 ; jareaportalnum) + continue; + dp = &dareaportals[numareaportals]; + if (e->portalareas[0] == i) + { + dp->portalnum = e->areaportalnum; + dp->otherarea = e->portalareas[1]; + numareaportals++; + } + else if (e->portalareas[1] == i) + { + dp->portalnum = e->areaportalnum; + dp->otherarea = e->portalareas[0]; + numareaportals++; + } + } + dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal; + } + + qprintf ("%5i numareas\n", numareas); + qprintf ("%5i numareaportals\n", numareaportals); +} + +/* +============= +FloodAreas + +Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL +============= +*/ +void FloodAreas (tree_t *tree) +{ + qprintf ("--- FloodAreas ---\n"); + FindAreas_r (tree->headnode); + SetAreaPortalAreas_r (tree->headnode); + qprintf ("%5i areas\n", c_areas); +} + +//====================================================== + +int c_outside; +int c_inside; +int c_solid; + +void FillOutside_r (node_t *node) +{ + if (node->planenum != PLANENUM_LEAF) + { + FillOutside_r (node->children[0]); + FillOutside_r (node->children[1]); + return; + } + + // anything not reachable by an entity + // can be filled away + if (!node->occupied) + { + if (node->contents != CONTENTS_SOLID) + { + c_outside++; + node->contents = CONTENTS_SOLID; + } + else + c_solid++; + } + else + c_inside++; + +} + +/* +============= +FillOutside + +Fill all nodes that can't be reached by entities +============= +*/ +void FillOutside (node_t *headnode) +{ + c_outside = 0; + c_inside = 0; + c_solid = 0; + qprintf ("--- FillOutside ---\n"); + FillOutside_r (headnode); + qprintf ("%5i solid leafs\n", c_solid); + qprintf ("%5i leafs filled\n", c_outside); + qprintf ("%5i inside leafs\n", c_inside); +} + + +//============================================================== + +/* +============ +FindPortalSide + +Finds a brush side to use for texturing the given portal +============ +*/ +void FindPortalSide (portal_t *p) +{ + int viscontents; + bspbrush_t *bb; + mapbrush_t *brush; + node_t *n; + int i,j; + int planenum; + side_t *side, *bestside; + float dot, bestdot; + plane_t *p1, *p2; + + // decide which content change is strongest + // solid > lava > water, etc + viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents); + if (!viscontents) + return; + + planenum = p->onnode->planenum; + bestside = NULL; + bestdot = 0; + + for (j=0 ; j<2 ; j++) + { + n = p->nodes[j]; + p1 = &mapplanes[p->onnode->planenum]; + for (bb=n->brushlist ; bb ; bb=bb->next) + { + brush = bb->original; + if ( !(brush->contents & viscontents) ) + continue; + for (i=0 ; inumsides ; i++) + { + side = &brush->original_sides[i]; + if (side->bevel) + continue; + if (side->texinfo == TEXINFO_NODE) + continue; // non-visible + if ((side->planenum&~1) == planenum) + { // exact match + bestside = &brush->original_sides[i]; + goto gotit; + } + // see how close the match is + p2 = &mapplanes[side->planenum&~1]; + dot = DotProduct (p1->normal, p2->normal); + if (dot > bestdot) + { + bestdot = dot; + bestside = side; + } + } + } + } + +gotit: + if (!bestside) + qprintf ("WARNING: side not found for portal\n"); + + p->sidefound = true; + p->side = bestside; +} + + +/* +=============== +MarkVisibleSides_r + +=============== +*/ +void MarkVisibleSides_r (node_t *node) +{ + portal_t *p; + int s; + + if (node->planenum != PLANENUM_LEAF) + { + MarkVisibleSides_r (node->children[0]); + MarkVisibleSides_r (node->children[1]); + return; + } + + // empty leafs are never boundary leafs + if (!node->contents) + return; + + // see if there is a visible face + for (p=node->portals ; p ; p = p->next[!s]) + { + s = (p->nodes[0] == node); + if (!p->onnode) + continue; // edge of world + if (!p->sidefound) + FindPortalSide (p); + if (p->side) + p->side->visible = true; + } + +} + +/* +============= +MarkVisibleSides + +============= +*/ +void MarkVisibleSides (tree_t *tree, int startbrush, int endbrush) +{ + int i, j; + mapbrush_t *mb; + int numsides; + + qprintf ("--- MarkVisibleSides ---\n"); + + // clear all the visible flags + for (i=startbrush ; inumsides; + for (j=0 ; joriginal_sides[j].visible = false; + } + + // set visible flags on the sides that are used by portals + MarkVisibleSides_r (tree->headnode); +} + diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/prtfile.c b/Toolkit/Programming/Tools/bsp/qbsp3/prtfile.c new file mode 100644 index 0000000..bf54ab4 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/prtfile.c @@ -0,0 +1,266 @@ + +#include "qbsp.h" + +/* +============================================================================== + +PORTAL FILE GENERATION + +Save out name.prt for qvis to read +============================================================================== +*/ + + +#define PORTALFILE "PRT1" + +FILE *pf; +int num_visclusters; // clusters the player can be in +int num_visportals; + +void WriteFloat (FILE *f, vec_t v) +{ + if ( fabs(v - Q_rint(v)) < 0.001 ) + fprintf (f,"%i ",(int)Q_rint(v)); + else + fprintf (f,"%f ",v); +} + +/* +================= +WritePortalFile_r +================= +*/ +void WritePortalFile_r (node_t *node) +{ + int i, s; + portal_t *p; + winding_t *w; + vec3_t normal; + vec_t dist; + + // decision node + if (node->planenum != PLANENUM_LEAF && !node->detail_seperator) + { + WritePortalFile_r (node->children[0]); + WritePortalFile_r (node->children[1]); + return; + } + + if (node->contents & CONTENTS_SOLID) + return; + + for (p = node->portals ; p ; p=p->next[s]) + { + w = p->winding; + s = (p->nodes[1] == node); + if (w && p->nodes[0] == node) + { + if (!Portal_VisFlood (p)) + continue; + // write out to the file + + // sometimes planes get turned around when they are very near + // the changeover point between different axis. interpret the + // plane the same way vis will, and flip the side orders if needed + // FIXME: is this still relevent? + WindingPlane (w, normal, &dist); + if ( DotProduct (p->plane.normal, normal) < 0.99 ) + { // backwards... + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster); + } + else + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster); + for (i=0 ; inumpoints ; i++) + { + fprintf (pf,"("); + WriteFloat (pf, w->p[i][0]); + WriteFloat (pf, w->p[i][1]); + WriteFloat (pf, w->p[i][2]); + fprintf (pf,") "); + } + fprintf (pf,"\n"); + } + } + +} + +/* +================ +FillLeafNumbers_r + +All of the leafs under node will have the same cluster +================ +*/ +void FillLeafNumbers_r (node_t *node, int num) +{ + if (node->planenum == PLANENUM_LEAF) + { + if (node->contents & CONTENTS_SOLID) + node->cluster = -1; + else + node->cluster = num; + return; + } + node->cluster = num; + FillLeafNumbers_r (node->children[0], num); + FillLeafNumbers_r (node->children[1], num); +} + +/* +================ +NumberLeafs_r +================ +*/ +void NumberLeafs_r (node_t *node) +{ + portal_t *p; + + if (node->planenum != PLANENUM_LEAF && !node->detail_seperator) + { // decision node + node->cluster = -99; + NumberLeafs_r (node->children[0]); + NumberLeafs_r (node->children[1]); + return; + } + + // either a leaf or a detail cluster + + if ( node->contents & CONTENTS_SOLID ) + { // solid block, viewpoint never inside + node->cluster = -1; + return; + } + + FillLeafNumbers_r (node, num_visclusters); + num_visclusters++; + + // count the portals + for (p = node->portals ; p ; ) + { + if (p->nodes[0] == node) // only write out from first leaf + { + if (Portal_VisFlood (p)) + num_visportals++; + p = p->next[0]; + } + else + p = p->next[1]; + } + +} + + +/* +================ +CreateVisPortals_r +================ +*/ +void CreateVisPortals_r (node_t *node) +{ + // stop as soon as we get to a detail_seperator, which + // means that everything below is in a single cluster + if (node->planenum == PLANENUM_LEAF || node->detail_seperator ) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + CreateVisPortals_r (node->children[0]); + CreateVisPortals_r (node->children[1]); +} + +/* +================ +FinishVisPortals_r +================ +*/ +void FinishVisPortals2_r (node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + FinishVisPortals2_r (node->children[0]); + FinishVisPortals2_r (node->children[1]); +} + +void FinishVisPortals_r (node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) + return; + + if (node->detail_seperator) + { + FinishVisPortals2_r (node); + return; + } + + FinishVisPortals_r (node->children[0]); + FinishVisPortals_r (node->children[1]); +} + + +int clusterleaf; +void SaveClusters_r (node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) + { + dleafs[clusterleaf++].cluster = node->cluster; + return; + } + SaveClusters_r (node->children[0]); + SaveClusters_r (node->children[1]); +} + +/* +================ +WritePortalFile +================ +*/ +void WritePortalFile (tree_t *tree) +{ + char filename[1024]; + node_t *headnode; + + qprintf ("--- WritePortalFile ---\n"); + + headnode = tree->headnode; + num_visclusters = 0; + num_visportals = 0; + + FreeTreePortals_r (headnode); + + MakeHeadnodePortals (tree); + + CreateVisPortals_r (headnode); + +// set the cluster field in every leaf and count the total number of portals + + NumberLeafs_r (headnode); + +// write the file + sprintf (filename, "%s.prt", source); + printf ("writing %s\n", filename); + pf = fopen (filename, "w"); + if (!pf) + Error ("Error opening %s", filename); + + fprintf (pf, "%s\n", PORTALFILE); + fprintf (pf, "%i\n", num_visclusters); + fprintf (pf, "%i\n", num_visportals); + + qprintf ("%5i visclusters\n", num_visclusters); + qprintf ("%5i visportals\n", num_visportals); + + WritePortalFile_r (headnode); + + fclose (pf); + + // we need to store the clusters out now because ordering + // issues made us do this after writebsp... + clusterleaf = 1; + SaveClusters_r (headnode); +} + diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/qbsp.h b/Toolkit/Programming/Tools/bsp/qbsp3/qbsp.h new file mode 100644 index 0000000..6c72acb --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/qbsp.h @@ -0,0 +1,337 @@ + +#include "cmdlib.h" +#include "mathlib.h" +#include "scriplib.h" +#include "polylib.h" +#include "threads.h" +#include "bspfile.h" + +#define MAX_BRUSH_SIDES 128 +#define CLIP_EPSILON 0.1 + +#define BOGUS_RANGE 8192 + +#define TEXINFO_NODE -1 // side is allready on a node + +typedef struct plane_s +{ + vec3_t normal; + vec_t dist; + int type; + struct plane_s *hash_chain; +} plane_t; + +typedef struct +{ + vec_t shift[2]; + vec_t rotate; + vec_t scale[2]; + char name[32]; + int flags; + int value; +} brush_texture_t; + +typedef struct side_s +{ + int planenum; + int texinfo; + winding_t *winding; + struct side_s *original; // bspbrush_t sides will reference the mapbrush_t sides + int contents; // from miptex + int surf; // from miptex + paletteRGBA_t lighting; // surface lighting + qboolean visible; // choose visble planes first + qboolean tested; // this plane allready checked as a split + qboolean bevel; // don't ever use for bsp splitting +} side_t; + +typedef struct brush_s +{ + int entitynum; + int brushnum; + + int contents; + + vec3_t mins, maxs; + + int numsides; + side_t *original_sides; +} mapbrush_t; + +#define PLANENUM_LEAF -1 + +#define MAXEDGES 20 + +typedef struct face_s +{ + struct face_s *next; // on node + + // the chain of faces off of a node can be merged or split, + // but each face_t along the way will remain in the chain + // until the entire tree is freed + struct face_s *merged; // if set, this face isn't valid anymore + struct face_s *split[2]; // if set, this face isn't valid anymore + + struct portal_s *portal; + int texinfo; + int planenum; + int contents; // faces in different contents can't merge + int outputnumber; + winding_t *w; + int numpoints; + qboolean badstartvert; // tjunctions cannot be fixed without a midpoint vertex + int vertexnums[MAXEDGES]; + paletteRGBA_t lighting; +} face_t; + + + +typedef struct bspbrush_s +{ + struct bspbrush_s *next; + vec3_t mins, maxs; + int side, testside; // side of node during construction + mapbrush_t *original; + int numsides; + side_t sides[6]; // variably sized +} bspbrush_t; + + + +#define MAX_NODE_BRUSHES 8 +typedef struct node_s +{ + // both leafs and nodes + int planenum; // -1 = leaf node + struct node_s *parent; + vec3_t mins, maxs; // valid after portalization + bspbrush_t *volume; // one for each leaf/node + + // nodes only + qboolean detail_seperator; // a detail brush caused the split + side_t *side; // the side that created the node + struct node_s *children[2]; + face_t *faces; + + // leafs only + bspbrush_t *brushlist; // fragments of all brushes in this leaf + int contents; // OR of all brush contents + int occupied; // 1 or greater can reach entity + entity_t *occupant; // for leak file testing + int cluster; // for portalfile writing + int area; // for areaportals + struct portal_s *portals; // also on nodes during construction +} node_t; + +typedef struct portal_s +{ + plane_t plane; + node_t *onnode; // NULL = outside box + node_t *nodes[2]; // [0] = front side of plane + struct portal_s *next[2]; + winding_t *winding; + + qboolean sidefound; // false if ->side hasn't been checked + side_t *side; // NULL = non-visible + face_t *face[2]; // output face in bsp file +} portal_t; + +typedef struct +{ + node_t *headnode; + node_t outside_node; + vec3_t mins, maxs; +} tree_t; + +extern int entity_num; + +extern plane_t mapplanes[MAX_MAP_PLANES]; +extern int nummapplanes; + +extern int nummapbrushes; +extern mapbrush_t mapbrushes[MAX_MAP_BRUSHES]; + +extern vec3_t map_mins, map_maxs; + +#define MAX_MAP_SIDES (MAX_MAP_BRUSHES*6) + +extern int nummapbrushsides; +extern side_t brushsides[MAX_MAP_SIDES]; + +extern qboolean noprune; +extern qboolean nodetail; +extern qboolean fulldetail; +extern qboolean nomerge; +extern qboolean nosubdiv; +extern qboolean nowater; +extern qboolean noweld; +extern qboolean noshare; +extern qboolean notjunc; + +extern vec_t microvolume; + +extern char outbase[32]; + +extern char source[1024]; + +void LoadMapFile (char *filename); +int FindFloatPlane (vec3_t normal, vec_t dist); + +//============================================================================= + +// textures.c + +typedef struct +{ + char name[64]; + int flags; + int value; + int contents; + char animname[64]; +} textureref_t; + +#define MAX_MAP_TEXTURES 1024 + +extern textureref_t textureref[MAX_MAP_TEXTURES]; + +int FindMiptex (char *name); + +int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin); + +//============================================================================= + +void FindGCD (int *v); + +mapbrush_t *Brush_LoadEntity (entity_t *ent); +int PlaneTypeForNormal (vec3_t normal); +qboolean MakeBrushPlanes (mapbrush_t *b); +int FindIntPlane (int *inormal, int *iorigin); +void CreateBrush (int brushnum); + + +//============================================================================= + +// draw.c +#ifdef _USEOPENGL +extern vec3_t draw_mins, draw_maxs; +extern qboolean drawflag; + +void Draw_ClearWindow (void); +void DrawWinding (winding_t *w); + +void GLS_BeginScene (void); +void GLS_Winding (winding_t *w, int code); +void GLS_EndScene (void); +#endif + +//============================================================================= + +// csg + +bspbrush_t *MakeBspBrushList (int startbrush, int endbrush, + vec3_t clipmins, vec3_t clipmaxs); +bspbrush_t *ChopBrushes (bspbrush_t *head); +bspbrush_t *InitialBrushList (bspbrush_t *list); +bspbrush_t *OptimizedBrushList (bspbrush_t *list); + +void WriteBrushMap (char *name, bspbrush_t *list); + +//============================================================================= + +// brushbsp + +void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis); + +bspbrush_t *CopyBrush (bspbrush_t *brush); + +void SplitBrush (bspbrush_t *brush, int planenum, + bspbrush_t **front, bspbrush_t **back); + +tree_t *AllocTree (void); +node_t *AllocNode (void); +bspbrush_t *AllocBrush (int numsides); +int CountBrushList (bspbrush_t *brushes); +void FreeBrush (bspbrush_t *brushes); +vec_t BrushVolume (bspbrush_t *brush); + +void BoundBrush (bspbrush_t *brush); +void FreeBrushList (bspbrush_t *brushes); + +tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs); + +//============================================================================= + +// portals.c + +int VisibleContents (int contents); + +void MakeHeadnodePortals (tree_t *tree); +void MakeNodePortal (node_t *node); +void SplitNodePortals (node_t *node); + +qboolean Portal_VisFlood (portal_t *p); + +qboolean FloodEntities (tree_t *tree); +void FillOutside (node_t *headnode); +void FloodAreas (tree_t *tree); +void MarkVisibleSides (tree_t *tree, int start, int end); +void FreePortal (portal_t *p); +void EmitAreaPortals (node_t *headnode); + +void MakeTreePortals (tree_t *tree); + +//============================================================================= + +// glfile.c + +void OutputWinding (winding_t *w, FILE *glview); +void WriteGLView (tree_t *tree, char *source); + +//============================================================================= + +// leakfile.c + +void LeakFile (tree_t *tree); + +//============================================================================= + +// prtfile.c + +void WritePortalFile (tree_t *tree); + +//============================================================================= + +// writebsp.c + +void SetModelNumbers (void); +void SetLightStyles (void); + +void BeginBSPFile (void); +void WriteBSP (node_t *headnode); +void EndBSPFile (void); +void BeginModel (void); +void EndModel (void); + +//============================================================================= + +// faces.c + +void MakeFaces (node_t *headnode); +void FixTjuncs (node_t *headnode); +int GetEdge2 (int v1, int v2, face_t *f); + +face_t *AllocFace (void); +void FreeFace (face_t *f); + +void MergeNodeFaces (node_t *node); + +//============================================================================= + +// tree.c + +void FreeTree (tree_t *tree); +void FreeTree_r (node_t *node); +void PrintTree_r (node_t *node, int depth); +void FreeTreePortals_r (node_t *node); +void PruneNodes_r (node_t *node); +void PruneNodes (node_t *node); diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/qbsp3.c b/Toolkit/Programming/Tools/bsp/qbsp3/qbsp3.c new file mode 100644 index 0000000..3338a93 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/qbsp3.c @@ -0,0 +1,525 @@ +// csg4.c + +#include "qbsp.h" + +extern float subdivide_size; + +char source[1024]; +char name[1024]; + +vec_t microvolume = 1.0; +qboolean noprune; +qboolean glview; +qboolean nodetail; +qboolean fulldetail; +qboolean onlyents; +qboolean nomerge; +qboolean nowater; +qboolean nofill; +qboolean nocsg; +qboolean noweld; +qboolean noshare; +qboolean nosubdiv; +qboolean notjunc; +qboolean noopt; +qboolean leaktest; +qboolean verboseentities; + +char outbase[32]; + +int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7; + +int entity_num; + + +node_t *block_nodes[10][10]; + +/* +============ +BlockTree + +============ +*/ +node_t *BlockTree (int xl, int yl, int xh, int yh) +{ + node_t *node; + vec3_t normal; + float dist; + int mid; + + if (xl == xh && yl == yh) + { + node = block_nodes[xl+5][yl+5]; + if (!node) + { // return an empty leaf + node = AllocNode (); + node->planenum = PLANENUM_LEAF; + node->contents = 0; //CONTENTS_SOLID; + return node; + } + return node; + } + + // create a seperator along the largest axis + node = AllocNode (); + + if (xh - xl > yh - yl) + { // split x axis + mid = xl + (xh-xl)/2 + 1; + normal[0] = 1; + normal[1] = 0; + normal[2] = 0; + dist = mid*1024; + node->planenum = FindFloatPlane (normal, dist); + node->children[0] = BlockTree ( mid, yl, xh, yh); + node->children[1] = BlockTree ( xl, yl, mid-1, yh); + } + else + { + mid = yl + (yh-yl)/2 + 1; + normal[0] = 0; + normal[1] = 1; + normal[2] = 0; + dist = mid*1024; + node->planenum = FindFloatPlane (normal, dist); + node->children[0] = BlockTree ( xl, mid, xh, yh); + node->children[1] = BlockTree ( xl, yl, xh, mid-1); + } + + return node; +} + +/* +============ +ProcessBlock_Thread + +============ +*/ +int brush_start, brush_end; +void ProcessBlock_Thread (int blocknum) +{ + int xblock, yblock; + vec3_t mins, maxs; + bspbrush_t *brushes; + tree_t *tree; + node_t *node; + + yblock = block_yl + blocknum / (block_xh-block_xl+1); + xblock = block_xl + blocknum % (block_xh-block_xl+1); + + qprintf ("############### block %2i,%2i ###############\n", xblock, yblock); + + mins[0] = xblock*1024; + mins[1] = yblock*1024; + mins[2] = -4096; + maxs[0] = (xblock+1)*1024; + maxs[1] = (yblock+1)*1024; + maxs[2] = 4096; + + // the makelist and chopbrushes could be cached between the passes... + brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs); + if (!brushes) + { + node = AllocNode (); + node->planenum = PLANENUM_LEAF; + node->contents = CONTENTS_SOLID; + block_nodes[xblock+5][yblock+5] = node; + return; + } + + if (!nocsg) + brushes = ChopBrushes (brushes); + + tree = BrushBSP (brushes, mins, maxs); + + block_nodes[xblock+5][yblock+5] = tree->headnode; +} + +/* +============ +ProcessWorldModel + +============ +*/ +void ProcessWorldModel (void) +{ + entity_t *e; + tree_t *tree; + qboolean leaked; + qboolean optimize; + + e = &entities[entity_num]; + + brush_start = e->firstbrush; + brush_end = brush_start + e->numbrushes; + leaked = false; + + // + // perform per-block operations + // + if (block_xh * 1024 > map_maxs[0]) + block_xh = floor(map_maxs[0]/1024.0); + if ( (block_xl+1) * 1024 < map_mins[0]) + block_xl = floor(map_mins[0]/1024.0); + if (block_yh * 1024 > map_maxs[1]) + block_yh = floor(map_maxs[1]/1024.0); + if ( (block_yl+1) * 1024 < map_mins[1]) + block_yl = floor(map_mins[1]/1024.0); + + if (block_xl <-4) + block_xl = -4; + if (block_yl <-4) + block_yl = -4; + if (block_xh > 3) + block_xh = 3; + if (block_yh > 3) + block_yh = 3; + + for (optimize = false ; optimize <= true ; optimize++) + { + qprintf ("--------------------------------------------\n"); + + RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1), + !verbose, ProcessBlock_Thread); + + // + // build the division tree + // oversizing the blocks guarantees that all the boundaries + // will also get nodes. + // + + qprintf ("--------------------------------------------\n"); + + tree = AllocTree (); + tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1); + + tree->mins[0] = (block_xl)*1024; + tree->mins[1] = (block_yl)*1024; + tree->mins[2] = map_mins[2] - 8; + + tree->maxs[0] = (block_xh+1)*1024; + tree->maxs[1] = (block_yh+1)*1024; + tree->maxs[2] = map_maxs[2] + 8; + + // + // perform the global operations + // + MakeTreePortals (tree); + + if (FloodEntities (tree)) + FillOutside (tree->headnode); + else + { + printf ("**** leaked ****\n"); + leaked = true; + LeakFile (tree); + if (leaktest) + { + printf ("--- MAP LEAKED ---\n"); + exit (0); + } + } + + MarkVisibleSides (tree, brush_start, brush_end); + if (noopt || leaked) + break; + if (!optimize) + { + FreeTree (tree); + } + } + + FloodAreas (tree); + if (glview) + WriteGLView (tree, source); + MakeFaces (tree->headnode); + FixTjuncs (tree->headnode); + + if (!noprune) + PruneNodes (tree->headnode); + + WriteBSP (tree->headnode); + + if (!leaked) + WritePortalFile (tree); + + FreeTree (tree); +} + +/* +============ +ProcessSubModel + +============ +*/ +void ProcessSubModel (void) +{ + entity_t *e; + int start, end; + tree_t *tree; + bspbrush_t *list; + vec3_t mins, maxs; + + e = &entities[entity_num]; + + start = e->firstbrush; + end = start + e->numbrushes; + + mins[0] = mins[1] = mins[2] = -4096; + maxs[0] = maxs[1] = maxs[2] = 4096; + list = MakeBspBrushList (start, end, mins, maxs); + if (!nocsg) + list = ChopBrushes (list); + tree = BrushBSP (list, mins, maxs); + MakeTreePortals (tree); + MarkVisibleSides (tree, start, end); + MakeFaces (tree->headnode); + FixTjuncs (tree->headnode); + WriteBSP (tree->headnode); + FreeTree (tree); +} + +/* +============ +ProcessModels +============ +*/ +void ProcessModels (void) +{ + BeginBSPFile (); + + for (entity_num=0 ; entity_num< num_entities ; entity_num++) + { + if (!entities[entity_num].numbrushes) + continue; + + qprintf ("############### model %i ###############\n", nummodels); + BeginModel (); + if (entity_num == 0) + ProcessWorldModel (); + else + ProcessSubModel (); + EndModel (); + + if (!verboseentities) + verbose = false; // don't bother printing submodels + } + + EndBSPFile (); +} + + +/* +============ +main +============ +*/ +int main (int argc, char **argv) +{ + void LoadMessageNames(); + void FreeMessageNames(); + int i; + double start, end; + char path[1024]; + + printf ("---- qbsp3 ----\n"); + + for (i=1 ; i +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=qbsp3 - Win32 Release +!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 "qbsp3.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 "qbsp3.mak" CFG="qbsp3 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qbsp3 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qbsp3 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName ""$/Wolf/Final/Utilities/bsp/qbsp3", YODAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qbsp3 - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Zi /Ox /Ot /Og /Oi /I "..\..\common" /I "..\..\ref_gl" /I "../../qcommon" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_TOOL" /FR /YX /FD /c +# SUBTRACT CPP /Oa /Ow +# 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:console /machine:I386 +# ADD LINK32 winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib advapi32.lib /nologo /subsystem:console /map /debug /machine:I386 + +!ELSEIF "$(CFG)" == "qbsp3 - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /MTd /W3 /Gm /Zi /Od /I "..\..\common" /I "..\..\ref_gl" /I "../../qcommon" /D "_DEBUG" /D "_TOOL" /D "WIN32" /D "_CONSOLE" /FR /YX /FD /c +# 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:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib /nologo /subsystem:console /map /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "qbsp3 - Win32 Release" +# Name "qbsp3 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\brushbsp.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\bspfile.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\cmdlib.c +# End Source File +# Begin Source File + +SOURCE=.\csg.c +# End Source File +# Begin Source File + +SOURCE=.\faces.c +# End Source File +# Begin Source File + +SOURCE=.\glfile.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\l3dslib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\lbmlib.c +# End Source File +# Begin Source File + +SOURCE=.\leakfile.c +# End Source File +# Begin Source File + +SOURCE=.\map.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\mathlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\md4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\polylib.c +# End Source File +# Begin Source File + +SOURCE=.\portals.c +# End Source File +# Begin Source File + +SOURCE=.\prtfile.c +# End Source File +# Begin Source File + +SOURCE=.\qbsp3.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\scriplib.c +# End Source File +# Begin Source File + +SOURCE=.\textures.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\threads.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\token.c +# End Source File +# Begin Source File + +SOURCE=.\tree.c +# End Source File +# Begin Source File + +SOURCE=.\writebsp.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=..\..\common\bspfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\cmdlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\ref_gl\fmodel.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\l3dslib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\lbmlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\mathlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\polylib.h +# End Source File +# Begin Source File + +SOURCE=..\..\qcommon\q_typedef.h +# End Source File +# Begin Source File + +SOURCE=.\qbsp.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\qfiles.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\scriplib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\threads.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\token.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\trilib.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/qbsp3.dsw b/Toolkit/Programming/Tools/bsp/qbsp3/qbsp3.dsw new file mode 100644 index 0000000..b57c1d9 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/qbsp3.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "qbsp3"=.\qbsp3.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/textures.c b/Toolkit/Programming/Tools/bsp/qbsp3/textures.c new file mode 100644 index 0000000..904118c --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/textures.c @@ -0,0 +1,215 @@ + +#include "qbsp.h" + +int nummiptex; +textureref_t textureref[MAX_MAP_TEXTURES]; + +//========================================================================== + + +int FindMiptex (char *name) +{ + int i; + char path[1024]; + miptex_t *mt; + miptex32_t *mt32; + + for (i=0 ; ivalue); + textureref[i].flags = LittleLong (mt32->flags); + textureref[i].contents = LittleLong (mt32->contents); + strcpy (textureref[i].animname, mt32->animname); + free (mt32); + } + else + { + sprintf (path, "%stextures/%s.m8", gamedir, name); + if (TryLoadFile (path, (void **)&mt) != -1) + { + textureref[i].value = LittleLong (mt->value); + textureref[i].flags = LittleLong (mt->flags); + textureref[i].contents = LittleLong (mt->contents); + strcpy (textureref[i].animname, mt->animname); + free (mt); + } + } + + nummiptex++; + + if (textureref[i].animname[0]) + FindMiptex (textureref[i].animname); + + return i; +} + + +/* +================== +textureAxisFromPlane +================== +*/ +vec3_t baseaxis[18] = +{ +{0,0,1}, {1,0,0}, {0,-1,0}, // floor +{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling +{1,0,0}, {0,1,0}, {0,0,-1}, // west wall +{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall +{0,1,0}, {1,0,0}, {0,0,-1}, // south wall +{0,-1,0}, {1,0,0}, {0,0,-1} // north wall +}; + +void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) +{ + int bestaxis; + vec_t dot,best; + int i; + + best = 0; + bestaxis = 0; + + for (i=0 ; i<6 ; i++) + { + dot = DotProduct (pln->normal, baseaxis[i*3]); + if (dot > best) + { + best = dot; + bestaxis = i; + } + } + + VectorCopy (baseaxis[bestaxis*3+1], xv); + VectorCopy (baseaxis[bestaxis*3+2], yv); +} + + + + +int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin) +{ + vec3_t vecs[2]; + int sv, tv; + vec_t ang, sinv, cosv; + vec_t ns, nt; + texinfo_t tx, *tc; + int i, j, k; + float shift[2]; + brush_texture_t anim; + int mt; + + if (!bt->name[0]) + return 0; + + memset (&tx, 0, sizeof(tx)); + strcpy (tx.texture, bt->name); + + TextureAxisFromPlane(plane, vecs[0], vecs[1]); + + shift[0] = DotProduct (origin, vecs[0]); + shift[1] = DotProduct (origin, vecs[1]); + + if (!bt->scale[0]) + bt->scale[0] = 1; + if (!bt->scale[1]) + bt->scale[1] = 1; + + +// rotate axis + if (bt->rotate == 0) + { sinv = 0 ; cosv = 1; } + else if (bt->rotate == 90) + { sinv = 1 ; cosv = 0; } + else if (bt->rotate == 180) + { sinv = 0 ; cosv = -1; } + else if (bt->rotate == 270) + { sinv = -1 ; cosv = 0; } + else + { + ang = bt->rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + } + + if (vecs[0][0]) + sv = 0; + else if (vecs[0][1]) + sv = 1; + else + sv = 2; + + if (vecs[1][0]) + tv = 0; + else if (vecs[1][1]) + tv = 1; + else + tv = 2; + + for (i=0 ; i<2 ; i++) + { + ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; + nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; + vecs[i][sv] = ns; + vecs[i][tv] = nt; + } + + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + tx.vecs[i][j] = vecs[i][j] / bt->scale[i]; + + tx.vecs[0][3] = bt->shift[0] + shift[0]; + tx.vecs[1][3] = bt->shift[1] + shift[1]; + tx.flags = bt->flags; + tx.value = bt->value; + + // + // find the texinfo + // + tc = texinfo; + for (i=0 ; iflags != tx.flags) + continue; + if (tc->value != tx.value) + continue; + for (j=0 ; j<2 ; j++) + { + if (strcmp (tc->texture, tx.texture)) + goto skip; + for (k=0 ; k<4 ; k++) + { + if (tc->vecs[j][k] != tx.vecs[j][k]) + goto skip; + } + } + return i; +skip:; + } + *tc = tx; + numtexinfo++; + + // load the next animation + mt = FindMiptex (bt->name); + if (textureref[mt].animname[0]) + { + anim = *bt; + strcpy (anim.name, textureref[mt].animname); + tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin); + } + else + tc->nexttexinfo = -1; + + + return i; +} diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/tree.c b/Toolkit/Programming/Tools/bsp/qbsp3/tree.c new file mode 100644 index 0000000..3f27350 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/tree.c @@ -0,0 +1,198 @@ +#include "qbsp.h" + +extern int c_nodes; + +void RemovePortalFromNode (portal_t *portal, node_t *l); + +node_t *NodeForPoint (node_t *node, vec3_t origin) +{ + plane_t *plane; + vec_t d; + + while (node->planenum != PLANENUM_LEAF) + { + plane = &mapplanes[node->planenum]; + d = DotProduct (origin, plane->normal) - plane->dist; + if (d >= 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return node; +} + + + +/* +============= +FreeTreePortals_r +============= +*/ +void FreeTreePortals_r (node_t *node) +{ + portal_t *p, *nextp; + int s; + + // free children + if (node->planenum != PLANENUM_LEAF) + { + FreeTreePortals_r (node->children[0]); + FreeTreePortals_r (node->children[1]); + } + + // free portals + for (p=node->portals ; p ; p=nextp) + { + s = (p->nodes[1] == node); + nextp = p->next[s]; + + RemovePortalFromNode (p, p->nodes[!s]); + FreePortal (p); + } + node->portals = NULL; +} + +/* +============= +FreeTree_r +============= +*/ +void FreeTree_r (node_t *node) +{ + face_t *f, *nextf; + + // free children + if (node->planenum != PLANENUM_LEAF) + { + FreeTree_r (node->children[0]); + FreeTree_r (node->children[1]); + } + + // free bspbrushes + FreeBrushList (node->brushlist); + + // free faces + for (f=node->faces ; f ; f=nextf) + { + nextf = f->next; + FreeFace (f); + } + + // free the node + if (node->volume) + FreeBrush (node->volume); + + if (numthreads == 1) + c_nodes--; + free (node); +} + + +/* +============= +FreeTree +============= +*/ +void FreeTree (tree_t *tree) +{ + FreeTreePortals_r (tree->headnode); + FreeTree_r (tree->headnode); + free (tree); +} + +//=============================================================== + +void PrintTree_r (node_t *node, int depth) +{ + int i; + plane_t *plane; + bspbrush_t *bb; + + for (i=0 ; iplanenum == PLANENUM_LEAF) + { + if (!node->brushlist) + printf ("NULL\n"); + else + { + for (bb=node->brushlist ; bb ; bb=bb->next) + printf ("%i ", bb->original->brushnum); + printf ("\n"); + } + return; + } + + plane = &mapplanes[node->planenum]; + printf ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum, + plane->normal[0], plane->normal[1], plane->normal[2], + plane->dist); + PrintTree_r (node->children[0], depth+1); + PrintTree_r (node->children[1], depth+1); +} + +/* +========================================================= + +NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED + +========================================================= +*/ + +int c_pruned; + +/* +============ +PruneNodes_r +============ +*/ +void PruneNodes_r (node_t *node) +{ + bspbrush_t *b, *next; + + if (node->planenum == PLANENUM_LEAF) + return; + PruneNodes_r (node->children[0]); + PruneNodes_r (node->children[1]); + + if ( (node->children[0]->contents & CONTENTS_SOLID) + && (node->children[1]->contents & CONTENTS_SOLID) ) + { + if (node->faces) + Error ("node->faces seperating CONTENTS_SOLID"); + if (node->children[0]->faces || node->children[1]->faces) + Error ("!node->faces with children"); + + // FIXME: free stuff + node->planenum = PLANENUM_LEAF; + node->contents = CONTENTS_SOLID; + node->detail_seperator = false; + + if (node->brushlist) + Error ("PruneNodes: node->brushlist"); + + // combine brush lists + node->brushlist = node->children[1]->brushlist; + + for (b=node->children[0]->brushlist ; b ; b=next) + { + next = b->next; + b->next = node->brushlist; + node->brushlist = b; + } + + c_pruned++; + } +} + + +void PruneNodes (node_t *node) +{ + qprintf ("--- PruneNodes ---\n"); + c_pruned = 0; + PruneNodes_r (node); + qprintf ("%5i pruned nodes\n", c_pruned); +} + +//=========================================================== diff --git a/Toolkit/Programming/Tools/bsp/qbsp3/writebsp.c b/Toolkit/Programming/Tools/bsp/qbsp3/writebsp.c new file mode 100644 index 0000000..603ff62 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qbsp3/writebsp.c @@ -0,0 +1,568 @@ +#include "qbsp.h" + +int c_nofaces; +int c_facenodes; + + +/* +========================================================= + +ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES + +========================================================= +*/ + +int planeused[MAX_MAP_PLANES]; + +/* +============ +EmitPlanes + +There is no oportunity to discard planes, because all of the original +brushes will be saved in the map. +============ +*/ +void EmitPlanes (void) +{ + int i; + dplane_t *dp; + plane_t *mp; + int planetranslate[MAX_MAP_PLANES]; + + mp = mapplanes; + for (i=0 ; inormal, dp->normal); + dp->dist = mp->dist; + dp->type = mp->type; + numplanes++; + } +} + + +//======================================================== + +void EmitMarkFace (dleaf_t *leaf_p, face_t *f) +{ + int i; + int facenum; + + while (f->merged) + f = f->merged; + + if (f->split[0]) + { + EmitMarkFace (leaf_p, f->split[0]); + EmitMarkFace (leaf_p, f->split[1]); + return; + } + + facenum = f->outputnumber; + if (facenum == -1) + return; // degenerate face + + if (facenum < 0 || facenum >= numfaces) + Error ("Bad leafface"); + for (i=leaf_p->firstleafface ; i= MAX_MAP_LEAFFACES) + Error ("MAX_MAP_LEAFFACES"); + + dleaffaces[numleaffaces] = facenum; + numleaffaces++; + } + +} + + +/* +================== +EmitLeaf +================== +*/ +void EmitLeaf (node_t *node) +{ + dleaf_t *leaf_p; + portal_t *p; + int s; + face_t *f; + bspbrush_t *b; + int i; + int brushnum; + + // emit a leaf + if (numleafs >= MAX_MAP_LEAFS) + Error ("MAX_MAP_LEAFS"); + + leaf_p = &dleafs[numleafs]; + numleafs++; + + leaf_p->contents = node->contents; + leaf_p->cluster = node->cluster; + leaf_p->area = node->area; + + // + // write bounding box info + // + VectorCopy (node->mins, leaf_p->mins); + VectorCopy (node->maxs, leaf_p->maxs); + + // + // write the leafbrushes + // + leaf_p->firstleafbrush = numleafbrushes; + for (b=node->brushlist ; b ; b=b->next) + { + if (numleafbrushes >= MAX_MAP_LEAFBRUSHES) + Error ("MAX_MAP_LEAFBRUSHES"); + + brushnum = b->original - mapbrushes; + for (i=leaf_p->firstleafbrush ; inumleafbrushes = numleafbrushes - leaf_p->firstleafbrush; + + // + // write the leaffaces + // + if (leaf_p->contents & CONTENTS_SOLID) + return; // no leaffaces in solids + + leaf_p->firstleafface = numleaffaces; + + for (p = node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + f = p->face[s]; + if (!f) + continue; // not a visible portal + + EmitMarkFace (leaf_p, f); + } + + leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface; +} + + +/* +================== +EmitFace +================== +*/ +void EmitFace (face_t *f) +{ + dface_t *df; + int i; + int e; + + f->outputnumber = -1; + + if (f->numpoints < 3) + { + return; // degenerated + } + if (f->merged || f->split[0] || f->split[1]) + { + return; // not a final face + } + + // save output number so leaffaces can use + f->outputnumber = numfaces; + + if (numfaces >= MAX_MAP_FACES) + Error ("numfaces == MAX_MAP_FACES"); + df = &dfaces[numfaces]; + numfaces++; + + // planenum is used by qlight, but not quake + df->planenum = f->planenum & (~1); + df->side = f->planenum & 1; + + df->firstedge = numsurfedges; + df->numedges = f->numpoints; + df->texinfo = f->texinfo; + df->lighting.c = f->lighting.c; + for (i=0 ; inumpoints ; i++) + { +// e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f); + e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f); + if (numsurfedges >= MAX_MAP_SURFEDGES) + Error ("numsurfedges == MAX_MAP_SURFEDGES"); + dsurfedges[numsurfedges] = e; + numsurfedges++; + } +} + +/* +============ +EmitDrawingNode_r +============ +*/ +int EmitDrawNode_r (node_t *node) +{ + dnode_t *n; + face_t *f; + int i; + + if (node->planenum == PLANENUM_LEAF) + { + EmitLeaf (node); + return -numleafs; + } + + // emit a node + if (numnodes == MAX_MAP_NODES) + Error ("MAX_MAP_NODES"); + n = &dnodes[numnodes]; + numnodes++; + + VectorCopy (node->mins, n->mins); + VectorCopy (node->maxs, n->maxs); + + planeused[node->planenum]++; + planeused[node->planenum^1]++; + + if (node->planenum & 1) + Error ("WriteDrawNodes_r: odd planenum"); + n->planenum = node->planenum; + n->firstface = numfaces; + + if (!node->faces) + c_nofaces++; + else + c_facenodes++; + + for (f=node->faces ; f ; f=f->next) + EmitFace (f); + + n->numfaces = numfaces - n->firstface; + + + // + // recursively output the other nodes + // + for (i=0 ; i<2 ; i++) + { + if (node->children[i]->planenum == PLANENUM_LEAF) + { + n->children[i] = -(numleafs + 1); + EmitLeaf (node->children[i]); + } + else + { + n->children[i] = numnodes; + EmitDrawNode_r (node->children[i]); + } + } + + return n - dnodes; +} + +//========================================================= + + +/* +============ +WriteBSP +============ +*/ +void WriteBSP (node_t *headnode) +{ + int oldfaces; + + c_nofaces = 0; + c_facenodes = 0; + + qprintf ("--- WriteBSP ---\n"); + + oldfaces = numfaces; + dmodels[nummodels].headnode = EmitDrawNode_r (headnode); + EmitAreaPortals (headnode); + + qprintf ("%5i nodes with faces\n", c_facenodes); + qprintf ("%5i nodes without faces\n", c_nofaces); + qprintf ("%5i faces\n", numfaces-oldfaces); +} + +//=========================================================== + +/* +============ +SetModelNumbers +============ +*/ +void SetModelNumbers (void) +{ + int i; + int models; + char value[10]; + + models = 1; + for (i=1 ; icontents = b->contents; + db->firstside = numbrushsides; + db->numsides = b->numsides; + for (j=0 ; jnumsides ; j++) + { + if (numbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + cp = &dbrushsides[numbrushsides]; + numbrushsides++; + cp->planenum = b->original_sides[j].planenum; + cp->texinfo = b->original_sides[j].texinfo; + } + + // add any axis planes not contained in the brush to bevel off corners + for (x=0 ; x<3 ; x++) + for (s=-1 ; s<=1 ; s+=2) + { + // add the plane + VectorCopy (vec3_origin, normal); + normal[x] = s; + if (s == -1) + dist = -b->mins[x]; + else + dist = b->maxs[x]; + planenum = FindFloatPlane (normal, dist); + for (i=0 ; inumsides ; i++) + if (b->original_sides[i].planenum == planenum) + break; + if (i == b->numsides) + { + if (numbrushsides >= MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + + dbrushsides[numbrushsides].planenum = planenum; + dbrushsides[numbrushsides].texinfo = + dbrushsides[numbrushsides-1].texinfo; + numbrushsides++; + db->numsides++; + } + } + + } + +} + +//=========================================================== + +/* +================== +BeginBSPFile +================== +*/ +void BeginBSPFile (void) +{ + // these values may actually be initialized + // if the file existed when loaded, so clear them explicitly + nummodels = 0; + numfaces = 0; + numnodes = 0; + numbrushsides = 0; + numvertexes = 0; + numleaffaces = 0; + numleafbrushes = 0; + numsurfedges = 0; + + // edge 0 is not used, because 0 can't be negated + numedges = 1; + + // leave vertex 0 as an error + numvertexes = 1; + + // leave leaf 0 as an error + numleafs = 1; + dleafs[0].contents = CONTENTS_SOLID; +} + + +/* +============ +EndBSPFile +============ +*/ +void EndBSPFile (void) +{ + char path[1024]; + + + EmitBrushes (); + EmitPlanes (); + UnparseEntities (); + + // load the pop +#if 0 + sprintf (path, "%s/pics/pop.lmp", gamedir); + len = LoadFile (path, &buf); + memcpy (dpop, buf, sizeof(dpop)); + free (buf); +#endif + + // write the map + sprintf (path, "%s.bsp", source); + printf ("Writing %s\n", path); + WriteBSPFile (path); +} + + +/* +================== +BeginModel +================== +*/ +int firstmodleaf; +extern int firstmodeledge; +extern int firstmodelface; +void BeginModel (void) +{ + dmodel_t *mod; + int start, end; + mapbrush_t *b; + int j; + entity_t *e; + vec3_t mins, maxs; + + if (nummodels == MAX_MAP_MODELS) + Error ("MAX_MAP_MODELS"); + mod = &dmodels[nummodels]; + + mod->firstface = numfaces; + + firstmodleaf = numleafs; + firstmodeledge = numedges; + firstmodelface = numfaces; + + // + // bound the brushes + // + e = &entities[entity_num]; + + start = e->firstbrush; + end = start + e->numbrushes; + ClearBounds (mins, maxs); + + for (j=start ; jnumsides) + continue; // not a real brush (origin brush) + AddPointToBounds (b->mins, mins, maxs); + AddPointToBounds (b->maxs, mins, maxs); + } + + VectorCopy (mins, mod->mins); + VectorCopy (maxs, mod->maxs); +} + + +/* +================== +EndModel +================== +*/ +void EndModel (void) +{ + dmodel_t *mod; + + mod = &dmodels[nummodels]; + + mod->numfaces = numfaces - mod->firstface; + + nummodels++; +} + diff --git a/Toolkit/Programming/Tools/bsp/qrad3/lightmap.c b/Toolkit/Programming/Tools/bsp/qrad3/lightmap.c new file mode 100644 index 0000000..6b4df73 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qrad3/lightmap.c @@ -0,0 +1,1359 @@ +#include "qrad.h" + +#define MAX_LSTYLES 256 + +typedef struct +{ + dface_t *faces[2]; + qboolean coplanar; +} edgeshare_t; + +edgeshare_t edgeshare[MAX_MAP_EDGES]; + +int facelinks[MAX_MAP_FACES]; +int planelinks[2][MAX_MAP_PLANES]; + +/* +============ +LinkPlaneFaces +============ +*/ +void LinkPlaneFaces (void) +{ + int i; + dface_t *f; + + f = dfaces; + for (i=0 ; iside][f->planenum]; + planelinks[f->side][f->planenum] = i; + } +} + +/* +============ +PairEdges +============ +*/ +void PairEdges (void) +{ + int i, j, k; + dface_t *f; + edgeshare_t *e; + + f = dfaces; + for (i=0 ; inumedges ; j++) + { + k = dsurfedges[f->firstedge + j]; + if (k < 0) + { + e = &edgeshare[-k]; + e->faces[1] = f; + } + else + { + e = &edgeshare[k]; + e->faces[0] = f; + } + + if (e->faces[0] && e->faces[1]) + { + // determine if coplanar + if (e->faces[0]->planenum == e->faces[1]->planenum) + e->coplanar = true; + } + } + } +} + +/* +================================================================= + + POINT TRIANGULATION + +================================================================= +*/ + +typedef struct triedge_s +{ + int p0, p1; + vec3_t normal; + vec_t dist; + struct triangle_s *tri; +} triedge_t; + +typedef struct triangle_s +{ + triedge_t *edges[3]; +} triangle_t; + +#define MAX_TRI_POINTS 1024 +#define MAX_TRI_EDGES (MAX_TRI_POINTS*6) +#define MAX_TRI_TRIS (MAX_TRI_POINTS*2) + +typedef struct +{ + int numpoints; + int numedges; + int numtris; + dplane_t *plane; + triedge_t *edgematrix[MAX_TRI_POINTS][MAX_TRI_POINTS]; + patch_t *points[MAX_TRI_POINTS]; + triedge_t edges[MAX_TRI_EDGES]; + triangle_t tris[MAX_TRI_TRIS]; +} triangulation_t; + +/* +=============== +AllocTriangulation +=============== +*/ +triangulation_t *AllocTriangulation (dplane_t *plane) +{ + triangulation_t *t; + + t = malloc(sizeof(triangulation_t)); + if (t == NULL) + Error("AllocTriangulation MALLOC failed! Could not allocate %s bytes.", sizeof(triangulation_t)); + + t->numpoints = 0; + t->numedges = 0; + t->numtris = 0; + + t->plane = plane; + +// memset (t->edgematrix, 0, sizeof(t->edgematrix)); + + return t; +} + +/* +=============== +FreeTriangulation +=============== +*/ +void FreeTriangulation (triangulation_t *tr) +{ + free (tr); +} + + +triedge_t *FindEdge (triangulation_t *trian, int p0, int p1) +{ + triedge_t *e, *be; + vec3_t v1; + vec3_t normal; + vec_t dist; + + if (trian->edgematrix[p0][p1]) + return trian->edgematrix[p0][p1]; + + if (trian->numedges > MAX_TRI_EDGES-2) + Error ("trian->numedges > MAX_TRI_EDGES-2"); + + VectorSubtract (trian->points[p1]->origin, trian->points[p0]->origin, v1); + VectorNormalize (v1, v1); + CrossProduct (v1, trian->plane->normal, normal); + dist = DotProduct (trian->points[p0]->origin, normal); + + e = &trian->edges[trian->numedges]; + e->p0 = p0; + e->p1 = p1; + e->tri = NULL; + VectorCopy (normal, e->normal); + e->dist = dist; + trian->numedges++; + trian->edgematrix[p0][p1] = e; + + be = &trian->edges[trian->numedges]; + be->p0 = p1; + be->p1 = p0; + be->tri = NULL; + VectorSubtract (vec3_origin, normal, be->normal); + be->dist = -dist; + trian->numedges++; + trian->edgematrix[p1][p0] = be; + + return e; +} + +triangle_t *AllocTriangle (triangulation_t *trian) +{ + triangle_t *t; + + if (trian->numtris >= MAX_TRI_TRIS) + Error ("trian->numtris >= MAX_TRI_TRIS"); + + t = &trian->tris[trian->numtris]; + trian->numtris++; + + return t; +} + +/* +============ +TriEdge_r +============ +*/ +void TriEdge_r (triangulation_t *trian, triedge_t *e) +{ + int i, bestp; + vec3_t v1, v2; + vec_t *p0, *p1, *p; + vec_t best, ang; + triangle_t *nt; + + if (e->tri) + return; // allready connected by someone + + // find the point with the best angle + p0 = trian->points[e->p0]->origin; + p1 = trian->points[e->p1]->origin; + best = 1.1; + for (i=0 ; i< trian->numpoints ; i++) + { + p = trian->points[i]->origin; + // a 0 dist will form a degenerate triangle + if (DotProduct(p, e->normal) - e->dist < 0) + continue; // behind edge + VectorSubtract (p0, p, v1); + VectorSubtract (p1, p, v2); + if (!VectorNormalize (v1,v1)) + continue; + if (!VectorNormalize (v2,v2)) + continue; + ang = DotProduct (v1, v2); + if (ang < best) + { + best = ang; + bestp = i; + } + } + if (best >= 1) + return; // edge doesn't match anything + + // make a new triangle + nt = AllocTriangle (trian); + nt->edges[0] = e; + nt->edges[1] = FindEdge (trian, e->p1, bestp); + nt->edges[2] = FindEdge (trian, bestp, e->p0); + for (i=0 ; i<3 ; i++) + nt->edges[i]->tri = nt; + TriEdge_r (trian, FindEdge (trian, bestp, e->p1)); + TriEdge_r (trian, FindEdge (trian, e->p0, bestp)); +} + +/* +============ +TriangulatePoints +============ +*/ +void TriangulatePoints (triangulation_t *trian) +{ + vec_t d, bestd; + vec3_t v1; + int bp1, bp2, i, j; + vec_t *p1, *p2; + triedge_t *e, *e2; + + if (trian->numpoints < 2) + return; + + // find the two closest points + bestd = 9999; + for (i=0 ; inumpoints ; i++) + { + p1 = trian->points[i]->origin; + for (j=i+1 ; jnumpoints ; j++) + { + p2 = trian->points[j]->origin; + VectorSubtract (p2, p1, v1); + d = VectorLength (v1); + if (d < bestd) + { + bestd = d; + bp1 = i; + bp2 = j; + } + } + } + + e = FindEdge (trian, bp1, bp2); + e2 = FindEdge (trian, bp2, bp1); + TriEdge_r (trian, e); + TriEdge_r (trian, e2); +} + +/* +=============== +AddPointToTriangulation +=============== +*/ +void AddPointToTriangulation (patch_t *patch, triangulation_t *trian) +{ + int pnum; + + pnum = trian->numpoints; + if (pnum == MAX_TRI_POINTS) + Error ("trian->numpoints == MAX_TRI_POINTS"); + trian->points[pnum] = patch; + trian->numpoints++; +} + +/* +=============== +LerpTriangle +=============== +*/ +void LerpTriangle (triangulation_t *trian, triangle_t *t, vec3_t point, vec3_t color) +{ + patch_t *p1, *p2, *p3; + vec3_t base, d1, d2; + float x, y, x1, y1, x2, y2; + + p1 = trian->points[t->edges[0]->p0]; + p2 = trian->points[t->edges[1]->p0]; + p3 = trian->points[t->edges[2]->p0]; + + VectorCopy (p1->totallight, base); + VectorSubtract (p2->totallight, base, d1); + VectorSubtract (p3->totallight, base, d2); + + x = DotProduct (point, t->edges[0]->normal) - t->edges[0]->dist; + y = DotProduct (point, t->edges[2]->normal) - t->edges[2]->dist; + + x1 = 0; + y1 = DotProduct (p2->origin, t->edges[2]->normal) - t->edges[2]->dist; + + x2 = DotProduct (p3->origin, t->edges[0]->normal) - t->edges[0]->dist; + y2 = 0; + + if (fabs(y1)edges[i]; + d = DotProduct (e->normal, point) - e->dist; + if (d < 0) + return false; // not inside + } + + return true; +} + +/* +=============== +SampleTriangulation +=============== +*/ +void SampleTriangulation (vec3_t point, triangulation_t *trian, vec3_t color) +{ + triangle_t *t; + triedge_t *e; + vec_t d, best; + patch_t *p0, *p1; + vec3_t v1, v2; + int i, j; + + if (trian->numpoints == 0) + { + VectorClear (color); + return; + } + if (trian->numpoints == 1) + { + VectorCopy (trian->points[0]->totallight, color); + return; + } + + // search for triangles + for (t = trian->tris, j=0 ; j < trian->numtris ; t++, j++) + { + if (!PointInTriangle (point, t)) + continue; + + // this is it + LerpTriangle (trian, t, point, color); + return; + } + + // search for exterior edge + for (e=trian->edges, j=0 ; j< trian->numedges ; e++, j++) + { + if (e->tri) + continue; // not an exterior edge + + d = DotProduct (point, e->normal) - e->dist; + if (d < 0) + continue; // not in front of edge + + p0 = trian->points[e->p0]; + p1 = trian->points[e->p1]; + + VectorSubtract (p1->origin, p0->origin, v1); + VectorNormalize (v1, v1); + VectorSubtract (point, p0->origin, v2); + d = DotProduct (v2, v1); + if (d < 0) + continue; + if (d > 1) + continue; + for (i=0 ; i<3 ; i++) + color[i] = p0->totallight[i] + d * (p1->totallight[i] - p0->totallight[i]); + return; + } + + // search for nearest point + best = 99999; + p1 = NULL; + for (j=0 ; jnumpoints ; j++) + { + p0 = trian->points[j]; + VectorSubtract (point, p0->origin, v1); + d = VectorLength (v1); + if (d < best) + { + best = d; + p1 = p0; + } + } + + if (!p1) + Error ("SampleTriangulation: no points"); + + VectorCopy (p1->totallight, color); +} + +/* +================================================================= + + LIGHTMAP SAMPLE GENERATION + +================================================================= +*/ + + +#define SINGLEMAP (64*64*4) + +typedef struct +{ + vec_t facedist; + vec3_t facenormal; + + int numsurfpt; + vec3_t surfpt[SINGLEMAP]; + + vec3_t modelorg; // for origined bmodels + + vec3_t texorg; + vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0] + vec3_t textoworld[2]; // world = texorg + s * textoworld[0] + + vec_t exactmins[2], exactmaxs[2]; + + int texmins[2], texsize[2]; + int surfnum; + dface_t *face; +} lightinfo_t; + + +/* +================ +CalcFaceExtents + +Fills in s->texmins[] and s->texsize[] +also sets exactmins[] and exactmaxs[] +================ +*/ +void CalcFaceExtents (lightinfo_t *l) +{ + dface_t *s; + vec_t mins[2], maxs[2], val; + int i,j, e; + dvertex_t *v; + texinfo_t *tex; + vec3_t vt; + + s = l->face; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = &texinfo[s->texinfo]; + + for (i=0 ; inumedges ; i++) + { + e = dsurfedges[s->firstedge+i]; + if (e >= 0) + v = dvertexes + dedges[e].v[0]; + else + v = dvertexes + dedges[-e].v[1]; + +// VectorAdd (v->point, l->modelorg, vt); + VectorCopy (v->point, vt); + + for (j=0 ; j<2 ; j++) + { + val = DotProduct (vt, tex->vecs[j]) + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + l->exactmins[i] = mins[i]; + l->exactmaxs[i] = maxs[i]; + + mins[i] = floor(mins[i]/16); + maxs[i] = ceil(maxs[i]/16); + + l->texmins[i] = mins[i]; + l->texsize[i] = maxs[i] - mins[i]; + if (l->texsize[0] * l->texsize[1] > SINGLEMAP/4) // div 4 for extrasamples + Error ("Surface to large to map"); + } +} + +/* +================ +CalcFaceVectors + +Fills in texorg, worldtotex. and textoworld +================ +*/ +void CalcFaceVectors (lightinfo_t *l) +{ + texinfo_t *tex; + int i, j; + vec3_t texnormal; + vec_t distscale; + vec_t dist, len; + int w, h; + + tex = &texinfo[l->face->texinfo]; + +// convert from float to double + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + l->worldtotex[i][j] = tex->vecs[i][j]; + +// calculate a normal to the texture axis. points can be moved along this +// without changing their S/T + texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2] + - tex->vecs[1][2]*tex->vecs[0][1]; + texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0] + - tex->vecs[1][0]*tex->vecs[0][2]; + texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1] + - tex->vecs[1][1]*tex->vecs[0][0]; + VectorNormalize (texnormal, texnormal); + +// flip it towards plane normal + distscale = DotProduct (texnormal, l->facenormal); + if (!distscale) + { + qprintf ("WARNING: Texture axis perpendicular to face\n"); + distscale = 1; + } + if (distscale < 0) + { + distscale = -distscale; + VectorSubtract (vec3_origin, texnormal, texnormal); + } + +// distscale is the ratio of the distance along the texture normal to +// the distance along the plane normal + distscale = 1/distscale; + + for (i=0 ; i<2 ; i++) + { + len = VectorLength (l->worldtotex[i]); + dist = DotProduct (l->worldtotex[i], l->facenormal); + dist *= distscale; + VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]); + VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]); + } + + +// calculate texorg on the texture plane + for (i=0 ; i<3 ; i++) + l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i]; + +// project back to the face plane + dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1; + dist *= distscale; + VectorMA (l->texorg, -dist, texnormal, l->texorg); + + // compensate for org'd bmodels + VectorAdd (l->texorg, l->modelorg, l->texorg); + + // total sample count + h = l->texsize[1]+1; + w = l->texsize[0]+1; + l->numsurfpt = w * h; +} + +/* +================= +CalcPoints + +For each texture aligned grid point, back project onto the plane +to get the world xyz value of the sample point +================= +*/ +void CalcPoints (lightinfo_t *l, float sofs, float tofs) +{ + int i; + int s, t, j; + int w, h, step; + vec_t starts, startt, us, ut; + vec_t *surf; + vec_t mids, midt; + vec3_t facemid; + dleaf_t *leaf; + + surf = l->surfpt[0]; + mids = (l->exactmaxs[0] + l->exactmins[0])/2; + midt = (l->exactmaxs[1] + l->exactmins[1])/2; + + for (j=0 ; j<3 ; j++) + facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt; + + h = l->texsize[1]+1; + w = l->texsize[0]+1; + l->numsurfpt = w * h; + + starts = l->texmins[0]*16; + startt = l->texmins[1]*16; + step = 16; + + + for (t=0 ; ttexorg[j] + l->textoworld[0][j]*us + + l->textoworld[1][j]*ut; + + leaf = PointInLeaf (surf); + if (leaf->contents != CONTENTS_SOLID) + { + if (!TestLine_r (0, facemid, surf)) + break; // got it + } + + // nudge it + if (i & 1) + { + if (us > mids) + { + us -= 8; + if (us < mids) + us = mids; + } + else + { + us += 8; + if (us > mids) + us = mids; + } + } + else + { + if (ut > midt) + { + ut -= 8; + if (ut < midt) + ut = midt; + } + else + { + ut += 8; + if (ut > midt) + ut = midt; + } + } + } + } + } + +} + + +//============================================================== + + + +#define MAX_STYLES 32 +typedef struct +{ + int numsamples; + float *origins; + int numstyles; + int stylenums[MAX_STYLES]; + float *samples[MAX_STYLES]; +} facelight_t; + +directlight_t *directlights[MAX_MAP_LEAFS]; +facelight_t facelight[MAX_MAP_FACES]; +int numdlights; + +/* +================== +FindTargetEntity +================== +*/ +entity_t *FindTargetEntity (char *target) +{ + int i; + char *n; + + for (i=0 ; itotallight[0] < DIRECT_LIGHT + && p->totallight[1] < DIRECT_LIGHT + && p->totallight[2] < DIRECT_LIGHT) + continue; + + numdlights++; + dl = malloc(sizeof(directlight_t)); + if (dl == NULL) + Error("CreateDirectLights (surfaces) MALLOC failed! Could not allocate %s bytes.", sizeof(directlight_t)); + + memset (dl, 0, sizeof(*dl)); + + VectorCopy (p->origin, dl->origin); + + leaf = PointInLeaf (dl->origin); + cluster = leaf->cluster; + dl->next = directlights[cluster]; + directlights[cluster] = dl; + + dl->type = emit_surface; + VectorCopy (p->plane->normal, dl->normal); + + dl->intensity = ColorNormalize (p->totallight, dl->color); + dl->intensity *= p->area * direct_scale; + VectorClear (p->totallight); // all sent now + } + + // + // entities + // + for (i=0 ; iorigin); + dl->style = FloatForKey (e, "_style"); + if (!dl->style) + dl->style = FloatForKey (e, "style"); + if (dl->style < 0 || dl->style >= MAX_LSTYLES) + dl->style = 0; + + leaf = PointInLeaf (dl->origin); + cluster = leaf->cluster; + + dl->next = directlights[cluster]; + directlights[cluster] = dl; + + intensity = FloatForKey (e, "light"); + if (!intensity) + intensity = FloatForKey (e, "_light"); + if (!intensity) + intensity = 300; + _color = ValueForKey (e, "_color"); + if (_color[1]) + { + sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]); + ColorNormalize (dl->color, dl->color); + } + else + dl->color[0] = dl->color[1] = dl->color[2] = 1.0; + dl->intensity = intensity*entity_scale; + dl->type = emit_point; + + target = ValueForKey (e, "target"); + + if (!strcmp (name, "light_spot") || target[0]) + { + dl->type = emit_spotlight; + dl->stopdot = FloatForKey (e, "_cone"); + if (!dl->stopdot) + dl->stopdot = 10; + dl->stopdot = cos(dl->stopdot/180*3.14159); + if (target[0]) + { // point towards target + e2 = FindTargetEntity (target); + if (!e2) + printf ("WARNING: light at (%i %i %i) has missing target\n", + (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]); + else + { + GetVectorForKey (e2, "origin", dest); + VectorSubtract (dest, dl->origin, dl->normal); + VectorNormalize (dl->normal, dl->normal); + } + } + else + { // point down angle + angle = FloatForKey (e, "angle"); + if (angle == ANGLE_UP) + { + dl->normal[0] = dl->normal[1] = 0; + dl->normal[2] = 1; + } + else if (angle == ANGLE_DOWN) + { + dl->normal[0] = dl->normal[1] = 0; + dl->normal[2] = -1; + } + else + { + dl->normal[2] = 0; + dl->normal[0] = cos (angle/180*3.14159); + dl->normal[1] = sin (angle/180*3.14159); + } + } + } + } + + qprintf ("%i direct lights\n", numdlights); +} + +/* +============= +GatherSampleLight + +Lightscale is the normalizer for multisampling +============= +*/ +void GatherSampleLight (vec3_t pos, vec3_t normal, + float **styletable, int offset, int mapsize, float lightscale) +{ + int i; + directlight_t *l; + byte pvs[(MAX_MAP_LEAFS+7)/8]; + vec3_t delta; + float dot, dot2; + float dist; + float scale; + float *dest; + + // get the PVS for the pos to limit the number of checks + if (!PvsForOrigin (pos, pvs)) + { + return; + } + + for (i = 0 ; inumclusters ; i++) + { + if ( ! (pvs[ i>>3] & (1<<(i&7))) ) + continue; + + for (l=directlights[i] ; l ; l=l->next) + { + VectorSubtract (l->origin, pos, delta); + dist = VectorNormalize (delta, delta); + + dot = DotProduct (delta, normal); + if (dot <= 0.001) + continue; // behind sample surface + + switch (l->type) + { + case emit_point: + // linear falloff + scale = (l->intensity - dist) * dot; + break; + + case emit_surface: + dot2 = -DotProduct (delta, l->normal); + if (dot2 <= 0.001) + goto skipadd; // behind light surface + scale = (l->intensity / (dist*dist) ) * dot * dot2; + break; + + case emit_spotlight: + // linear falloff + dot2 = -DotProduct (delta, l->normal); + if (dot2 <= l->stopdot) + goto skipadd; // outside light cone + scale = (l->intensity - dist) * dot; + break; + default: + Error ("Bad l->type"); + } + + if (TestLine_r (0, pos, l->origin)) + continue; // occluded + + if (scale <= 0) + continue; + + // if this style doesn't have a table yet, allocate one + if (!styletable[l->style]) + { + styletable[l->style] = malloc (mapsize); + if (styletable[l->style] == NULL) + Error("GatherSampleLight MALLOC failed! Could not allocate %s bytes.", mapsize); + + memset (styletable[l->style], 0, mapsize); + } + + dest = styletable[l->style] + offset; + // add some light to it + VectorMA (dest, scale*lightscale, l->color, dest); + +skipadd: ; + } + } + +} + +/* +============= +AddSampleToPatch + +Take the sample's collected light and +add it back into the apropriate patch +for the radiosity pass. + +The sample is added to all patches that might include +any part of it. They are counted and averaged, so it +doesn't generate extra light. +============= +*/ +void AddSampleToPatch (vec3_t pos, vec3_t color, int facenum) +{ + patch_t *patch; + vec3_t mins, maxs; + int i; + + if (numbounce == 0) + return; + if (color[0] + color[1] + color[2] < 3) + return; + + for (patch = face_patches[facenum] ; patch ; patch=patch->next) + { + // see if the point is in this patch (roughly) + WindingBounds (patch->winding, mins, maxs); + for (i=0 ; i<3 ; i++) + { + if (mins[i] > pos[i] + 16) + goto nextpatch; + if (maxs[i] < pos[i] - 16) + goto nextpatch; + } + + // add the sample to the patch + patch->samples++; + VectorAdd (patch->samplelight, color, patch->samplelight); +nextpatch:; + } + +} + + +/* +============= +BuildFacelights +============= +*/ +float sampleofs[5][2] = +{ {0,0}, {-0.25, -0.25}, {0.25, -0.25}, {0.25, 0.25}, {-0.25, 0.25} }; + + +void BuildFacelights (int facenum) +{ + dface_t *f; + lightinfo_t l[5]; + float *styletable[MAX_LSTYLES]; + int i, j; + float *spot; + patch_t *patch; + int numsamples; + int tablesize; + facelight_t *fl; + int numPatches = 0;; + + f = &dfaces[facenum]; + + if( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) ) + { + return; // non-lit texture + } + + if((texinfo[f->texinfo].flags & SURF_TALL_WALL) && (f->lighting.r|f->lighting.g|f->lighting.b)) + { + return; + } + + memset (styletable,0, sizeof(styletable)); + + if (extrasamples) + numsamples = 5; + else + numsamples = 1; + for (i=0 ; iplanenum].normal, l[i].facenormal); + l[i].facedist = dplanes[f->planenum].dist; + if (f->side) + { + VectorSubtract (vec3_origin, l[i].facenormal, l[i].facenormal); + l[i].facedist = -l[i].facedist; + } + + // get the origin offset for rotating bmodels + VectorCopy (face_offset[facenum], l[i].modelorg); + + CalcFaceVectors (&l[i]); + CalcFaceExtents (&l[i]); + CalcPoints (&l[i], sampleofs[i][0], sampleofs[i][1]); + } + + tablesize = l[0].numsurfpt * sizeof(vec3_t); + styletable[0] = malloc(tablesize); + if (styletable[0] == NULL) + Error("BuildFaceLights (styletable) MALLOC failed! Could not allocate %s bytes.", tablesize); + + memset (styletable[0], 0, tablesize); + + fl = &facelight[facenum]; + fl->numsamples = l[0].numsurfpt; + fl->origins = malloc (tablesize); + if (fl->origins == NULL) + Error("BuildFaceLights (origins) MALLOC failed! Could not allocate %s bytes.", sizeof(tablesize)); + + memcpy (fl->origins, l[0].surfpt, tablesize); + + for (i=0 ; inext) + { + if (patch->samples) + { + VectorScale (patch->samplelight, 1.0/patch->samples, patch->samplelight); + + ++numPatches; + } + else + { +// printf ("patch with no samples\n"); + } + } + + if(texinfo[f->texinfo].flags & SURF_TALL_WALL) + { + f->lighting.r = 0; + f->lighting.g = 0; + f->lighting.b = 0; + + for (patch = face_patches[facenum] ; patch ; patch=patch->next) + { + if (patch->samples) + { + f->lighting.r += patch->samplelight[0]/numPatches; + f->lighting.g += patch->samplelight[1]/numPatches; + f->lighting.b += patch->samplelight[2]/numPatches; + } + else + { + // printf ("patch with no samples\n"); + } + } + + for (i=0 ; iorigins); + + fl->origins = NULL; + fl->numsamples = 0; + + return; + } + + for (i=0 ; inumstyles == MAX_STYLES) + break; + fl->samples[fl->numstyles] = styletable[i]; + fl->stylenums[fl->numstyles] = i; + fl->numstyles++; + } + + // the light from DIRECT_LIGHTS is sent out, but the + // texture itself should still be full bright + + if (face_patches[facenum]->baselight[0] >= DIRECT_LIGHT || + face_patches[facenum]->baselight[1] >= DIRECT_LIGHT || + face_patches[facenum]->baselight[2] >= DIRECT_LIGHT + ) + { + spot = fl->samples[0]; + for (i=0 ; ibaselight, spot); + } + } +} + + +/* +============= +FinalLightFace + +Add the indirect lighting on top of the direct +lighting and save into final map format +============= +*/ +void FinalLightFace (int facenum) +{ + dface_t *f; + int i, j, k, st; + vec3_t lb; + patch_t *patch; + triangulation_t *trian; + facelight_t *fl; + float minlight; + float max, newmax; + byte *dest; + int pfacenum; + vec3_t facemins, facemaxs; + + f = &dfaces[facenum]; + fl = &facelight[facenum]; + + if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY|SURF_TALL_WALL) ) + return; // non-lit texture + + ThreadLock (); + f->lightofs = lightdatasize; + lightdatasize += fl->numstyles*(fl->numsamples*3); + +// add green sentinals between lightmaps +#if 0 +lightdatasize += 64*3; +for (i=0 ; i<64 ; i++) +dlightdata[lightdatasize-(i+1)*3 + 1] = 255; +#endif + + if (lightdatasize > MAX_MAP_LIGHTING) + Error ("MAX_MAP_LIGHTING"); + ThreadUnlock (); + + f->styles[0] = 0; + f->styles[1] = f->styles[2] = f->styles[3] = 0xff; + + // + // set up the triangulation + // + if (numbounce > 0) + { + ClearBounds (facemins, facemaxs); + for (i=0 ; inumedges ; i++) + { + int ednum; + + ednum = dsurfedges[f->firstedge+i]; + if (ednum >= 0) + AddPointToBounds (dvertexes[dedges[ednum].v[0]].point, + facemins, facemaxs); + else + AddPointToBounds (dvertexes[dedges[-ednum].v[1]].point, + facemins, facemaxs); + } + + trian = AllocTriangulation (&dplanes[f->planenum]); + + // for all faces on the plane, add the nearby patches + // to the triangulation + for (pfacenum = planelinks[f->side][f->planenum] + ; pfacenum ; pfacenum = facelinks[pfacenum]) + { + for (patch = face_patches[pfacenum] ; patch ; patch=patch->next) + { + for (i=0 ; i < 3 ; i++) + { + if (facemins[i] - patch->origin[i] > subdiv*2) + break; + if (patch->origin[i] - facemaxs[i] > subdiv*2) + break; + } + if (i != 3) + continue; // not needed for this face + AddPointToTriangulation (patch, trian); + } + } + for (i=0 ; inumpoints ; i++) + memset (trian->edgematrix[i], 0, trian->numpoints*sizeof(trian->edgematrix[0][0]) ); + TriangulatePoints (trian); + } + + // + // sample the triangulation + // + + // _minlight allows models that have faces that would not be + // illuminated to receive a mottled light pattern instead of + // black + minlight = FloatForKey (face_entity[facenum], "_minlight") * 128; + + dest = &dlightdata[f->lightofs]; + + if (fl->numstyles > MAXLIGHTMAPS) + { + fl->numstyles = MAXLIGHTMAPS; + printf ("face with too many lightstyles: (%f %f %f)\n", + face_patches[facenum]->origin[0], + face_patches[facenum]->origin[1], + face_patches[facenum]->origin[2] + ); + } + + for (st=0 ; stnumstyles ; st++) + { + f->styles[st] = fl->stylenums[st]; + for (j=0 ; jnumsamples ; j++) + { + VectorCopy ( (fl->samples[st]+j*3), lb); + if (numbounce > 0 && st == 0) + { + vec3_t add; + + SampleTriangulation (fl->origins + j*3, trian, add); + VectorAdd (lb, add, lb); + } + // add an ambient term if desired + lb[0] += ambient; + lb[1] += ambient; + lb[2] += ambient; + + VectorScale (lb, lightscale, lb); + + // we need to clamp without allowing hue to change + for (k=0 ; k<3 ; k++) + if (lb[k] < 1) + lb[k] = 1; + max = lb[0]; + if (lb[1] > max) + max = lb[1]; + if (lb[2] > max) + max = lb[2]; + newmax = max; + if (newmax < 0) + newmax = 0; // roundoff problems + if (newmax < minlight) + { + newmax = minlight + (rand()%48); + } + if (newmax > maxlight) + newmax = maxlight; + + for (k=0 ; k<3 ; k++) + { + *dest++ = lb[k]*newmax/max; + } + } + } + + if (numbounce > 0) + FreeTriangulation (trian); +} diff --git a/Toolkit/Programming/Tools/bsp/qrad3/patches.c b/Toolkit/Programming/Tools/bsp/qrad3/patches.c new file mode 100644 index 0000000..1c29ed6 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qrad3/patches.c @@ -0,0 +1,532 @@ + +#include "qrad.h" + +vec3_t texture_reflectivity[MAX_MAP_TEXINFO]; + +/* +=================================================================== + + TEXTURE LIGHT VALUES + +=================================================================== +*/ + +/* +====================== +CalcTextureReflectivity +====================== +*/ +void CalcTextureReflectivity (void) +{ + int i; + int j, texels; + int color[3]; + int texel; + char path[1024]; + float r; +// float scale; + miptex_t *mt; + miptex32_t *mt32; + byte *pos; + + //sprintf (path, "%spics/colormap.pcx", gamedir); + + // get the game palette +// Load256Image (path, NULL, &palette, NULL, NULL); + + // allways set index 0 even if no textures + texture_reflectivity[0][0] = 0.5; + texture_reflectivity[0][1] = 0.5; + texture_reflectivity[0][2] = 0.5; + + for (i=0 ; iwidth[0])*LittleLong(mt->height[0]); + color[0] = color[1] = color[2] = 0; + + for (j=0 ; joffsets[0]) + j]; + color[0] += mt->palette[texel].r; + color[1] += mt->palette[texel].g; + color[2] += mt->palette[texel].b; + } + + free(mt); + } + else + { + texels = LittleLong(mt32->width[0])*LittleLong(mt32->height[0]); + color[0] = color[1] = color[2] = 0; + + for (j=0 ; joffsets[0] + (j<<2); + color[0] += *pos++; // r + color[1] += *pos++; // g + color[2] += *pos++; // b + } + + free(mt32); + } + + + for (j=0 ; j<3 ; j++) + { + r = color[j]/((float) texels*255.0); + texture_reflectivity[i][j] = r; + } + + // scale the reflectivity up, because the textures are + // so dim +// scale = ColorNormalize (texture_reflectivity[i], +// texture_reflectivity[i]); + +// VectorScale (texture_reflectivity[i], 0.001, texture_reflectivity[i]); + +/* if (scale < 0.5) + { + scale *= 2; + VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]); + }*/ +#if 0 +texture_reflectivity[i][0] = 0.1; +texture_reflectivity[i][1] = 0.1; +texture_reflectivity[i][2] = 0.1; +#endif + } +} + +/* +======================================================================= + +MAKE FACES + +======================================================================= +*/ + +/* +============= +WindingFromFace +============= +*/ +winding_t *WindingFromFace (dface_t *f) +{ + int i; + int se; + dvertex_t *dv; + int v; + winding_t *w; + + w = AllocWinding (f->numedges); + w->numpoints = f->numedges; + + for (i=0 ; inumedges ; i++) + { + se = dsurfedges[f->firstedge + i]; + if (se < 0) + v = dedges[-se].v[1]; + else + v = dedges[se].v[0]; + + dv = &dvertexes[v]; + VectorCopy (dv->point, w->p[i]); + } + + RemoveColinearPoints (w); + + return w; +} + +/* +============= +BaseLightForFace +============= +*/ +void BaseLightForFace (dface_t *f, vec3_t color) +{ + texinfo_t *tx; + + // + // check for light emited by texture + // + tx = &texinfo[f->texinfo]; + if (!(tx->flags & SURF_LIGHT) || tx->value == 0) + { + VectorClear (color); + return; + } + + VectorScale (texture_reflectivity[f->texinfo], tx->value, color); +} + +qboolean IsSky (dface_t *f) +{ + texinfo_t *tx; + + tx = &texinfo[f->texinfo]; + if (tx->flags & SURF_SKY) + return true; + return false; +} + +/* +============= +MakePatchForFace +============= +*/ +float totalarea; +void MakePatchForFace (int fn, winding_t *w) +{ + dface_t *f; + float area; + patch_t *patch; + dplane_t *pl; + int i; + vec3_t color; + dleaf_t *leaf; + + f = &dfaces[fn]; + + area = WindingArea (w); + totalarea += area; + + patch = &patches[num_patches]; + if (num_patches == MAX_PATCHES) + Error ("num_patches == MAX_PATCHES"); + patch->next = face_patches[fn]; + face_patches[fn] = patch; + + patch->winding = w; + + if (f->side) + patch->plane = &backplanes[f->planenum]; + else + patch->plane = &dplanes[f->planenum]; + if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] ) + { // origin offset faces must create new planes + if (numplanes + fakeplanes >= MAX_MAP_PLANES) + Error ("numplanes + fakeplanes >= MAX_MAP_PLANES"); + pl = &dplanes[numplanes + fakeplanes]; + fakeplanes++; + + *pl = *(patch->plane); + pl->dist += DotProduct (face_offset[fn], pl->normal); + patch->plane = pl; + } + + WindingCenter (w, patch->origin); + VectorAdd (patch->origin, patch->plane->normal, patch->origin); + leaf = PointInLeaf(patch->origin); + patch->cluster = leaf->cluster; + if (patch->cluster == -1) + qprintf ("patch->cluster == -1\n"); + + patch->area = area; + if (patch->area <= 1) + patch->area = 1; + patch->sky = IsSky (f); + + VectorCopy (texture_reflectivity[f->texinfo], patch->reflectivity); + + // non-bmodel patches can emit light + if (fn < dmodels[0].numfaces) + { + BaseLightForFace (f, patch->baselight); + +#if 1 + ColorNormalize (patch->reflectivity, color); + + for (i=0 ; i<3 ; i++) + patch->baselight[i] *= color[i]; + +#else + for (i=0 ; i<3 ; i++) + { + patch->baselight[i] *= patch->reflectivity[i]; + } +#endif + + VectorCopy (patch->baselight, patch->totallight); + } + num_patches++; +} + + +entity_t *EntityForModel (int modnum) +{ + int i; + char *s; + char name[16]; + + sprintf (name, "*%i", modnum); + // search the entities for one using modnum + for (i=0 ; inumfaces ; j++) + { + fn = mod->firstface + j; + face_entity[fn] = ent; + VectorCopy (origin, face_offset[fn]); + f = &dfaces[fn]; + w = WindingFromFace (f); + for (k=0 ; knumpoints ; k++) + { + VectorAdd (w->p[k], origin, w->p[k]); + } + MakePatchForFace (fn, w); + } + } + + qprintf ("%i sqaure feet\n", (int)(totalarea/64)); +} + +/* +======================================================================= + +SUBDIVIDE + +======================================================================= +*/ + +void FinishSplit (patch_t *patch, patch_t *newp) +{ + dleaf_t *leaf; + + VectorCopy (patch->baselight, newp->baselight); + VectorCopy (patch->totallight, newp->totallight); + VectorCopy (patch->reflectivity, newp->reflectivity); + newp->plane = patch->plane; + newp->sky = patch->sky; + + patch->area = WindingArea (patch->winding); + newp->area = WindingArea (newp->winding); + + if (patch->area <= 1) + patch->area = 1; + if (newp->area <= 1) + newp->area = 1; + + WindingCenter (patch->winding, patch->origin); + VectorAdd (patch->origin, patch->plane->normal, patch->origin); + leaf = PointInLeaf(patch->origin); + patch->cluster = leaf->cluster; + if (patch->cluster == -1) + qprintf ("patch->cluster == -1\n"); + + WindingCenter (newp->winding, newp->origin); + VectorAdd (newp->origin, newp->plane->normal, newp->origin); + leaf = PointInLeaf(newp->origin); + newp->cluster = leaf->cluster; + if (newp->cluster == -1) + qprintf ("patch->cluster == -1\n"); +} + +/* +============= +SubdividePatch + +Chops the patch only if its local bounds exceed the max size +============= +*/ +void SubdividePatch (patch_t *patch) +{ + winding_t *w, *o1, *o2; + vec3_t mins, maxs, total; + vec3_t split; + vec_t dist; + int i, j; + vec_t v; + patch_t *newp; + + w = patch->winding; + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + { + v = w->p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } + VectorSubtract (maxs, mins, total); + for (i=0 ; i<3 ; i++) + if (total[i] > (subdiv+1) ) + break; + if (i == 3) + { + // no splitting needed + return; + } + + // + // split the winding + // + VectorCopy (vec3_origin, split); + split[i] = 1; + dist = (mins[i] + maxs[i])*0.5; + ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); + + // + // create a new patch + // + if (num_patches == MAX_PATCHES) + Error ("MAX_PATCHES"); + newp = &patches[num_patches]; + num_patches++; + + newp->next = patch->next; + patch->next = newp; + + patch->winding = o1; + newp->winding = o2; + + FinishSplit (patch, newp); + + SubdividePatch (patch); + SubdividePatch (newp); +} + + +/* +============= +DicePatch + +Chops the patch by a global grid +============= +*/ +void DicePatch (patch_t *patch) +{ + winding_t *w, *o1, *o2; + vec3_t mins, maxs; + vec3_t split; + vec_t dist; + int i; + patch_t *newp; + + w = patch->winding; + WindingBounds (w, mins, maxs); + for (i=0 ; i<3 ; i++) + if (floor((mins[i]+1)/subdiv) < floor((maxs[i]-1)/subdiv)) + break; + if (i == 3) + { + // no splitting needed + return; + } + + // + // split the winding + // + VectorCopy (vec3_origin, split); + split[i] = 1; + dist = subdiv*(1+floor((mins[i]+1)/subdiv)); + ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); + + // + // create a new patch + // + if (num_patches == MAX_PATCHES) + Error ("MAX_PATCHES"); + newp = &patches[num_patches]; + num_patches++; + + newp->next = patch->next; + patch->next = newp; + + patch->winding = o1; + newp->winding = o2; + + FinishSplit (patch, newp); + + DicePatch (patch); + DicePatch (newp); +} + + +/* +============= +SubdividePatches +============= +*/ +void SubdividePatches (void) +{ + int i, num; + + if (subdiv < 1) + return; + + num = num_patches; // because the list will grow + for (i=0 ; i +#endif + +typedef enum +{ + emit_surface, + emit_point, + emit_spotlight +} emittype_t; + + + +typedef struct directlight_s +{ + struct directlight_s *next; + emittype_t type; + + float intensity; + int style; + vec3_t origin; + vec3_t color; + vec3_t normal; // for surfaces and spotlights + float stopdot; // for spotlights +} directlight_t; + + +// the sum of all tranfer->transfer values for a given patch +// should equal exactly 0x10000, showing that all radiance +// reaches other patches +typedef struct +{ + unsigned short patch; + unsigned short transfer; +} transfer_t; + + +#define MAX_PATCHES 65000 // larger will cause 32 bit overflows + +typedef struct patch_s +{ + winding_t *winding; + struct patch_s *next; // next in face + int numtransfers; + transfer_t *transfers; + + int cluster; // for pvs checking + vec3_t origin; + dplane_t *plane; + + qboolean sky; + + vec3_t totallight; // accumulated by radiosity + // does NOT include light + // accounted for by direct lighting + float area; + + // illuminance * reflectivity = radiosity + vec3_t reflectivity; + vec3_t baselight; // emissivity only + + // each style 0 lightmap sample in the patch will be + // added up to get the average illuminance of the entire patch + vec3_t samplelight; + int samples; // for averaging direct light +} patch_t; + +extern patch_t *face_patches[MAX_MAP_FACES]; +extern entity_t *face_entity[MAX_MAP_FACES]; +extern vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels +extern patch_t patches[MAX_PATCHES]; +extern unsigned num_patches; + +extern int leafparents[MAX_MAP_LEAFS]; +extern int nodeparents[MAX_MAP_NODES]; + +extern float lightscale; + + +void MakeShadowSplits (void); + +//============================================== + + +void BuildVisMatrix (void); +qboolean CheckVisBit (unsigned p1, unsigned p2); + +//============================================== + +extern float ambient, maxlight; + +void LinkPlaneFaces (void); + +extern qboolean extrasamples; +extern int numbounce; + +extern directlight_t *directlights[MAX_MAP_LEAFS]; + +extern byte nodehit[MAX_MAP_NODES]; + +void BuildLightmaps (void); + +void BuildFacelights (int facenum); + +void FinalLightFace (int facenum); + +qboolean PvsForOrigin (vec3_t org, byte *pvs); + +int TestLine_r (int node, vec3_t start, vec3_t stop); + +void CreateDirectLights (void); + +dleaf_t *PointInLeaf (vec3_t point); + + +extern dplane_t backplanes[MAX_MAP_PLANES]; +extern int fakeplanes; // created planes for origin offset + +extern float subdiv; + +extern float direct_scale; +extern float entity_scale; + +int PointInLeafnum (vec3_t point); +void MakeTnodes (dmodel_t *bm); +void FreeTnodes (); +void MakePatches (void); +void SubdividePatches (void); +void PairEdges (void); +void CalcTextureReflectivity (void); diff --git a/Toolkit/Programming/Tools/bsp/qrad3/qrad3.c b/Toolkit/Programming/Tools/bsp/qrad3/qrad3.c new file mode 100644 index 0000000..d5a0373 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qrad3/qrad3.c @@ -0,0 +1,716 @@ +// qrad.c + +#include "qrad.h" +#include + + + +/* + +NOTES +----- + +every surface must be divided into at least two patches each axis + +*/ + +patch_t *face_patches[MAX_MAP_FACES]; +entity_t *face_entity[MAX_MAP_FACES]; +patch_t patches[MAX_PATCHES]; +unsigned num_patches; + +vec3_t radiosity[MAX_PATCHES]; // light leaving a patch +vec3_t illumination[MAX_PATCHES]; // light arriving at a patch + +vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels +dplane_t backplanes[MAX_MAP_PLANES]; + +char inbase[32], outbase[32]; + +int fakeplanes; // created planes for origin offset + +int numbounce = 8; +qboolean extrasamples=false; + +float subdiv = 64; +qboolean dumppatches=false; + +void BuildLightmaps (void); +int TestLine (vec3_t start, vec3_t stop); + +int junk; + +float ambient = 0; +float maxlight = 196; + +float lightscale = 1.0; + +qboolean glview; + +qboolean nopvs; + +char source[1024]; + +float direct_scale = 0.4; +float entity_scale = 1.0; + +/* +=================================================================== + +MISC + +=================================================================== +*/ + + +/* +============= +MakeBackplanes +============= +*/ +void MakeBackplanes (void) +{ + int i; + + for (i=0 ; ichildren[i]; + if (j < 0) + leafparents[-j - 1] = nodenum; + else + MakeParents (j, nodenum); + } +} + + +/* +=================================================================== + +TRANSFER SCALES + +=================================================================== +*/ + +int PointInLeafnum (vec3_t point) +{ + int nodenum; + vec_t dist; + dnode_t *node; + dplane_t *plane; + + nodenum = 0; + while (nodenum >= 0) + { + node = &dnodes[nodenum]; + plane = &dplanes[node->planenum]; + dist = DotProduct (point, plane->normal) - plane->dist; + if (dist > 0) + nodenum = node->children[0]; + else + nodenum = node->children[1]; + } + + return -nodenum - 1; +} + + +dleaf_t *PointInLeaf (vec3_t point) +{ + int num; + + num = PointInLeafnum (point); + return &dleafs[num]; +} + + +qboolean PvsForOrigin (vec3_t org, byte *pvs) +{ + dleaf_t *leaf; + + if (!visdatasize) + { + memset (pvs, 255, (numleafs+7)/8 ); + return true; + } + + leaf = PointInLeaf (org); + if (leaf->cluster == -1) + return false; // in solid leaf + + DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs); + return true; +} + + +/* +============= +MakeTransfers + +============= +*/ +int total_transfer; + +void MakeTransfers (int i) +{ + int j; + vec3_t delta; + vec_t dist, scale; + float trans; + int itrans; + patch_t *patch, *patch2; + float total; + dplane_t plane; + vec3_t origin; + float transfers[MAX_PATCHES], *all_transfers; + int s; + int itotal; + byte pvs[(MAX_MAP_LEAFS+7)/8]; + int cluster; + + patch = patches + i; + total = 0; + + VectorCopy (patch->origin, origin); + plane = *patch->plane; + + if (!PvsForOrigin (patch->origin, pvs)) + return; + + // find out which patch2s will collect light + // from patch + + all_transfers = transfers; + patch->numtransfers = 0; + for (j=0, patch2 = patches ; jcluster; + if (cluster == -1) + continue; + if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) ) + continue; // not in pvs + } + + // calculate vector + VectorSubtract (patch2->origin, origin, delta); + dist = VectorNormalize (delta, delta); + if (!dist) + continue; // should never happen + + // reletive angles + scale = DotProduct (delta, plane.normal); + scale *= -DotProduct (delta, patch2->plane->normal); + if (scale <= 0) + continue; + + // check exact transfer + if (TestLine_r (0, patch->origin, patch2->origin) ) + continue; + + trans = scale * patch2->area / (dist*dist); + + if (trans < 0) + trans = 0; // rounding errors... + + transfers[j] = trans; + if (trans > 0) + { + total += trans; + patch->numtransfers++; + } + } + + // copy the transfers out and normalize + // total should be somewhere near PI if everything went right + // because partial occlusion isn't accounted for, and nearby + // patches have underestimated form factors, it will usually + // be higher than PI + if (patch->numtransfers) + { + transfer_t *t; + + if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES) + Error ("Weird numtransfers"); + s = patch->numtransfers * sizeof(transfer_t); + patch->transfers = malloc (s); + if (patch->transfers == NULL) + Error("MakeTransfers MALLOC failed! Could not allocate %s bytes.", s); + + // + // normalize all transfers so all of the light + // is transfered to the surroundings + // + t = patch->transfers; + itotal = 0; + for (j=0 ; jtransfer = itrans; + t->patch = j; + t++; + } + } + + // don't bother locking around this. not that important. + total_transfer += patch->numtransfers; +} + + +/* +============= +FreeTransfers +============= +*/ +void FreeTransfers (void) +{ + int i; + + for (i=0 ; iwinding; + fprintf (out, "%i\n", w->numpoints); + for (i=0 ; inumpoints ; i++) + { + fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n", + w->p[i][0], + w->p[i][1], + w->p[i][2], + patch->totallight[0], + patch->totallight[1], + patch->totallight[2]); + } + fprintf (out, "\n"); + } + + fclose (out); +} + +/* +============= +WriteGlView +============= +*/ +void WriteGlView (void) +{ + char name[1024]; + FILE *f; + int i, j; + patch_t *p; + winding_t *w; + + strcpy (name, source); + StripExtension (name); + strcat (name, ".glr"); + + f = fopen (name, "w"); + if (!f) + Error ("Couldn't open %s", f); + + for (j=0 ; jwinding; + fprintf (f, "%i\n", w->numpoints); + for (i=0 ; inumpoints ; i++) + { + fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n", + w->p[i][0], + w->p[i][1], + w->p[i][2], + p->totallight[0]/128, + p->totallight[1]/128, + p->totallight[2]/128); + } + fprintf (f, "\n"); + } + + fclose (f); +} + + +//============================================================== + +/* +============= +CollectLight +============= +*/ +float CollectLight (void) +{ + int i, j; + patch_t *patch; + vec_t total; + + total = 0; + + for (i=0, patch=patches ; isky) + { + VectorClear (radiosity[i]); + VectorClear (illumination[i]); + continue; + } + + for (j=0 ; j<3 ; j++) + { + patch->totallight[j] += illumination[i][j] / patch->area; + radiosity[i][j] = illumination[i][j] * patch->reflectivity[j]; + } + + total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2]; + VectorClear (illumination[i]); + } + + return total; +} + + +/* +============= +ShootLight + +Send light out to other patches + Run multi-threaded +============= +*/ +void ShootLight (int patchnum) +{ + int k, l; + transfer_t *trans; + int num; + patch_t *patch; + vec3_t send; + + // this is the amount of light we are distributing + // prescale it so that multiplying by the 16 bit + // transfer values gives a proper output value + for (k=0 ; k<3 ; k++) + send[k] = radiosity[patchnum][k] / 0x10000; + patch = &patches[patchnum]; + + trans = patch->transfers; + num = patch->numtransfers; + + for (k=0 ; kpatch][l] += send[l]*trans->transfer; + } +} + +/* +============= +BounceLight +============= +*/ +void BounceLight (void) +{ + int i, j; + float added; + char name[64]; + patch_t *p; + + printf ("bouncing light on %i patches\n", num_patches); + for (i=0 ; itotallight[j] = p->samplelight[j]; + radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area; + + } + +#if 0 + if(radiosity[i][0] || radiosity[i][1] || radiosity[i][2]) + { + int b; + + b = 0; + } +#endif + } + + for (i=0 ; itotallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0) + Error ("negative patch totallight\n"); + } +} + +/* +============= +RadWorld +============= +*/ +void RadWorld (void) +{ + if (numnodes == 0 || numfaces == 0) + Error ("Empty map"); + MakeBackplanes (); + MakeParents (0, -1); + MakeTnodes (&dmodels[0]); + + // turn each face into a single patch + MakePatches (); + + // subdivide patches to a maximum dimension + SubdividePatches (); + + // create directlights out of patches and lights + CreateDirectLights (); + + // build initial facelights + RunThreadsOnIndividual (numfaces, true, BuildFacelights); + + if (numbounce > 0) + { + // build transfer lists + RunThreadsOnIndividual (num_patches, true, MakeTransfers); + qprintf ("transfer lists: %5.1f megs\n" + , (float)total_transfer * sizeof(transfer_t) / (1024*1024)); + + FreeTnodes (); + + // spread light around + BounceLight (); + + FreeTransfers (); + + CheckPatches (); + } + + if (glview) + WriteGlView (); + + // blend bounced light into direct light and save + PairEdges (); + LinkPlaneFaces (); + + lightdatasize = 0; + RunThreadsOnIndividual (numfaces, true, FinalLightFace); +} + + +/* +======== +main + +light modelfile +======== +*/ +int main (int argc, char **argv) +{ + int i; + double start, end; + char name[1024]; + + printf ("----- Radiosity Version 1.02 ----\n"); + + verbose = false; + + for (i=1 ; i 255) + maxlight = 255; + + if (i != argc - 1) + Error ("usage: qrad [-v] [-chop num(64)] [-scale num(1)] [-direct num(1)] [-entity num(1)] [-ambient num(0)] [-maxlight num(1.5)] [-threads num] [-bounce num(8)] [-extra] [-dump] bspfile"); + + start = I_FloatTime (); + + SetQdirFromPath (argv[i]); + strcpy (source, ExpandArg(argv[i])); + StripExtension (source); + DefaultExtension (source, ".bsp"); + +// ReadLightFile (); + + sprintf (name, "%s%s", inbase, source); + printf ("reading %s\n", name); + LoadBSPFile (name); + ParseEntities (); + CalcTextureReflectivity (); + + if (!visdatasize) + { + printf ("No vis information, direct lighting only.\n"); + numbounce = 0; + ambient = 0.1; + } + + RadWorld (); + + sprintf (name, "%s%s", outbase, source); + printf ("writing %s\n", name); + WriteBSPFile (name); + + end = I_FloatTime (); + printf ("%5.0f seconds elapsed\n", end-start); + +#ifdef _DEBUG + getch(); +#endif + + return 0; +} + + \ No newline at end of file diff --git a/Toolkit/Programming/Tools/bsp/qrad3/qrad3.dsp b/Toolkit/Programming/Tools/bsp/qrad3/qrad3.dsp new file mode 100644 index 0000000..82092df --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qrad3/qrad3.dsp @@ -0,0 +1,209 @@ +# Microsoft Developer Studio Project File - Name="qrad3" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=qrad3 - Win32 Release +!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 "qrad3.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 "qrad3.mak" CFG="qrad3 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qrad3 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qrad3 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName ""$/Wolf/Final/Utilities/bsp/qrad3", ZODAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qrad3 - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Zi /O2 /I "..\..\common" /I "..\..\ref_gl" /I "../../qcommon" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_TOOL" /FR /YX /FD /c +# 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:console /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 /nologo /subsystem:console /map /debug /machine:I386 + +!ELSEIF "$(CFG)" == "qrad3 - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /G6 /MTd /W3 /Gm /Gi /Zi /Od /I "..\..\common" /I "..\..\ref_gl" /I "../../qcommon" /D "_DEBUG" /D "_TOOL" /D "WIN32" /D "_CONSOLE" /Fr /YX /FD /c +# 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:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib 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:console /map /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "qrad3 - Win32 Release" +# Name "qrad3 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\..\common\bspfile.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\cmdlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\l3dslib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\lbmlib.c +# End Source File +# Begin Source File + +SOURCE=.\lightmap.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\mathlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\md4.c +# End Source File +# Begin Source File + +SOURCE=.\patches.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\polylib.c +# End Source File +# Begin Source File + +SOURCE=.\qrad.h +# End Source File +# Begin Source File + +SOURCE=.\qrad3.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\scriplib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\threads.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\token.c +# End Source File +# Begin Source File + +SOURCE=.\trace.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=..\..\common\bspfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\cmdlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\ref_gl\fmodel.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\l3dslib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\lbmlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\mathlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\polylib.h +# End Source File +# Begin Source File + +SOURCE=..\..\qcommon\q_typedef.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\qfiles.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\scriplib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\threads.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\token.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\trilib.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Toolkit/Programming/Tools/bsp/qrad3/trace.c b/Toolkit/Programming/Tools/bsp/qrad3/trace.c new file mode 100644 index 0000000..85beaeb --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qrad3/trace.c @@ -0,0 +1,288 @@ +// trace.c + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" + +#define ON_EPSILON 0.1 + +typedef struct tnode_s +{ + int type; + vec3_t normal; + float dist; + int children[2]; + int pad; +} tnode_t; + +void *malloctnodes; +tnode_t *tnodes, *tnode_p; + +/* +============== +MakeTnode + +Converts the disk node structure into the efficient tracing structure +============== +*/ +void MakeTnode (int nodenum) +{ + tnode_t *t; + dplane_t *plane; + int i; + dnode_t *node; + + t = tnode_p++; + + node = dnodes + nodenum; + plane = dplanes + node->planenum; + + t->type = plane->type; + VectorCopy (plane->normal, t->normal); + t->dist = plane->dist; + + for (i=0 ; i<2 ; i++) + { + if (node->children[i] < 0) + t->children[i] = (dleafs[-node->children[i] - 1].contents & CONTENTS_SOLID) | (1<<31); + else + { + t->children[i] = tnode_p - tnodes; + MakeTnode (node->children[i]); + } + } + +} + + +/* +============= +MakeTnodes + +Loads the node structure out of a .bsp file to be used for light occlusion +============= +*/ +void MakeTnodes (dmodel_t *bm) +{ + // 32 byte align the structs + malloctnodes = tnodes = malloc( (numnodes+1) * sizeof(tnode_t)); + if (tnodes == NULL) + Error("MakeTnodes MALLOC failed! Could not allocate %s bytes.", (numnodes+1)*sizeof(tnode_t)); + + tnodes = (tnode_t *)(((int)tnodes + 31)&~31); + tnode_p = tnodes; + + MakeTnode (0); +} + +void FreeTnodes () +{ + if (malloctnodes == NULL) + Error("FreeTnodes after free.\n"); + free(malloctnodes); + malloctnodes = tnodes = NULL; + +} + + +//========================================================== + + +int TestLine_r (int node, vec3_t start, vec3_t stop) +{ + tnode_t *tnode; + float front, back; + vec3_t mid; + float frac; + int side; + int r; + + if (node & (1<<31)) + return node & ~(1<<31); // leaf node + + tnode = &tnodes[node]; + switch (tnode->type) + { + case PLANE_X: + front = start[0] - tnode->dist; + back = stop[0] - tnode->dist; + break; + case PLANE_Y: + front = start[1] - tnode->dist; + back = stop[1] - tnode->dist; + break; + case PLANE_Z: + front = start[2] - tnode->dist; + back = stop[2] - tnode->dist; + break; + default: + front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist; + back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist; + break; + } + + if (front >= -ON_EPSILON && back >= -ON_EPSILON) + return TestLine_r (tnode->children[0], start, stop); + + if (front < ON_EPSILON && back < ON_EPSILON) + return TestLine_r (tnode->children[1], start, stop); + + side = front < 0; + + frac = front / (front-back); + + mid[0] = start[0] + (stop[0] - start[0])*frac; + mid[1] = start[1] + (stop[1] - start[1])*frac; + mid[2] = start[2] + (stop[2] - start[2])*frac; + + r = TestLine_r (tnode->children[side], start, mid); + if (r) + return r; + return TestLine_r (tnode->children[!side], mid, stop); +} + +int TestLine (vec3_t start, vec3_t stop) +{ + return TestLine_r (0, start, stop); +} + +/* +============================================================================== + +LINE TRACING + +The major lighting operation is a point to point visibility test, performed +by recursive subdivision of the line by the BSP tree. + +============================================================================== +*/ + +typedef struct +{ + vec3_t backpt; + int side; + int node; +} tracestack_t; + + +/* +============== +TestLine +============== +*/ +qboolean _TestLine (vec3_t start, vec3_t stop) +{ + int node; + float front, back; + tracestack_t *tstack_p; + int side; + float frontx,fronty, frontz, backx, backy, backz; + tracestack_t tracestack[64]; + tnode_t *tnode; + + frontx = start[0]; + fronty = start[1]; + frontz = start[2]; + backx = stop[0]; + backy = stop[1]; + backz = stop[2]; + + tstack_p = tracestack; + node = 0; + + while (1) + { + if (node == CONTENTS_SOLID) + { +#if 0 + float d1, d2, d3; + + d1 = backx - frontx; + d2 = backy - fronty; + d3 = backz - frontz; + + if (d1*d1 + d2*d2 + d3*d3 > 1) +#endif + return false; // DONE! + } + + while (node < 0) + { + // pop up the stack for a back side + tstack_p--; + if (tstack_p < tracestack) + return true; + node = tstack_p->node; + + // set the hit point for this plane + + frontx = backx; + fronty = backy; + frontz = backz; + + // go down the back side + + backx = tstack_p->backpt[0]; + backy = tstack_p->backpt[1]; + backz = tstack_p->backpt[2]; + + node = tnodes[tstack_p->node].children[!tstack_p->side]; + } + + tnode = &tnodes[node]; + + switch (tnode->type) + { + case PLANE_X: + front = frontx - tnode->dist; + back = backx - tnode->dist; + break; + case PLANE_Y: + front = fronty - tnode->dist; + back = backy - tnode->dist; + break; + case PLANE_Z: + front = frontz - tnode->dist; + back = backz - tnode->dist; + break; + default: + front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist; + back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist; + break; + } + + if (front > -ON_EPSILON && back > -ON_EPSILON) +// if (front > 0 && back > 0) + { + node = tnode->children[0]; + continue; + } + + if (front < ON_EPSILON && back < ON_EPSILON) +// if (front <= 0 && back <= 0) + { + node = tnode->children[1]; + continue; + } + + side = front < 0; + + front = front / (front-back); + + tstack_p->node = node; + tstack_p->side = side; + tstack_p->backpt[0] = backx; + tstack_p->backpt[1] = backy; + tstack_p->backpt[2] = backz; + + tstack_p++; + + backx = frontx + front*(backx-frontx); + backy = fronty + front*(backy-fronty); + backz = frontz + front*(backz-frontz); + + node = tnode->children[side]; + } +} + + diff --git a/Toolkit/Programming/Tools/bsp/qvis3/flow.c b/Toolkit/Programming/Tools/bsp/qvis3/flow.c new file mode 100644 index 0000000..5b8c3c6 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qvis3/flow.c @@ -0,0 +1,913 @@ +#include "vis.h" + +/* + + each portal will have a list of all possible to see from first portal + + if (!thread->portalmightsee[portalnum]) + + portal mightsee + + for p2 = all other portals in leaf + get sperating planes + for all portals that might be seen by p2 + mark as unseen if not present in seperating plane + flood fill a new mightsee + save as passagemightsee + + + void CalcMightSee (leaf_t *leaf, +*/ +#define BIG_EPSILON 50 //unormalized dists have big values + +int CountBits (byte *bits, int numbits) +{ + int i; + int c; + + c = 0; + for (i=0 ; i>3] & (1<<(i&7)) ) + c++; + + return c; +} + +int c_fullskip; +int c_portalskip, c_leafskip; +int c_vistest, c_mighttest; + +int c_chop, c_nochop; + +int active; + +void CheckStack (leaf_t *leaf, threaddata_t *thread) +{ + pstack_t *p, *p2; + + for (p=thread->pstack_head.next ; p ; p=p->next) + { +// printf ("="); + if (p->leaf == leaf) + Error ("CheckStack: leaf recursion"); + for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next) + if (p2->leaf == p->leaf) + Error ("CheckStack: late leaf recursion"); + } +// printf ("\n"); +} + + +winding_t *AllocStackWinding (pstack_t *stack) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (stack->freewindings[i]) + { + stack->freewindings[i] = 0; + return &stack->windings[i]; + } + } + + Error ("AllocStackWinding: failed"); + + return NULL; +} + +void FreeStackWinding (winding_t *w, pstack_t *stack) +{ + int i; + + i = w - stack->windings; + + if (i<0 || i>2) + return; // not from local + + if (stack->freewindings[i]) + Error ("FreeStackWinding: allready free"); + stack->freewindings[i] = 1; +} + +/* +============== +ChopWinding + +============== +*/ +winding_t *ChopWinding (winding_t *in, pstack_t *stack, plane_t *split) +{ + vec_t dists[128]; + int sides[128]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *neww; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; +#ifdef DONORMAL + if (dot > ON_EPSILON) +#else + if (dot > BIG_EPSILON) +#endif + sides[i] = SIDE_FRONT; +#ifdef DONORMAL + else if (dot < -ON_EPSILON) +#else + else if (dot < -BIG_EPSILON) +#endif + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + + if (!counts[1]) + return in; // completely on front side + + if (!counts[0]) + { + FreeStackWinding (in, stack); + return NULL; + } + + sides[i] = sides[0]; + dists[i] = dists[0]; + + neww = AllocStackWinding (stack); + + neww->numpoints = 0; + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) + { + FreeStackWinding (neww, stack); + return in; // can't chop -- fall back to original + } + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) + { + FreeStackWinding (neww, stack); + return in; // can't chop -- fall back to original + } + + // generate a split point + if (i == (in->numpoints-1)) + p2 = in->points[0]; + else + p2 = in->points[i+1]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible +#ifdef DONORMAL + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else +#endif + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + +// free the original winding + FreeStackWinding (in, stack); + + return neww; +} + + + +float ComputeBoundingSphere(winding_t *source,vec3_t c) +{ + int i; + float r,tr; + vec3_t dif; + c[0]=0; + c[1]=0; + c[2]=0; + for (i=0 ; inumpoints ; i++) + { + c[0]+=source->points[i][0]; + c[1]+=source->points[i][1]; + c[2]+=source->points[i][2]; + } + r=1/(float)source->numpoints; + c[0]*=r; + c[1]*=r; + c[2]*=r; + r=0; + for (i=0 ; inumpoints ; i++) + { + VectorSubtract(source->points[i],c,dif); + tr=dif[0]*dif[0]+dif[1]*dif[1]+dif[2]*dif[2]; + if (tr>r) + r=tr; + } + return sqrt(r); +} + +int BoundSphereReject(winding_t *source, winding_t *pass, winding_t *target) +{ + vec3_t cs,cp,ct,cone; + float rs,rp,rt,h,rtot; + rs=ComputeBoundingSphere(source,cs); + rp=ComputeBoundingSphere(pass,cp); + rt=ComputeBoundingSphere(target,ct); + VectorSubtract(cp,cs,cone); + //h=(rs+2*rp); + h=(rs+rp); + if (h< ON_EPSILON) + return 0; + h=rs/h; + cone[0]*=h; + cone[1]*=h; + cone[2]*=h; + cone[0]+=cs[0]; + cone[1]+=cs[1]; + cone[2]+=cs[2]; + //cone is now the vertex of the cone + VectorSubtract(cp,cone,cp); + h=VectorLength(cp); + if (h< ON_EPSILON) + return 0; + h=1/h; + rp*=h; + cp[0]*=h; + cp[1]*=h; + cp[2]*=h; + //cp is now a unit vector pointing from cone to center of the portal + VectorSubtract(ct,cone,cs); + //cs points from the cone point to the center of the target + h=DotProduct(cs,cp); + if (h<0) + { + return 0; + } + h+=rt; //fudge intersection between cone and sphere. + cp[0]*=h; + cp[1]*=h; + cp[2]*=h; + VectorAdd(cp,cone,cp); + //cp is closest to ct on line connecting cone and cp, + VectorSubtract(cp,ct,ct) + rtot=VectorLength(ct); + h*=rp; + if (rtot-rt>h) + return 1; + return 0; +} + + +/* +============== +ClipToSeperators + +Source, pass, and target are an ordering of portals. + +Generates seperating planes canidates by taking two points from source and one +point from pass, and clips target by them. + +If target is totally clipped away, that portal can not be seen through. + +Normal clip keeps target on the same side as pass, which is correct if the +order goes source, pass, target. If the order goes pass, source, target then +flipclip should be set. +============== +*/ + +winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack) +{ + int i, j, k, l; + plane_t plane; + vec3_t v1, v2; + float d; + vec_t length; + int counts[3]; + qboolean fliptest; + + +#ifdef GILMODE + if (!flipclip) + { + if (BoundSphereReject(source,pass,target)) + { + FreeStackWinding (target, stack); + return NULL; + } + } +#endif + +// check all combinations + for (i=0 ; inumpoints ; i++) + { + l = (i+1)%source->numpoints; + VectorSubtract (source->points[l] , source->points[i], v1); + + // fing a vertex of pass that makes a plane that puts all of the + // vertexes of pass on the front side and all of the vertexes of + // source on the back side + for (j=0 ; jnumpoints ; j++) + { + VectorSubtract (pass->points[j], source->points[i], v2); + + plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1]; + plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2]; + plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0]; + + // if points don't make a valid plane, skip it + + length = plane.normal[0] * plane.normal[0] + + plane.normal[1] * plane.normal[1] + + plane.normal[2] * plane.normal[2]; + + if (length < ON_EPSILON) + continue; +#ifdef DONORMAL + length = 1/sqrt(length); + + plane.normal[0] *= length; + plane.normal[1] *= length; + plane.normal[2] *= length; +#endif + plane.dist = DotProduct (pass->points[j], plane.normal); + + // + // find out which side of the generated seperating plane has the + // source portal + // +#if 1 + fliptest = false; + for (k=0 ; knumpoints ; k++) + { + if (k == i || k == l) + continue; + d = DotProduct (source->points[k], plane.normal) - plane.dist; +#ifdef DONORMAL + if (d < -ON_EPSILON) +#else + if (d < -BIG_EPSILON) +#endif + { // source is on the negative side, so we want all + // pass and target on the positive side + fliptest = false; + break; + } +#ifdef DONORMAL + else if (d > ON_EPSILON) +#else + else if (d > BIG_EPSILON) +#endif + { // source is on the positive side, so we want all + // pass and target on the negative side + fliptest = true; + break; + } + } + if (k == source->numpoints) + continue; // planar with source portal +#else + fliptest = flipclip; +#endif + // + // flip the normal if the source portal is backwards + // + if (fliptest) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } +#if 1 + // + // if all of the pass portal points are now on the positive side, + // this is the seperating plane + // + counts[0] = counts[1] = counts[2] = 0; + for (k=0 ; knumpoints ; k++) + { + if (k==j) + continue; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; +#ifdef DONORMAL + if (d < -ON_EPSILON) +#else + if (d < -BIG_EPSILON) +#endif + break; +#ifdef DONORMAL + else if (d > ON_EPSILON) +#else + else if (d > BIG_EPSILON) +#endif + counts[0]++; + else + counts[2]++; + } + if (k != pass->numpoints) + continue; // points on negative side, not a seperating plane + + if (!counts[0]) + continue; // planar with seperating plane +#else + k = (j+1)%pass->numpoints; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + continue; + k = (j+pass->numpoints-1)%pass->numpoints; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + continue; +#endif + // + // flip the normal if we want the back side + // + if (flipclip) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } + + // + // clip target by the seperating plane + // + target = ChopWinding (target, stack, &plane); + if (!target) + return NULL; // target is not visible + } + } + + return target; +} + + + +/* +================== +RecursiveLeafFlow + +Flood fill through the leafs +If src_portal is NULL, this is the originating leaf +================== +*/ +void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack) +{ + pstack_t stack; + portal_t *p; + plane_t backplane; + leaf_t *leaf; + int i, j; + long *test, *might, *vis, more; + int pnum; + + thread->c_chains++; + + leaf = &leafs[leafnum]; +// CheckStack (leaf, thread); + + prevstack->next = &stack; + + stack.next = NULL; + stack.leaf = leaf; + stack.portal = NULL; + + might = (long *)stack.mightsee; + vis = (long *)thread->base->portalvis; + +// check all portals for flowing into other leafs + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + pnum = p - portals; + + if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) + { + continue; // can't possibly see it + } + + // if the portal can't see anything we haven't allready seen, skip it + if (p->status == stat_done) + { + test = (long *)p->portalvis; + } + else + { + test = (long *)p->portalflood; + } + + more = 0; + for (j=0 ; jmightsee)[j]) + { + might[j] = 0; + } + else + { + might[j] = ((long *)prevstack->mightsee)[j] & test[j]; + more |= (might[j] & ~vis[j]); + } + } + + if (!more && + (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) ) + { // can't see anything new + continue; + } + + // get plane of portal, point normal into the neighbor leaf + stack.portalplane = p->plane; + VectorSubtract (vec3_origin, p->plane.normal, backplane.normal); + backplane.dist = -p->plane.dist; + +// c_portalcheck++; + + stack.portal = p; + stack.next = NULL; + stack.freewindings[0] = 1; + stack.freewindings[1] = 1; + stack.freewindings[2] = 1; + +#if 1 +{ +float d; + + d = DotProduct (p->origin, thread->pstack_head.portalplane.normal); + d -= thread->pstack_head.portalplane.dist; + if (d < -p->radius) + { + continue; + } + else if (d > p->radius) + { + stack.pass = p->winding; + } + else + { + stack.pass = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); + if (!stack.pass) + continue; + } +} +#else + stack.pass = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); + if (!stack.pass) + continue; +#endif + + +#if 1 +{ +float d; + + d = DotProduct (thread->base->origin, p->plane.normal); + d -= p->plane.dist; + if (d > p->radius) + { + continue; + } + else if (d < -p->radius) + { + stack.source = prevstack->source; + } + else + { + stack.source = ChopWinding (prevstack->source, &stack, &backplane); + if (!stack.source) + continue; + } +} +#else + stack.source = ChopWinding (prevstack->source, &stack, &backplane); + if (!stack.source) + continue; +#endif + + if (!prevstack->pass) + { // the second leaf can only be blocked if coplanar + + // mark the portal as visible + thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); + + RecursiveLeafFlow (p->leaf, thread, &stack); + continue; + } + + stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, false, &stack); + if (!stack.pass) + continue; + + stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, true, &stack); + if (!stack.pass) + continue; + + // mark the portal as visible + thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); + + // flow through it for real + RecursiveLeafFlow (p->leaf, thread, &stack); + } +} + + +/* +=============== +PortalFlow + +generates the portalvis bit vector +=============== +*/ +void PortalFlow (int portalnum) +{ + threaddata_t data; + int i; + portal_t *p; + int c_might, c_can; + + p = sorted_portals[portalnum]; + p->status = stat_working; + + c_might = CountBits (p->portalflood, numportals*2); + + memset (&data, 0, sizeof(data)); + data.base = p; + + data.pstack_head.portal = p; + data.pstack_head.source = p->winding; + data.pstack_head.portalplane = p->plane; + for (i=0 ; iportalflood)[i]; + RecursiveLeafFlow (p->leaf, &data, &data.pstack_head); + + p->status = stat_done; + + c_can = CountBits (p->portalvis, numportals*2); + + qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", + (int)(p - portals), c_might, c_can, data.c_chains); +} + + +/* +=============================================================================== + +This is a rough first-order aproximation that is used to trivially reject some +of the final calculations. + + +Calculates portalfront and portalflood bit vectors + +thinking about: + +typedef struct passage_s +{ + struct passage_s *next; + struct portal_s *to; + stryct sep_s *seperators; + byte *mightsee; +} passage_t; + +typedef struct portal_s +{ + struct passage_s *passages; + int leaf; // leaf portal faces into +} portal_s; + +leaf = portal->leaf +clear +for all portals + + +calc portal visibility + clear bit vector + for all passages + passage visibility + + +for a portal to be visible to a passage, it must be on the front of +all seperating planes, and both portals must be behind the mew portal + +=============================================================================== +*/ + +int c_flood, c_vis; +extern float distcull; + + +/* +================== +SimpleFlood + +================== +*/ +void SimpleFlood (portal_t *srcportal, int leafnum) +{ + int i; + leaf_t *leaf; + portal_t *p; + int pnum; + vec3_t c; + + leaf = &leafs[leafnum]; + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + pnum = p - portals; + + if ( ! (srcportal->portalfront[pnum>>3] & (1<<(pnum&7)) ) ) + continue; + + if (srcportal->portalflood[pnum>>3] & (1<<(pnum&7)) ) + continue; + + if (distcull) + { + VectorSubtract(srcportal->origin,p->origin,c); + if (VectorLength(c)-srcportal->radius-p->radius>distcull) + continue; + } + srcportal->portalflood[pnum>>3] |= (1<<(pnum&7)); + + SimpleFlood (srcportal, p->leaf); + } +} + +/* +============== +BasePortalVis +============== +*/ +void BasePortalVis (int portalnum) +{ + int j, k; + portal_t *tp, *p; + float d; + winding_t *w; + + p = portals+portalnum; + + p->portalfront = malloc (portalbytes); + if (p->portalfront == NULL) + Error("BasePortalVis (front) MALLOC failed! Could not allocate %s bytes.", portalbytes); + memset (p->portalfront, 0, portalbytes); + + p->portalflood = malloc (portalbytes); + if (p->portalflood == NULL) + Error("BasePortalVis (flood) MALLOC failed! Could not allocate %s bytes.", portalbytes); + memset (p->portalflood, 0, portalbytes); + + p->portalvis = malloc (portalbytes); + if (p->portalvis == NULL) + Error("BasePortalVis (vis) MALLOC failed! Could not allocate %s bytes.", portalbytes); + memset (p->portalvis, 0, portalbytes); + + for (j=0, tp = portals ; jwinding; + for (k=0 ; knumpoints ; k++) + { + d = DotProduct (w->points[k], p->plane.normal) + - p->plane.dist; + if (d > ON_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + w = p->winding; + for (k=0 ; knumpoints ; k++) + { + d = DotProduct (w->points[k], tp->plane.normal) + - tp->plane.dist; + if (d < -ON_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + p->portalfront[j>>3] |= (1<<(j&7)); + } + + SimpleFlood (p, p->leaf); + + p->nummightsee = CountBits (p->portalflood, numportals*2); +// printf ("portal %i: %i mightsee\n", portalnum, p->nummightsee); + c_flood += p->nummightsee; +} + + + + + +/* +=============================================================================== + +This is a second order aproximation + +Calculates portalvis bit vector + +WAAAAAAY too slow. + +=============================================================================== +*/ + +/* +================== +RecursiveLeafBitFlow + +================== +*/ +void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee) +{ + portal_t *p; + leaf_t *leaf; + int i, j; + long more; + int pnum; + byte newmight[MAX_PORTALS/8]; + + leaf = &leafs[leafnum]; + +// check all portals for flowing into other leafs + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + pnum = p - portals; + + // if some previous portal can't see it, skip + if (! (mightsee[pnum>>3] & (1<<(pnum&7)) ) ) + continue; + + // if this portal can see some portals we mightsee, recurse + more = 0; + for (j=0 ; jportalflood)[j]; + more |= ((long *)newmight)[j] & ~((long *)cansee)[j]; + } + + if (!more) + continue; // can't see anything new + + cansee[pnum>>3] |= (1<<(pnum&7)); + + RecursiveLeafBitFlow (p->leaf, newmight, cansee); + } +} + +/* +============== +BetterPortalVis +============== +*/ +void BetterPortalVis (int portalnum) +{ + portal_t *p; + + p = portals+portalnum; + + RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis); + + // build leaf vis information + p->nummightsee = CountBits (p->portalvis, numportals*2); + c_vis += p->nummightsee; +} + + diff --git a/Toolkit/Programming/Tools/bsp/qvis3/qvis3.c b/Toolkit/Programming/Tools/bsp/qvis3/qvis3.c new file mode 100644 index 0000000..6168234 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qvis3/qvis3.c @@ -0,0 +1,615 @@ +// vis.c + +#include "vis.h" +#include "threads.h" +#include "stdlib.h" + +int numportals; +int portalclusters; + +char inbase[32]; +char outbase[32]; + +portal_t *portals; +leaf_t *leafs; + +int c_portaltest, c_portalpass, c_portalcheck; + +byte *uncompressedvis; + +byte *vismap, *vismap_p, *vismap_end; // past visfile +int originalvismapsize; + +int leafbytes; // (portalclusters+63)>>3 +int leaflongs; + +int portalbytes, portallongs; + +qboolean fastvis; +qboolean nosort; + +float distcull = 0; + +int totalvis; + +portal_t *sorted_portals[MAX_MAP_PORTALS*2]; + + +//============================================================================= + +void PlaneFromWinding (winding_t *w, plane_t *plane) +{ + vec3_t v1, v2; + +// calc plane + VectorSubtract (w->points[2], w->points[1], v1); + VectorSubtract (w->points[0], w->points[1], v2); + CrossProduct (v2, v1, plane->normal); + VectorNormalize (plane->normal, plane->normal); + plane->dist = DotProduct (w->points[0], plane->normal); +} + + +/* +================== +NewWinding +================== +*/ +winding_t *NewWinding (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("NewWinding: %i points", points); + + size = (int)((winding_t *)0)->points[points]; + + w = malloc (size); + if (w == NULL) + Error("NewWinding MALLOC failed! Could not allocate %s bytes.", size); + memset (w, 0, size); + + return w; +} + + + +void pw(winding_t *w) +{ + int i; + for (i=0 ; inumpoints ; i++) + printf ("(%5.1f, %5.1f, %5.1f)\n",w->points[i][0], w->points[i][1],w->points[i][2]); +} + +void prl(leaf_t *l) +{ + int i; + portal_t *p; + plane_t pl; + + for (i=0 ; inumportals ; i++) + { + p = l->portals[i]; + pl = p->plane; + printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]); + } +} + + +//============================================================================= + +/* +============= +SortPortals + +Sorts the portals from the least complex, so the later ones can reuse +the earlier information. +============= +*/ +int PComp (const void *a, const void *b) +{ + if ( (*(portal_t **)a)->nummightsee == (*(portal_t **)b)->nummightsee) + return 0; + if ( (*(portal_t **)a)->nummightsee < (*(portal_t **)b)->nummightsee) + return -1; + return 1; +} +void SortPortals (void) +{ + int i; + + for (i=0 ; i>3] & (1<<(i&7)) ) + { + p = portals+i; + leafbits[p->leaf>>3] |= (1<<(p->leaf&7)); + } + } + + c_leafs = CountBits (leafbits, portalclusters); + + return c_leafs; +} + + +/* +=============== +ClusterMerge + +Merges the portal visibility for a leaf +=============== +*/ +void ClusterMerge (int leafnum) +{ + leaf_t *leaf; + byte portalvector[MAX_PORTALS/8]; + byte uncompressed[MAX_MAP_LEAFS/8]; + byte compressed[MAX_MAP_LEAFS/8]; + int i, j; + int numvis; + byte *dest; + portal_t *p; + int pnum; + + // OR together all the portalvis bits + + memset (portalvector, 0, portalbytes); + leaf = &leafs[leafnum]; + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + if (p->status != stat_done) + Error ("portal not done"); + for (j=0 ; jportalvis)[j]; + pnum = p - portals; + portalvector[pnum>>3] |= 1<<(pnum&7); + } + + // convert portal bits to leaf bits + numvis = LeafVectorFromPortalVector (portalvector, uncompressed); + + if (uncompressed[leafnum>>3] & (1<<(leafnum&7))) + { + printf ("WARNING: Leaf portals saw into leaf; leafnum %i\n", leafnum); + } + + uncompressed[leafnum>>3] |= (1<<(leafnum&7)); + numvis++; // count the leaf itself + + // save uncompressed for PHS calculation + memcpy (uncompressedvis + leafnum*leafbytes, uncompressed, leafbytes); + +// +// compress the bit string +// + qprintf ("cluster %4i : %4i visible\n", leafnum, numvis); + totalvis += numvis; + + i = CompressVis (uncompressed, compressed); + + dest = vismap_p; + vismap_p += i; + + if (vismap_p > vismap_end) + { + Error ("Vismap expansion overflow in ClusterMerge; vismap_p %n leafnum %i", vismap_p, leafnum); + } + + dvis->bitofs[leafnum][DVIS_PVS] = dest-vismap; + + memcpy (dest, compressed, i); +} + + +/* +================== +CalcPortalVis +================== +*/ +void CalcPortalVis (void) +{ + int i; + +// fastvis just uses mightsee for a very loose bound + if (fastvis) + { + for (i=0 ; iwinding; + VectorCopy (vec3_origin, total); + for (i=0 ; inumpoints ; i++) + { + VectorAdd (total, w->points[i], total); + } + + for (i=0 ; i<3 ; i++) + total[i] /= w->numpoints; + + bestr = 0; + for (i=0 ; inumpoints ; i++) + { + VectorSubtract (w->points[i], total, dist); + r = VectorLength (dist); + if (r > bestr) + bestr = r; + } + VectorCopy (total, p->origin); + p->radius = bestr; +} + +/* +============ +LoadPortals +============ +*/ +void LoadPortals (char *name) +{ + int i, j; + portal_t *p; + leaf_t *l; + char magic[80]; + FILE *f; + int numpoints; + winding_t *w; + int leafnums[2]; + plane_t plane; + + if (!strcmp(name,"-")) + f = stdin; + else + { + f = fopen(name, "r"); + if (!f) + Error ("LoadPortals: couldn't read %s\n",name); + } + + if (fscanf (f,"%79s\n%i\n%i\n",magic, &portalclusters, &numportals) != 3) + Error ("LoadPortals: failed to read header"); + if (strcmp(magic,PORTALFILE)) + Error ("LoadPortals: not a portal file"); + + printf ("%4i portalclusters\n", portalclusters); + printf ("%4i numportals\n", numportals); + + // these counts should take advantage of 64 bit systems automatically + leafbytes = ((portalclusters+63)&~63)>>3; + leaflongs = leafbytes/sizeof(long); + + portalbytes = ((numportals*2+63)&~63)>>3; + portallongs = portalbytes/sizeof(long); + +// each file portal is split into two memory portals + portals = malloc(2*numportals*sizeof(portal_t)); + if (portals == NULL) + Error("LoadPortals (portals) MALLOC failed! Could not allocate %s bytes.", 2*numportals*sizeof(portal_t)); + memset (portals, 0, 2*numportals*sizeof(portal_t)); + + leafs = malloc(portalclusters*sizeof(leaf_t)); + if (leafs == NULL) + Error("LoadPortals (leafs) MALLOC failed! Could not allocate %s bytes.", portalclusters*sizeof(leaf_t)); + memset (leafs, 0, portalclusters*sizeof(leaf_t)); + + originalvismapsize = portalclusters*leafbytes; + uncompressedvis = malloc(originalvismapsize); + if (uncompressedvis == NULL) + Error("LoadPortals (vis) MALLOC failed! Could not allocate %s bytes.", originalvismapsize); + + vismap = vismap_p = dvisdata; + dvis->numclusters = portalclusters; + vismap_p = (byte *)&dvis->bitofs[portalclusters]; + + vismap_end = vismap + MAX_MAP_VISIBILITY; + + for (i=0, p=portals ; i MAX_POINTS_ON_WINDING) + Error ("LoadPortals: portal %i has too many points", i); + if ( (unsigned)leafnums[0] > portalclusters + || (unsigned)leafnums[1] > portalclusters) + Error ("LoadPortals: reading portal %i", i); + + w = p->winding = NewWinding (numpoints); + w->original = true; + w->numpoints = numpoints; + + for (j=0 ; jpoints[j][k] = v[k]; + } + fscanf (f, "\n"); + + // calc plane + PlaneFromWinding (w, &plane); + + // create forward portal + l = &leafs[leafnums[0]]; + if (l->numportals == MAX_PORTALS_ON_LEAF) + Error ("Leaf with too many portals"); + l->portals[l->numportals] = p; + l->numportals++; + + p->winding = w; + VectorSubtract (vec3_origin, plane.normal, p->plane.normal); + p->plane.dist = -plane.dist; + p->leaf = leafnums[1]; + SetPortalSphere (p); + p++; + + // create backwards portal + l = &leafs[leafnums[1]]; + if (l->numportals == MAX_PORTALS_ON_LEAF) + Error ("Leaf with too many portals"); + l->portals[l->numportals] = p; + l->numportals++; + + p->winding = NewWinding(w->numpoints); + p->winding->numpoints = w->numpoints; + for (j=0 ; jnumpoints ; j++) + { + VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]); + } + + p->plane = plane; + p->leaf = leafnums[0]; + SetPortalSphere (p); + p++; + + } + + fclose (f); +} + + +/* +================ +CalcPHS + +Calculate the PHS (Potentially Hearable Set) +by ORing together all the PVS visible from a leaf +================ +*/ +void CalcPHS (void) +{ + int i, j, k, l, index; + int bitbyte; + long *dest, *src; + byte *scan; + int count; + byte uncompressed[MAX_MAP_LEAFS/8]; + byte compressed[MAX_MAP_LEAFS/8]; + + printf ("Building PHS...\n"); + + count = 0; + for (i=0 ; i= portalclusters) + Error ("Bad bit in PVS"); // pad bits should be 0 + src = (long *)(uncompressedvis + index*leafbytes); + dest = (long *)uncompressed; + for (l=0 ; l>3] & (1<<(j&7)) ) + { + count++; + } + } + + // + // compress the bit string + // + j = CompressVis (uncompressed, compressed); + + dest = (long *)vismap_p; + vismap_p += j; + + if (vismap_p > vismap_end) + { + Error ("Vismap expansion overflow in CalcPHS; vismap_p %n count %i", vismap_p, count); + } + + dvis->bitofs[i][DVIS_PHS] = (byte *)dest-vismap; + + memcpy (dest, compressed, j); + } + + printf ("Average clusters hearable: %i\n", count/portalclusters); +} + +/* +=========== +main +=========== +*/ +int main (int argc, char **argv) +{ + char portalfile[1024]; + char source[1024]; + char name[1024]; + int i; + double start, end; + + printf ("---- vis ----\n"); + + verbose = false; + for (i=1 ; i +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=qvis3 - Win32 Release +!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 "qvis3.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 "qvis3.mak" CFG="qvis3 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qvis3 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qvis3 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName ""$/Wolf/Final/Utilities/bsp/qvis3", APDAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qvis3 - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Zi /O2 /I "..\..\common" /I "..\..\ref_gl" /I "../../qcommon" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_TOOL" /FR /YX /FD /c +# 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:console /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 /nologo /subsystem:console /map /debug /machine:I386 + +!ELSEIF "$(CFG)" == "qvis3 - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /MTd /W3 /Gm /Zi /Od /I "..\..\common" /I "..\..\ref_gl" /I "../../qcommon" /D "_DEBUG" /D "_TOOL" /D "WIN32" /D "_CONSOLE" /FR /YX /FD /c +# 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:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib 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:console /map /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "qvis3 - Win32 Release" +# Name "qvis3 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\..\common\bspfile.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\cmdlib.c +# End Source File +# Begin Source File + +SOURCE=.\flow.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\l3dslib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\lbmlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\mathlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\md4.c +# End Source File +# Begin Source File + +SOURCE=.\qvis3.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\scriplib.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\threads.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\token.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=..\..\common\bspfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\cmdlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\ref_gl\fmodel.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\l3dslib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\lbmlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\mathlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\polylib.h +# End Source File +# Begin Source File + +SOURCE=..\..\qcommon\q_typedef.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\qfiles.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\scriplib.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\threads.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\token.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\trilib.h +# End Source File +# Begin Source File + +SOURCE=.\vis.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Toolkit/Programming/Tools/bsp/qvis3/vis.h b/Toolkit/Programming/Tools/bsp/qvis3/vis.h new file mode 100644 index 0000000..ab0659f --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/qvis3/vis.h @@ -0,0 +1,127 @@ +// vis.h + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" + +#define MAX_PORTALS 32768 + +#define PORTALFILE "PRT1" + +#define ON_EPSILON 0.1 + +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +#define MAX_POINTS_ON_WINDING 64 +#define MAX_POINTS_ON_FIXED_WINDING 12 + +typedef struct +{ + qboolean original; // don't free, it's part of the portal + int numpoints; + vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized +} winding_t; + +winding_t *NewWinding (int points); +void FreeWinding (winding_t *w); +winding_t *CopyWinding (winding_t *w); + + +typedef enum {stat_none, stat_working, stat_done} vstatus_t; +typedef struct +{ + plane_t plane; // normal pointing into neighbor + int leaf; // neighbor + + vec3_t origin; // for fast clip testing + float radius; + + winding_t *winding; + vstatus_t status; + byte *portalfront; // [portals], preliminary + byte *portalflood; // [portals], intermediate + byte *portalvis; // [portals], final + + int nummightsee; // bit count on portalflood for sort +} portal_t; + +typedef struct seperating_plane_s +{ + struct seperating_plane_s *next; + plane_t plane; // from portal is on positive side +} sep_t; + + +typedef struct passage_s +{ + struct passage_s *next; + int from, to; // leaf numbers + sep_t *planes; +} passage_t; + +#define MAX_PORTALS_ON_LEAF 128 +typedef struct leaf_s +{ + int numportals; + passage_t *passages; + portal_t *portals[MAX_PORTALS_ON_LEAF]; +} leaf_t; + + +typedef struct pstack_s +{ + byte mightsee[MAX_PORTALS/8]; // bit string + struct pstack_s *next; + leaf_t *leaf; + portal_t *portal; // portal exiting + winding_t *source; + winding_t *pass; + + winding_t windings[3]; // source, pass, temp in any order + int freewindings[3]; + + plane_t portalplane; +} pstack_t; + +typedef struct +{ + portal_t *base; + int c_chains; + pstack_t pstack_head; +} threaddata_t; + + + +extern int numportals; +extern int portalclusters; + +extern portal_t *portals; +extern leaf_t *leafs; + +extern int c_portaltest, c_portalpass, c_portalcheck; +extern int c_portalskip, c_leafskip; +extern int c_vistest, c_mighttest; +extern int c_chains; + +extern byte *vismap, *vismap_p, *vismap_end; // past visfile + +extern byte *uncompressed; + +extern int leafbytes, leaflongs; +extern int portalbytes, portallongs; + + +void LeafFlow (int leafnum); + + +void BasePortalVis (int portalnum); +void BetterPortalVis (int portalnum); +void PortalFlow (int portalnum); + +extern portal_t *sorted_portals[MAX_MAP_PORTALS*2]; + +int CountBits (byte *bits, int numbits); diff --git a/Toolkit/Programming/Tools/bsp/tonet.bat b/Toolkit/Programming/Tools/bsp/tonet.bat new file mode 100644 index 0000000..d9aba55 --- /dev/null +++ b/Toolkit/Programming/Tools/bsp/tonet.bat @@ -0,0 +1,3 @@ +xcopy/d qrad3\release\qrad3.exe r:\bin_nt\ +xcopy/d qbsp3\release\qbsp3.exe r:\bin_nt\ +xcopy/d qvis3\release\qvis3.exe r:\bin_nt\ diff --git a/Toolkit/Programming/Tools/qMView/Angles.h b/Toolkit/Programming/Tools/qMView/Angles.h new file mode 100644 index 0000000..3b1059e --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Angles.h @@ -0,0 +1,10 @@ +#define ANGLE_180 3.1415926535 +#define ANGLE_45 ANGLE_180*0.25 +#define ANGLE_90 ANGLE_180*0.5 +#define ANGLE_135 ANGLE_90+ANGLE_45 +#define ANGLE_270 ANGLE_180+ANGLE_90 +#define ANGLE_360 ANGLE_180*2.0 + +#define ANGLE_TO_RAD ANGLE_180/180.0 +#define RAD_TO_ANGLE 180.0/ANGLE_180 + diff --git a/Toolkit/Programming/Tools/qMView/ChildFrm.cpp b/Toolkit/Programming/Tools/qMView/ChildFrm.cpp new file mode 100644 index 0000000..a916304 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/ChildFrm.cpp @@ -0,0 +1,2032 @@ +// ChildFrm.cpp : implementation of the CChildFrame class +// + +#include "stdafx.h" +#include "qMView.h" + +#include "ChildFrm.h" +#include "MainFrm.h" + +#include +#include +#include +#include + +#include "D3DGlobal.h" +#include "MDL2.h" +#include "flex.h" + +#include "ManagerTree.h" +#include "TickerDlg.h" + +#include "ddutil.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +int curSkin = 0; +int curNode = 0; +BOOL useNodes = FALSE; + +HTREEITEM nodes[MAX_FM_MESH_NODES]; + +BOOL PICK_ON; + +skinStruct skinTreeInfo; + +double globalField = 0.5; + +BOOL LSHFT_DN = FALSE; + +BOOL paint_first = TRUE; + +CMenu NEAR CChildFrame::menu; + +mdl_p mainModel; + +BOOL drag = FALSE; +BOOL end_drag = FALSE; + +BOOL r_drag = FALSE; +BOOL r_end_drag = FALSE; + +int last_x = 0, last_y = 0; +int r_last_x = 0, r_last_y = 0; + +BOOL LOCK_ROT_X, LOCK_ROT_Y, LOCK_ROT_Z; +BOOL LOCK_TRAN_X, LOCK_TRAN_Y, LOCK_TRAN_Z; +BOOL LOCK_SCALE_X, LOCK_SCALE_Y, LOCK_SCALE_Z; + +extern CManagerTree m_wndFrameTreeDlg; + +int playMode = ANIM_FORWARD; + +BOOL ZOOM_ON = FALSE; + +BOOL MDL_WritePaletteToFile(char *filename, DWORD fileType); + +///////////////////////////////////////////////////////////////////////////// +// CChildFrame + +IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWnd) + +BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd) + //{{AFX_MSG_MAP(CChildFrame) + ON_WM_CREATE() + ON_WM_PAINT() + ON_WM_MDIACTIVATE() + ON_WM_SIZE() + ON_WM_MOUSEMOVE() + ON_WM_ERASEBKGND() + ON_WM_DESTROY() + ON_COMMAND(ID_ALL_LOCK, OnAllLock) + ON_COMMAND(ID_ALL_UNLOCK, OnAllUnlock) + ON_COMMAND(ID_ANIMATE_PLAY, OnAnimatePlay) + ON_UPDATE_COMMAND_UI(ID_ANIMATE_PLAY, OnUpdateAnimatePlay) + ON_COMMAND(ID_ANIMATE_STEP_BACK, OnAnimateStepBack) + ON_COMMAND(ID_ANIMATE_STEP_FORE, OnAnimateStepFore) + ON_COMMAND(ID_ANIMATE_STOP, OnAnimateStop) + ON_UPDATE_COMMAND_UI(ID_ANIMATE_STOP, OnUpdateAnimateStop) + ON_COMMAND(ID_ANIMATE_TYPE_BACK, OnAnimateTypeBack) + ON_UPDATE_COMMAND_UI(ID_ANIMATE_TYPE_BACK, OnUpdateAnimateTypeBack) + ON_COMMAND(ID_ANIMATE_TYPE_FRONT, OnAnimateTypeFront) + ON_UPDATE_COMMAND_UI(ID_ANIMATE_TYPE_FRONT, OnUpdateAnimateTypeFront) + ON_COMMAND(ID_ANIMATE_TYPE_PINGPONG, OnAnimateTypePingpong) + ON_UPDATE_COMMAND_UI(ID_ANIMATE_TYPE_PINGPONG, OnUpdateAnimateTypePingpong) + ON_COMMAND(ID_FRAME_EXPORT, OnFrameExport) + ON_COMMAND(ID_FRAME_IMPORT, OnFrameImport) + ON_COMMAND(ID_GOTOPOS_BACK, OnGotoposBack) + ON_COMMAND(ID_GOTOPOS_BOTTOM, OnGotoposBottom) + ON_COMMAND(ID_GOTOPOS_FRONT, OnGotoposFront) + ON_COMMAND(ID_GOTOPOS_LEFT, OnGotoposLeft) + ON_COMMAND(ID_GOTOPOS_RIGHT, OnGotoposRight) + ON_COMMAND(ID_GOTOPOS_TOP, OnGotoposTop) + ON_COMMAND(ID_LOCK_ROT_X, OnLockRotX) + ON_UPDATE_COMMAND_UI(ID_LOCK_ROT_X, OnUpdateLockRotX) + ON_COMMAND(ID_LOCK_ROT_Y, OnLockRotY) + ON_UPDATE_COMMAND_UI(ID_LOCK_ROT_Y, OnUpdateLockRotY) + ON_COMMAND(ID_LOCK_ROT_Z, OnLockRotZ) + ON_UPDATE_COMMAND_UI(ID_LOCK_ROT_Z, OnUpdateLockRotZ) + ON_COMMAND(ID_LOCK_SCALE_X, OnLockScaleX) + ON_UPDATE_COMMAND_UI(ID_LOCK_SCALE_X, OnUpdateLockScaleX) + ON_COMMAND(ID_LOCK_SCALE_Y, OnLockScaleY) + ON_UPDATE_COMMAND_UI(ID_LOCK_SCALE_Y, OnUpdateLockScaleY) + ON_COMMAND(ID_LOCK_SCALE_Z, OnLockScaleZ) + ON_UPDATE_COMMAND_UI(ID_LOCK_SCALE_Z, OnUpdateLockScaleZ) + ON_COMMAND(ID_LOCK_TRAN_X, OnLockTranX) + ON_UPDATE_COMMAND_UI(ID_LOCK_TRAN_X, OnUpdateLockTranX) + ON_COMMAND(ID_LOCK_TRAN_Y, OnLockTranY) + ON_UPDATE_COMMAND_UI(ID_LOCK_TRAN_Y, OnUpdateLockTranY) + ON_COMMAND(ID_LOCK_TRAN_Z, OnLockTranZ) + ON_UPDATE_COMMAND_UI(ID_LOCK_TRAN_Z, OnUpdateLockTranZ) + ON_COMMAND(ID_PALETTE_EXPORT, OnPaletteExport) + ON_COMMAND(ID_PALETTE_IMPORT, OnPaletteImport) + ON_COMMAND(ID_RENDER_FLAT, OnRenderFlat) + ON_UPDATE_COMMAND_UI(ID_RENDER_FLAT, OnUpdateRenderFlat) + ON_COMMAND(ID_RENDER_GOURAUD, OnRenderGouraud) + ON_UPDATE_COMMAND_UI(ID_RENDER_GOURAUD, OnUpdateRenderGouraud) + ON_COMMAND(ID_RENDER_TEXTURE, OnRenderTexture) + ON_UPDATE_COMMAND_UI(ID_RENDER_TEXTURE, OnUpdateRenderTexture) + ON_COMMAND(ID_RENDER_TRANS, OnRenderTrans) + ON_UPDATE_COMMAND_UI(ID_RENDER_TRANS, OnUpdateRenderTrans) + ON_COMMAND(ID_RENDER_WIREFRAME, OnRenderWireframe) + ON_UPDATE_COMMAND_UI(ID_RENDER_WIREFRAME, OnUpdateRenderWireframe) + ON_COMMAND(ID_SKIN_EXPORT, OnSkinExport) + ON_COMMAND(ID_SKIN_IMPORT, OnSkinImport) + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_RBUTTONDOWN() + ON_WM_RBUTTONUP() + ON_COMMAND(ID_FILE_OPEN, OnFileOpen) + ON_WM_KEYDOWN() + ON_WM_KEYUP() + ON_COMMAND(ID_GOTOPOS_WEAPON, OnGotoposWeapon) + ON_COMMAND(ID_FIELD_PLUS, OnFieldPlus) + ON_COMMAND(ID_FIELD_MINUS, OnFieldMinus) + ON_COMMAND(ID_TICKER_OPTIONS, OnTickerOptions) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CChildFrame construction/destruction + +CChildFrame::CChildFrame() +{ + // TODO: add member initialization code here + +} + +CChildFrame::~CChildFrame() +{ +} + +BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs) +{ + // TODO: Modify the Window class or styles here by modifying + // the CREATESTRUCT cs + + cs.style = WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU + | FWS_ADDTOTITLE | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_MAXIMIZE; + + return CMDIChildWnd::PreCreateWindow(cs); +} + +///////////////////////////////////////////////////////////////////////////// +// CChildFrame diagnostics + +#ifdef _DEBUG +void CChildFrame::AssertValid() const +{ + CMDIChildWnd::AssertValid(); +} + +void CChildFrame::Dump(CDumpContext& dc) const +{ + CMDIChildWnd::Dump(dc); +} + +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// CChildFrame message handlers + +BOOL CChildFrame::CreateDevice() +{ + HWND m_Hwnd = m_hWnd; + + HRESULT ddrval = DirectDrawCreate( NULL, &lpDD, NULL ); + if( ddrval != DD_OK ) + { + return FALSE; + } + + lpDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL ); + + HRESULT r = DirectDrawCreateClipper( 0, &clipper, NULL ); + if (r != D3DRM_OK) + { + TRACE("failed to create D3D clipper\n"); + return FALSE; + } + + r = clipper->SetHWnd( NULL, m_Hwnd ); + if (r != D3DRM_OK) + { + TRACE("failed in SetHWnd call\n"); + return FALSE; + } + + RECT rect; + ::GetClientRect( m_Hwnd, &rect ); + + r = d3drm->CreateDeviceFromClipper( clipper, GetGUID(), + rect.right, rect.bottom, + &device ); + + if (r!=D3DRM_OK) + { + AfxMessageBox("CreateDeviceFromClipper() failed"); + return FALSE; + } + + device->SetQuality( D3DRMRENDER_FLAT ); + + HDC hdc = ::GetDC( m_Hwnd ); + int bpp = ::GetDeviceCaps( hdc, BITSPIXEL ); + ::ReleaseDC( m_Hwnd, hdc ); + + switch ( bpp ) + { + case 1: + device->SetShades( 4 ); + d3drm->SetDefaultTextureShades( 4 ); + device->SetDither( TRUE ); + break; + case 8: + //device->SetDither( FALSE ); + break; + case 16: + device->SetShades( 32 ); + d3drm->SetDefaultTextureColors( 64 ); + d3drm->SetDefaultTextureShades( 32 ); + device->SetDither( FALSE ); + break; + case 24: + case 32: + device->SetShades( 256 ); + d3drm->SetDefaultTextureColors( 64 ); + d3drm->SetDefaultTextureShades( 256 ); + device->SetDither( FALSE ); + break; + } + + d3drm->CreateFrame( 0, &scene ); + + if (CreateScene()==FALSE) + { + AfxMessageBox("CreateScene() failed"); + return FALSE; + } + + viewport->SetBack( D3DVALUE(8000) ); + + ASSERT( camera ); + ASSERT( viewport ); + return TRUE; +} + +D3DVALUE CChildFrame::ScaleMesh( LPDIRECT3DRMMESHBUILDER mesh, D3DVALUE dim) +{ + D3DRMBOX box; + mesh->GetBox( &box ); + D3DVALUE sizex = box.max.x - box.min.x; + D3DVALUE sizey = box.max.y - box.min.y; + D3DVALUE sizez = box.max.z - box.min.z; + D3DVALUE largedim=D3DVALUE(0); + if (sizex>largedim) + largedim=sizex; + if (sizey>largedim) + largedim=sizey; + if (sizez>largedim) + largedim=sizez; + D3DVALUE scalefactor = dim/largedim; + mesh->Scale( scalefactor, scalefactor, scalefactor ); + return scalefactor; +} + + +GUID* CChildFrame::GetGUID() +{ + static GUID* lpguid; + HRESULT r; + + D3DFINDDEVICESEARCH searchdata; + memset(&searchdata, 0, sizeof searchdata); + searchdata.dwSize = sizeof searchdata; + searchdata.dwFlags = D3DFDS_COLORMODEL; + searchdata.dcmColorModel = colormodel; + + static D3DFINDDEVICERESULT resultdata; + memset( &resultdata, 0, sizeof resultdata ); + resultdata.dwSize = sizeof resultdata; + + LPDIRECTDRAW ddraw; + r = DirectDrawCreate( 0, &ddraw, 0 ); + if (r!=DD_OK) + { + AfxMessageBox("DirectDrawCreate() failed"); + return 0; + } + + LPDIRECT3D d3d; + r = ddraw->QueryInterface( IID_IDirect3D, (void**)&d3d ); + if ( r != D3DRM_OK ) + { + AfxMessageBox("d3drm->QueryInterface() failed\n"); + ddraw->Release(); + ddraw = NULL; + return 0; + } + + r=d3d->FindDevice( &searchdata, &resultdata ); + if ( r==D3D_OK ) + lpguid = &resultdata.guid; + else + { + AfxMessageBox("FindDevice() failed"); + lpguid=0; + } + + d3d->Release(); + d3d = NULL; + ddraw->Release(); + ddraw = NULL; + + return lpguid; +} + +BOOL CChildFrame::CreateScene() +{ + scene->SetSceneBackgroundRGB( D3DVALUE(.3), D3DVALUE(.3), D3DVALUE(.3) ); + + d3drm->CreateFrame (scene, &frame); + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1) ); + + frame->AddMoveCallback( UpdateDrag, frame ); + + // ---------DIRECTIONAL LIGHT-------- + LPDIRECT3DRMLIGHT dlight; + d3drm->CreateLightRGB( D3DRMLIGHT_AMBIENT, + D3DVALUE(1.00), D3DVALUE(1.00), D3DVALUE(1.00), + &dlight); + + LPDIRECT3DRMFRAME dlightframe; + d3drm->CreateFrame( scene, &dlightframe ); + dlightframe->AddLight( dlight ); + dlightframe->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1), + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); + + dlight->Release(); + dlight=0; + dlightframe->Release(); + dlightframe=0; + + //------ CAMERA----------- + d3drm->CreateFrame( scene, &camera ); + camera->SetPosition( scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(curscale)); + d3drm->CreateViewport( device, camera, 0, 0, + device->GetWidth(), device->GetHeight(), + &viewport); + + d3drm_up = TRUE; + + return TRUE; +} + +BOOL CChildFrame::Create(LPCTSTR szTitle, LONG style, const RECT& rect, CMDIFrameWnd* parent) +{ + if (menu.m_hMenu == NULL) + menu.LoadMenu(IDR_QMVIEWTYPE); + m_hMenuShared = menu.m_hMenu; + + + LPCTSTR lpszChildClass = + AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, + LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_HAND_OPEN)), + 0, + LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME))); + + return CMDIChildWnd::Create(lpszChildClass, szTitle, style, rect, parent); +} + +int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1) + return -1; + + drag = FALSE; + end_drag = FALSE; + + r_drag = FALSE; + r_end_drag = FALSE; + + last_x = 0, last_y = 0; + r_last_x = 0, r_last_y = 0; + + //Setup the D3DDevice + HRESULT r = Direct3DRMCreate( (LPDIRECT3DRM*) &d3drm ); + if (r != D3DRM_OK) + { + TRACE("failed to create D3DRM object\n"); + return -1; + } + + return 0; +} + +void CChildFrame::OnPaint() +{ + if (paint_first) + { + paint_first = FALSE; + if (CreateDevice()==FALSE) + PostQuitMessage(0); + if (MDL_process) + { + if (MDL_type == MODEL_QUAKE) + { + MDL_LoadFromFile(MDL_filename); + LoadModelFrameInfo(MODEL_QUAKE); + LoadModelSkinInfo(); + + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); + } + else if (MDL_type == MODEL_QUAKE2) + { + MDL2_LoadFromFile(MDL_filename); + LoadModelFrameInfo(MODEL_QUAKE2); + LoadModelSkinInfo(); + } + else + { + FM_LoadFromFile(MDL_filename); + LoadModelFrameInfo(MODEL_FLEX); + LoadModelSkinInfo(); + } + } + } + + if (GetUpdateRect( 0, FALSE )==FALSE) + return; + + if (device) + { + LPDIRECT3DRMWINDEVICE windev; + PAINTSTRUCT ps; + BeginPaint(&ps); + if (device->QueryInterface(IID_IDirect3DRMWinDevice, (void**)&windev)==0) + { + if (windev->HandlePaint(ps.hdc)!=0) + AfxMessageBox("windev->HandlePaint() failure"); + windev->Release(); + windev = NULL; + } + else + AfxMessageBox("Failed to create Windows device to handle WM_PAINT"); + EndPaint(&ps); + } +} + +void CChildFrame::OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd* pDeactivateWnd) +{ + LPDIRECT3DRMWINDEVICE windev; + if (device) + { + if (device->QueryInterface( IID_IDirect3DRMWinDevice, (void**)&windev)==0) + { + if (windev->HandleActivate((unsigned short)MAKELONG((WORD)WM_MDIACTIVATE,(WORD)0))!=0) + AfxMessageBox("windev->HandleActivate() failure"); + windev->Release(); + windev = NULL; + } + else + AfxMessageBox("device->QueryInterface(WinDevice) failure"); + } + CMDIChildWnd::OnMDIActivate(bActivate, pActivateWnd, pDeactivateWnd); +} + +void CChildFrame::OnSize(UINT nType, int cx, int cy) +{ + CMDIChildWnd::OnSize(nType, cx, cy); + + if (!device) + return; + + int width = cx; + int height = cy; + + if (width && height) + { + int view_width = viewport->GetWidth(); + int view_height = viewport->GetHeight(); + int dev_width = device->GetWidth(); + int dev_height = device->GetHeight(); + + if (view_width == width && view_height == height) + return; + + int old_dither = device->GetDither(); + D3DRMRENDERQUALITY old_quality = device->GetQuality(); + int old_shades = device->GetShades(); + + viewport->Release(); + viewport = NULL; + device->Release(); + device = NULL; + d3drm->CreateDeviceFromClipper( clipper, GetGUID(), width, height, &device ); + + device->SetDither(old_dither); + device->SetQuality(old_quality); + device->SetShades(old_shades); + + width = device->GetWidth(); + height = device->GetHeight(); + d3drm->CreateViewport(device, camera,0, 0, width, height, &viewport); + } +} + +void CChildFrame::OnMouseMove(UINT nFlags, CPoint point) +{ + mousestate = nFlags; + mousex = point.x; + mousey = point.y; + + CMDIChildWnd::OnMouseMove(nFlags, point); +} + +BOOL CChildFrame::OnEraseBkgnd(CDC* pDC) +{ + COLORREF bgcolor; + if (scene) + { + D3DCOLOR scenecolor=scene->GetSceneBackground(); + bgcolor=D3DCOLOR_2_COLORREF(scenecolor); + } + else + bgcolor=RGB(0,0,0); + + CBrush br( bgcolor ); + CRect rc; + GetClientRect(&rc); + pDC->FillRect(&rc, &br); + + return TRUE; +} + +void CChildFrame::OnDestroy() +{ + + if (useNodes) + { + useNodes = false; + curNode = -1; + for (int i = 1; i < numnodes; i++) + { + frame->DeleteVisual(node_mesh[i]); + node_mesh[i]->Release(); + node_mesh[i] = NULL; + } + } + else if (mesh) + { + frame->DeleteVisual(mesh); + + mesh->Release(); + mesh = NULL; + } + + if (lpDDSSkin) + { + lpDDSSkin->Release(); + lpDDSSkin = 0; + } + + if (texture) + { + texture->Release(); + texture=0; + } + + if (scene) + { + scene->Release(); + scene=0; + } + + if (device) + { + device->Release(); + device=0; + } + + if (d3drm) + { + d3drm->Release(); + d3drm=0; + } + + if (clipper) + { + clipper->Release(); + clipper=0; + } + + if (lpDD) + { + lpDD->Release(); + lpDD = 0; + } + + if (frame) + { + frame->Release(); + frame = 0; + } + + CTreeCtrl* treeDlg = (CTreeCtrl*)m_wndFrameTreeDlg.GetDlgItem(IDC_FRAMETREE); + treeDlg->DeleteAllItems(); + rootFrame = treeDlg->InsertItem("Animations", TVI_ROOT, TVI_LAST); + + treeDlg = (CTreeCtrl*)m_wndFrameTreeDlg.GetDlgItem(IDC_SKINTREE); + treeDlg->DeleteAllItems(); + rootSkin = treeDlg->InsertItem("Skins", TVI_ROOT, TVI_LAST); + + treeDlg = (CTreeCtrl*)m_wndFrameManager2.GetDlgItem(IDC_NODETREE); + treeDlg->DeleteAllItems(); + rootNode = treeDlg->InsertItem("Nodes", TVI_ROOT, TVI_LAST); + + treeDlg = (CTreeCtrl*)m_wndFrameManager2.GetDlgItem(IDC_JOINTTREE); + treeDlg->DeleteAllItems(); + rootJoint = treeDlg->InsertItem("Joint", TVI_ROOT, TVI_LAST); + + d3drm_up = FALSE; + paint_first = TRUE; + + CMDIChildWnd::OnDestroy(); +} + +/* + * UpdateDrag + * + * Mesh animation callback function + * + */ +void CChildFrame::UpdateDrag(LPDIRECT3DRMFRAME frame, void*, D3DVALUE) +{ + D3DVECTOR dv; + + if (drag) + { + double delta_x = GetMouseX() - last_x; + double delta_y = GetMouseY() - last_y; + + if (delta_x || delta_y) has_moved = TRUE; + + if (LOCK_ROT_X) delta_x = 0; + if (LOCK_ROT_Y) delta_y = 0; + + last_x = GetMouseX(); + last_y = GetMouseY(); + double delta_r = sqrt(delta_x * delta_x + delta_y * delta_y); + double radius = 50; + double denom= sqrt(radius * radius + delta_r * delta_r); + if (fabs(delta_r) > 1) + { + if (!(delta_r == 0 || denom == 0)) + { + if (LSHFT_DN) + { + frame->SetRotation( 0, + D3DVALUE(0.0), + D3DVALUE(0.0), + D3DVALUE(1.0), + D3DVALUE(delta_x / 100) ); + } + else + { + frame->SetRotation( 0, + D3DDivide(-delta_y, delta_r), + D3DDivide(-delta_x, delta_r), + D3DVALUE(0.0), + D3DDivide(delta_r, denom) ); + } + } + } + else + { + frame->SetRotation( 0, 0, 0, D3DVALUE(0.0), 0); + } + } + + if (r_drag) + { + double delta_x = GetMouseX() - r_last_x; + double delta_y = GetMouseY() - r_last_y; + + if (delta_x || delta_y) r_has_moved = TRUE; + + r_last_x = GetMouseX(); + r_last_y = GetMouseY(); + + frame->GetPosition( scene, &dv ); + + if (!LOCK_TRAN_X) dv.x += D3DVALUE(delta_x / 10); + if (!LOCK_TRAN_Y) dv.y -= D3DVALUE(delta_y / 10); + dv.z = D3DVALUE(0.0); + + frame->SetPosition( scene, D3DVALUE(dv.x), D3DVALUE(dv.y), D3DVALUE(0) ); + + if (ZOOM_ON) + { + curscale += delta_y; + camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(curscale)); + } + } + + if (r_end_drag) + { + r_drag=FALSE; + r_end_drag=FALSE; + } + + if (end_drag) + { + drag=FALSE; + end_drag=FALSE; + } +} + +void CChildFrame::OnAllLock() +{ + LOCK_ROT_X = TRUE; + LOCK_ROT_Y = TRUE; + LOCK_ROT_Z = TRUE; + + LOCK_TRAN_X = TRUE; + LOCK_TRAN_Y = TRUE; + LOCK_TRAN_Z = TRUE; + + LOCK_SCALE_X = TRUE; + LOCK_SCALE_Y = TRUE; + LOCK_SCALE_Z = TRUE; +} + +void CChildFrame::OnAllUnlock() +{ + LOCK_ROT_X = FALSE; + LOCK_ROT_Y = FALSE; + LOCK_ROT_Z = FALSE; + + LOCK_TRAN_X = FALSE; + LOCK_TRAN_Y = FALSE; + LOCK_TRAN_Z = FALSE; + + LOCK_SCALE_X = FALSE; + LOCK_SCALE_Y = FALSE; + LOCK_SCALE_Z = FALSE; +} + +void CChildFrame::OnAnimatePlay() +{ + if (playing) + playing = FALSE; + else + playing = TRUE; +} + +void CChildFrame::OnUpdateAnimatePlay(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(playing); +} + +void CChildFrame::OnAnimateStepBack() +{ + MDL_UpdateFrame(&mainModel, ANIM_BACKWARD); + updateView = TRUE; +} + +void CChildFrame::OnAnimateStepFore() +{ + MDL_UpdateFrame(&mainModel, ANIM_FORWARD); + updateView = TRUE; +} + +void CChildFrame::OnAnimateStop() +{ + playing = FALSE; +} + +void CChildFrame::OnUpdateAnimateStop(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(playing); +} + +void CChildFrame::OnAnimateTypeBack() +{ + playMode = ANIM_BACKWARD; + usePingPong = FALSE; +} + +void CChildFrame::OnUpdateAnimateTypeBack(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnAnimateTypeFront() +{ + playMode = ANIM_FORWARD; + usePingPong = FALSE; +} + +void CChildFrame::OnUpdateAnimateTypeFront(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnAnimateTypePingpong() +{ + usePingPong = TRUE; +} + +void CChildFrame::OnUpdateAnimateTypePingpong(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnFrameExport() +{ +} + +void CChildFrame::OnFrameImport() +{ + // TODO: Add your command handler code here + +} + +void CChildFrame::OnGotoposBack() +{ + frame->SetPosition( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + if (mainModel.modelType == MODEL_QUAKE) + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0) ); + } + else + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); + } +} + +void CChildFrame::OnGotoposBottom() +{ + frame->SetPosition( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + if (mainModel.modelType == MODEL_QUAKE) + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1), + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0) ); + } + else + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); + } +} + +void CChildFrame::OnGotoposFront() +{ + frame->SetPosition( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + if (mainModel.modelType == MODEL_QUAKE) + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); + } + else + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) ); + } +} + +void CChildFrame::OnGotoposLeft() +{ + frame->SetPosition( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + if (mainModel.modelType == MODEL_QUAKE) + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1) ); + } + else + { + frame->SetOrientation( scene, + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1) ); + } +} + +void CChildFrame::OnGotoposRight() +{ + frame->SetPosition( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + if (mainModel.modelType == MODEL_QUAKE) + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1) ); + } + else + { + frame->SetOrientation( scene, + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1) ); + } +} + +void CChildFrame::OnGotoposTop() +{ + frame->SetPosition( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + if (mainModel.modelType == MODEL_QUAKE) + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0) ); + } + else + { + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) ); + } +} + +void CChildFrame::OnLockRotX() +{ + LOCK_ROT_X = !LOCK_ROT_X; +} + +void CChildFrame::OnUpdateLockRotX(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnLockRotY() +{ + LOCK_ROT_Y = !LOCK_ROT_Y; +} + +void CChildFrame::OnUpdateLockRotY(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnLockRotZ() +{ + LOCK_ROT_Z = !LOCK_ROT_Z; +} + +void CChildFrame::OnUpdateLockRotZ(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnLockScaleX() +{ + LOCK_SCALE_X = !LOCK_SCALE_X; +} + +void CChildFrame::OnUpdateLockScaleX(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnLockScaleY() +{ + LOCK_SCALE_Y = !LOCK_SCALE_Y; +} + +void CChildFrame::OnUpdateLockScaleY(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnLockScaleZ() +{ + LOCK_SCALE_Z = !LOCK_SCALE_Z; +} + +void CChildFrame::OnUpdateLockScaleZ(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnLockTranX() +{ + LOCK_TRAN_X = !LOCK_TRAN_X; +} + +void CChildFrame::OnUpdateLockTranX(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnLockTranY() +{ + LOCK_TRAN_Y = !LOCK_TRAN_Y; +} + +void CChildFrame::OnUpdateLockTranY(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnLockTranZ() +{ + LOCK_TRAN_Z = !LOCK_TRAN_Z; +} + +void CChildFrame::OnUpdateLockTranZ(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnPaletteExport() +{ + DWORD palType; + + CFileDialog fdSaveAsFile(FALSE,"*.pal",NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST, "RAW (*.raw)|*.raw|JASC Palette(*.pal)|*.pal||", this); + + if (fdSaveAsFile.DoModal()==IDOK) + { + CString strHelp = fdSaveAsFile.GetPathName(); + CString strExt = fdSaveAsFile.GetFileExt(); + + LPSTR szHelp = strHelp.GetBuffer(10); + LPSTR szExt = strExt.GetBuffer(10); + + if (!stricmp(szExt, "raw")) + palType = PALTYPE_RAW; + else if (!stricmp(szExt, "pal")) + palType = PALTYPE_JASC; + else if (!stricmp(szExt, "pcx")) + palType = PALTYPE_PCX; + + MDL_WritePaletteToFile(szHelp, palType); + } +} + +void CChildFrame::OnPaletteImport() +{ + if (useNodes) + return; + + CFileDialog fdOpenFile(TRUE,"*.pcx",NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST, "PCX (*.pcx)|*.pcx|BMP (*.bmp)|*.bmp|RAW (*.raw)|*.raw|JASC (*.pal)|*.pal||", this); + + if (fdOpenFile.DoModal()==IDOK) + { + CString strHelp = fdOpenFile.GetPathName(); + CString strExt = fdOpenFile.GetFileExt(); + + LPSTR szHelp = strHelp.GetBuffer(10); + LPSTR szExt = strExt.GetBuffer(10); + + if (!stricmp(szExt, "pal")) + { + if (MDL_LoadPaletteFromFile(szHelp, PALTYPE_JASC)) + { + palNum = PAL_FROMFILE; + MDL_LoadSkin(&mainModel,curSkin); + mesh->SetGroupTexture(group, NULL); + mesh->SetGroupTexture(group, texture); + updateView = TRUE; + } + } + else if (!stricmp(szExt, "raw")) + { + if (MDL_LoadPaletteFromFile(szHelp, PALTYPE_RAW)) + { + palNum = PAL_FROMFILE; + MDL_LoadSkin(&mainModel,curSkin); + mesh->SetGroupTexture(group, NULL); + mesh->SetGroupTexture(group, texture); + updateView = TRUE; + } + } + else if (!stricmp(szExt, "pcx")) + { + if (MDL_LoadPaletteFromFile(szHelp, PALTYPE_PCX)) + { + palNum = PAL_FROMFILE; + MDL_LoadSkin(&mainModel,curSkin); + mesh->SetGroupTexture(group, NULL); + mesh->SetGroupTexture(group, texture); + updateView = TRUE; + } + } + else if (!stricmp(szExt, "bmp")) + { + if (MDL_LoadPaletteFromFile(szHelp, PALTYPE_BMP)) + { + palNum = PAL_FROMFILE; + MDL_LoadSkin(&mainModel,curSkin); + mesh->SetGroupTexture(group, NULL); + mesh->SetGroupTexture(group, texture); + updateView = TRUE; + } + } + else + { + sprintf(out, "Unknown extension [%s]: unable to parse palette file", szExt); + AfxMessageBox(out); + } + } +} + +void CChildFrame::OnRenderFlat() +{ + if (useNodes) + { + if (curNode < 0) + { + for (int i = 1; i < numnodes;i++) + { + node_mesh[i]->SetGroupQuality(0, D3DRMRENDER_FLAT); + FM_ShowNodeFrame(&mainModel, curframe, i); + } + } + else + { + node_mesh[curNode]->SetGroupQuality(0, D3DRMRENDER_FLAT); + FM_ShowNodeFrame(&mainModel, curframe, curNode); + } + } + else + { + mesh->SetGroupQuality(group, D3DRMRENDER_FLAT); + MDL_ShowFrame(&mainModel, curframe); + } +} + +void CChildFrame::OnUpdateRenderFlat(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnRenderGouraud() +{ + mesh->SetGroupQuality(group, D3DRMRENDER_GOURAUD); + MDL_ShowFrame(&mainModel, curframe); +} + +void CChildFrame::OnUpdateRenderGouraud(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnRenderTexture() +{ + if (useNodes) + { +/* if (curNode < 0) + { + if (curstate == true) + { + curstate = false; + + for (int i = 1; i < numnodes;i++) + { + node_mesh[i]->SetGroupTexture(0, NULL); + FM_ShowNodeFrame(&mainModel, curframe, i); + } + } + else + { + curstate = true; + + for (int i = 1; i < numnodes;i++) + { + if (curNode > -1) + { + node_mesh[i]->SetGroupTexture(0, node_texture[curNode]); + FM_ShowNodeFrame(&mainModel, curframe, i); + } + } + } + } + else + { + node_mesh[curNode]->SetGroupTexture(0, texture); + FM_ShowNodeFrame(&mainModel, curframe, curNode); + }*/ + } + + if (mesh) + { + if (curstate == TRUE) + { + curstate = FALSE; + mesh->SetGroupTexture( group, NULL ); + } + else + { + curstate = TRUE; + mesh->SetGroupTexture( group, texture ); + } + MDL_ShowFrame(&mainModel, curframe); + } +} + +void CChildFrame::OnUpdateRenderTexture(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(curstate); +} + +void CChildFrame::OnRenderTrans() +{ + transtate = !transtate; + + texture->SetDecalTransparency( transtate ); + + mesh->SetGroupTexture( group, NULL ); + mesh->SetGroupTexture( group, texture ); + + MDL_ShowFrame(&mainModel, curframe); +} + +void CChildFrame::OnUpdateRenderTrans(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(transtate); +} + +void CChildFrame::OnRenderWireframe() +{ + if (useNodes) + { + if (curNode < 0) + { + for (int i = 1; i < numnodes;i++) + { + node_mesh[i]->SetGroupQuality(0, D3DRMRENDER_WIREFRAME); + FM_ShowNodeFrame(&mainModel, curframe, i); + } + } + else + { + node_mesh[curNode]->SetGroupQuality(0, D3DRMRENDER_WIREFRAME); + FM_ShowNodeFrame(&mainModel, curframe, curNode); + } + } + else + { + mesh->SetGroupQuality(group, D3DRMRENDER_WIREFRAME); + MDL_ShowFrame(&mainModel, curframe); + } +} + +void CChildFrame::OnUpdateRenderWireframe(CCmdUI* pCmdUI) +{ +} + +void CChildFrame::OnSkinExport() +{ + // TODO: Add your command handler code here + +} + +void CChildFrame::OnSkinImport() +{ + if (useNodes) + return; + + CFileDialog fdOpenFile(TRUE,"*.pcx;*.m8",NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST, "Supported Formats|*.pcx;*.m8|PCX File (*.pcx)|*.pcx|M8 File (*.m8)|*.m8||", this); + + if (fdOpenFile.DoModal()==IDOK) + { + CString strHelp = fdOpenFile.GetPathName(); + CString strExt = fdOpenFile.GetFileExt(); + + LPSTR szHelp= strHelp.GetBuffer(10); + LPSTR szExt = strExt.GetBuffer(10); + + if (!stricmp(szExt, "pcx")) + { + if (!MDL_LoadSkinFromPCX(szHelp, &mainModel)) + { + AfxMessageBox("Could not load PCX"); + } + } + else if (!stricmp(szExt, "m8")) + { + if (!FM_LoadSkinFromFile(szHelp)) + { + AfxMessageBox("Could not load M8"); + } + } + + texture->Changed(true, true); + + mesh->SetGroupTexture( group, NULL ); + mesh->SetGroupTexture( group, texture ); + + if (mainModel.modelType == MODEL_FLEX) + FM_ShowFrame(&mainModel, curframe); + else + MDL_ShowFrame(&mainModel, curframe); + } +} + +LRESULT CChildFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + return CMDIChildWnd::WindowProc(message, wParam, lParam); +} + +int PickFace( const CPoint &point) +{ + HRESULT r; + LPDIRECT3DRMPICKEDARRAY pickarray; + + viewport->Pick(point.x, point.y, &pickarray); + + int faceindex=-1; + DWORD numpicks=pickarray->GetSize(); + + if(numpicks>0) + { + LPDIRECT3DRMVISUAL visual; + LPDIRECT3DRMFRAMEARRAY framearray; + D3DRMPICKDESC pickdesc; + + r=pickarray->GetPick( 0, &visual, &framearray, &pickdesc ); + if(r==D3DRM_OK) + { + faceindex=pickdesc.ulFaceIdx; + visual->Release(); + visual = NULL; + framearray->Release(); + framearray = NULL; + } + } + pickarray->Release(); + pickarray = NULL; + + return faceindex; +} + +void CChildFrame::PickMesh(CPoint point) +{ + HRESULT r; + LPDIRECT3DRMPICKEDARRAY pickarray; + + viewport->Pick(point.x, point.y, &pickarray); + + int faceindex=-1; + DWORD numpicks=pickarray->GetSize(); + + if(numpicks>0) + { + LPDIRECT3DRMVISUAL visual; + LPDIRECT3DRMFRAMEARRAY framearray; + D3DRMPICKDESC pickdesc; + + r=pickarray->GetPick( 0, &visual, &framearray, &pickdesc ); + + if(r==D3DRM_OK) + { + for (int i = 1; i < numnodes; i++) + { + if (node_mesh[i] == visual) + { + for (int j = 1; j < numnodes; j++) + { + node_mesh[j]->SetGroupColorRGB( 0, 255, 255, 255); + } + + node_mesh[i]->SetGroupColorRGB( 0, 255, 0, 0); + curNode = i; + + CTreeCtrl *pCTree = (CTreeCtrl*)m_wndFrameManager2.GetDlgItem(IDC_NODETREE); + pCTree->Select(nodes[i],TVGN_CARET); + break; + } + } + + visual->Release(); + visual = NULL; + framearray->Release(); + framearray = NULL; + } + } + pickarray->Release(); + pickarray = NULL; +} + +void CChildFrame::OnLButtonDown(UINT nFlags, CPoint point) +{ + SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_HAND_CLOSED))); + + if (PICK_ON && useNodes) + { + PickMesh(point); + CMDIChildWnd::OnLButtonDown(nFlags, point); + return; + } + + if (!drag) + { + drag=TRUE; + last_x = GetMouseX(); + last_y = GetMouseY(); + SetCapture(); + //ShowCursor(FALSE); + } + + CMDIChildWnd::OnLButtonDown(nFlags, point); +} + +void CChildFrame::OnLButtonUp(UINT nFlags, CPoint point) +{ + SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_HAND_OPEN))); + + if (drag) + { + double delta_x = GetMouseX() - last_x; + double delta_y = GetMouseY() - last_y; + + if (!delta_x && !delta_y) + { + if (!has_moved) + { + curscale += 5; + camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(curscale)); + } + else + has_moved = FALSE; + } + + end_drag=TRUE; + ReleaseCapture(); + } + else + + CMDIChildWnd::OnLButtonUp(nFlags, point); +} + +void CChildFrame::OnRButtonDown(UINT nFlags, CPoint point) +{ + SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_HAND_CLOSED))); + + if (!r_drag) + { + r_drag=TRUE; + r_last_x = GetMouseX(); + r_last_y = GetMouseY(); + SetCapture(); + //ShowCursor(FALSE); + } + + CMDIChildWnd::OnRButtonDown(nFlags, point); +} + +void CChildFrame::OnRButtonUp(UINT nFlags, CPoint point) +{ + SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_HAND_OPEN))); + + if (r_drag && (mesh || useNodes)) + { + double delta_x = GetMouseX() - r_last_x; + double delta_y = GetMouseY() - r_last_y; + + if (!delta_x && !delta_y) + { + if (!r_has_moved) + { + curscale -= 5; + camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(curscale)); + } + else + r_has_moved = FALSE; + } + + r_end_drag=TRUE; + ReleaseCapture(); + } + + CMDIChildWnd::OnRButtonUp(nFlags, point); +} + +void CChildFrame::OnFileOpen() +{ + CTreeCtrl* treeDlg = (CTreeCtrl*)m_wndFrameTreeDlg.GetDlgItem(IDC_FRAMETREE); + CFileDialog fdOpenFile(TRUE,"*.md2;*.fm;*.mdl",NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST, "Supported Formats|*.md2;*.fm;*.mdl|Quake2 Models (*.md2)|*.md2|Flex Models (*.fm)|*.fm|All Files (*.*)|*.*||", this); + + if (fdOpenFile.DoModal()==IDOK) + { + CString strHelp = fdOpenFile.GetPathName(); + CString strExt = fdOpenFile.GetFileExt(); + + LPSTR szHelp= strHelp.GetBuffer(10); + LPSTR szExt = strExt.GetBuffer(10); + + if (frame && (mesh||useNodes)) + { + frame->SetPosition( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1) ); + + MDL_Free(&mainModel); + + if (useNodes) + { + useNodes = false; + curNode = -1; + for (int i = 1; i < numnodes; i++) + { + frame->DeleteVisual(node_mesh[i]); + node_mesh[i]->Release(); + node_mesh[i] = 0; + } + } + else if (mesh) + { + frame->DeleteVisual(mesh); + mesh->Release(); + mesh = 0; + } + + if (frameUp) + { + if (treeInfo != NULL) delete treeInfo; + if (frameIndex != NULL) delete frameIndex; + + treeDlg->DeleteAllItems(); + rootFrame = treeDlg->InsertItem("Animations", TVI_ROOT, TVI_LAST); + + treeDlg = (CTreeCtrl*)m_wndFrameTreeDlg.GetDlgItem(IDC_SKINTREE); + treeDlg->DeleteAllItems(); + rootSkin = treeDlg->InsertItem("Skins", TVI_ROOT, TVI_LAST); + + treeDlg = (CTreeCtrl*)m_wndFrameManager2.GetDlgItem(IDC_NODETREE); + treeDlg->DeleteAllItems(); + rootNode = treeDlg->InsertItem("Nodes", TVI_ROOT, TVI_LAST); + + treeDlg = (CTreeCtrl*)m_wndFrameManager2.GetDlgItem(IDC_JOINTTREE); + treeDlg->DeleteAllItems(); + rootJoint = treeDlg->InsertItem("Joint", TVI_ROOT, TVI_LAST); + + frameUp = FALSE; + } + } + + if (!stricmp(szExt, "md2")) + { + mainModel.modelType = MODEL_QUAKE2; + mainModelType = MODEL_QUAKE2; + MDL2_LoadFromFile(szHelp); + LoadModelFrameInfo(MODEL_QUAKE2); + LoadModelSkinInfo(); + } + else if (!stricmp(szExt, "fm")) + { + mainModel.modelType = MODEL_FLEX; + mainModelType = MODEL_FLEX; + FM_LoadFromFile(szHelp); + LoadModelFrameInfo(MODEL_FLEX); + LoadModelSkinInfo(); + } + else + { + mainModel.modelType = MODEL_QUAKE; + mainModelType = MODEL_QUAKE; + MDL_LoadFromFile(szHelp); + LoadModelFrameInfo(MODEL_QUAKE); + LoadModelSkinInfo(); + + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); + } + } +} + +void StripExt(char *gname) +{ + int len = strlen(gname); + char newname[256]; + + memset(newname, 0, sizeof(newname)); + + for (int i = 0; i < len; i++) + { + if (gname[i]=='.') break; + else newname[i] = gname[i]; + } + + strcpy(gname, newname); +} + +void CChildFrame::LoadModelSkinInfo() +{ + CTreeCtrl* pCTree = (CTreeCtrl*)m_wndFrameTreeDlg.GetDlgItem(IDC_SKINTREE); + char *newname; + char name[256]; + HTREEITEM point; + + struct _finddata_t c_file; + long hFile; + + if (mainModel.modelType == MODEL_QUAKE) + { + if (mainModel.header->numskins > 1) + { + frameUp = TRUE; + + if (skinTreeInfo.skins) delete skinTreeInfo.skins; + + skinTreeInfo.skins = new skinItem[mainModel.header->numskins]; + skinTreeInfo.numskins = mainModel.header->numskins; + + for (int i = 0; i < mainModel.header->numskins; i++) + { + sprintf(name, "skin%d", i); + point = pCTree->InsertItem(name, rootSkin, TVI_LAST); + pCTree->SetItemImage(point, 0, 0); + skinTreeInfo.skins[i].pointer = point; + skinTreeInfo.skins[i].type = 0; + skinTreeInfo.skins[i].skin_num = i; + } + } + } + + if( (hFile = _findfirst( "*.pcx", &c_file )) == -1L ) + return; + else + { + frameUp = TRUE; + + strcpy(name , c_file.name); + newname = (char *)&name; + //StripExt(newname); + + point = pCTree->InsertItem(newname, rootSkin, TVI_LAST); + pCTree->SetItemImage(point, 1, 1); + while( _findnext( hFile, &c_file ) == 0 ) + { + strcpy(name , c_file.name); + newname = (char *)&name; + //StripExt(newname); + point = pCTree->InsertItem(newname, rootSkin, TVI_LAST); + pCTree->SetItemImage(point, 1, 1); + } + + _findclose( hFile ); + } + + if( (hFile = _findfirst( "*.m8", &c_file )) == -1L ) + return; + else + { + strcpy(name , c_file.name); + newname = (char *)&name; + //StripExt(newname); + + point = pCTree->InsertItem(newname, rootSkin, TVI_LAST); + pCTree->SetItemImage(point, 1, 1); + while( _findnext( hFile, &c_file ) == 0 ) + { + strcpy(name , c_file.name); + newname = (char *)&name; + //StripExt(newname); + point = pCTree->InsertItem(newname, rootSkin, TVI_LAST); + pCTree->SetItemImage(point, 1, 1); + } + + _findclose( hFile ); + } + + pCTree->Expand(rootSkin, TVE_EXPAND); +} + +/* + * inGroupList + * + * Checks if this frame belongs to a frame group + * + */ +int inGroupList(char *test) +{ + for (int i = 0; i < numGroups; i++) + { + if (!strcmp(test, groupList[i].id)) return i; + } + + strcpy(groupList[numGroups].id, test); + numGroups++; + + return -1; +} + +/* + * stringGroupName + * + * Strips off any numbers and returns the group identifier + * + */ +void stripGroupName(char *gname) +{ + int len = strlen(gname); + char newname[16]; + + memset(newname, 0, sizeof(newname)); + + for (int i = 0; i < len; i++) + { + if (isdigit((int)gname[i])) break; + else newname[i] = gname[i]; + } + + strcpy(gname, newname); +} + +void CChildFrame::LoadModelFrameInfo(int modelType) +{ + int curgroup = 0, thisgroup = 0; + char name[16], *newname; + HTREEITEM point; + frameinfo2_t *frameinfo1; + CTreeCtrl* treeDlg = (CTreeCtrl*)m_wndFrameTreeDlg.GetDlgItem(IDC_FRAMETREE); + + if (modelType == MODEL_QUAKE) + { + if (mainModel.header->numframes < 2) return; + + numGroups = 0; + frameUp = TRUE; + + treeInfo = new treehead_t[mainModel.header->numframes]; + if (treeInfo == NULL) Error("Null tree"); + + groupList = new framegroup_t[mainModel.header->numframes]; + if (groupList == NULL) Error("Null groupList"); + + frameIndex = new HTREEITEM[mainModel.header->numframes]; + if (frameIndex == NULL) Error("Null frameIndex"); + + for (int i = 0; i < mainModel.header->numframes; i++) + { + if (mainModel.frames[i].type == 1) + { + AfxMessageBox("Tricky Frames not supported!\n"); + } + else + { + strcpy(name , mainModel.frames[i].info->name); + newname = (char *)&name; + stripGroupName(newname); + + if ((thisgroup = inGroupList(newname)) == -1) + { + point = treeDlg->InsertItem(newname, rootFrame, TVI_LAST); + + frameIndex[i] = point; + treeInfo[curgroup].head = point; + treeInfo[curgroup].bFrame = i; + treeInfo[curgroup].eFrame = i; + point = treeDlg->InsertItem(mainModel.frames[i].info->name, point, TVI_LAST); + frameIndex[i] = point; + treeDlg->SetItemImage(point, 1, 1); + + curgroup++; + } + else + { + if (i > treeInfo[thisgroup].eFrame) + treeInfo[thisgroup].eFrame = i; + + point = treeDlg->InsertItem(mainModel.frames[i].info->name, treeInfo[thisgroup].head, TVI_LAST); + treeDlg->SetItemImage(point, 1, 1); + frameIndex[i] = point; + } + } + } + if (frameUp) + { + if (groupList) delete groupList; + treeDlg->Expand(rootFrame, TVE_EXPAND); + } + } + else if (mainModelType == MODEL_QUAKE2) + { + if (mainModel.header2->num_frames > 1) + { + numGroups = 0; + frameUp = TRUE; + + treeInfo = new treehead_t[mainModel.header2->num_frames]; + if (treeInfo == NULL) Error("Null tree"); + + groupList = new framegroup_t[mainModel.header2->num_frames]; + if (groupList == NULL) Error("Null groupList"); + + frameIndex = new HTREEITEM[mainModel.header2->num_frames]; + if (frameIndex == NULL) Error("Null frameIndex"); + + for (int i = 0; i < mainModel.header2->num_frames; i++) + { + frameinfo1 = (frameinfo2_t *)((char *)mainModel.frames2 + mainModel.header2->framesize * i); + strcpy(name , frameinfo1->name); + newname = (char *)&name; + stripGroupName(newname); + if ((thisgroup = inGroupList(newname)) == -1) + { + point = treeDlg->InsertItem(newname, rootFrame, TVI_LAST); + + frameIndex[i] = point; + treeInfo[curgroup].head = point; + treeInfo[curgroup].bFrame = i; + treeInfo[curgroup].eFrame = i; + HTREEITEM temp = treeDlg->InsertItem(frameinfo1->name, point, TVI_LAST); + frameIndex[i] = temp; + treeDlg->SetItemImage(temp, 1, 1); + curgroup++; + } + else + { + if (i > treeInfo[thisgroup].eFrame) + treeInfo[thisgroup].eFrame = i; + + point = treeDlg->InsertItem(frameinfo1->name, treeInfo[thisgroup].head, TVI_LAST); + treeDlg->SetItemImage(point, 1, 1); + frameIndex[i] = point; + } + } + if (frameUp) + { + if (groupList) delete groupList; + treeDlg->Expand(rootFrame, TVE_EXPAND); + } + } + } + else + { + if (mainModel.flex.header.num_frames > 1) + { + numGroups = 0; + frameUp = TRUE; + + treeInfo = new treehead_t[mainModel.flex.header.num_frames]; + if (treeInfo == NULL) Error("Null tree"); + + groupList = new framegroup_t[mainModel.flex.header.num_frames]; + if (groupList == NULL) Error("Null groupList"); + + frameIndex = new HTREEITEM[mainModel.flex.header.num_frames]; + if (frameIndex == NULL) Error("Null frameIndex"); + + for (int i = 0; i < mainModel.flex.header.num_frames; i++) + { + frameinfo1 = (frameinfo2_t *)((char *)mainModel.flex.frames + mainModel.flex.header.framesize * i); + strcpy(name , frameinfo1->name); + newname = (char *)&name; + stripGroupName(newname); + if ((thisgroup = inGroupList(newname)) == -1) + { + point = treeDlg->InsertItem(newname, rootFrame, TVI_LAST); + + frameIndex[i] = point; + treeInfo[curgroup].head = point; + treeInfo[curgroup].bFrame = i; + treeInfo[curgroup].eFrame = i; + HTREEITEM temp = treeDlg->InsertItem(frameinfo1->name, point, TVI_LAST); + frameIndex[i] = temp; + treeDlg->SetItemImage(temp, 1, 1); + curgroup++; + } + else + { + if (i > treeInfo[thisgroup].eFrame) + treeInfo[thisgroup].eFrame = i; + + point = treeDlg->InsertItem(frameinfo1->name, treeInfo[thisgroup].head, TVI_LAST); + treeDlg->SetItemImage(point, 1, 1); + frameIndex[i] = point; + } + } + if (frameUp) + { + if (groupList) delete groupList; + treeDlg->Expand(rootFrame, TVE_EXPAND); + } + } + } +} + +void CChildFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (nChar == VK_SHIFT) + { + LSHFT_DN = TRUE; + } + + if (nFlags & MK_CONTROL) + { + ZOOM_ON = TRUE; + } + + if (LSHFT_DN && ZOOM_ON) + { + PICK_ON = true; + } + + CMDIChildWnd::OnKeyDown(nChar, nRepCnt, nFlags); +} + +void CChildFrame::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (nChar == VK_SHIFT) + { + PICK_ON = false; + LSHFT_DN = FALSE; + } + + if (nFlags & MK_CONTROL) + { + PICK_ON = false; + ZOOM_ON = false; + } + + CMDIChildWnd::OnKeyUp(nChar, nRepCnt, nFlags); +} + +void CChildFrame::OnGotoposWeapon() +{ + frame->SetPosition( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-50) ); + + frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); + + viewport->SetField(D3DVALUE(globalField)); +} + +void CChildFrame::OnFieldPlus() +{ + globalField += 0.1; + viewport->SetField(D3DVALUE(globalField)); + MDL_ShowFrame(&mainModel, curframe); +} + +void CChildFrame::OnFieldMinus() +{ + globalField -= 0.1; + viewport->SetField(D3DVALUE(globalField)); + MDL_ShowFrame(&mainModel, curframe); +} + +void CChildFrame::OnTickerOptions() +{ + CTickerDlg tDlg; + + if (tDlg.DoModal()==IDOK) + { + frameTickIncr = tDlg.m_nTickerDelay; + tickerOn = tDlg.m_nUseTicker; + } +} diff --git a/Toolkit/Programming/Tools/qMView/ChildFrm.h b/Toolkit/Programming/Tools/qMView/ChildFrm.h new file mode 100644 index 0000000..813d35b --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/ChildFrm.h @@ -0,0 +1,155 @@ +// ChildFrm.h : interface of the CChildFrame class +// +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +class CChildFrame : public CMDIChildWnd +{ + DECLARE_DYNCREATE(CChildFrame) +public: + CChildFrame(); + BOOL Create(LPCTSTR szTitle, LONG style = 0,const RECT& rect = rectDefault,CMDIFrameWnd* pParent = NULL); + + static void UpdateDrag(LPDIRECT3DRMFRAME frame, void*, D3DVALUE); + + void LoadModelFrameInfo(int modelType); + void LoadModelSkinInfo(); + + GUID* GetGUID(); + BOOL CreateScene(); + D3DVALUE ScaleMesh( LPDIRECT3DRMMESHBUILDER mesh, D3DVALUE dim); + + void PickMesh(CPoint point); + + void SetColorModel( D3DCOLORMODEL cm ) { colormodel=cm; } + inline COLORREF D3DCOLOR_2_COLORREF(D3DCOLOR d3dclr); + inline D3DCOLOR COLORREF_2_D3DCOLOR(COLORREF cref); + + D3DCOLORMODEL colormodel; + CRect winrect; + +// Attributes +public: + +// Operations +public: + BOOL CreateDevice(); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CChildFrame) + public: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + protected: + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CChildFrame(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +// Generated message map functions +protected: + static CMenu NEAR menu; + + //{{AFX_MSG(CChildFrame) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnPaint(); + afx_msg void OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd* pDeactivateWnd); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnDestroy(); + afx_msg void OnAllLock(); + afx_msg void OnAllUnlock(); + afx_msg void OnAnimatePlay(); + afx_msg void OnUpdateAnimatePlay(CCmdUI* pCmdUI); + afx_msg void OnAnimateStepBack(); + afx_msg void OnAnimateStepFore(); + afx_msg void OnAnimateStop(); + afx_msg void OnUpdateAnimateStop(CCmdUI* pCmdUI); + afx_msg void OnAnimateTypeBack(); + afx_msg void OnUpdateAnimateTypeBack(CCmdUI* pCmdUI); + afx_msg void OnAnimateTypeFront(); + afx_msg void OnUpdateAnimateTypeFront(CCmdUI* pCmdUI); + afx_msg void OnAnimateTypePingpong(); + afx_msg void OnUpdateAnimateTypePingpong(CCmdUI* pCmdUI); + afx_msg void OnFrameExport(); + afx_msg void OnFrameImport(); + afx_msg void OnGotoposBack(); + afx_msg void OnGotoposBottom(); + afx_msg void OnGotoposFront(); + afx_msg void OnGotoposLeft(); + afx_msg void OnGotoposRight(); + afx_msg void OnGotoposTop(); + afx_msg void OnLockRotX(); + afx_msg void OnUpdateLockRotX(CCmdUI* pCmdUI); + afx_msg void OnLockRotY(); + afx_msg void OnUpdateLockRotY(CCmdUI* pCmdUI); + afx_msg void OnLockRotZ(); + afx_msg void OnUpdateLockRotZ(CCmdUI* pCmdUI); + afx_msg void OnLockScaleX(); + afx_msg void OnUpdateLockScaleX(CCmdUI* pCmdUI); + afx_msg void OnLockScaleY(); + afx_msg void OnUpdateLockScaleY(CCmdUI* pCmdUI); + afx_msg void OnLockScaleZ(); + afx_msg void OnUpdateLockScaleZ(CCmdUI* pCmdUI); + afx_msg void OnLockTranX(); + afx_msg void OnUpdateLockTranX(CCmdUI* pCmdUI); + afx_msg void OnLockTranY(); + afx_msg void OnUpdateLockTranY(CCmdUI* pCmdUI); + afx_msg void OnLockTranZ(); + afx_msg void OnUpdateLockTranZ(CCmdUI* pCmdUI); + afx_msg void OnPaletteExport(); + afx_msg void OnPaletteImport(); + afx_msg void OnRenderFlat(); + afx_msg void OnUpdateRenderFlat(CCmdUI* pCmdUI); + afx_msg void OnRenderGouraud(); + afx_msg void OnUpdateRenderGouraud(CCmdUI* pCmdUI); + afx_msg void OnRenderTexture(); + afx_msg void OnUpdateRenderTexture(CCmdUI* pCmdUI); + afx_msg void OnRenderTrans(); + afx_msg void OnUpdateRenderTrans(CCmdUI* pCmdUI); + afx_msg void OnRenderWireframe(); + afx_msg void OnUpdateRenderWireframe(CCmdUI* pCmdUI); + afx_msg void OnSkinExport(); + afx_msg void OnSkinImport(); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnRButtonUp(UINT nFlags, CPoint point); + afx_msg void OnFileOpen(); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnGotoposWeapon(); + afx_msg void OnFieldPlus(); + afx_msg void OnFieldMinus(); + afx_msg void OnTickerOptions(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +inline D3DCOLOR CChildFrame::COLORREF_2_D3DCOLOR(COLORREF cref) +{ + D3DVALUE r=D3DVALUE(GetRValue(cref))/D3DVALUE(255); + D3DVALUE g=D3DVALUE(GetGValue(cref))/D3DVALUE(255); + D3DVALUE b=D3DVALUE(GetBValue(cref))/D3DVALUE(255); + return D3DRMCreateColorRGB( r, g, b ); +} + +inline COLORREF CChildFrame::D3DCOLOR_2_COLORREF(D3DCOLOR d3dclr) +{ + D3DVALUE red=D3DVALUE(255)*D3DRMColorGetRed(d3dclr); + D3DVALUE green=D3DVALUE(255)*D3DRMColorGetGreen( d3dclr ); + D3DVALUE blue=D3DVALUE(255)*D3DRMColorGetBlue( d3dclr ); + return RGB((int)red,(int)green,(int)blue); +} + +///////////////////////////////////////////////////////////////////////////// diff --git a/Toolkit/Programming/Tools/qMView/Ddutil.cpp b/Toolkit/Programming/Tools/qMView/Ddutil.cpp new file mode 100644 index 0000000..51f69af --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Ddutil.cpp @@ -0,0 +1,420 @@ +/*========================================================================== + * + * Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved. + * + * File: ddutil.cpp + * Content: Routines for loading bitmap and palettes from resources + * + ***************************************************************************/ +#undef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#include "stdafx.h" +#include "ddutil.h" + +LPDIRECTDRAW CDDHelper::lpDD; + +CRGB16* CDDHelper::CreateRGB16 ( LPDIRECTDRAWSURFACE Surface) +{ + DDSURFACEDESC ddsd; + BYTE shiftcount; + //get a surface despriction + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_PIXELFORMAT; + if (Surface->GetSurfaceDesc ( &ddsd ) != DD_OK ) + return FALSE; + //get red + shiftcount = 0; + CRGB16* rgb16 = new CRGB16(); + while ( !(ddsd.ddpfPixelFormat.dwRBitMask & 1) ) + { + ddsd.ddpfPixelFormat.dwRBitMask >>= 1; + shiftcount++; + } + rgb16->depth.rgbRed = (BYTE) ddsd.ddpfPixelFormat.dwRBitMask; + rgb16->Position.rgbRed = shiftcount; + rgb16->Amount.rgbRed = (ddsd.ddpfPixelFormat.dwRBitMask + == 0x1f) ? 3 : 2; + //get green + shiftcount = 0; + while ( !(ddsd.ddpfPixelFormat.dwGBitMask & 1) ) + { + ddsd.ddpfPixelFormat.dwGBitMask >>= 1; + shiftcount++; + } + rgb16->depth.rgbGreen =(BYTE)ddsd.ddpfPixelFormat.dwGBitMask; + rgb16->Position.rgbGreen = shiftcount; + rgb16->Amount.rgbGreen = (ddsd.ddpfPixelFormat.dwGBitMask + == 0x1f) ? 3 : 2; + //get Blue + shiftcount = 0; + while ( !(ddsd.ddpfPixelFormat.dwBBitMask & 1) ) + { + ddsd.ddpfPixelFormat.dwBBitMask >>= 1; + shiftcount++; + } + rgb16->depth.rgbBlue =(BYTE)ddsd.ddpfPixelFormat.dwBBitMask; + rgb16->Position.rgbBlue = shiftcount; + rgb16->Amount.rgbBlue = (ddsd.ddpfPixelFormat.dwBBitMask + == 0x1f) ? 3 : 2; + return rgb16; +} + +/* + * DDLoadBitmap + * + * create a DirectDrawSurface from a bitmap resource. + * + */ +IDirectDrawSurface * CDDHelper::DDLoadBitmap(LPCSTR szBitmap, int dx, int dy) +{ + HBITMAP hbm; + BITMAP bm; + DDSURFACEDESC ddsd; + IDirectDrawSurface *pdds; + + // + // try to load the bitmap as a resource, if that fails, try it as a file + // + hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, dx, dy, LR_CREATEDIBSECTION); + + if (hbm == NULL) + hbm = (HBITMAP)LoadImage(NULL, szBitmap, IMAGE_BITMAP, dx, dy, LR_LOADFROMFILE|LR_CREATEDIBSECTION); + + if (hbm == NULL) + return NULL; + + // + // get size of the bitmap + // + GetObject(hbm, sizeof(bm), &bm); // get size of bitmap + + // + // create a DirectDrawSurface for this bitmap + // + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + ddsd.dwWidth = bm.bmWidth; + ddsd.dwHeight = bm.bmHeight; + + if (lpDD->CreateSurface(&ddsd, &pdds, NULL) != DD_OK) + return NULL; + + DDCopyBitmap(pdds, hbm, 0, 0, 0, 0); + + DeleteObject(hbm); + + return pdds; +} + +/* + * DDReLoadBitmap + * + * load a bitmap from a file or resource into a directdraw surface. + * normaly used to re-load a surface after a restore. + * + */ +HRESULT CDDHelper::DDReLoadBitmap(IDirectDrawSurface *pdds, LPCSTR szBitmap) +{ + HBITMAP hbm; + HRESULT hr; + + // + // try to load the bitmap as a resource, if that fails, try it as a file + // + hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + + if (hbm == NULL) + hbm = (HBITMAP)LoadImage(NULL, szBitmap, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); + + if (hbm == NULL) + { + OutputDebugString("handle is null\n"); + return E_FAIL; + } + + hr = DDCopyBitmap(pdds, hbm, 0, 0, 0, 0); + if (hr != DD_OK) + { + OutputDebugString("ddcopybitmap failed\n"); + } + + + DeleteObject(hbm); + return hr; +} + +/* + * DDCopyBitmap + * + * draw a bitmap into a DirectDrawSurface + * + */ +HRESULT CDDHelper::DDCopyBitmap(IDirectDrawSurface *pdds, HBITMAP hbm, int x, int y, int dx, int dy) +{ + HDC hdcImage; + HDC hdc; + BITMAP bm; + DDSURFACEDESC ddsd; + HRESULT hr; + + if (hbm == NULL || pdds == NULL) + return E_FAIL; + + // + // make sure this surface is restored. + // + pdds->Restore(); + + // + // select bitmap into a memoryDC so we can use it. + // + hdcImage = CreateCompatibleDC(NULL); + if (!hdcImage) + OutputDebugString("createcompatible dc failed\n"); + SelectObject(hdcImage, hbm); + + // + // get size of the bitmap + // + GetObject(hbm, sizeof(bm), &bm); // get size of bitmap + dx = dx == 0 ? bm.bmWidth : dx; // use the passed size, unless zero + dy = dy == 0 ? bm.bmHeight : dy; + + // + // get size of surface. + // + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; + pdds->GetSurfaceDesc(&ddsd); + + if ((hr = pdds->GetDC(&hdc)) == DD_OK) + { + StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, x, y, dx, dy, SRCCOPY); + pdds->ReleaseDC(hdc); + } + + DeleteDC(hdcImage); + + return hr; +} + +// +// DDLoadPalette +// +// Create a DirectDraw palette object from a bitmap resoure +// +// if the resource does not exist or NULL is passed create a +// default 332 palette. +// +IDirectDrawPalette * CDDHelper::DDLoadPalette(LPCSTR szBitmap) +{ + IDirectDrawPalette* ddpal; + int i; + int n; + int fh; + HRSRC h; + LPBITMAPINFOHEADER lpbi; + PALETTEENTRY ape[256]; + RGBQUAD * prgb; + + // + // build a 332 palette as the default. + // + for (i=0; i<256; i++) + { + ape[i].peRed = (BYTE)(((i >> 5) & 0x07) * 255 / 7); + ape[i].peGreen = (BYTE)(((i >> 2) & 0x07) * 255 / 7); + ape[i].peBlue = (BYTE)(((i >> 0) & 0x03) * 255 / 3); + ape[i].peFlags = (BYTE)0; + } + + // + // get a pointer to the bitmap resource. + // + if (szBitmap && (h = FindResource(NULL, szBitmap, RT_BITMAP))) + { + lpbi = (LPBITMAPINFOHEADER)LockResource(LoadResource(NULL, h)); + if (!lpbi) + OutputDebugString("lock resource failed\n"); + prgb = (RGBQUAD*)((BYTE*)lpbi + lpbi->biSize); + + if (lpbi == NULL || lpbi->biSize < sizeof(BITMAPINFOHEADER)) + n = 0; + else if (lpbi->biBitCount > 8) + n = 0; + else if (lpbi->biClrUsed == 0) + n = 1 << lpbi->biBitCount; + else + n = lpbi->biClrUsed; + + // + // a DIB color table has its colors stored BGR not RGB + // so flip them around. + // + for(i=0; i 8) + n = 0; + else if (bi.biClrUsed == 0) + n = 1 << bi.biBitCount; + else + n = bi.biClrUsed; + + // + // a DIB color table has its colors stored BGR not RGB + // so flip them around. + // + for(i=0; iCreatePalette(DDPCAPS_8BIT, ape, &ddpal, NULL); + + return ddpal; +} + +/* + * DDColorMatch + * + * convert a RGB color to a pysical color. + * + * we do this by leting GDI SetPixel() do the color matching + * then we lock the memory and see what it got mapped to. + */ +DWORD CDDHelper::DDColorMatch(IDirectDrawSurface *pdds, COLORREF rgb) +{ + COLORREF rgbT; + HDC hdc; + DWORD dw = CLR_INVALID; + DDSURFACEDESC ddsd; + HRESULT hres; + + // + // use GDI SetPixel to color match for us + // + if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) + { + rgbT = GetPixel(hdc, 0, 0); // save current pixel value + SetPixel(hdc, 0, 0, rgb); // set our value + pdds->ReleaseDC(hdc); + } + + // + // now lock the surface so we can read back the converted color + // + ddsd.dwSize = sizeof(ddsd); + while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING) + ; + + if (hres == DD_OK) + { + dw = *(DWORD *)ddsd.lpSurface; // get DWORD + dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1; // mask it to bpp + pdds->Unlock(NULL); + } + + // + // now put the color that was there back. + // + if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) + { + SetPixel(hdc, 0, 0, rgbT); + pdds->ReleaseDC(hdc); + } + + return dw; +} + +/* + * DDSetColorKey + * + * set a color key for a surface, given a RGB. + * if you pass CLR_INVALID as the color key, the pixel + * in the upper-left corner will be used. + */ +HRESULT CDDHelper::DDSetColorKey(IDirectDrawSurface *pdds, COLORREF rgb) +{ + DDCOLORKEY ddck; + + ddck.dwColorSpaceLowValue = DDColorMatch(pdds, rgb); + ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue; + return pdds->SetColorKey(DDCKEY_SRCBLT, &ddck); +} + +static char out[256]; + +char * CDDHelper::TraceError(HRESULT ddrval) +{ + switch(ddrval) + { + case D3DRM_OK : break; + case D3DRMERR_BADALLOC : + return("Out of Memory"); + break; + case D3DRMERR_BADDEVICE : + return("Device is not compatible with render"); + break; + case D3DRMERR_BADFILE : + return("Data file is corrupt"); + break; + case D3DRMERR_BADMAJORVERSION : + return("Bad DLL major version"); + break; + case D3DRMERR_BADMINORVERSION : + return("Bad DLL minor version"); + break; + case D3DRMERR_BADOBJECT : + return("Object expected in argument"); + break; + case D3DRMERR_BADTYPE : + return("Bad argument type passed"); + break; + case D3DRMERR_BADVALUE : + return("Bad argument value passed"); + break; + case D3DRMERR_FACEUSED : + return("Face already used in a mesh"); + break; + case D3DRMERR_FILENOTFOUND : + return("File cannot be opened"); + break; + case D3DRMERR_NOTDONEYET : + return("Unimplemented"); + break; + case D3DRMERR_NOTFOUND : + return("Object not found in specified place"); + break; + case D3DRMERR_UNABLETOEXECUTE : + return("Unable to carry out procedure"); + break; + + } + + sprintf(out, "Unknown: %d", ddrval); + return (out); +} + diff --git a/Toolkit/Programming/Tools/qMView/Ddutil.h b/Toolkit/Programming/Tools/qMView/Ddutil.h new file mode 100644 index 0000000..c106653 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Ddutil.h @@ -0,0 +1,58 @@ +/*========================================================================== + * + * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved. + * + * File: ddutil.cpp + * Content: Routines for loading bitmap and palettes from resources + * + ***************************************************************************/ + +#define PI 3.141592654 + +typedef float vec_t[3]; + +typedef unsigned char u_char; + +typedef float scalar_t; +typedef BOOL qboolean; + +typedef struct +{ + scalar_t x; + scalar_t y; + scalar_t z; +} vec3_t; + +typedef struct +{ + scalar_t x; + scalar_t y; + scalar_t z; + scalar_t s; + scalar_t t; +} vec5_t; + +class CRGB16 +{ +public: + RGBQUAD depth; + RGBQUAD Amount; + RGBQUAD Position; +}; + +class CDDHelper +{ +public: + static LPDIRECTDRAW lpDD; + + static CRGB16* CreateRGB16 (LPDIRECTDRAWSURFACE Surface); + static IDirectDrawPalette * DDLoadPalette(LPCSTR szBitmap); + static IDirectDrawSurface * DDLoadBitmap(LPCSTR szBitmap, int dx, int dy); + static HRESULT DDReLoadBitmap(IDirectDrawSurface *pdds, LPCSTR szBitmap); + static HRESULT DDCopyBitmap(IDirectDrawSurface *pdds, HBITMAP hbm, int x, int y, int dx, int dy); + static DWORD DDColorMatch(IDirectDrawSurface *pdds, COLORREF rgb); + static HRESULT DDSetColorKey(IDirectDrawSurface *pdds, COLORREF rgb); + + static char *TraceError(HRESULT ddrval); +}; + diff --git a/Toolkit/Programming/Tools/qMView/Dibapi.cpp b/Toolkit/Programming/Tools/qMView/Dibapi.cpp new file mode 100644 index 0000000..f4d0f65 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Dibapi.cpp @@ -0,0 +1,482 @@ +// dibapi.cpp +// +// Source file for Device-Independent Bitmap (DIB) API. Provides +// the following functions: +// +// PaintDIB() - Painting routine for a DIB +// CreateDIBPalette() - Creates a palette from a DIB +// FindDIBBits() - Returns a pointer to the DIB bits +// DIBWidth() - Gets the width of the DIB +// DIBHeight() - Gets the height of the DIB +// PaletteSize() - Gets the size required to store the DIB's palette +// DIBNumColors() - Calculates the number of colors +// in the DIB's color table +// CopyHandle() - Makes a copy of the given global memory block +// +// This is a part of the Microsoft Foundation Classes C++ library. +// Copyright (C) 1992-1997 Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Microsoft Foundation Classes Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Microsoft Foundation Classes product. + +#include "stdafx.h" +#include "dibapi.h" +#include +#include + +/************************************************************************* + * + * PaintDIB() + * + * Parameters: + * + * HDC hDC - DC to do output to + * + * LPRECT lpDCRect - rectangle on DC to do output to + * + * HDIB hDIB - handle to global memory with a DIB spec + * in it followed by the DIB bits + * + * LPRECT lpDIBRect - rectangle of DIB to output into lpDCRect + * + * CPalette* pPal - pointer to CPalette containing DIB's palette + * + * Return Value: + * + * BOOL - TRUE if DIB was drawn, FALSE otherwise + * + * Description: + * Painting routine for a DIB. Calls StretchDIBits() or + * SetDIBitsToDevice() to paint the DIB. The DIB is + * output to the specified DC, at the coordinates given + * in lpDCRect. The area of the DIB to be output is + * given by lpDIBRect. + * + ************************************************************************/ + +BOOL WINAPI PaintDIB(HDC hDC, + LPRECT lpDCRect, + HDIB hDIB, + LPRECT lpDIBRect, + CPalette* pPal) +{ + LPSTR lpDIBHdr; // Pointer to BITMAPINFOHEADER + LPSTR lpDIBBits; // Pointer to DIB bits + BOOL bSuccess=FALSE; // Success/fail flag + HPALETTE hPal=NULL; // Our DIB's palette + HPALETTE hOldPal=NULL; // Previous palette + + /* Check for valid DIB handle */ + if (hDIB == NULL) + return FALSE; + + /* Lock down the DIB, and get a pointer to the beginning of the bit + * buffer + */ + lpDIBHdr = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); + lpDIBBits = ::FindDIBBits(lpDIBHdr); + + // Get the DIB's palette, then select it into DC + if (pPal != NULL) + { + hPal = (HPALETTE) pPal->m_hObject; + + // Select as background since we have + // already realized in forground if needed + hOldPal = ::SelectPalette(hDC, hPal, TRUE); + } + + /* Make sure to use the stretching mode best for color pictures */ + ::SetStretchBltMode(hDC, COLORONCOLOR); + + /* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */ + if ((RECTWIDTH(lpDCRect) == RECTWIDTH(lpDIBRect)) && + (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect))) + bSuccess = ::SetDIBitsToDevice(hDC, // hDC + lpDCRect->left, // DestX + lpDCRect->top, // DestY + RECTWIDTH(lpDCRect), // nDestWidth + RECTHEIGHT(lpDCRect), // nDestHeight + lpDIBRect->left, // SrcX + (int)DIBHeight(lpDIBHdr) - + lpDIBRect->top - + RECTHEIGHT(lpDIBRect), // SrcY + 0, // nStartScan + (WORD)DIBHeight(lpDIBHdr), // nNumScans + lpDIBBits, // lpBits + (LPBITMAPINFO)lpDIBHdr, // lpBitsInfo + DIB_RGB_COLORS); // wUsage + else + bSuccess = ::StretchDIBits(hDC, // hDC + lpDCRect->left, // DestX + lpDCRect->top, // DestY + RECTWIDTH(lpDCRect), // nDestWidth + RECTHEIGHT(lpDCRect), // nDestHeight + lpDIBRect->left, // SrcX + lpDIBRect->top, // SrcY + RECTWIDTH(lpDIBRect), // wSrcWidth + RECTHEIGHT(lpDIBRect), // wSrcHeight + lpDIBBits, // lpBits + (LPBITMAPINFO)lpDIBHdr, // lpBitsInfo + DIB_RGB_COLORS, // wUsage + SRCCOPY); // dwROP + + ::GlobalUnlock((HGLOBAL) hDIB); + + /* Reselect old palette */ + if (hOldPal != NULL) + { + ::SelectPalette(hDC, hOldPal, TRUE); + } + + return bSuccess; +} + +/************************************************************************* + * + * CreateDIBPalette() + * + * Parameter: + * + * HDIB hDIB - specifies the DIB + * + * Return Value: + * + * HPALETTE - specifies the palette + * + * Description: + * + * This function creates a palette from a DIB by allocating memory for the + * logical palette, reading and storing the colors from the DIB's color table + * into the logical palette, creating a palette from this logical palette, + * and then returning the palette's handle. This allows the DIB to be + * displayed using the best possible colors (important for DIBs with 256 or + * more colors). + * + ************************************************************************/ + + +BOOL WINAPI CreateDIBPalette(HDIB hDIB, CPalette* pPal) +{ + LPLOGPALETTE lpPal; // pointer to a logical palette + HANDLE hLogPal; // handle to a logical palette + HPALETTE hPal = NULL; // handle to a palette + int i; // loop index + WORD wNumColors; // number of colors in color table + LPSTR lpbi; // pointer to packed-DIB + LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0) + LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (old) + BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB + BOOL bResult = FALSE; + + /* if handle to DIB is invalid, return FALSE */ + + if (hDIB == NULL) + return FALSE; + + lpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); + + /* get pointer to BITMAPINFO (Win 3.0) */ + lpbmi = (LPBITMAPINFO)lpbi; + + /* get pointer to BITMAPCOREINFO (old 1.x) */ + lpbmc = (LPBITMAPCOREINFO)lpbi; + + /* get the number of colors in the DIB */ + wNumColors = ::DIBNumColors(lpbi); + + if (wNumColors != 0) + { + /* allocate memory block for logical palette */ + hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE) + + sizeof(PALETTEENTRY) + * wNumColors); + + /* if not enough memory, clean up and return NULL */ + if (hLogPal == 0) + { + ::GlobalUnlock((HGLOBAL) hDIB); + return FALSE; + } + + lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal); + + /* set version and number of palette entries */ + lpPal->palVersion = PALVERSION; + lpPal->palNumEntries = (WORD)wNumColors; + + /* is this a Win 3.0 DIB? */ + bWinStyleDIB = IS_WIN30_DIB(lpbi); + for (i = 0; i < (int)wNumColors; i++) + { + if (bWinStyleDIB) + { + lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed; + lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen; + lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue; + lpPal->palPalEntry[i].peFlags = 0; + } + else + { + lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed; + lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen; + lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue; + lpPal->palPalEntry[i].peFlags = 0; + } + } + + /* create the palette and get handle to it */ + bResult = pPal->CreatePalette(lpPal); + ::GlobalUnlock((HGLOBAL) hLogPal); + ::GlobalFree((HGLOBAL) hLogPal); + } + + ::GlobalUnlock((HGLOBAL) hDIB); + + return bResult; +} + +/************************************************************************* + * + * FindDIBBits() + * + * Parameter: + * + * LPSTR lpbi - pointer to packed-DIB memory block + * + * Return Value: + * + * LPSTR - pointer to the DIB bits + * + * Description: + * + * This function calculates the address of the DIB's bits and returns a + * pointer to the DIB bits. + * + ************************************************************************/ + + +LPSTR WINAPI FindDIBBits(LPSTR lpbi) +{ + return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi)); +} + + +/************************************************************************* + * + * DIBWidth() + * + * Parameter: + * + * LPSTR lpbi - pointer to packed-DIB memory block + * + * Return Value: + * + * DWORD - width of the DIB + * + * Description: + * + * This function gets the width of the DIB from the BITMAPINFOHEADER + * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER + * width field if it is an other-style DIB. + * + ************************************************************************/ + + +DWORD WINAPI DIBWidth(LPSTR lpDIB) +{ + LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB + LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB + + /* point to the header (whether Win 3.0 and old) */ + + lpbmi = (LPBITMAPINFOHEADER)lpDIB; + lpbmc = (LPBITMAPCOREHEADER)lpDIB; + + /* return the DIB width if it is a Win 3.0 DIB */ + if (IS_WIN30_DIB(lpDIB)) + return lpbmi->biWidth; + else /* it is an other-style DIB, so return its width */ + return (DWORD)lpbmc->bcWidth; +} + + +/************************************************************************* + * + * DIBHeight() + * + * Parameter: + * + * LPSTR lpbi - pointer to packed-DIB memory block + * + * Return Value: + * + * DWORD - height of the DIB + * + * Description: + * + * This function gets the height of the DIB from the BITMAPINFOHEADER + * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER + * height field if it is an other-style DIB. + * + ************************************************************************/ + + +DWORD WINAPI DIBHeight(LPSTR lpDIB) +{ + LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB + LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB + + /* point to the header (whether old or Win 3.0 */ + + lpbmi = (LPBITMAPINFOHEADER)lpDIB; + lpbmc = (LPBITMAPCOREHEADER)lpDIB; + + /* return the DIB height if it is a Win 3.0 DIB */ + if (IS_WIN30_DIB(lpDIB)) + return lpbmi->biHeight; + else /* it is an other-style DIB, so return its height */ + return (DWORD)lpbmc->bcHeight; +} + + +/************************************************************************* + * + * PaletteSize() + * + * Parameter: + * + * LPSTR lpbi - pointer to packed-DIB memory block + * + * Return Value: + * + * WORD - size of the color palette of the DIB + * + * Description: + * + * This function gets the size required to store the DIB's palette by + * multiplying the number of colors by the size of an RGBQUAD (for a + * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an other- + * style DIB). + * + ************************************************************************/ + + +WORD WINAPI PaletteSize(LPSTR lpbi) +{ + /* calculate the size required by the palette */ + if (IS_WIN30_DIB (lpbi)) + return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD)); + else + return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE)); +} + + +/************************************************************************* + * + * DIBNumColors() + * + * Parameter: + * + * LPSTR lpbi - pointer to packed-DIB memory block + * + * Return Value: + * + * WORD - number of colors in the color table + * + * Description: + * + * This function calculates the number of colors in the DIB's color table + * by finding the bits per pixel for the DIB (whether Win3.0 or other-style + * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256, + * if 24, no colors in color table. + * + ************************************************************************/ + + +WORD WINAPI DIBNumColors(LPSTR lpbi) +{ + WORD wBitCount; // DIB bit count + + /* If this is a Windows-style DIB, the number of colors in the + * color table can be less than the number of bits per pixel + * allows for (i.e. lpbi->biClrUsed can be set to some value). + * If this is the case, return the appropriate value. + */ + + if (IS_WIN30_DIB(lpbi)) + { + DWORD dwClrUsed; + + dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed; + if (dwClrUsed != 0) + return (WORD)dwClrUsed; + } + + /* Calculate the number of colors in the color table based on + * the number of bits per pixel for the DIB. + */ + if (IS_WIN30_DIB(lpbi)) + wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount; + else + wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount; + + /* return number of colors based on bits per pixel */ + switch (wBitCount) + { + case 1: + return 2; + + case 4: + return 16; + + case 8: + return 256; + + default: + return 0; + } +} + + +////////////////////////////////////////////////////////////////////////// +//// Clipboard support + +//--------------------------------------------------------------------- +// +// Function: CopyHandle (from SDK DibView sample clipbrd.c) +// +// Purpose: Makes a copy of the given global memory block. Returns +// a handle to the new memory block (NULL on error). +// +// Routine stolen verbatim out of ShowDIB. +// +// Parms: h == Handle to global memory to duplicate. +// +// Returns: Handle to new global memory block. +// +//--------------------------------------------------------------------- + +HGLOBAL WINAPI CopyHandle (HGLOBAL h) +{ + if (h == NULL) + return NULL; + + DWORD dwLen = ::GlobalSize((HGLOBAL) h); + HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen); + + if (hCopy != NULL) + { + void* lpCopy = ::GlobalLock((HGLOBAL) hCopy); + void* lp = ::GlobalLock((HGLOBAL) h); + memcpy(lpCopy, lp, dwLen); + ::GlobalUnlock(hCopy); + ::GlobalUnlock(h); + } + + return hCopy; +} diff --git a/Toolkit/Programming/Tools/qMView/Dibapi.h b/Toolkit/Programming/Tools/qMView/Dibapi.h new file mode 100644 index 0000000..0a5e567 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Dibapi.h @@ -0,0 +1,49 @@ +// dibapi.h +// +// This is a part of the Microsoft Foundation Classes C++ library. +// Copyright (C) 1992-1997 Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Microsoft Foundation Classes Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Microsoft Foundation Classes product. + + +#ifndef _INC_DIBAPI +#define _INC_DIBAPI + +/* Handle to a DIB */ +DECLARE_HANDLE(HDIB); + +/* DIB constants */ +#define PALVERSION 0x300 + +/* DIB Macros*/ + +#define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER)) +#define RECTWIDTH(lpRect) ((lpRect)->right - (lpRect)->left) +#define RECTHEIGHT(lpRect) ((lpRect)->bottom - (lpRect)->top) + +// WIDTHBYTES performs DWORD-aligning of DIB scanlines. The "bits" +// parameter is the bit count for the scanline (biWidth * biBitCount), +// and this macro returns the number of DWORD-aligned bytes needed +// to hold those bits. + +#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4) + +/* Function prototypes */ +BOOL WINAPI PaintDIB (HDC, LPRECT, HDIB, LPRECT, CPalette* pPal); +BOOL WINAPI CreateDIBPalette(HDIB hDIB, CPalette* cPal); +LPSTR WINAPI FindDIBBits (LPSTR lpbi); +DWORD WINAPI DIBWidth (LPSTR lpDIB); +DWORD WINAPI DIBHeight (LPSTR lpDIB); +WORD WINAPI PaletteSize (LPSTR lpbi); +WORD WINAPI DIBNumColors (LPSTR lpbi); +HGLOBAL WINAPI CopyHandle (HGLOBAL h); + +BOOL WINAPI SaveDIB (HDIB hDib, CFile& file); +HDIB WINAPI ReadDIBFile(CFile& file); + +#endif //!_INC_DIBAPI diff --git a/Toolkit/Programming/Tools/qMView/FlexModel.cpp b/Toolkit/Programming/Tools/qMView/FlexModel.cpp new file mode 100644 index 0000000..042b0c7 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/FlexModel.cpp @@ -0,0 +1,2295 @@ +// FlexModel.cpp +// + +#include "stdafx.h" +#include "vector.h" +#include "resource.h" +#include "DDUtil.h" +#include "Matrix.h" +#include "Model.h" +#include "FrameManager2.h" +#include "FlexModel.h" + + +// +// CNode +// + +void CNode::Init() +{ + m_group = 0; + m_treeitem = NULL; + m_mesh = NULL; + m_visible = true; + m_numTris = 0; + m_numVerts = 0; + m_vertPath = NULL; + m_tris = NULL; + m_verts = NULL; + m_start_glcmds = NULL; + m_num_glcmds = 0; + m_defaultSkin = 0; + m_curSkin = NULL; +} + +void CNode::Delete() +{ + DeleteMesh(); + if (m_tris != NULL) + { + free(m_tris); + m_tris = NULL; + } + if (m_verts != NULL) + { + free(m_verts); + m_verts = NULL; + } + if (m_vertPath != NULL) + { + delete m_vertPath; + m_vertPath = NULL; + } +} + +void CNode::DeleteMesh() +{ + if (m_mesh != NULL) + { + m_mesh->Release(); + m_mesh = NULL; + } +} + +LPDIRECT3DRMMESH CNode::GetMesh() +{ + return m_mesh; +} + +CBitmap* CNode::GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC, int& width, int& height) +{ + width = m_curSkin->GetWidth(d3drm, pDC); + height = m_curSkin->GetHeight(d3drm, pDC); + return m_curSkin->GetBitmap(d3drm, pDC); +} + +void CNode::ChangeSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, CSkin* skin) +{ + if (m_curSkin == skin) + { + return; + } +// if (m_curSkin != NULL) +// { +// m_curSkin->GetTexture(d3drm, pDC)->Release(); +// } + m_mesh->SetGroupTexture(m_group, skin->GetTexture(d3drm, pDC)); + m_mesh->SetGroupMapping(m_group, D3DRMMAP_PERSPCORRECT); + m_mesh->SetGroupQuality(m_group, D3DRMRENDER_FLAT); + m_curSkin = skin; +} + +void CNode::LoadSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, CSkin* skin, int skinnum) +{ +// if (m_defaultSkin == skinnum) + { + if (m_curSkin != skin) + { + ChangeSkin(d3drm, pDC, skin); + } + } +} + +bool CNode::IsVisible() +{ + return m_visible; +} + +void CNode::SetVisible(bool visible) +{ + m_visible = visible; +} + +int CNode::GetNumTris() +{ + return m_numTris; +} + +void CNode::SetTris(byte* buf, int numTris) +{ + m_numTris = numTris; + m_tris = (byte*)malloc(numTris); + memcpy(m_tris, buf, numTris); +} + +void CNode::SetVerts(byte* buf, int numVerts) +{ + m_numVerts = numVerts; + m_verts = (byte*)malloc(numVerts); + memcpy(m_verts, buf, numVerts); +} + +void CNode::SetGlcmds(long* glcmds, int num) +{ + m_start_glcmds = glcmds; + m_num_glcmds = num; +} + +void CNode::RenderTexture(LPDIRECT3DRM2 d3drm, CDC* pDC, bool useTexture) +{ + if (useTexture) + { + m_mesh->SetGroupTexture(m_group, m_curSkin->GetTexture(d3drm, pDC)); + } + else + { + m_mesh->SetGroupTexture(m_group, NULL); + } +} + +void CNode::SetTransparency(LPDIRECT3DRM2 d3drm, CDC* pDC, bool trans) +{ + m_curSkin->GetTexture(d3drm, pDC)->SetDecalTransparency(trans); +} + +HRESULT CNode::SetQuality(D3DRMRENDERQUALITY value) +{ + return m_mesh->SetGroupQuality(m_group, value); +} + +HRESULT CNode::SetColorRGB(D3DVALUE red, D3DVALUE green, D3DVALUE blue) +{ + return m_mesh->SetGroupColorRGB(m_group, red, green, blue); +} + +void CNode::BuildMesh(LPDIRECT3DRM2 d3drm, frameinfo2_t* frameinfo1, int skinwidth, int skinheight) +{ + D3DRMVERTEX* vertexlist = new D3DRMVERTEX[m_numTris * 3 + 1]; + if (vertexlist == NULL) + { + AfxMessageBox("Cannot make vertexlist"); + return; + } + + int curvert=0; + + d3drm->CreateMesh(&m_mesh); + + vec5_t* vertlist = (vec5_t*)malloc(sizeof(vec5_t) * m_numTris * 3); + m_vertPath = new int[m_numTris * 3]; + + long* command = m_start_glcmds; + int cur_glcmnd = m_num_glcmds; + + //do the gl commands + int realvert = 0; + int realTris = 0; + while (*command && cur_glcmnd) + { + cur_glcmnd--; + + int num_verts; + int command_type; + bool odd = true; + + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (int i = 0; i < num_verts; i++) + { + vec5_t p1; + //grab the floating point s and t + p1.s = (*((float *)command)) * skinwidth; command++; + p1.t = (*((float *)command)) * skinheight; command++; + + //grab the vertex index + int vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[i] = p1; + } + + D3DVECTOR p[3]; + switch (command_type) + { + case 0: + //tristrip + for (i = 0;i < num_verts - 2; i++) + { + + for (int j = 0; j < 3; j++) + { + p[j].x = vertlist[i+j].x; + p[j].y = vertlist[i+j].y; + p[j].z = vertlist[i+j].z; + } + + if (odd) + { + for (j = 2; j > -1; j--) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / skinwidth; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / skinheight; + m_vertPath[curvert] = realvert+i+j; + curvert++; + } + realTris++; + } + else + { + for (j = 0; j < 3; j++) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / skinwidth; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / skinheight; + m_vertPath[curvert] = realvert+i+j; + curvert++; + } + realTris++; + } + odd = !odd; + } + break; + + case 1: + //trifan + for (i = 0; i < num_verts - 2; i++) + { + for (int j = 2; j > -1; j--) + { + int x; + if (j == 0) + x = 0; + else + x = i; + + p[j].x = vertlist[x+j].x; + p[j].y = vertlist[x+j].y; + p[j].z = vertlist[x+j].z; + } + + for (j = 2; j > -1; j--) + { + int x; + if (j == 0) + x = 0; + else + x = i; + + vertexlist[curvert].position.x = vertlist[x+j].x; + vertexlist[curvert].position.y = vertlist[x+j].y; + vertexlist[curvert].position.z = vertlist[x+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[x+j].s) / skinwidth; + vertexlist[curvert].tv = D3DVALUE(vertlist[x+j].t) / skinheight; + m_vertPath[curvert] = realvert + x + j; + curvert++; + } + realTris++; + } + break; + } + + realvert += num_verts; + } + + int tempvert = curvert; + + unsigned* vertorder = new unsigned[curvert + 1]; + if (vertorder == NULL) + { + AfxMessageBox("Cannot make vertorder"); + return; + } + + for (int i = 0; i < (curvert); i++) + { + tempvert--; + vertorder[i] = tempvert; + } + + m_numTris = realTris; + m_numVerts = curvert; + + m_mesh->AddGroup(curvert, realTris, 3, vertorder, &m_group); + m_mesh->SetVertices(m_group, 0, curvert, vertexlist ); + + if (vertexlist) delete vertexlist; + if (vertorder) delete vertorder; + if (vertlist) free(vertlist); + + return; +} + +void CNode::SetSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, CSkin* skin, int skinnum) +{ + m_defaultSkin = skinnum; + ChangeSkin(d3drm, pDC, skin); +} + +void CNode::AddVisual(LPDIRECT3DRMFRAME frame) +{ + HRESULT ddrval = frame->AddVisual(m_mesh); + if (ddrval != D3DRM_OK) + { + AfxMessageBox(CDDHelper::TraceError(ddrval)); + return; + } +} + +bool CNode::ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC, vec3a_t* rotVerts, frameinfo2_t* frameinfo1) +{ + + D3DRMVERTEX* vertexlist = new D3DRMVERTEX[m_numTris * 3 + 1]; + if (vertexlist == NULL) + { + AfxMessageBox("Cannot make vertexlist"); + return false; + } + + vec5_t* vertlist = (vec5_t*)malloc(sizeof(vec5_t) * m_numTris * 3); + + long* command = m_start_glcmds; + int cur_glcmnd = m_num_glcmds; + + int realvert = 0; + int skinwidth = m_curSkin->GetWidth(d3drm, pDC); + int skinheight = m_curSkin->GetHeight(d3drm, pDC); + + //do the gl commands + while (*command && cur_glcmnd) + { + cur_glcmnd--; + + int num_verts; + if (*command>0) + { + //triangle strip + num_verts = *command; + } + else + { + //triangle fan + num_verts = -(*command); + } + command++; + + vec5_t p1; + for (int i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * skinwidth; command++; + p1.t = (*((float *)command)) * skinheight; command++; + + //grab the vertex index + int vert_index = *command; command++; + + p1.z = -((rotVerts[vert_index][0] * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((rotVerts[vert_index][1] * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((rotVerts[vert_index][2] * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[realvert] = p1; + realvert++; + } + } + + for (int i = 0; i < m_numVerts; i++) + { + vertexlist[i].position.x = vertlist[m_vertPath[i]].x; + vertexlist[i].position.y = vertlist[m_vertPath[i]].y; + vertexlist[i].position.z = vertlist[m_vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[m_vertPath[i]].s) / skinwidth; + vertexlist[i].tv = D3DVALUE(vertlist[m_vertPath[i]].t) / skinheight; + } + + m_mesh->SetVertices(m_group, 0, m_numVerts, vertexlist); + + free(vertlist); + delete (vertexlist); + + return true; +} + +void CNode::ShowInterFrame(LPDIRECT3DRM2 d3drm, CDC* pDC, frameinfo2_t* frameinfo1, frameinfo2_t* frameinfo2, int step, int numsteps) +{ + D3DRMVERTEX* vertexlist = new D3DRMVERTEX[m_numTris * 3 + 1]; + if (vertexlist == NULL) + { + AfxMessageBox("Cannot make vertexlist"); + return; + } + + vec5_t* vertlist = (vec5_t*)malloc(sizeof(vec5_t) * m_numTris * 3); + + long* command = m_start_glcmds; + int cur_glcmnd = m_num_glcmds; + int realvert = 0; + int skinwidth = m_curSkin->GetWidth(d3drm, pDC); + int skinheight = m_curSkin->GetHeight(d3drm, pDC); + + //do the gl commands + while (*command && cur_glcmnd) + { + cur_glcmnd--; + + int num_verts; + if (*command>0) + { + //triangle strip + num_verts = *command; + } + else + { + //triangle fan + num_verts = -(*command); + } + + command++; + + for (int i = 0; i < num_verts; i++) + { + vec5_t p1; + vec5_t p2; + //grab the floating point s and t + p1.s = (*((float *)command)) * skinwidth; command++; + p1.t = (*((float *)command)) * skinheight; command++; + + //grab the vertex index + long vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + p2.z = -((frameinfo2->verts[vert_index].x * frameinfo2->scale.x) + frameinfo2->origin.x); + p2.y = ((frameinfo2->verts[vert_index].y * frameinfo2->scale.y) + frameinfo2->origin.y); + p2.x = -((frameinfo2->verts[vert_index].z * frameinfo2->scale.z) + frameinfo2->origin.z); + + D3DVECTOR delta; + delta.x = (p2.x - p1.x) / numsteps; + delta.y = (p2.y - p1.y) / numsteps; + delta.z = (p2.z - p1.z) / numsteps; + + p1.x += delta.x * step; + p1.y += delta.y * step; + p1.z += delta.z * step; + + vertlist[realvert] = p1; + realvert++; + } + } + + for (int i = 0; i < m_numVerts; i++) + { + vertexlist[i].position.x = vertlist[m_vertPath[i]].x; + vertexlist[i].position.y = vertlist[m_vertPath[i]].y; + vertexlist[i].position.z = vertlist[m_vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[m_vertPath[i]].s) / skinwidth; + vertexlist[i].tv = D3DVALUE(vertlist[m_vertPath[i]].t) / skinheight; + } + + m_mesh->SetVertices(m_group, 0, m_numVerts, vertexlist); + + free(vertlist); + delete (vertexlist); +} + +// +// CFlexModel +// +bool CFlexModel::LoadSkin(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, int skinnum, CDC* pDC) +{ + CSkin* skin = GetSkin(skinnum); + for (int i = 0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].LoadSkin(d3drm, pDC, skin, skinnum); + } + return true; +} + +void CFlexModel::CreateJointVisuals(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame) +{ + if (m_numClusters) + { + for (int i = 0; i < m_numClusters; i++) + { + CreateJointVisual(d3drm, m_skeletons[0].rootJoint[i].model, i, frame); + } + } +} + +void CFlexModel::CreateJointVisual(LPDIRECT3DRM2 d3drm, Placement_t model, int jointNum, LPDIRECT3DRMFRAME frame) +{ + D3DRMVERTEX vertexlist[12]; + unsigned vertorder[24]; + + frameinfo2_t *frameinfo1 = (frameinfo2_t *)m_frames; + + vertexlist[0].position.z = -(((model.origin[0] - 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[0].position.y = (((model.origin[1]) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[0].position.x = -(((model.origin[2]) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[2].position.z = -(((model.origin[0] + 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[2].position.y = (((model.origin[1]) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[2].position.x = -(((model.origin[2]) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[1].position.z = -(((model.origin[0]) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[1].position.y = (((model.origin[1]) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[1].position.x = -(((model.origin[2] + 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[3].position.z = -(((model.origin[0]) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[3].position.y = (((model.origin[1]) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[3].position.x = -(((model.origin[2] - 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[4].position.z = -(((model.origin[0]) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[4].position.y = (((model.origin[1] + 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[4].position.x = -(((model.origin[2]) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[5].position.z = -(((model.origin[0]) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[5].position.y = (((model.origin[1] - 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[5].position.x = -(((model.origin[2]) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertorder[0] = 1; + vertorder[1] = 4; + vertorder[2] = 0; + + vertorder[3] = 4; + vertorder[4] = 3; + vertorder[5] = 0; + + vertorder[6] = 1; + vertorder[7] = 2; + vertorder[8] = 4; + + vertorder[9] = 2; + vertorder[10] = 3; + vertorder[11] = 4; + + ////////////////// + + vertorder[12] = 3; + vertorder[13] = 5; + vertorder[14] = 0; + + vertorder[15] = 5; + vertorder[16] = 1; + vertorder[17] = 0; + + vertorder[18] = 3; + vertorder[19] = 2; + vertorder[20] = 5; + + vertorder[21] = 2; + vertorder[22] = 1; + vertorder[23] = 5; + + d3drm->CreateMesh(&m_joint_visuals[jointNum].origin); + + m_joint_visuals[jointNum].origin->AddGroup( 24, 8, 3, vertorder, &m_group ); + m_joint_visuals[jointNum].origin->SetVertices(m_group, 0, 23, vertexlist ); + + m_joint_visuals[jointNum].origin->SetGroupQuality(m_group, D3DRMRENDER_FLAT ); + m_joint_visuals[jointNum].origin->SetGroupColorRGB(m_group, D3DVALUE( 255 ), D3DVALUE( 0 ), D3DVALUE( 0 )); + + HRESULT ddrval = frame->AddVisual(m_joint_visuals[jointNum].origin); + if (ddrval != D3DRM_OK) + AfxMessageBox(CDDHelper::TraceError(ddrval)); + + /**************************************************************************/ + + D3DVECTOR dir, up, org; + + dir.x = model.direction[0]; + dir.y = model.direction[1]; + dir.z = model.direction[2]; + + up.x = model.up[0]; + up.y = model.up[1]; + up.z = model.up[2]; + + org.x = model.origin[0]; + org.y = model.origin[1]; + org.z = model.origin[2]; + + D3DRMVectorSubtract(&dir, &dir, &org); + D3DRMVectorNormalize(&dir); + + dir.x *= 5; + dir.y *= 5; + dir.z *= 5; + + dir.x += org.x; + dir.y += org.y; + dir.z += org.z; + + D3DRMVectorSubtract(&up, &up, &org); + D3DRMVectorNormalize(&up); + + up.x *= 5; + up.y *= 5; + up.z *= 5; + + up.x += org.x; + up.y += org.y; + up.z += org.z; + + vertexlist[0].position.z = -(((dir.x - 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[0].position.y = (((dir.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[0].position.x = -(((dir.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[2].position.z = -(((dir.x + 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[2].position.y = (((dir.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[2].position.x = -(((dir.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[1].position.z = -(((dir.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[1].position.y = (((dir.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[1].position.x = -(((dir.z + 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[3].position.z = -(((dir.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[3].position.y = (((dir.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[3].position.x = -(((dir.z - 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[4].position.z = -(((dir.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[4].position.y = (((dir.y + 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[4].position.x = -(((dir.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[5].position.z = -(((dir.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[5].position.y = (((dir.y - 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[5].position.x = -(((dir.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + d3drm->CreateMesh(&m_joint_visuals[jointNum].dir); + + m_joint_visuals[jointNum].dir->AddGroup( 24, 8, 3, vertorder, &m_group ); + m_joint_visuals[jointNum].dir->SetVertices(m_group, 0, 23, vertexlist ); + + m_joint_visuals[jointNum].dir->SetGroupQuality(m_group, D3DRMRENDER_FLAT ); + m_joint_visuals[jointNum].dir->SetGroupColorRGB(m_group, D3DVALUE( 0 ), D3DVALUE( 255 ), D3DVALUE( 0 )); + + ddrval = frame->AddVisual(m_joint_visuals[jointNum].dir ); + if (ddrval != D3DRM_OK) + AfxMessageBox(CDDHelper::TraceError(ddrval)); + + /**************************************************************************/ + + vertexlist[0].position.z = -(((up.x - 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[0].position.y = (((up.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[0].position.x = -(((up.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[2].position.z = -(((up.x + 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[2].position.y = (((up.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[2].position.x = -(((up.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[1].position.z = -(((up.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[1].position.y = (((up.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[1].position.x = -(((up.z + 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[3].position.z = -(((up.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[3].position.y = (((up.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[3].position.x = -(((up.z - 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[4].position.z = -(((up.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[4].position.y = (((up.y + 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[4].position.x = -(((up.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[5].position.z = -(((up.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[5].position.y = (((up.y - 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[5].position.x = -(((up.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + d3drm->CreateMesh(&m_joint_visuals[jointNum].up); + + m_joint_visuals[jointNum].up->AddGroup( 24, 8, 3, vertorder, &m_group ); + m_joint_visuals[jointNum].up->SetVertices(m_group, 0, 23, vertexlist ); + + m_joint_visuals[jointNum].up->SetGroupQuality(m_group, D3DRMRENDER_FLAT ); + m_joint_visuals[jointNum].up->SetGroupColorRGB(m_group, D3DVALUE( 0 ), D3DVALUE( 0 ), D3DVALUE( 255 )); + + ddrval = frame->AddVisual(m_joint_visuals[jointNum].up ); + if (ddrval != D3DRM_OK) + AfxMessageBox(CDDHelper::TraceError(ddrval)); +} + +CFlexModel::CFlexModel() +{ +} + +CFlexModel::~CFlexModel() +{ +} + +void CFlexModel::Init() +{ + m_compdata.start_frame =0; + m_compdata.num_frames = 0; + m_compdata.degrees = 0; + m_compdata.mat = NULL; + m_compdata.ccomp = NULL; + m_compdata.cbase = NULL; + m_compdata.cscale = NULL; + m_compdata.coffset = NULL; + m_compdata.complerp = NULL; + m_compdata.trans[0] = 0; + m_compdata.scale[0] = 0; + m_compdata.bmin[0] = 0; + m_compdata.bmax[0] = 0; + m_compdata.trans[1] = 0; + m_compdata.scale[1] = 0; + m_compdata.bmin[1] = 0; + m_compdata.bmax[1] = 0; + m_compdata.trans[2] = 0; + m_compdata.scale[2] = 0; + m_compdata.bmin[2] = 0; + m_compdata.bmax[2] = 0; + + m_curFrame = 0; + m_framenames = NULL; + + m_lightnormalindex = NULL; + m_skeletalType = 0; + m_skeletons = NULL; + m_referenceType = -1; + for (int i = 0; i < JOINT_VISUALS; i++) + { + m_joint_visuals[i].origin = NULL; + m_joint_visuals[i].dir = NULL; + m_joint_visuals[i].up = NULL; + } + + m_num_mesh_nodes = 0; + m_curNode = -1; + m_nodes = NULL; + + m_skin_names = NULL; + CModel::Init(); +// joint support + m_jointsOn = false; + m_curJoint = -1; + m_jointConstraintAngles = NULL; + m_modelJointAngles = NULL; + m_skeletalClusters = NULL; + m_numClusters = 0; +} + +void CFlexModel::DeleteMeshs(LPDIRECT3DRMFRAME frame) +{ + for (int i = 0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].DeleteMesh(); + } + m_curNode = -1; +} + +void CFlexModel::DeleteVisuals(LPDIRECT3DRMFRAME frame) +{ + for (int i = 0; i < m_num_mesh_nodes; i++) + { + LPDIRECT3DRMMESH mesh = m_nodes[i].GetMesh(); + if (mesh != NULL) + { + frame->DeleteVisual(mesh); + } + } + for (i = 0; i < m_numClusters; i++) + { + if (m_joint_visuals[i].origin != NULL) + { + frame->DeleteVisual(m_joint_visuals[i].origin); + m_joint_visuals[i].origin->Release(); + m_joint_visuals[i].origin = NULL; + } + if (m_joint_visuals[i].dir != NULL) + { + frame->DeleteVisual(m_joint_visuals[i].dir); + m_joint_visuals[i].dir->Release(); + m_joint_visuals[i].dir = NULL; + } + if (m_joint_visuals[i].up != NULL) + { + frame->DeleteVisual(m_joint_visuals[i].up); + m_joint_visuals[i].up->Release(); + m_joint_visuals[i].up = NULL; + } + } +} + +void CFlexModel::Delete() +{ + if (m_skin_names) + { + for (int i = 0; i < m_num_skins; i++) + { + free(m_skin_names[i]); + m_skin_names[i] = NULL; + } + free (m_skin_names); + m_skin_names = NULL; + } + + if (m_nodes != NULL) + { + for (int i = 0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].Delete(); + } + delete m_nodes; + m_nodes = NULL; + } + if (m_compdata.mat) + { + free (m_compdata.mat); + m_compdata.mat = NULL; + } + + if (m_compdata.ccomp) + { + free (m_compdata.ccomp); + m_compdata.ccomp = NULL; + } + + if (m_compdata.cbase) + { + free (m_compdata.cbase); + m_compdata.cbase = NULL; + } + + if (m_compdata.cscale) + { + free (m_compdata.cscale); + m_compdata.cscale = NULL; + } + + if (m_compdata.coffset) + { + free (m_compdata.coffset); + m_compdata.coffset = NULL; + } + + if (m_compdata.complerp) + { + free (m_compdata.complerp); + m_compdata.complerp = NULL; + } + + if (m_framenames != NULL) + { + free(m_framenames); + m_framenames = NULL; + } + + if (m_lightnormalindex) + { + free (m_lightnormalindex); + m_lightnormalindex = NULL; + } + + if (m_skeletons) + { + free (m_skeletons); + m_skeletons = NULL; + } + + for (int i = 0; i < m_numClusters; i++) + { + delete (m_skeletalClusters[i].verticies); + m_skeletalClusters[i].verticies = NULL; + } + if (m_skeletalClusters != NULL) + { + delete m_skeletalClusters; + m_skeletalClusters = NULL; + m_numClusters = 0; + } + if (m_jointConstraintAngles != NULL) + { + delete m_jointConstraintAngles; + m_jointConstraintAngles = NULL; + } + if (m_modelJointAngles != NULL) + { + delete m_modelJointAngles; + m_modelJointAngles = NULL; + } + m_num_mesh_nodes = -1; + CModel::Delete(); +} + +HRESULT CFlexModel::SetGroupQuality(D3DRMRENDERQUALITY value) +{ + HRESULT retval; + if (m_num_mesh_nodes > 0) + { + if (m_curNode < 0) + { + for (int i = 0; i < m_num_mesh_nodes;i++) + { + retval = m_nodes[i].SetQuality(value); + } + } + else + { + retval = m_nodes[m_curNode].SetQuality(value); + } + } + else + { + retval = CModel::SetGroupQuality(value); + } + return retval; +} + +LPDIRECT3DRMMESH CFlexModel::GetMesh(int i) +{ + if (i < 0) + { + if (m_curNode < 0) + { + return m_nodes[0].GetMesh(); + } + return m_nodes[m_curNode].GetMesh(); + } + return m_nodes[i].GetMesh(); +} + +void CFlexModel::Drag(double delta_x, double delta_y) +{ + if (GetKeyState(VK_SHIFT)&0x8000) + { + m_modelJointAngles[m_curJoint].y += (float) delta_x / 100; + + if (m_modelJointAngles[m_curJoint].y > PI*2) + m_modelJointAngles[m_curJoint].y = (float) PI*2 - m_modelJointAngles[m_curJoint].y; + else if (m_modelJointAngles[m_curJoint].y < 0) + m_modelJointAngles[m_curJoint].y = (float) PI*2 + m_modelJointAngles[m_curJoint].y; + } + else + { + m_modelJointAngles[m_curJoint].x += (float) delta_x / 100; + + m_modelJointAngles[m_curJoint].z += (float) delta_y / 100; + + if (m_modelJointAngles[m_curJoint].x > PI*2) + m_modelJointAngles[m_curJoint].x = (float) PI*2 - m_modelJointAngles[m_curJoint].x; + else if (m_modelJointAngles[m_curJoint].x < 0) + m_modelJointAngles[m_curJoint].x = (float) PI*2 + m_modelJointAngles[m_curJoint].x; + + if (m_modelJointAngles[m_curJoint].z > PI*2) + m_modelJointAngles[m_curJoint].z = (float) PI*2 - m_modelJointAngles[m_curJoint].z; + else if (m_modelJointAngles[m_curJoint].z < 0) + m_modelJointAngles[m_curJoint].z = (float) PI*2 + m_modelJointAngles[m_curJoint].z; + } +// ShowFrame(); +// ConstrainJoint(); +} + +void CFlexModel::DeSelectAll() +{ + m_curNode = -1; + for (int i = 0; i < m_num_mesh_nodes; i++) + { + GetMesh(i)->SetGroupColorRGB( 0, D3DVALUE(255), + D3DVALUE(255), + D3DVALUE(255) ); + } +} + +void CFlexModel::ChangeVisual(LPDIRECT3DRMFRAME frame, int nodeNum) +{ + if (nodeNum != m_curNode) + { + if (m_curNode != -1 && !m_nodes[m_curNode].IsVisible()) + { + frame->DeleteVisual(m_nodes[m_curNode].GetMesh()); + } + + if (nodeNum != -1 && !m_nodes[nodeNum].IsVisible()) + { + frame->AddVisual(m_nodes[nodeNum].GetMesh()); + } + } + +} + +int CFlexModel::SelectNode(int nodeNum) +{ + int retval = m_curNode; + for (int i = 0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].SetColorRGB(D3DVALUE(255), D3DVALUE(255), D3DVALUE(255)); + } + + m_nodes[nodeNum].SetColorRGB(D3DVALUE(255), D3DVALUE(0), D3DVALUE(0)); + m_curNode = nodeNum; + return retval; +} + +HTREEITEM CFlexModel::SelectMesh(LPDIRECT3DRMVISUAL selection) +{ + HTREEITEM retval = NULL; + for (int i = 0; i < m_num_mesh_nodes; i++) + { + if (m_nodes[i].GetMesh() == selection) + { + m_curNode = i; + m_nodes[i].SetColorRGB(255, 0, 0); + retval = m_nodes[i].m_treeitem; + } + else + { + m_nodes[i].SetColorRGB(255, 255, 255); + } + } + return retval; +} + +bool CFlexModel::ToggleNodeVisibility(int node) +{ + m_nodes[node].SetVisible(!m_nodes[node].IsVisible()); + return m_nodes[node].IsVisible (); +} + +void CFlexModel::MakeAllNodesVisible(LPDIRECT3DRMFRAME frame) +{ + for (int i = 0; i < m_num_mesh_nodes; i++) + { + if (!m_nodes[i].IsVisible()) + { + m_nodes[i].SetVisible(true); + frame->AddVisual(m_nodes[i].GetMesh()); + } + } +} + +void CFlexModel::SetCurJoint(long joint) +{ + m_curJoint = joint; +} + +bool CFlexModel::ValidNode() +{ + return m_curNode >= 0; +} + +long CFlexModel::GetNumNodes() +{ + return m_num_mesh_nodes; +} + +long CFlexModel::GetNumTris() +{ + return m_nodes[m_curNode].GetNumTris(); +} + +long CFlexModel::GetCurJoint() +{ + return m_curJoint; +} + +CBitmap* CFlexModel::GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC, int skinnum, int& width, int& height) +{ + if (skinnum >= 0) + { + CSkin* skin = GetSkin(skinnum); + width = skin->GetWidth(d3drm, pDC); + height = skin->GetHeight(d3drm, pDC); + return skin->GetBitmap(d3drm, pDC); + } + if (m_curNode > -1) + { + return m_nodes[m_curNode].GetBitmap(d3drm, pDC, width, height); + } + width = 0; + height = 0; + return NULL; +} + +void CFlexModel::Snap() +{ + if (m_curJoint < 0) + { + return; + } + m_modelJointAngles[m_curJoint].x = 0; + m_modelJointAngles[m_curJoint].y = 0; + m_modelJointAngles[m_curJoint].z = 0; +} + +void CFlexModel::LoadSkinInfo(CTreeCtrl* pCTree, HTREEITEM rootSkin) +{ + for (int i = 0; i < m_num_skins; i++) + { + HTREEITEM point = pCTree->InsertItem(m_skin_names[i], rootSkin, TVI_LAST); + pCTree->SetItemImage(point, 0, 0); + pCTree->SetItemData(point, i); + } +} + +void CFlexModel::UpdateJointVisuals(int jointNum) +{ + D3DRMVERTEX vertexlist[12]; + + Placement_t model = m_skeletons[m_curFrame].rootJoint[jointNum].model; + + frameinfo2_t *frameinfo1 = (frameinfo2_t *)((char *)m_frames + m_framesize * m_curFrame); + + vertexlist[0].position.z = -(((model.origin[0] - 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[0].position.y = (((model.origin[1]) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[0].position.x = -(((model.origin[2]) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[2].position.z = -(((model.origin[0] + 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[2].position.y = (((model.origin[1]) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[2].position.x = -(((model.origin[2]) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[1].position.z = -(((model.origin[0]) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[1].position.y = (((model.origin[1]) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[1].position.x = -(((model.origin[2] + 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[3].position.z = -(((model.origin[0]) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[3].position.y = (((model.origin[1]) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[3].position.x = -(((model.origin[2] - 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[4].position.z = -(((model.origin[0]) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[4].position.y = (((model.origin[1] + 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[4].position.x = -(((model.origin[2]) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[5].position.z = -(((model.origin[0]) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[5].position.y = (((model.origin[1] - 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[5].position.x = -(((model.origin[2]) * frameinfo1->scale.z) + frameinfo1->origin.z); + + m_joint_visuals[jointNum].origin->SetVertices( 0, 0, 23, vertexlist ); + + /**************************************************************************/ + + D3DVECTOR dir, up, org; + + dir.x = model.direction[0]; + dir.y = model.direction[1]; + dir.z = model.direction[2]; + + up.x = model.up[0]; + up.y = model.up[1]; + up.z = model.up[2]; + + org.x = model.origin[0]; + org.y = model.origin[1]; + org.z = model.origin[2]; + + D3DRMVectorSubtract(&dir, &dir, &org); + D3DRMVectorNormalize(&dir); + + dir.x *= 8; + dir.y *= 8; + dir.z *= 8; + + dir.x += org.x; + dir.y += org.y; + dir.z += org.z; + + D3DRMVectorSubtract(&up, &up, &org); + D3DRMVectorNormalize(&up); + + up.x *= 8; + up.y *= 8; + up.z *= 8; + + up.x += org.x; + up.y += org.y; + up.z += org.z; + + vertexlist[0].position.z = -(((dir.x - 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[0].position.y = (((dir.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[0].position.x = -(((dir.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[2].position.z = -(((dir.x + 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[2].position.y = (((dir.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[2].position.x = -(((dir.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[1].position.z = -(((dir.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[1].position.y = (((dir.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[1].position.x = -(((dir.z + 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[3].position.z = -(((dir.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[3].position.y = (((dir.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[3].position.x = -(((dir.z - 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[4].position.z = -(((dir.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[4].position.y = (((dir.y + 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[4].position.x = -(((dir.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[5].position.z = -(((dir.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[5].position.y = (((dir.y - 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[5].position.x = -(((dir.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + m_joint_visuals[jointNum].dir->SetVertices( 0, 0, 23, vertexlist ); + + /**************************************************************************/ + + vertexlist[0].position.z = -(((up.x - 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[0].position.y = (((up.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[0].position.x = -(((up.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[2].position.z = -(((up.x + 1) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[2].position.y = (((up.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[2].position.x = -(((up.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[1].position.z = -(((up.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[1].position.y = (((up.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[1].position.x = -(((up.z + 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[3].position.z = -(((up.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[3].position.y = (((up.y) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[3].position.x = -(((up.z - 1) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[4].position.z = -(((up.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[4].position.y = (((up.y + 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[4].position.x = -(((up.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertexlist[5].position.z = -(((up.x) * frameinfo1->scale.x) + frameinfo1->origin.x); + vertexlist[5].position.y = (((up.y - 1) * frameinfo1->scale.y) + frameinfo1->origin.y); + vertexlist[5].position.x = -(((up.z) * frameinfo1->scale.z) + frameinfo1->origin.z); + + m_joint_visuals[jointNum].up->SetVertices( 0, 0, 23, vertexlist ); +} + +void CFlexModel::FillRawVerts(vec3a_t *foo) +{ + frameinfo2_t *frameinfo1 = (frameinfo2_t *)((char *)m_frames + m_framesize * m_curFrame); + + for (int i = 0; i < m_num_xyz; i++) + { + foo[i][0] = frameinfo1->verts[i].x; + foo[i][1] = frameinfo1->verts[i].y; + foo[i][2] = frameinfo1->verts[i].z; + } +} + +BOOL CFlexModel::ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC) +{ + for (int i = 0; i < m_numClusters; i++) + UpdateJointVisuals(i); + + if (m_num_mesh_nodes > 0) + { + vec3a_t angles; + + if (m_curJoint > -1) + { + angles[0] = m_modelJointAngles[m_curJoint].x; + angles[1] = m_modelJointAngles[m_curJoint].y; + angles[2] = m_modelJointAngles[m_curJoint].z; + } + else + { + angles[0] = 0; + angles[1] = 0; + angles[2] = 0; + } + + vec3a_t* rotVerts = (vec3a_t *) malloc(sizeof(vec3a_t)*m_num_tris*3); + + FillRawVerts(rotVerts); + + if (m_skeletons && m_jointsOn) + RotateModelSegment((M_SkeletalJoint_s *) &m_skeletons[m_curFrame].rootJoint[m_curJoint], rotVerts, angles, &m_skeletalClusters[m_curJoint]); + + frameinfo2_t* frameinfo1 = (frameinfo2_t*)((char *)m_frames + m_framesize * GetCurFrame()); + for (i = 0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].ShowFrame(d3drm, pDC, rotVerts, frameinfo1); + } + + free (rotVerts); + return true; + } + + return TRUE; +} + +BOOL CFlexModel::CalcInterpolate(LPDIRECT3DRM2 d3drm, CDC* pDC, int step, int numsteps, int intertype, int direction) +{ + int curvert = 0; + int lastframe, i; + + if (direction == ANIM_FORWARD) + { + if (m_curGroup == -1) + { + if (m_curFrame + 1 > m_num_frames-1) + lastframe = 0; + else + lastframe = m_curFrame + 1; + } + else + { + if (m_curFrame + 1 > m_treeInfo[m_curGroup].eFrame) + { + lastframe = m_treeInfo[m_curGroup].bFrame; + } + else + { + lastframe = m_curFrame + 1; + } + } + } + + frameinfo2_t* frameinfo1 = (frameinfo2_t*)((char*)m_frames + m_framesize * m_curFrame); + frameinfo2_t* frameinfo2 = (frameinfo2_t*)((char*)m_frames + m_framesize * lastframe); + if (m_num_mesh_nodes > 0) + { + for (i=0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].ShowInterFrame(d3drm, pDC, frameinfo1, frameinfo2, step, numsteps); + } + } + else + { + m_nodes[0].ShowInterFrame(d3drm, pDC, frameinfo1, frameinfo2, step, numsteps); + } + + if (step + 1 > numsteps) m_curstep = 0; + else m_curstep++; + + return true; +} + +// Node Tree Ctrl Support +void CFlexModel::AddNode (CTreeCtrl*pCTree, HTREEITEM rootNode, int nodeNum) +{ + CString foo; + foo.Format("Node %d", nodeNum); + HTREEITEM point = pCTree->InsertItem(foo, rootNode, TVI_LAST); + m_nodes[nodeNum].m_treeitem = point; + pCTree->SetItemData(point, nodeNum); + pCTree->SetItemImage(point, 1, 1); + pCTree->Expand(rootNode, TVE_EXPAND); +} + +void CFlexModel::AddNodes(CTreeCtrl* pCTreeCtrl, HTREEITEM rootNode) +{ + if (m_num_mesh_nodes > 0) + { + for (int i = 0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].SetVisible(true); + AddNode(pCTreeCtrl, rootNode, i); + } + } +} + +void CFlexModel::FillMenuWithSkins(CMenu* menu) +{ + int curID = IDR_SKIN_SELECT_START; + for (int i = 0; i < m_num_skins; i++) + { + menu->AppendMenu(MF_ENABLED | MF_UNCHECKED | MF_STRING, curID++, m_skin_names[i]); + } +} + +void CFlexModel::ChangeSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, int nodenum, int skinnum) +{ + CSkin* skin = CModel::GetSkin(m_skin_names[skinnum]); + m_nodes[nodenum].ChangeSkin(d3drm, pDC, skin); +} + +void CFlexModel::AddSkin(LPCTSTR skinname) +{ + char** holdSkins = m_skin_names; + m_skin_names = (char**)malloc(sizeof(char*) * (m_num_skins + 1)); + for (int i = 0; i < m_num_skins; i++) + { + m_skin_names[i] = holdSkins[i]; + } + free(holdSkins); + CString result = skinname; + + while(true) + { + int destChar = result.Find("/"); + if (destChar < 0) + { + break; + } + result.SetAt(destChar, '\\'); + } + + m_skin_names[m_num_skins] = (char*)malloc(result.GetLength() + 1); + strcpy(m_skin_names[m_num_skins], result); + m_num_skins++; +} + +void CFlexModel::ReplaceSkin(int i, LPCTSTR skinname) +{ + if (m_skin_names[i] != NULL) + { + free(m_skin_names[i]); + m_skin_names[i] = NULL; + } + m_skin_names[i] = (char*)malloc(strlen(skinname) + 1); + strcpy(m_skin_names[i], skinname); +} + +CSkin* CFlexModel::GetSkin(int i) +{ + return CModel::GetSkin(m_skin_names[i]); +} + +void CFlexModel::BuildMesh(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene, CDC* pDC) +{ + CSkin* skin = GetSkin(0); + + if (m_num_mesh_nodes > 0) + { + for (int i = 0; i < m_num_mesh_nodes; i++) + { + m_curNode = i; + m_nodes[i].BuildMesh(d3drm, (frameinfo2_t*)m_frames, skin->GetWidth(d3drm, pDC), skin->GetHeight(d3drm, pDC)); + m_nodes[i].SetSkin(d3drm, pDC, skin, 0); + m_nodes[i].AddVisual(frame); + } + frame->SetOrientation(scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0)); + } +} + +void CFlexModel::RotateModelSegment(M_SkeletalJoint_t *joint, vec3a_t *modelVerticies, vec3a_t angles, M_SkeletalCluster_t *modelCluster) +{ + int i; + matrix3_t rotation, rotation2, toWorld, partialBackToLocal; + vec3a_t localAngles; + + localAngles[0] = 0;//angles[0]; + localAngles[1] = 0;//angles[1]; + localAngles[2] = 0;//angles[2]; + + memset(rotation, 0, sizeof(rotation)); + + CMatrix::Matrix3FromAngles(angles, rotation); + + //D3DVECTOR dir, up; + vec3a_t fdir, fup; + + fdir[0] = joint->model.direction[0]; + fdir[1] = joint->model.direction[1]; + fdir[2] = joint->model.direction[2]; + + Vec3Normalize(fdir); + + fup[0] = joint->model.up[0]; + fup[1] = joint->model.up[1]; + fup[2] = joint->model.up[2]; + + Vec3Normalize(fup); + + localAngles[ROLL] += (float) CMatrix::Matricies3FromDirAndUp(fdir, fup, toWorld, partialBackToLocal); + + CMatrix::Matrix3MultByMartrix3(rotation, toWorld, rotation2); + CMatrix::Matrix3MultByMartrix3(partialBackToLocal, rotation2, rotation); + + for(i = 0; i < modelCluster->numVerticies; ++i) + { + CMatrix::RotatePointAboutLocalOrigin_d(rotation, joint->model.origin, modelVerticies[modelCluster->verticies[i]]); + } +} + +// frame tree ctrl support + +void CFlexModel::LoadFrameInfo(CTreeCtrl* treeDlg, HTREEITEM rootFrame) +{ + if (m_num_frames > 0) + { + m_numGroups = 0; + + m_treeInfo = new CTreeHead[m_num_frames]; + if (m_treeInfo == NULL) AfxMessageBox("Null tree"); + + CTreeGroup* groupList = new CTreeGroup[m_num_frames]; + if (groupList == NULL) AfxMessageBox("Null groupList"); + + for (int i = 0; i < m_num_frames; i++) + { + frameinfo2_t* frameinfo1 = (frameinfo2_t *)((char *)m_frames + m_framesize * i); + char name[18]; + memcpy(name , frameinfo1->name, 16); + name[16] = '\0'; + char* newname = name; + StripGroupName(newname); + int thisgroup = InGroupList(newname, groupList, m_numGroups); + if (thisgroup == -1) + { + thisgroup = m_numGroups; + groupList[thisgroup].head = treeDlg->InsertItem(newname, rootFrame, TVI_LAST); + treeDlg->SetItemData(groupList[thisgroup].head, thisgroup); + m_treeInfo[m_numGroups].bFrame = i; + m_numGroups++; + } + m_treeInfo[thisgroup].eFrame = i; + HTREEITEM item = treeDlg->InsertItem(frameinfo1->name, groupList[thisgroup].head); + treeDlg->SetItemData(item, i); + treeDlg->SetItemImage(item, 1, 1); + } + treeDlg->Expand(rootFrame, TVE_EXPAND); + if (groupList) + { + delete groupList; + groupList = NULL; + } + + } +} + +// file serialization support + +#define FM_HEADER_NAME "header" +#define FM_HEADER_VER 2 +#define FM_SKIN_NAME "skin" +#define FM_SKIN_VER 1 +#define FM_ST_NAME "st coord" +#define FM_ST_VER 1 +#define FM_TRI_NAME "tris" +#define FM_TRI_VER 1 +#define FM_FRAME_NAME "frames" +#define FM_FRAME_VER 1 +#define FM_SHORT_FRAME_NAME "short frames" +#define FM_SHORT_FRAME_VER 1 +#define FM_NORMAL_NAME "normals" +#define FM_NORMAL_VER 1 +#define FM_COMP_NAME "comp data" +#define FM_COMP_VER 1 +#define FM_GLCMDS_NAME "glcmds" +#define FM_GLCMDS_VER 1 +#define FM_MESH_NAME "mesh nodes" +#define FM_MESH_VER 3 +#define FM_SKELETON_NAME "skeleton" +#define FM_SKELETON_VER 1 +#define FM_REFERENCES_NAME "references" +#define FM_REFERENCES_VER 1 +#define FRAME_NAME_LEN (16) + +enum +{ + FM_BLOCK_HEADER, + FM_BLOCK_SKIN, + FM_BLOCK_ST, + FM_BLOCK_TRIS, + FM_BLOCK_FRAMES, + FM_BLOCK_GLCMDS, + FM_BLOCK_MESHNODES, + FM_BLOCK_SHORTFRAMES, + FM_BLOCK_NORMAL, + FM_BLOCK_COMP, + FM_BLOCK_SKELETON, + FM_BLOCK_REFERENCES, +}; + +fmblock_t CFlexModel::m_fmblocks[] = +{ + {FM_HEADER_NAME, FM_BLOCK_HEADER}, + {FM_SKIN_NAME, FM_BLOCK_SKIN}, + {FM_ST_NAME, FM_BLOCK_ST}, + {FM_TRI_NAME, FM_BLOCK_TRIS}, + {FM_FRAME_NAME , FM_BLOCK_FRAMES}, + {FM_GLCMDS_NAME, FM_BLOCK_GLCMDS}, + {FM_MESH_NAME, FM_BLOCK_MESHNODES}, + {FM_SHORT_FRAME_NAME, FM_BLOCK_SHORTFRAMES}, + {FM_NORMAL_NAME, FM_BLOCK_NORMAL}, + {FM_COMP_NAME, FM_BLOCK_COMP}, + {FM_SKELETON_NAME, FM_BLOCK_SKELETON}, + {FM_REFERENCES_NAME, FM_BLOCK_REFERENCES}, + {"", -1} +}; + +void CFlexModel::Serialize(CArchive& ar) +{ + DWORD filesize = ar.GetFile()->GetLength(); + char* buffer = new char[filesize]; + ar.Read(buffer, filesize); + + char* back = buffer; + + while(filesize > 0) + { + int version; + int size; + + char* blockname = buffer; + + int i = 0; + while (m_fmblocks[i].blocktype >= 0) + { + if (strcmpi(buffer, m_fmblocks[i].blockid)==0) + { + break; + } + i++; + } + buffer += sizeof(m_fmblocks[0].blockid); + version = *(int*)buffer; + buffer += sizeof(version); + size = *(int*)buffer; + buffer += sizeof(size); + filesize = filesize - sizeof(m_fmblocks[0].blockid) - sizeof(version) - sizeof(size); + + + CString foo; + switch (m_fmblocks[i].blocktype) + { + case FM_BLOCK_HEADER: + SerializeHeader(version, size, buffer); + break; + case FM_BLOCK_SKIN: + SerializeSkin(version, size, buffer); + break; + case FM_BLOCK_ST: + SerializeSt(version, size, buffer); + break; + case FM_BLOCK_TRIS: + SerializeTris(version, size, buffer); + break; + case FM_BLOCK_FRAMES: + SerializeFrames(version, size, buffer); + break; + case FM_BLOCK_GLCMDS: + SerializeGLCmds(version, size, buffer); + break; + case FM_BLOCK_MESHNODES: + SerializeMeshNodes(version, size, buffer); + break; + case FM_BLOCK_SHORTFRAMES: + SerializeShortFrames(version, size, buffer); + break; + case FM_BLOCK_NORMAL: + SerializeNormal(version, size, buffer); + break; + case FM_BLOCK_COMP: + SerializeComp(version, size, buffer); + break; + case FM_BLOCK_SKELETON: + SerializeSkeleton(version, size, buffer); + break; + case FM_BLOCK_REFERENCES: + SerializeReferences(version, size, buffer); + break; + default: + foo.Format("Unknown block %s\n", blockname); + AfxMessageBox(foo); + } + filesize -= size; + buffer += size; + } + + for (int i = 0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].SetVisible(true); + } + + m_curNode = -1; + if (back) + { + delete(back); + back = buffer = NULL; + } +} + +void CFlexModel::SerializeHeader(int version, int length, char *buffer) +{ + if (version != FM_HEADER_VER) + { + AfxMessageBox("Invalid header version for block\n"); + return; + } + + int* offset = (int*)buffer; + m_skinwidth = *offset++; + m_skinheight = *offset++; + m_framesize = *offset++; + m_num_skins = *offset++; + m_num_xyz = *offset++; + m_num_st = *offset++; + m_num_tris = *offset++; + m_num_glcmds = *offset++; + m_num_frames = *offset++; + m_num_mesh_nodes = *offset++; + + if ((char*)offset != (buffer + length)) + { + AfxMessageBox("Invalid header read"); + return; + } + + if (m_skinheight > MAX_LBM_HEIGHT) + { + AfxMessageBox("Model has a skin taller than max LBM height\n"); + return; + } + + if (m_num_xyz <= 0) + { + AfxMessageBox("Model has no verts\n"); + return; + } + + if (m_num_xyz > MAX_FM_VERTS) + { + AfxMessageBox("Model has too many vertices\n"); + return; + } + + if (m_num_st <= 0) + { + AfxMessageBox("Model has no st verts\n"); + return; + } + + if (m_num_tris <= 0) + { + AfxMessageBox("Model has no tris\n"); + return; + } + + if (m_num_frames <= 0) + { + AfxMessageBox("Model has no frames\n"); + return; + } +} + +void CFlexModel::SerializeSkin(int version, int length, char *buffer) +{ + if (m_skin_names != NULL) + { + AfxMessageBox("Duplicate skin block!\n"); + return; + } + if (version != FM_SKIN_VER) + { + AfxMessageBox("Invalid skin version!\n"); + return; + } + + CString filePath = m_filename; + int destChar = filePath.ReverseFind('\\'); + if (destChar > -1) + { + filePath = filePath.Left(destChar); + } + + m_skin_names = (char**)malloc(sizeof(char*) * m_num_skins); + char* strname = buffer; + + for (int i = 0; i < m_num_skins; i++) + { + CString result = strname; + strname += 64; + + while(true) + { + destChar = result.Find("/"); + if (destChar < 0) + { + break; + } + result.SetAt(destChar, '\\'); + } + + CString namePart; + CString partialPath = result; + destChar = partialPath.ReverseFind('\\'); + if (destChar > -1) + { + namePart = partialPath.Right(partialPath.GetLength() - destChar); + partialPath = partialPath.Left(destChar); + } + + if (partialPath.CompareNoCase(filePath.Right(partialPath.GetLength())) == 0) + { + partialPath = filePath; + } + partialPath = partialPath + namePart; + + m_skin_names[i] = (char*)malloc(partialPath.GetLength() + 1); + strcpy(m_skin_names[i], partialPath); + } +} + + +void CFlexModel::SerializeSt(int version, int length, char *buffer) +{ + // ignoring data +} + +void CFlexModel::SerializeTris(int version, int length, char *buffer) +{ + // ignoring data +} + +void CFlexModel::SerializeFrames(int version, int length, char *buffer) +{ + int i,j; + fmaliasframe_t *pinframe, *poutframe; + + if (m_frames != NULL) + { + AfxMessageBox("Duplicate frames block!\n"); + return; + } + if (version != FM_FRAME_VER) + { + AfxMessageBox("Invalid frames version\n"); + false; + } + + m_frames = (void*) malloc(m_num_frames * m_framesize); + + for (i=0 ; iname, pinframe->name, sizeof(poutframe->name)); + for (j=0 ; j<3 ; j++) + { + poutframe->scale[j] = pinframe->scale[j]; + poutframe->translate[j] = pinframe->translate[j]; + } + + // verts are all 8 bit, so no swapping needed + memcpy (poutframe->verts, pinframe->verts, m_num_xyz*sizeof(fmtrivertx_t)); + } +} + +void CFlexModel::SerializeGLCmds(int version, int length, char *buffer) +{ + if (m_glcmds != NULL) + { + AfxMessageBox("Duplicate glCmds block!\n"); + return; + } + if (version != FM_GLCMDS_VER) + { + AfxMessageBox("Invalid glcmds version\n"); + return; + } + + int* poutcmd = (int *) malloc(sizeof(int) * m_num_glcmds); + m_glcmds = (long*)poutcmd; + int* pincmd = (int *) ((byte *)buffer); + for (int i=0 ; i>3]; + byte verts[MAX_FM_VERTS>>3]; + short start_glcmds, num_glcmds; +} fmmeshnode_t; + +void CFlexModel::SerializeMeshNodes(int version, int length, char *buffer) +{ + int i; + fmmeshnode_t *node; + + if (m_nodes != NULL) + { + AfxMessageBox("Duplicate mesh node block!\n"); + return; + } + if (version != FM_MESH_VER) + { + AfxMessageBox("Invalid mesh version\n"); + return; + } + + if (m_num_mesh_nodes) + { + m_nodes = new CNode[m_num_mesh_nodes]; + for(i=0,node = (fmmeshnode_t *)buffer;i (MAX_FM_TRIANGLES>>3)) +// { +// numtris = MAX_FM_TRIANGLES>>3; +// } + m_nodes[i].SetTris(node->tris, numtris); + + int numverts = m_num_xyz; +// if (numverts > (MAX_FM_VERTS>>3)) +// { +// numverts = MAX_FM_VERTS>>3; +// } + m_nodes[i].SetVerts(node->verts, numverts); + m_nodes[i].SetGlcmds((long*)((long*)m_glcmds + node->start_glcmds), node->num_glcmds); + } + } +} + +void CFlexModel::SerializeShortFrames(int version, int length, char *buffer) +{ + if (m_framenames != NULL) + { + AfxMessageBox("Duplicate short frames block!\n"); + return; + } + AfxMessageBox("This is short frames\n"); + if (version != FM_SHORT_FRAME_VER) + { + AfxMessageBox("Invalid shortframes version\n"); + return; + } + +//?? m_frames=NULL; + m_framenames=(char *) (m_num_frames*FRAME_NAME_LEN); + memcpy(m_framenames,buffer,m_num_frames*FRAME_NAME_LEN); +} + +void CFlexModel::SerializeNormal(int version, int length, char *buffer) +{ + if (m_lightnormalindex != NULL) + { + AfxMessageBox("Duplicate light normal block!\n"); + return; + } + if (version != FM_NORMAL_VER) + { + AfxMessageBox("Invalid normal version\n"); + return; + } + m_lightnormalindex=(byte *)malloc(m_num_xyz*sizeof(byte)); + memcpy(m_lightnormalindex,buffer,m_num_xyz*sizeof(byte)); +} + +void CFlexModel::SerializeComp(int version, int length, char *buff) +{ + fmgroup_t *g; + char *buffer; + + AfxMessageBox("This is compressed\n"); + + buffer= (char *)buff; + g=&m_compdata; + + if (version != FM_COMP_VER) + { + AfxMessageBox("Invalid comp version\n"); + return; + } + + g->start_frame=*(int *)buffer; + buffer+=sizeof(int); + g->num_frames= *(int *)buffer; + buffer+=sizeof(int); + g->degrees=*(int *)buffer; + buffer+=sizeof(int); + + g->mat= (char *)malloc(m_num_xyz*3*g->degrees*sizeof(char)); + g->ccomp= (char *)malloc(g->num_frames*g->degrees*sizeof(char)); + g->cbase= (unsigned char*)malloc(m_num_xyz*3*sizeof(unsigned char)); + g->cscale= (float *)malloc(g->degrees*sizeof(float)); + g->coffset= (float *)malloc(g->degrees*sizeof(float)); + g->complerp=(float *)malloc(g->degrees*sizeof(float)); + + memcpy(g->mat,buffer,m_num_xyz*3*g->degrees*sizeof(char)); + buffer+=m_num_xyz*3*g->degrees*sizeof(char); + memcpy(g->ccomp,buffer,g->num_frames*g->degrees*sizeof(char)); + buffer+=g->num_frames*g->degrees*sizeof(char); + memcpy(g->cbase,buffer,m_num_xyz*3*sizeof(unsigned char)); + buffer+=m_num_xyz*3*sizeof(unsigned char); + memcpy(g->cscale,buffer,g->degrees*sizeof(float)); + buffer+=g->degrees*sizeof(float); + memcpy(g->coffset,buffer,g->degrees*sizeof(float)); + buffer+=g->degrees*sizeof(float); + memcpy(g->trans,buffer,3*sizeof(float)); + buffer+=3*sizeof(float); + memcpy(g->scale,buffer,3*sizeof(float)); + buffer+=3*sizeof(float); + memcpy(g->bmin,buffer,3*sizeof(float)); + buffer+=3*sizeof(float); + memcpy(g->bmax,buffer,3*sizeof(float)); + buffer+=3*sizeof(float); +} + +void CFlexModel::SerializeSkeleton(int version, int length, char *buffer) +{ + int i, j, k; + int *basei; + int runningTotalVertices = 0; + int indexBase = 0; + float *basef; + + if (m_skeletons != NULL) + { + AfxMessageBox("Duplicate skeleton block!\n"); + return; + } + if (version != FM_SKELETON_VER) + { + AfxMessageBox("Invalid skeleton version\n"); + return; + } + + basei = (int *)buffer; + + m_skeletalType = *basei; + + m_numClusters = *(++basei); + + m_jointConstraintAngles = new rangeVector_t[m_numClusters]; + m_modelJointAngles = new D3DVECTOR[m_numClusters]; + m_skeletalClusters = new M_SkeletalCluster_t[m_numClusters]; + + for(i = m_numClusters - 1; i >= 0; --i) + { + m_jointConstraintAngles[i].min.x = 0; + m_jointConstraintAngles[i].min.y = 0; + m_jointConstraintAngles[i].min.z = 0; + m_jointConstraintAngles[i].max.x = 0; + m_jointConstraintAngles[i].max.y = 0; + m_jointConstraintAngles[i].max.z = 0; + m_modelJointAngles[i].x = 0; + m_modelJointAngles[i].y = 0; + m_modelJointAngles[i].z = 0; + + runningTotalVertices += *(++basei); + m_skeletalClusters[i].numVerticies = runningTotalVertices; + m_skeletalClusters[i].verticies = (int*)malloc(m_skeletalClusters[i].numVerticies*sizeof(int)); + } + + for(j = m_numClusters - 1; j >= 0; --j) + { + for(i = indexBase; i < m_skeletalClusters[j].numVerticies; ++i) + { + ++basei; + + for(k = 0; k <= j; ++ k) + { + m_skeletalClusters[k].verticies[i] = *basei; + } + } + + indexBase = m_skeletalClusters[j].numVerticies; + } + + if(*(++basei)) + { + basef = (float *)++basei; + + m_skeletons = (ModelSkeleton_t*) malloc(m_num_frames*sizeof(ModelSkeleton_t)); + + for (i = 0; i < m_num_frames; ++i) + { + for(j = 0; j < m_numClusters; ++j) + { + m_skeletons[i].rootJoint[j].model.origin[0] = *(basef++); + m_skeletons[i].rootJoint[j].model.origin[1] = *(basef++); + m_skeletons[i].rootJoint[j].model.origin[2] = *(basef++); + + m_skeletons[i].rootJoint[j].model.direction[0] = *(basef++); + m_skeletons[i].rootJoint[j].model.direction[1] = *(basef++); + m_skeletons[i].rootJoint[j].model.direction[2] = *(basef++); + + m_skeletons[i].rootJoint[j].model.up[0] = *(basef++); + m_skeletons[i].rootJoint[j].model.up[1] = *(basef++); + m_skeletons[i].rootJoint[j].model.up[2] = *(basef++); + } + } + + } + else + { + m_num_xyz -= m_numClusters*3; + } +} + +void CFlexModel::SerializeReferences(int version, int length, char *buffer) +{ + if (version != FM_REFERENCES_VER) + { + AfxMessageBox("Invalid reference version\n"); + return; + } + + int* basei = (int*)buffer; + m_referenceType = *basei++; + /* remainder of this data structure is hard coded logic for specific models -- just ignore */ +} + +// skin texture support + +void CFlexModel::SetTransparency(LPDIRECT3DRM2 d3drm, CDC* pDC, bool trans) +{ + for (int i = 0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].SetTransparency(d3drm, pDC, trans); + } +} + +// joint support + +void CFlexModel::ToggleJointOn() +{ + m_jointsOn = !m_jointsOn; +} + +bool CFlexModel::IsJointOn() +{ + return m_jointsOn; +} + +void CFlexModel::ConstrainJoint() +{ + if (m_jointConstraintAngles[m_curJoint].max.x || m_jointConstraintAngles[m_curJoint].min.x) + { + if (m_modelJointAngles[m_curJoint].x > m_jointConstraintAngles[m_curJoint].max.x) + m_modelJointAngles[m_curJoint].x = m_jointConstraintAngles[m_curJoint].max.x; + + if (m_modelJointAngles[m_curJoint].x < m_jointConstraintAngles[m_curJoint].min.x) + m_modelJointAngles[m_curJoint].x = m_jointConstraintAngles[m_curJoint].min.x; + } + + if (m_jointConstraintAngles[m_curJoint].max.y || m_jointConstraintAngles[m_curJoint].min.y) + { + if (m_modelJointAngles[m_curJoint].y > m_jointConstraintAngles[m_curJoint].max.y) + m_modelJointAngles[m_curJoint].y = m_jointConstraintAngles[m_curJoint].max.y; + + if (m_modelJointAngles[m_curJoint].y < m_jointConstraintAngles[m_curJoint].min.y) + m_modelJointAngles[m_curJoint].y = m_jointConstraintAngles[m_curJoint].min.y; + } + + if (m_jointConstraintAngles[m_curJoint].max.z || m_jointConstraintAngles[m_curJoint].min.z) + { + if (m_modelJointAngles[m_curJoint].z > m_jointConstraintAngles[m_curJoint].max.z) + m_modelJointAngles[m_curJoint].z = m_jointConstraintAngles[m_curJoint].max.z; + + if (m_modelJointAngles[m_curJoint].z < m_jointConstraintAngles[m_curJoint].min.z) + m_modelJointAngles[m_curJoint].z = m_jointConstraintAngles[m_curJoint].min.z; + } + +// ShowFrame(); +} + +void CFlexModel::GetModelAngles(float* x, float* y, float* z) +{ + *x = m_modelJointAngles[m_curJoint].x; + *y = m_modelJointAngles[m_curJoint].y; + *z = m_modelJointAngles[m_curJoint].z; +} + +void CFlexModel::SetModelAngles(float x, float y, float z) +{ + m_modelJointAngles[m_curJoint].x = x; + m_modelJointAngles[m_curJoint].y = y; + m_modelJointAngles[m_curJoint].z = z; + + if (m_modelJointAngles[m_curJoint].y > PI*2) + m_modelJointAngles[m_curJoint].y = (float) PI*2 - m_modelJointAngles[m_curJoint].y; + else if (m_modelJointAngles[m_curJoint].y < 0) + m_modelJointAngles[m_curJoint].y = (float) PI*2 + m_modelJointAngles[m_curJoint].y; + + if (m_modelJointAngles[m_curJoint].x > PI*2) + m_modelJointAngles[m_curJoint].x = (float) PI*2 - m_modelJointAngles[m_curJoint].x; + else if (m_modelJointAngles[m_curJoint].x < 0) + m_modelJointAngles[m_curJoint].x = (float) PI*2 + m_modelJointAngles[m_curJoint].x; + + if (m_modelJointAngles[m_curJoint].z > PI*2) + m_modelJointAngles[m_curJoint].z = (float) PI*2 - m_modelJointAngles[m_curJoint].z; + else if (m_modelJointAngles[m_curJoint].z < 0) + m_modelJointAngles[m_curJoint].z = (float) PI*2 + m_modelJointAngles[m_curJoint].z; +} + +void CFlexModel::RenderTexture(LPDIRECT3DRM2 d3drm, CDC* pDC, bool useTexture) +{ + for (int i = 0; i < m_num_mesh_nodes; i++) + { + m_nodes[i].RenderTexture(d3drm, pDC, useTexture); + } +} + +void CFlexModel::GetConstraintAngleMaxs(float* x, float* y, float* z) +{ + *x = m_jointConstraintAngles[m_curJoint].max.x; + *y = m_jointConstraintAngles[m_curJoint].max.y; + *z = m_jointConstraintAngles[m_curJoint].max.z; +} + +void CFlexModel::GetConstraintAngleMins(float* x, float* y, float* z) +{ + *x = m_jointConstraintAngles[m_curJoint].min.x; + *y = m_jointConstraintAngles[m_curJoint].min.y; + *z = m_jointConstraintAngles[m_curJoint].min.z; +} + +void CFlexModel::SetConstraintAngleMaxs(float x, float y, float z) +{ + m_jointConstraintAngles[m_curJoint].max.x = x; + m_jointConstraintAngles[m_curJoint].max.y = y; + m_jointConstraintAngles[m_curJoint].max.z = z; + ConstrainJoint(); +} + +void CFlexModel::SetConstraintAngleMins(float x, float y, float z) +{ + m_jointConstraintAngles[m_curJoint].min.x = x; + m_jointConstraintAngles[m_curJoint].min.y = y; + m_jointConstraintAngles[m_curJoint].min.z = z; + ConstrainJoint(); +} + +// joint tree control support + +void CFlexModel::AddJoints(CTreeCtrl* pCTree, HTREEITEM rootJoint) +{ + if (m_skeletons != NULL) + { + CString name; + for (int i = 0; i < m_numClusters; i++) + { + name.Format("Joint %d", i); + HTREEITEM item = pCTree->InsertItem(name, rootJoint, TVI_LAST); + pCTree->SetItemData(item, i); + pCTree->SetItemImage(item, 1, 1); + } + pCTree->Expand(rootJoint, TVE_EXPAND); + } +} + +// property page support + +void CFlexModel::AddPropPages(CPropertySheet* propSheet) +{ + CModel::AddPropPages(propSheet); + // add private pages +} + +void CFlexModel::UpdateFromPropPages(CPropertySheet* propSheet) +{ + // update data from private pages (some could be after) + CModel::UpdateFromPropPages(propSheet); + // update data from private pages (some could be before) +} + +void CFlexModel::RemovePropPages(CPropertySheet* propSheet) +{ + // remove private pages + CModel::RemovePropPages(propSheet); +} + diff --git a/Toolkit/Programming/Tools/qMView/FlexModel.h b/Toolkit/Programming/Tools/qMView/FlexModel.h new file mode 100644 index 0000000..a3da3f7 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/FlexModel.h @@ -0,0 +1,259 @@ +// FlexModel.h +// + +#define MAX_LBM_HEIGHT 480 +#define MAX_FM_TRIANGLES 2048 +#define MAX_FM_VERTS 2048 +#define MAX_FM_FRAMES 2048 +#define MAX_FM_SKINS 64 +#define MAX_FM_SKINNAME 64 +#define MAX_FM_MESH_NODES 16 // also defined in game/qshared.h +#define MAX_JOINTS_PER_SKELETON 8 // arbitrary small number +#define MAX_JOINT_NODES_PER_SKELETON (MAX_JOINTS_PER_SKELETON - 1) +#define JOINT_VISUALS 10 +#define SKELETON_COUNT 256 + +class CNode +{ +public: + void Init(); + void Delete(); + + void DeleteMesh(); + LPDIRECT3DRMMESH GetMesh(); + + void SetSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, CSkin* skin, int skinnum); + void ChangeSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, CSkin* skin); + void LoadSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, CSkin* skin, int skinnum); + + CBitmap* GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC, int& width, int& height); + void AddVisual(LPDIRECT3DRMFRAME frame); + bool IsVisible(); + void SetVisible(bool visible); + int GetNumTris(); + void SetTris(byte* buf, int numTris); + void SetVerts(byte* buf, int numVerts); + void SetGlcmds(long* glcmds, int num); + void SetTexture(bool useTexture); + + HRESULT SetQuality(D3DRMRENDERQUALITY value); + void SetTransparency(LPDIRECT3DRM2 d3drm, CDC* pDC, bool trans); + HRESULT SetColorRGB(D3DVALUE red, D3DVALUE green, D3DVALUE blue); + void RenderTexture(LPDIRECT3DRM2 d3drm, CDC* pDC, bool useTexture); + + void BuildMesh(LPDIRECT3DRM2 d3drm, frameinfo2_t* frameinfo1, int skinwidth, int shinheight); + bool ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC, vec3a_t* rotVerts, frameinfo2_t* frameinfo1); + void ShowInterFrame(LPDIRECT3DRM2 d3drm, CDC* pDC, frameinfo2_t* frameinfo1, frameinfo2_t* frameinfo2, int step, int numsteps); + + HTREEITEM m_treeitem; +// char* m_skinbuf; +// int m_skinheight; +// int m_skinwidth; +// LPDIRECT3DRMTEXTURE m_texture; +protected: + int* m_vertPath; + byte* m_tris; + byte* m_verts; + long* m_start_glcmds; + short m_num_glcmds; + LPDIRECT3DRMMESH m_mesh; + bool m_visible; + int m_numTris; + int m_numVerts; + + long m_group; + int m_defaultSkin; + CSkin* m_curSkin; +}; + +typedef struct +{ + LPDIRECT3DRMMESH dir, up, origin, right; +} jointTri; + +typedef struct +{ + D3DVECTOR min, max; +} rangeVector_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} fmtriangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} fmtrivertx_t; + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + fmtrivertx_t verts[1]; // variable sized +} fmaliasframe_t; + +typedef struct +{ + int start_frame; + int num_frames; + int degrees; + char *mat; + char *ccomp; + unsigned char *cbase; + float *cscale; + float *coffset; + float trans[3]; + float scale[3]; + float bmin[3]; + float bmax[3]; + float *complerp; +} fmgroup_t; + +typedef struct M_SkeletalCluster_s +{ + int children; // must be the first field + int numVerticies; + int *verticies; + qboolean inUse; +} M_SkeletalCluster_t; + +typedef struct +{ + char blockid[32]; + int blocktype; +} fmblock_t; + +// flex model itself + +class CFlexModel : public CModel +{ +public: + CFlexModel(); + ~CFlexModel(); + virtual void Delete(); + + virtual CBitmap* GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC, int skinnum, int& width, int& height); + virtual void DeleteVisuals(LPDIRECT3DRMFRAME frame); + virtual void DeleteMeshs(LPDIRECT3DRMFRAME frame); + virtual void RenderTexture(LPDIRECT3DRM2 d3drm, CDC* pDC, bool useTexture); + virtual void CreateJointVisuals(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame); + + virtual LPDIRECT3DRMMESH GetMesh(int i); + virtual void MakeAllNodesVisible(LPDIRECT3DRMFRAME frame); + virtual bool ToggleNodeVisibility(int node); + virtual HTREEITEM SelectMesh(LPDIRECT3DRMVISUAL selection); + virtual int SelectNode(int nodeNum); + virtual void ChangeVisual(LPDIRECT3DRMFRAME frame, int nodeNum); + virtual void DeSelectAll(); + virtual HRESULT SetGroupQuality(D3DRMRENDERQUALITY value); + virtual void BuildMesh(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene, CDC* pDC); + virtual bool ValidNode(); + virtual long GetNumNodes(); + virtual long GetNumTris(); + + CSkin* GetSkin(int i); + virtual void ReplaceSkin(int i, LPCTSTR skinname); + virtual void AddSkin(LPCTSTR skinname); + virtual void FillMenuWithSkins(CMenu* menu); + virtual void ChangeSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, int nodenum, int skinnum); + + virtual BOOL ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC); + + virtual void Drag(double delta_x, double delta_y); + virtual void Snap(); + + virtual BOOL CalcInterpolate(LPDIRECT3DRM2 d3drm, CDC* pDC, int step, int numsteps, int intertype, int direction); + + // Ctrl window support + virtual void AddJoints(CTreeCtrl* pCTree, HTREEITEM rootJoint); + virtual void AddNodes (CTreeCtrl*pCTree, HTREEITEM rootNode); + virtual void LoadSkinInfo(CTreeCtrl* pCTree, HTREEITEM rootSkin); + virtual bool LoadSkin(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, int skinnum, CDC* pDC); +// frame tree ctrl support + virtual void LoadFrameInfo(CTreeCtrl* treeDlg, HTREEITEM rootFrame); + +protected: + fmgroup_t m_compdata; + char* m_framenames; + byte* m_lightnormalindex; + + char** m_skin_names; + + int m_num_mesh_nodes; + CNode* m_nodes; + int m_curNode; + + int m_skeletalType; + ModelSkeleton_t* m_skeletons; + jointTri m_joint_visuals[JOINT_VISUALS]; + int m_referenceType; + + + virtual void Init(); + void UpdateJointVisuals(int jointNum); + void FillRawVerts(vec3a_t *foo); + + void CreateJointVisual(LPDIRECT3DRM2 d3drm, Placement_t model, int jointNum, LPDIRECT3DRMFRAME frame); + +// File read support + static fmblock_t m_fmblocks[]; + + virtual void Serialize(CArchive& ar); + void SerializeHeader(int version, int length, char* buffer); + void SerializeSkin(int version, int length, char* buffer); + void SerializeSt(int version, int length, char* buffer); + void SerializeTris(int version, int length, char* buffer); + void SerializeFrames(int version, int length, char* buffer); + void SerializeGLCmds(int version, int length, char* buffer); + void SerializeMeshNodes(int version, int length, char* buffer); + void SerializeShortFrames(int version, int length, char* buffer); + void SerializeNormal(int version, int length, char* buffer); + void SerializeComp(int version, int length, char* buffer); + void SerializeSkeleton(int version, int length, char* buffer); + void SerializeReferences(int version, int length, char* buffer); + +// Ctrl Window Support + void AddNode (CTreeCtrl* pCTree, HTREEITEM rootNode, int nodeNum); + void RotateModelSegment(M_SkeletalJoint_t *joint, vec3a_t *modelVerticies, vec3a_t angles, M_SkeletalCluster_t *modelCluster); + +// skin texturing support + +public: + virtual void SetTransparency(LPDIRECT3DRM2 d3drm, CDC* pDC, bool trans); + + // joint support +public: + virtual bool IsJointOn(); + virtual void ToggleJointOn(); + virtual void GetModelAngles(float* x, float* y, float* z); + virtual void SetModelAngles(float x, float y, float z); + virtual void GetConstraintAngleMaxs(float* x, float* y, float* z); + virtual void GetConstraintAngleMins(float* x, float* y, float* z); + virtual void SetConstraintAngleMaxs(float x, float y, float z); + virtual void SetConstraintAngleMins(float x, float y, float z); + virtual void SetCurJoint(long joint); + virtual long GetCurJoint(); + +protected: + bool m_jointsOn; + long m_curJoint; + rangeVector_t* m_jointConstraintAngles; + D3DVECTOR* m_modelJointAngles; + M_SkeletalCluster_t* m_skeletalClusters; + int m_numClusters; + + void ConstrainJoint(); + + // property sheet support +public: + virtual void AddPropPages(CPropertySheet* propSheet); + virtual void UpdateFromPropPages(CPropertySheet* propSheet); + virtual void RemovePropPages(CPropertySheet* propSheet); +protected: + // specific prop page declaration +}; + diff --git a/Toolkit/Programming/Tools/qMView/FrameManager2.cpp b/Toolkit/Programming/Tools/qMView/FrameManager2.cpp new file mode 100644 index 0000000..a9cdad2 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/FrameManager2.cpp @@ -0,0 +1,113 @@ +// FrameManager2.cpp : implementation file +// + +#include "stdafx.h" +#include "DDutil.h" +#include "qMView.h" +#include "Matrix.h" +#include "Model.h" +#include "JointConstraintDlg.h" +#include "JointAnglesDlg.h" +#include "FrameManager2.h" + +#include "NodeTreeCtrl.h" +#include "JointTreeCtrl.h" +#include "SkinTreeCtrl.h" +#include "FrameTreeCtrl.h" +#include "ManagerTree.h" +#include "MainFrm.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// FrameManager2 + +FrameManager2::FrameManager2() +{ +} + +FrameManager2::~FrameManager2() +{ +} + +void FrameManager2::DeleteContents() +{ + m_nNodeTree->DeleteContents(); + m_nJointTree->DeleteContents(); +} + +void FrameManager2::PickNode(HTREEITEM item) +{ + m_nNodeTree->Select(item,TVGN_CARET); +} + +CTreeCtrl* FrameManager2::GetNodeTreeCtrl() +{ + return m_nNodeTree; +} + +CModel* FrameManager2::GetModel() +{ + return ((CMainFrame*)GetParent())->GetModel(); +} + +void FrameManager2::SetModel(CModel* model) +{ + m_nNodeTree->SetModel(model); + m_nJointTree->SetModel(model); +} + +BOOL FrameManager2::Create(CWnd* pParentWnd, UINT nStyle) +{ + if (!CDialogBar::Create (pParentWnd, CG_IDD_FRAMEMANAGER2, nStyle, CG_IDD_FRAMEMANAGER2)) + return FALSE; + + m_nNodeTree = new CNodeTreeCtrl(); + m_nJointTree = new CJointTreeCtrl(); + m_nNodeTree->SubclassDlgItem(IDC_NODETREE,this); + m_nJointTree->SubclassDlgItem(IDC_JOINTTREE,this); + m_nNodeTree->SetModel(NULL); + m_nJointTree->SetModel(NULL); + return TRUE; +} + +BEGIN_MESSAGE_MAP(FrameManager2, CDialogBar) + //{{AFX_MSG_MAP(FrameManager2) + ON_WM_RBUTTONDOWN() + ON_WM_DESTROY() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// FrameManager2 message handlers + +void FrameManager2::OnRButtonDown(UINT nFlags, CPoint point) +{ + CDialogBar::OnRButtonDown(nFlags, point); +} + +void FrameManager2::OnDestroy() +{ + CDialogBar::OnDestroy(); + + // TODO: Add your message handler code here + + if (m_nNodeTree != NULL) + { + m_nNodeTree->DestroyWindow(); + delete m_nNodeTree; + m_nNodeTree = NULL; + } + + if (m_nJointTree != NULL) + { + m_nJointTree->DestroyWindow(); + delete m_nJointTree; + m_nJointTree = NULL; + } +} diff --git a/Toolkit/Programming/Tools/qMView/FrameManager2.h b/Toolkit/Programming/Tools/qMView/FrameManager2.h new file mode 100644 index 0000000..7792c61 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/FrameManager2.h @@ -0,0 +1,60 @@ +#if !defined(AFX_FRAMEMANAGER2_H__358B2D84_C279_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_FRAMEMANAGER2_H__358B2D84_C279_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// FrameManager2.h : header file +// + +#include "NodeTreeCtrl.h" +#include "JointTreeCtrl.h" + +///////////////////////////////////////////////////////////////////////////// +// FrameManager2 window + +class FrameManager2 : public CDialogBar +{ +// Construction +public: + + CNodeTreeCtrl* m_nNodeTree; + CJointTreeCtrl* m_nJointTree; + FrameManager2(); + BOOL Create(CWnd* pParentWnd, UINT nStyle); + void DeleteContents(); + void PickNode(HTREEITEM item); + CModel* GetModel(); + CTreeCtrl* GetNodeTreeCtrl(); + +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(FrameManager2) + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~FrameManager2(); + void SetModel(CModel* model); + + // Generated message map functions +protected: + //{{AFX_MSG(FrameManager2) + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnDestroy(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_FRAMEMANAGER2_H__358B2D84_C279_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/FrameTreeCtrl.cpp b/Toolkit/Programming/Tools/qMView/FrameTreeCtrl.cpp new file mode 100644 index 0000000..ca5bfaf --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/FrameTreeCtrl.cpp @@ -0,0 +1,133 @@ +// FrameTreeCtrl.cpp : implementation file +// + +#include "stdafx.h" +#include "DDUtil.h" +#include "qMView.h" +#include "Matrix.h" +#include "Model.h" +#include "FrameTreeCtrl.h" +#include "SkinTreeCtrl.h" +#include "ManagerTree.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CFrameTreeCtrl + +CFrameTreeCtrl::CFrameTreeCtrl() +{ + m_rootFrame = NULL; +} + +CFrameTreeCtrl::~CFrameTreeCtrl() +{ +} + +void CFrameTreeCtrl::DeleteContents() +{ + DeleteAllItems(); + m_rootFrame = InsertItem("Animations", TVI_ROOT, TVI_FIRST); + SetItemImage(m_rootFrame, 0, 0); +} + +CModel* CFrameTreeCtrl::GetModel() +{ + return ((CManagerTree*)GetParent())->GetModel(); +} + +void CFrameTreeCtrl::SetModel(CModel* model) +{ + DeleteContents(); + if (model != NULL) + { + model->LoadFrameInfo(this, m_rootFrame); + } +} + +BEGIN_MESSAGE_MAP(CFrameTreeCtrl, CTreeCtrlEx) + //{{AFX_MSG_MAP(CFrameTreeCtrl) + ON_WM_LBUTTONDOWN() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CFrameTreeCtrl message handlers + +void CFrameTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) +{ + CTreeCtrlEx::OnLButtonDown(nFlags, point); + + CModel* model = GetModel(); + if (model == NULL) + { + return; + } + + int count = GetSelectedCount(); + + if (count > 0) + { + model->SetCurGroup(-1); + HTREEITEM thisSel = GetFirstSelectedItem(); + if (thisSel == m_rootFrame) + { + model->SetPunch(false); + model->SetCurFrame(0); + ((CFrameWnd*)AfxGetMainWnd())->GetActiveDocument()->UpdateAllViews(NULL, QM_UPDATE_MODEL, NULL); + return; + } + + model->SetPunch(true); + + frameStruct* frameSels = model->GetFrameSels(); + if (frameSels->frames != NULL) + { + delete frameSels->frames; + frameSels->frames = NULL; + } + frameSels->frames = new int[model->GetNumFrames()]; + frameSels->numFrames = 0; + frameSels->info = 0; + + + while (thisSel) + { + if (GetParentItem(thisSel) == m_rootFrame) + { + int i = GetItemData(thisSel); + model->SetCurGroup(i); + count -= 1; + for (int j = model->GetTreeInfo(i)->bFrame; j <= model->GetTreeInfo(i)->eFrame; j++) + { + frameSels->frames[frameSels->numFrames] = j; + frameSels->numFrames++; + count++; + } + } + else + { + frameSels->frames[frameSels->numFrames] = GetItemData(thisSel); + frameSels->numFrames++; + } + thisSel = GetNextSelectedItem(thisSel); + } + model->SetCurFrame(frameSels->frames[0]); + ((CFrameWnd*)AfxGetMainWnd())->GetActiveDocument()->UpdateAllViews(NULL, QM_UPDATE_MODEL, NULL); + } + else + model->SetPunch(false); +} + +void CFrameTreeCtrl::PreSubclassWindow() +{ + // TODO: Add your specialized code here and/or call the base class + + CTreeCtrlEx::PreSubclassWindow(); + m_image.Create(IDB_BITMAP1, 13, 1, RGB(255,255,255)); + SetImageList(&(m_image), TVSIL_NORMAL); +} diff --git a/Toolkit/Programming/Tools/qMView/FrameTreeCtrl.h b/Toolkit/Programming/Tools/qMView/FrameTreeCtrl.h new file mode 100644 index 0000000..b9ace83 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/FrameTreeCtrl.h @@ -0,0 +1,46 @@ +// FrameTreeCtrl.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CFrameTreeCtrl window + +#include "TreeCtrlEx.h" + +class CFrameTreeCtrl : public CTreeCtrlEx +{ +// Construction +public: + CFrameTreeCtrl(); + void SetModel(CModel* model); + void DeleteContents(); + CModel* GetModel(); +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CFrameTreeCtrl) + protected: + virtual void PreSubclassWindow(); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CFrameTreeCtrl(); + + // Generated message map functions +protected: + //{{AFX_MSG(CFrameTreeCtrl) + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() + + CImageList m_image; + HTREEITEM m_rootFrame; +}; + +///////////////////////////////////////////////////////////////////////////// diff --git a/Toolkit/Programming/Tools/qMView/GeneralPref.cpp b/Toolkit/Programming/Tools/qMView/GeneralPref.cpp new file mode 100644 index 0000000..e9f0033 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/GeneralPref.cpp @@ -0,0 +1,41 @@ +// GeneralPref.cpp : implementation file +// + +#include "stdafx.h" +#include "qMView.h" +#include "GeneralPref.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CGeneralPref + +IMPLEMENT_DYNAMIC(CGeneralPref, CPropertySheet) + +CGeneralPref::CGeneralPref(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) + :CPropertySheet(nIDCaption, pParentWnd, iSelectPage) +{ +} + +CGeneralPref::CGeneralPref(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) + :CPropertySheet(pszCaption, pParentWnd, iSelectPage) +{ +} + +CGeneralPref::~CGeneralPref() +{ +} + + +BEGIN_MESSAGE_MAP(CGeneralPref, CPropertySheet) + //{{AFX_MSG_MAP(CGeneralPref) + // NOTE - the ClassWizard will add and remove mapping macros here. + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGeneralPref message handlers diff --git a/Toolkit/Programming/Tools/qMView/GeneralPref.h b/Toolkit/Programming/Tools/qMView/GeneralPref.h new file mode 100644 index 0000000..6eb555f --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/GeneralPref.h @@ -0,0 +1,41 @@ +// GeneralPref.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CGeneralPref + +#include "stdafx.h" + +class CGeneralPref : public CPropertySheet +{ + DECLARE_DYNAMIC(CGeneralPref) + +// Construction +public: + CGeneralPref(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); + CGeneralPref(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); + +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGeneralPref) + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CGeneralPref(); + + // Generated message map functions +protected: + //{{AFX_MSG(CGeneralPref) + // NOTE - the ClassWizard will add and remove member functions here. + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// diff --git a/Toolkit/Programming/Tools/qMView/JointAnglesDlg.cpp b/Toolkit/Programming/Tools/qMView/JointAnglesDlg.cpp new file mode 100644 index 0000000..11535e9 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/JointAnglesDlg.cpp @@ -0,0 +1,102 @@ +// JointAnglesDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "DDUtil.h" +#include "qMView.h" + +#include "Matrix.h" +#include "Model.h" +#include "JointAnglesDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CJointAnglesDlg dialog + + +CJointAnglesDlg::CJointAnglesDlg(CWnd* pParent /*=NULL*/) + : CDialog(CJointAnglesDlg::IDD, pParent) +{ + m_model = NULL; + //{{AFX_DATA_INIT(CJointAnglesDlg) + m_nXVal = 0.0f; + m_nYVal = 0.0f; + m_nZVal = 0.0f; + //}}AFX_DATA_INIT +} + + +void CJointAnglesDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CJointAnglesDlg) + DDX_Control(pDX, IDC_ZVAL, m_nZCtrl); + DDX_Control(pDX, IDC_YVAL, m_nYCtrl); + DDX_Control(pDX, IDC_XVAL, m_nXCtrl); + DDX_Text(pDX, IDC_XVAL, m_nXVal); + DDX_Text(pDX, IDC_YVAL, m_nYVal); + DDX_Text(pDX, IDC_ZVAL, m_nZVal); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CJointAnglesDlg, CDialog) + //{{AFX_MSG_MAP(CJointAnglesDlg) + ON_WM_HSCROLL() + ON_BN_CLICKED(IDC_APPLY, OnApplyClicked) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CJointAnglesDlg message handlers + +void CJointAnglesDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + // TODO: Add your message handler code here and/or call default + + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); +} + +BOOL CJointAnglesDlg::OnInitDialog() +{ + if (m_model != NULL) + { + m_model->GetModelAngles(&m_nXVal, &m_nYVal, &m_nZVal); + } + CDialog::OnInitDialog(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CJointAnglesDlg::OnApplyClicked() +{ + UpdateData(true); + + if (m_model != NULL) + { + m_model->SetModelAngles(m_nXVal, m_nYVal, m_nZVal); + +// m_model->ShowFrame(); + } +} + +void CJointAnglesDlg::UpdateVisuals(void) +{ + if (m_model != NULL) + { + m_model->GetModelAngles(&m_nXVal, &m_nYVal, &m_nZVal); + + UpdateData(false); + } +} + +void CJointAnglesDlg::SetModel(CModel* model) +{ + model = m_model; +} \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qMView/JointAnglesDlg.h b/Toolkit/Programming/Tools/qMView/JointAnglesDlg.h new file mode 100644 index 0000000..d246f03 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/JointAnglesDlg.h @@ -0,0 +1,58 @@ +#if !defined(AFX_JOINTANGLESDLG_H__4203DC61_D052_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_JOINTANGLESDLG_H__4203DC61_D052_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// JointAnglesDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CJointAnglesDlg dialog + +class CJointAnglesDlg : public CDialog +{ +// Construction +public: + void SetModel(CModel* model); + CJointAnglesDlg(CWnd* pParent = NULL); // standard constructor + + void UpdateVisuals(void); + + // Dialog Data + //{{AFX_DATA(CJointAnglesDlg) + enum { IDD = IDD_JOINT_ANGLES }; + CEdit m_nZCtrl; + CEdit m_nYCtrl; + CEdit m_nXCtrl; + float m_nXVal; + float m_nYVal; + float m_nZVal; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CJointAnglesDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CJointAnglesDlg) + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + virtual BOOL OnInitDialog(); + afx_msg void OnApplyClicked(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + CModel* m_model; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_JOINTANGLESDLG_H__4203DC61_D052_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/JointConstraintDlg.cpp b/Toolkit/Programming/Tools/qMView/JointConstraintDlg.cpp new file mode 100644 index 0000000..b4d2a40 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/JointConstraintDlg.cpp @@ -0,0 +1,87 @@ +// JointConstraintDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "DDUtil.h" +#include "qMView.h" +#include "Matrix.h" + +#include "Model.h" +#include "JointConstraintDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CJointConstraintDlg dialog + +CJointConstraintDlg::CJointConstraintDlg(CWnd* pParent /*=NULL*/) + : CDialog(CJointConstraintDlg::IDD, pParent) +{ + m_model = NULL; + //{{AFX_DATA_INIT(CJointConstraintDlg) + m_nXVal = 0.0f; + m_nYVal = 0.0f; + m_nZVal = 0.0f; + m_nXVal2 = 0.0f; + m_nYVal2 = 0.0f; + m_nZVal2 = 0.0f; + //}}AFX_DATA_INIT +} + + +void CJointConstraintDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CJointConstraintDlg) + DDX_Text(pDX, IDC_XVAL, m_nXVal); + DDX_Text(pDX, IDC_YVAL, m_nYVal); + DDX_Text(pDX, IDC_ZVAL, m_nZVal); + DDX_Text(pDX, IDC_XVAL2, m_nXVal2); + DDX_Text(pDX, IDC_YVAL2, m_nYVal2); + DDX_Text(pDX, IDC_ZVAL2, m_nZVal2); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CJointConstraintDlg, CDialog) + //{{AFX_MSG_MAP(CJointConstraintDlg) + // NOTE: the ClassWizard will add message map macros here + ON_BN_CLICKED(IDC_APPLY, OnApplyClicked) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CJointConstraintDlg message handlers + +BOOL CJointConstraintDlg::OnInitDialog() +{ + if (m_model != NULL) + { + m_model->GetConstraintAngleMaxs(&m_nXVal, &m_nYVal, &m_nZVal); + m_model->GetConstraintAngleMins(&m_nXVal2, &m_nYVal2, &m_nZVal2); + } + CDialog::OnInitDialog(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CJointConstraintDlg::OnApplyClicked() +{ + UpdateData(true); + if (m_model != NULL) + { + m_model->SetConstraintAngleMaxs(m_nXVal, m_nYVal, m_nZVal); + m_model->SetConstraintAngleMins(m_nXVal2, m_nYVal2, m_nZVal2); +// m_model->ShowFrame(); + } +} + +void CJointConstraintDlg::SetModel(CModel* model) +{ + m_model = model; +} \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qMView/JointConstraintDlg.h b/Toolkit/Programming/Tools/qMView/JointConstraintDlg.h new file mode 100644 index 0000000..6fb8d19 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/JointConstraintDlg.h @@ -0,0 +1,57 @@ +#if !defined(AFX_JOINTCONSTRAINTDLG_H__4203DC62_D052_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_JOINTCONSTRAINTDLG_H__4203DC62_D052_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// JointConstraintDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CJointConstraintDlg dialog + +class CJointConstraintDlg : public CDialog +{ +// Construction +public: + void SetModel(CModel* model); + + CJointConstraintDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CJointConstraintDlg) + enum { IDD = IDD_JOINT_LOCK_ANGLES }; + float m_nXVal; + float m_nYVal; + float m_nZVal; + float m_nXVal2; + float m_nYVal2; + float m_nZVal2; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CJointConstraintDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CJointConstraintDlg) + // NOTE: the ClassWizard will add member functions here + virtual BOOL OnInitDialog(); + afx_msg void OnApplyClicked(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + CModel* m_model; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_JOINTCONSTRAINTDLG_H__4203DC62_D052_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/JointTreeCtrl.cpp b/Toolkit/Programming/Tools/qMView/JointTreeCtrl.cpp new file mode 100644 index 0000000..ea7865a --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/JointTreeCtrl.cpp @@ -0,0 +1,99 @@ +// JointTreeCtrl.cpp : implementation file +// + +#include "stdafx.h" +#include "DDUtil.h" +#include "qMView.h" + +#include "Matrix.h" +#include "Model.h" +#include "JointTreeCtrl.h" +#include "NodeTreeCtrl.h" +#include "FrameManager2.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CJointTreeCtrl + +CJointTreeCtrl::CJointTreeCtrl() +{ + m_rootJoint = NULL; +} + +CJointTreeCtrl::~CJointTreeCtrl() +{ +} + + +BEGIN_MESSAGE_MAP(CJointTreeCtrl, CTreeCtrl) + //{{AFX_MSG_MAP(CJointTreeCtrl) + ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CJointTreeCtrl message handlers + +void CJointTreeCtrl::DeleteContents() +{ + DeleteAllItems(); + m_rootJoint = InsertItem("Joints", TVI_ROOT, TVI_FIRST); + SetItemImage(m_rootJoint, 0, 0); +} + +CModel* CJointTreeCtrl::GetModel() +{ + return ((FrameManager2*)GetParent())->GetModel(); +} + +void CJointTreeCtrl::SetModel(CModel* model) +{ + DeleteContents(); + if (model != NULL) + { + model->AddJoints(this, m_rootJoint); + } + +} + +void CJointTreeCtrl::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; + HTREEITEM item, parent; + + CModel* model = GetModel(); + if (model == NULL) + { + return; + } + if (!model->GetMesh()) + return; + + item = GetSelectedItem(); + parent = GetParentItem(item); + + if (parent == TVI_ROOT) + { + model->SetCurJoint(-1); + *pResult = 0; + return; + } + + model->SetCurJoint(GetItemData(item)); + + *pResult = 0; +} + +void CJointTreeCtrl::PreSubclassWindow() +{ + // TODO: Add your specialized code here and/or call the base class + + CTreeCtrl::PreSubclassWindow(); + m_image.Create(IDB_BITMAP4, 13, 1, RGB(255,255,255)); + SetImageList(&(m_image), TVSIL_NORMAL); +} diff --git a/Toolkit/Programming/Tools/qMView/JointTreeCtrl.h b/Toolkit/Programming/Tools/qMView/JointTreeCtrl.h new file mode 100644 index 0000000..9d7c94e --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/JointTreeCtrl.h @@ -0,0 +1,56 @@ +#if !defined(AFX_JOINTTREECTRL_H__358B2D86_C279_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_JOINTTREECTRL_H__358B2D86_C279_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// JointTreeCtrl.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CJointTreeCtrl window + +class CJointTreeCtrl : public CTreeCtrl +{ +// Construction +public: + CJointTreeCtrl(); + void SetModel(CModel* model); + void DeleteContents(); + CModel* GetModel(); + +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CJointTreeCtrl) + protected: + virtual void PreSubclassWindow(); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CJointTreeCtrl(); + + // Generated message map functions +protected: + //{{AFX_MSG(CJointTreeCtrl) + afx_msg void OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() + + HTREEITEM m_rootJoint; + CImageList m_image; +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_JOINTTREECTRL_H__358B2D86_C279_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/MDL.cpp b/Toolkit/Programming/Tools/qMView/MDL.cpp new file mode 100644 index 0000000..aebfe76 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/MDL.cpp @@ -0,0 +1,2106 @@ +// +// MDL Functions + +#include "stdafx.h" + +#include +#include +#include +#include + +#include "ddutil.h" + +#include +#include +#include + +#include "d3dglobal.h" +#include "flex.h" + +#include "pal.h" + +#define PI 3.141592654 + +#define MODEL_QUAKE 0 +#define MODEL_QUAKE2 1 + +int mainModelType = MODEL_QUAKE; + +int *vertPath; + +BOOL updateView = FALSE; +BOOL transtate = FALSE; +BOOL usePingPong = FALSE; + +typedef struct +{ + BYTE manufacturer; + BYTE version; + BYTE encoding; + BYTE bpp; + WORD Xmin,Ymin,Xmax,Ymax; + WORD HDpi, VDpi; + BYTE Colormap[48]; + BYTE reserved; + BYTE nPlanes; + WORD bpl; + WORD palInfo; + WORD HScreenSize, VScreenSize; + BYTE pad[54]; +} pcx_header_t; + +int palNum = PAL_HEXEN2; + +pal_t filepal[256]; + +BOOL frameChanged = FALSE; + +HTREEITEM *frameIndex; +HTREEITEM master; +BOOL frameUp = FALSE; + +unsigned interSteps = 4; +BOOL interOn = FALSE; +double interThresh; +int curstep = 0; +BOOL interNext = FALSE; + +unsigned long frameTick = 0; +unsigned long frameTickIncr = 50; +BOOL tickerOn = FALSE; + +unsigned long rtx = 512, rty = 512; + +treehead_t *treeInfo; +framegroup_t *groupList; +int numGroups = 0; +int curGroup = -1; + +BOOL curstate = TRUE; +char out[256]; + +BOOL playing = FALSE; + +int curframe = 0, Pcurframe = 0; + +double curscale = -150; + +BOOL has_moved; +BOOL r_has_moved; + +int numframes = 0; + +long mousex; +long mousey; +UINT mousestate; + +int GetMouseX() +{ + return mousex; +} + +int GetMouseY() +{ + return mousey; +} + +/* + * TraceError + * + * Scans all possible result values for DD functions + * + */ +char *TraceError(HRESULT ddrval) +{ + switch(ddrval) + { + case D3DRM_OK : break; + case D3DRMERR_BADALLOC : + return("Out of Memory"); + break; + case D3DRMERR_BADDEVICE : + return("Device is not compatible with render"); + break; + case D3DRMERR_BADFILE : + return("Data file is corrupt"); + break; + case D3DRMERR_BADMAJORVERSION : + return("Bad DLL major version"); + break; + case D3DRMERR_BADMINORVERSION : + return("Bad DLL minor version"); + break; + case D3DRMERR_BADOBJECT : + return("Object expected in argument"); + break; + case D3DRMERR_BADTYPE : + return("Bad argument type passed"); + break; + case D3DRMERR_BADVALUE : + return("Bad argument value passed"); + break; + case D3DRMERR_FACEUSED : + return("Face already used in a mesh"); + break; + case D3DRMERR_FILENOTFOUND : + return("File cannot be opened"); + break; + case D3DRMERR_NOTDONEYET : + return("Unimplemented"); + break; + case D3DRMERR_NOTFOUND : + return("Object not found in specified place"); + break; + case D3DRMERR_UNABLETOEXECUTE : + return("Unable to carry out procedure"); + break; + + } + + sprintf(out, "Unknown: %d", ddrval); + return (out); +} + +/* + * Error + * + * Prints the error message and returns FALSE + * + */ +BOOL Error(char *msg) +{ + AfxMessageBox(msg); + return FALSE; +} + +/* + * MDL_Free + * + * Frees the main model from memory + * + */ +BOOL MDL_Free( mdl_p *mdl ) +{ + int i,j; + + if (mdl == NULL) mdl = &mainModel; + + if (mdl->modelType == MODEL_QUAKE) + { + if (mdl->skins!=NULL) + { + for (i=0;iheader->numskins;i++) + { + if (mdl->skins[i].skin!=NULL) + { + for (j=0;jskins[i].numgroupskins;j++) + { + if (mdl->skins[i].skin[j]!=NULL) free(mdl->skins[i].skin[j]); + } + free(mdl->skins[i].skin); + } + if (mdl->skins[i].interval!=NULL) free(mdl->skins[i].interval); + } + free(mdl->skins); + } + + if (mdl->stverts!=NULL) free(mdl->stverts); + + if (mdl->tris!=NULL) free(mdl->tris); + + if (mdl->frames!=NULL) + { + for (i=0;iheader->numframes;i++) + { + if (mdl->frames[i].data!=NULL) + { + for (j=0;jframes[i].numgroupframes;j++) + { + if (mdl->frames[i].data[j]!=NULL) free(mdl->frames[i].data[j]); + } + free(mdl->frames[i].data); + } + if (mdl->frames[i].info!=NULL) free(mdl->frames[i].info); + if (mdl->frames[i].interval!=NULL) free(mdl->frames[i].interval); + } + free(mdl->frames); + } + } + else if (mdl->modelType == MODEL_FLEX) + { + if (mdl->skins != NULL) + { + if (mdl->skins[0].skin != NULL) + { + free(mdl->skins[0].skin); + mdl->skins[0].skin = NULL; + } + free(mdl->skins); + + mdl->skins = NULL; + } + + if (mdl->flex.glcmds) + { + free(mdl->flex.glcmds); + mdl->flex.glcmds = NULL; + } + + if (mdl->flex.frames) + { + free(mdl->flex.frames); + mdl->flex.frames = NULL; + } + + if (mdl->flex.skin_names) + { + free (mdl->flex.skin_names); + mdl->flex.skin_names = NULL; + } + + if (mdl->flex.st_verts) + { + free (mdl->flex.st_verts); + mdl->flex.st_verts = NULL; + } + + if (mdl->flex.tris) + { + free (mdl->flex.tris); + mdl->flex.tris = NULL; + } + + if (useNodes) + { + if (mdl->flex.mesh_nodes) + { + free (mdl->flex.mesh_nodes); + mdl->flex.mesh_nodes = NULL; + } + } + + if (mdl->flex.lightnormalindex) + { + free (mdl->flex.lightnormalindex); + mdl->flex.lightnormalindex = NULL; + } + + if (mdl->flex.compdata.mat) + { + free (mdl->flex.compdata.mat); + mdl->flex.compdata.mat = NULL; + } + + if (mdl->flex.compdata.ccomp) + { + free (mdl->flex.compdata.ccomp); + mdl->flex.compdata.ccomp = NULL; + } + + if (mdl->flex.compdata.cbase) + { + free (mdl->flex.compdata.cbase); + mdl->flex.compdata.cbase = NULL; + } + + if (mdl->flex.compdata.cscale) + { + free (mdl->flex.compdata.cscale); + mdl->flex.compdata.cscale = NULL; + } + + + if (mdl->flex.compdata.coffset) + { + free (mdl->flex.compdata.coffset); + mdl->flex.compdata.coffset = NULL; + } + + if (mdl->flex.compdata.complerp) + { + free (mdl->flex.compdata.complerp); + mdl->flex.compdata.complerp = NULL; + } + } + + else if (mdl->modelType == MODEL_QUAKE2) + { + if (mdl->skins != NULL) + { + if (mdl->skins[0].skin != NULL) + { + free(mdl->skins[0].skin); + mdl->skins[0].skin = NULL; + } + free(mdl->skins); + mdl->skins = NULL; + } + + if (mdl->glcmds) + { + free(mdl->glcmds); + mdl->glcmds = NULL; + } + + if (mdl->frames2) + { + free(mdl->frames2); + mdl->frames2 = NULL; + } + + if (mdl->header2) + { + free(mdl->header2); + mdl->header2 = NULL; + } + + if (mdl->header) + { + delete mdl->header; + mdl->header = NULL; + } + } + + + return TRUE; +} + +/* + * MDL_CalcInterpolate + * + * Calculates the appropriate interpolated frame and displays it + * + */ +BOOL MDL_CalcInterpolate(mdl_p *model, int step, int numsteps, int intertype, int direction) +{ + D3DVECTOR delta; + D3DVECTOR d1,d2; + D3DVECTOR p[3]; + int curvert = 0; + trivertx_t *triverts, *triverts2; + int v1; + D3DRMVERTEX *vertexlist; + int lastframe, i, j; + + vec5_t p1,p2; + frameinfo2_t *frameinfo1, *frameinfo2; + long *command; + int num_verts,vert_index; + int command_type; + vec5_t *vertlist; + BOOL ODD; + long s, t; + + if (mainModel.modelType == MODEL_FLEX) + { + if (direction == ANIM_FORWARD) + { + if (curGroup == -1) + { + if (curframe + 1 > model->flex.header.num_frames-1) + lastframe = 0; + else + lastframe = curframe + 1; + } + else + { + if (curframe + 1 > treeInfo[curGroup].eFrame) + { + lastframe = treeInfo[curGroup].bFrame; + } + else + lastframe = curframe + 1; + } + } + + if (useNodes) + { + for (i=1; i < numnodes; i++) + { + FM_ShowInterNodeFrame(model, curframe, lastframe, i, step, numsteps); + } + } + else + FM_ShowInterNodeFrame(model, curframe, lastframe, 0, step, numsteps); + + if (step + 1 > numsteps) curstep = 0; + else curstep++; + + return true; + } + + if (mainModel.modelType == MODEL_QUAKE) + { + vertexlist = new D3DRMVERTEX[model->header->numtris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + } + else if (mainModel.modelType == MODEL_QUAKE2) + { + vertexlist = new D3DRMVERTEX[model->header2->num_tris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + } + + if (mainModel.modelType == MODEL_QUAKE) + { + if (direction == ANIM_FORWARD) + { + if (curGroup == -1) + { + if (curframe + 1 > model->header->numframes-1) + lastframe = 0; + else + lastframe = curframe + 1; + } + else + { + if (curframe + 1 > treeInfo[curGroup].eFrame) + lastframe = treeInfo[curGroup].bFrame; + else + lastframe = curframe + 1; + } + } + } + else if (mainModel.modelType == MODEL_QUAKE2) + { + if (direction == ANIM_FORWARD) + { + if (curGroup == -1) + { + if (curframe + 1 > model->header2->num_frames-1) + lastframe = 0; + else + lastframe = curframe + 1; + } + else + { + if (curframe + 1 > treeInfo[curGroup].eFrame) + { + lastframe = treeInfo[curGroup].bFrame; + } + else + lastframe = curframe + 1; + } + } + } + + if (mainModel.modelType == MODEL_QUAKE) + { + //mesh->GetVertices( group, 0, model->header->numtris*3, vertexlist); + + triverts = model->frames[curframe].data[0]; + triverts2 = model->frames[lastframe].data[0]; + + for (i = 0; i < model->header->numtris; i++) + { + for (j = 2; j >= 0; j--) + { + + v1 = model->tris[i].vertices[j]; + + s = model->stverts[v1].s; + t = model->stverts[v1].t; + + if (s > model->header->skinwidth) + Error("Invalid skin vertex (S)"); + + if (t > model->header->skinheight) + Error("Invalid skin vertex (T)"); + + if( (model->stverts[v1].onseam) && (!model->tris[i].facesfront)) + s += model->header->skinwidth / 2; + + d1.x = triverts[v1].x; + d1.y = triverts[v1].y; + d1.z = triverts[v1].z; + + d2.x = triverts2[v1].x; + d2.y = triverts2[v1].y; + d2.z = triverts2[v1].z; + + delta.x = (d1.x - d2.x) / numsteps; + delta.y = (d1.y - d2.y) / numsteps; + delta.z = (d1.z - d2.z) / numsteps; + + d1.x -= delta.x * step; + d1.y -= delta.y * step; + d1.z -= delta.z * step; + + p[j].x = ( model->header->scale.x * d1.x ) + model->header->origin.x; + p[j].y = ( model->header->scale.y * d1.y ) + model->header->origin.y; + p[j].z = ( model->header->scale.z * d1.z ) + model->header->origin.z; + + vertexlist[curvert].position.x = -p[j].x; + vertexlist[curvert].position.y = -p[j].y; + vertexlist[curvert].position.z = -p[j].z; + + vertexlist[curvert].tu = D3DVALUE(s) / rtx; + vertexlist[curvert].tv = D3DVALUE(t) / rty; + + curvert++; + } + } + + mesh->SetVertices( group, 0, model->header->numtris*3, vertexlist ); + + //mesh->Scale( D3DVALUE(curscale), D3DVALUE(curscale), D3DVALUE(curscale) ); + } + else if (mainModel.modelType == MODEL_QUAKE2) + { + //mesh->GetVertices( group, 0, model->header2->num_tris*3, vertexlist); + + curvert = 0; + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*model->header2->num_tris*3); + + frameinfo1 = (frameinfo2_t *)((char *)model->frames2 + model->header2->framesize * curframe); + frameinfo2 = (frameinfo2_t *)((char *)model->frames2 + model->header2->framesize * lastframe); + command = (long *)model->glcmds; + + //do the gl commands + while (*command) + { + ODD = TRUE; + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * model->header->skinwidth; command++; + p1.t = (*((float *)command)) * model->header->skinheight; command++; + + //grab the vertex index + vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + p2.z = -((frameinfo2->verts[vert_index].x * frameinfo2->scale.x) + frameinfo2->origin.x); + p2.y = ((frameinfo2->verts[vert_index].y * frameinfo2->scale.y) + frameinfo2->origin.y); + p2.x = -((frameinfo2->verts[vert_index].z * frameinfo2->scale.z) + frameinfo2->origin.z); + + delta.x = (p2.x - p1.x) / numsteps; + delta.y = (p2.y - p1.y) / numsteps; + delta.z = (p2.z - p1.z) / numsteps; + + p1.x += delta.x * step; + p1.y += delta.y * step; + p1.z += delta.z * step; + + vertlist[curvert] = p1; + curvert++; + } + + } + + for (i = 0; i < model->header2->num_tris*3; i++) + { + vertexlist[i].position.x = vertlist[vertPath[i]].x; + vertexlist[i].position.y = vertlist[vertPath[i]].y; + vertexlist[i].position.z = vertlist[vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[vertPath[i]].s) / rtx; + vertexlist[i].tv = D3DVALUE(vertlist[vertPath[i]].t) / rty; + } + + mesh->SetVertices( group, 0, model->header2->num_tris*3, vertexlist ); + + //mesh->Scale( D3DVALUE(curscale), D3DVALUE(curscale), D3DVALUE(curscale) ); + + free(vertlist); + } + + delete (vertexlist); + + if (step + 1 > numsteps) curstep = 0; + else curstep++; + + return TRUE; +} + +/* + * MDL_ShowFrame + * + * Shows the frame + * + */ +BOOL MDL_ShowFrame(mdl_p *model, int frame) +{ + long s,t; + D3DVECTOR p[3], v; + int curvert = 0; + trivertx_t *triverts; + int v1; + D3DRMVERTEX *vertexlist; + vec5_t *vertlist; + int i,j; + vec5_t p1; + frameinfo2_t *frameinfo1; + long *command; + int num_verts,vert_index; + int command_type; + + if (mainModel.modelType == MODEL_FLEX) + return FM_ShowFrame(model, frame); + + if (mainModel.modelType == MODEL_QUAKE) + { + vertexlist = new D3DRMVERTEX[model->header->numtris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + + mesh->GetVertices( group, 0, model->header->numtris*3, vertexlist); + } + else + { + vertexlist = new D3DRMVERTEX[model->header2->num_tris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + + //mesh->GetVertices( group, 0, model->header2->num_tris*3, vertexlist); + } + + if (mainModel.modelType == MODEL_QUAKE) + { + triverts = model->frames[curframe].data[0]; + + for (i = 0; i < model->header->numtris; i++) + { + for (j = 2; j >= 0; j--) + { + + v1 = model->tris[i].vertices[j]; + + v.x = triverts[v1].x; + v.y = triverts[v1].y; + v.z = triverts[v1].z; + + s = model->stverts[v1].s; + t = model->stverts[v1].t; + + if (s > model->header->skinwidth) + s = model->header->skinwidth;//Error("Invalid skin vertex (S)"); + + if (t > model->header->skinheight) + t = model->header->skinheight;//Error("Invalid skin vertex (T)"); + + if( (model->stverts[v1].onseam) && (!model->tris[i].facesfront)) + s += model->header->skinwidth / 2; + + p[j].x = ( model->header->scale.x * v.x ) + model->header->origin.x; + p[j].y = ( model->header->scale.y * v.y ) + model->header->origin.y; + p[j].z = ( model->header->scale.z * v.z ) + model->header->origin.z; + + vertexlist[curvert].position.x = -p[j].x; + vertexlist[curvert].position.y = -p[j].y; + vertexlist[curvert].position.z = -p[j].z; + + vertexlist[curvert].tu = D3DVALUE(s) / rtx; + vertexlist[curvert].tv = D3DVALUE(t) / rty; + + curvert++; + } + } + mesh->SetVertices( group, 0, model->header->numtris*3, vertexlist ); + + //mesh->Scale( D3DVALUE(curscale), D3DVALUE(curscale), D3DVALUE(curscale) ); + } + else + { + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*model->header2->num_tris*3); + + frameinfo1 = (frameinfo2_t *)((char *)model->frames2 + model->header2->framesize * curframe); + command = (long *)model->glcmds; + + curvert = 0; + //do the gl commands + while (*command) + { + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * model->header->skinwidth; command++; + p1.t = (*((float *)command)) * model->header->skinheight; command++; + + //grab the vertex index + vert_index = *command; + command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[curvert] = p1; + curvert++; + } + + } + + for (i = 0; i < model->header2->num_tris*3; i++) + { + vertexlist[i].position.x = vertlist[vertPath[i]].x; + vertexlist[i].position.y = vertlist[vertPath[i]].y; + vertexlist[i].position.z = vertlist[vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[vertPath[i]].s) / rtx; + vertexlist[i].tv = D3DVALUE(vertlist[vertPath[i]].t) / rty; + } + + mesh->SetVertices( group, 0, model->header2->num_tris*3, vertexlist ); + + //mesh->Scale( D3DVALUE(curscale), D3DVALUE(curscale), D3DVALUE(curscale) ); + + free(vertlist); + } + + + delete (vertexlist); + + frameChanged = FALSE; + return TRUE; +} + +/* + * MDL_UpdateFrame + * + * Updates the animation values + * + */ +BOOL MDL_UpdateFrame(mdl_p *model, int direction) +{ + if (numframes < 2) return TRUE; + + unsigned long thisTick = GetTickCount(); + + if (tickerOn) + { + if (thisTick < frameTick) return TRUE; + } + + frameTick = thisTick + frameTickIncr; + + if (interOn && curstep != 0) + { + return MDL_CalcInterpolate(model, curstep, interSteps, 0, direction); + } + else curstep = 1; + + if (usePunch) + { + if (usePingPong) + { + if (direction == ANIM_FORWARD) + { + if (Pcurframe > frameSels.numFrames-2) + direction = playMode = ANIM_BACKWARD; + } + else if (direction == ANIM_BACKWARD) + { + if (Pcurframe <= 0) + direction = playMode = ANIM_FORWARD; + } + } + + if (direction == ANIM_FORWARD) + { + if (Pcurframe > frameSels.numFrames-2) + Pcurframe = 0; + else + Pcurframe++; + + curframe = frameSels.frames[Pcurframe].frameIndex; + + if (curframe < 0) + { + curframe = 0; + } + } + else if (direction == ANIM_BACKWARD) + { + if (Pcurframe < 0) + Pcurframe = frameSels.numFrames-1; + else + Pcurframe--; + + curframe = frameSels.frames[Pcurframe].frameIndex; + + if (curframe < 0) + { + curframe = 0; + } + } + } + + if (direction == ANIM_FORWARD) + { + if (mainModel.modelType == MODEL_QUAKE) + { + if (curGroup == -1) + { + if (curframe + 1 > model->header->numframes-1) + { + if (usePingPong) + { + curframe--; + playMode = ANIM_BACKWARD; + } + else + curframe = 0; + } + else + curframe++; + } + else + { + if (curframe + 1 > treeInfo[curGroup].eFrame) + { + if (usePingPong) + { + playMode = ANIM_BACKWARD; + curframe--; + } + else + curframe = treeInfo[curGroup].bFrame; + } + else + curframe++; + } + } + else if (mainModelType == MODEL_QUAKE2) + { + if (curGroup == -1) + { + if (curframe + 1 > model->header2->num_frames-1) + { + if (usePingPong) + { + playMode = ANIM_BACKWARD; + curframe--; + } + else + curframe = 0; + } + else + curframe++; + } + else + { + if (curframe + 1 > treeInfo[curGroup].eFrame) + { + if (usePingPong) + { + playMode = ANIM_BACKWARD; + curframe--; + } + else + curframe = treeInfo[curGroup].bFrame; + } + else + curframe++; + } + } + else + { + if (curGroup == -1) + { + if (curframe + 1 > model->flex.header.num_frames-1) + { + if (usePingPong) + { + playMode = ANIM_BACKWARD; + curframe--; + } + else + curframe = 0; + } + else + curframe++; + } + else + { + if (curframe + 1 > treeInfo[curGroup].eFrame) + { + if (usePingPong) + { + playMode = ANIM_BACKWARD; + curframe--; + } + else + curframe = treeInfo[curGroup].bFrame; + } + else + curframe++; + } + } + } + else + { + if (mainModel.modelType == MODEL_QUAKE) + { + if (curGroup == -1) + { + if (curframe - 1 < 0) + { + if (usePingPong) + { + playMode = ANIM_FORWARD; + curframe++; + } + else + curframe = model->header->numframes-1; + } + else + curframe--; + } + else + { + if (curframe - 1 < treeInfo[curGroup].bFrame) + { + if (usePingPong) + { + curframe++; + playMode = ANIM_FORWARD; + } + else + curframe = treeInfo[curGroup].eFrame; + } + else + curframe--; + } + } + else if (mainModelType == MODEL_QUAKE2) + { + if (curGroup == -1) + { + if (curframe - 1 < 0) + { + if (usePingPong) + { + curframe++; + playMode = ANIM_FORWARD; + } + else + curframe = model->header2->num_frames-1; + } + else + curframe--; + } + else + { + if (curframe - 1 < treeInfo[curGroup].bFrame) + { + if (usePingPong) + { + curframe++; + playMode = ANIM_FORWARD; + } + else + curframe = treeInfo[curGroup].eFrame; + } + else + curframe--; + } + } + else + { + if (curGroup == -1) + { + if (curframe - 1 < 0) + { + if (usePingPong) + { + curframe++; + playMode = ANIM_FORWARD; + } + else + curframe = model->flex.header.num_frames-1; + } + else + curframe--; + } + else + { + if (curframe - 1 < treeInfo[curGroup].bFrame) + { + if (usePingPong) + { + curframe++; + playMode = ANIM_FORWARD; + } + else + curframe = treeInfo[curGroup].eFrame; + } + else + curframe--; + } + } + } + + if (mainModelType == MODEL_FLEX) + return FM_ShowFrame(model, curframe); + + return MDL_ShowFrame(model, curframe); +} + +/* + * MDL_LoadSkin + * + * Loads the model's skin onto a texture with the current palette + * + */ +BOOL MDL_LoadSkin(mdl_p *model, int skinnum) +{ + DDSURFACEDESC ddsd; + BYTE *src; + BYTE *dest; + int curpos = 0; + int x,y; + int tx, ty, mx, my; + int pos; + BYTE r, g, b; + BYTE color; + long yofs, yofs2; + HRESULT ddrval; + + if (lpDDSSkin) + { + lpDDSSkin->Release(); + lpDDSSkin = 0; + } + + char *buf; + + if (useNodes && curNode > -1) + { + buf = (char *)node_state[curNode].skin; + mx = node_state[curNode].skinwidth; + my = node_state[curNode].skinheight; + } + else + { + buf = (char *)model->skins->skin[0]; + mx = model->header->skinwidth; + my = model->header->skinheight; + } + + tx = 256; + ty = 256; + + if (mx>512) { tx=1024;} + else if (mx>256){ tx=512; } + else if (mx>128){ tx=256; } + else if (mx>64) { tx=128; } + else if (mx>32) { tx=64; } + else if (mx>16) { tx=32; } + else if (mx>8) { tx=16; } + else if (mx>4) { tx=8; } + else if (mx>2) { tx=4; } + else if (mx>1) { tx=2; } + else Error("Bad texture width"); + + if (my>512) { ty=1024;} + else if (my>256){ ty=512; } + else if (my>128){ ty=256; } + else if (my>64) { ty=128; } + else if (my>32) { ty=64; } + else if (my>16) { ty=32; } + else if (my>8) { ty=16; } + else if (my>4) { ty=8; } + else if (my>2) { ty=4; } + else if (my>1) { ty=2; } + else Error("Bad texture height"); + + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + rtx = ddsd.dwWidth = tx; + rty = ddsd.dwHeight = ty; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat); + ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; + ddsd.ddpfPixelFormat.dwRGBBitCount = 32; + ddsd.ddpfPixelFormat.dwRBitMask = 0xff0000; + ddsd.ddpfPixelFormat.dwGBitMask = 0xff00; + ddsd.ddpfPixelFormat.dwBBitMask = 0xff; + ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0; + + ddrval = lpDD->CreateSurface( &ddsd, &lpDDSSkin, NULL ); + if( ddrval != DD_OK ) + return Error("Fail on CreateSurface 1"); + + (BYTE *) src = (BYTE *) buf;//model->skins[skinnum].skin[0]; + + ddsd.dwSize = sizeof(ddsd); + ddrval = lpDDSSkin->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + + (BYTE *) dest = (BYTE *)ddsd.lpSurface; + + if (ddrval == DD_OK) + { + for (y = 0; y < my; y++) + { + yofs = y * (ddsd.lPitch); + yofs2 = y * mx; + + for (x = 0; x < mx; x++) + { + color = (BYTE) src[x + yofs2]; + + if (palNum == PAL_QUAKE) + { + r = qpal[color].r; + g = qpal[color].g; + b = qpal[color].b; + } + else if (palNum == PAL_HEXEN2) + { + r = h2pal[color].r; + g = h2pal[color].g; + b = h2pal[color].b; + } + else if (palNum == PAL_FROMFILE) + { + r = filepal[color].r; + g = filepal[color].g; + b = filepal[color].b; + } + + pos = (x << 2) + yofs; + + dest[pos] = b; + dest[pos+1] = g; + dest[pos+2] = r; + dest[pos+3] = 0; + } + } + + lpDDSSkin->Unlock(NULL); + } + else + Error("No go"); + + if (useNodes && curNode > -1) + { + ddrval = d3drm->CreateTextureFromSurface(lpDDSSkin, &node_texture[curNode]); + if (ddrval != D3DRM_OK) + AfxMessageBox(TraceError(ddrval)); + } + else + { + ddrval = d3drm->CreateTextureFromSurface(lpDDSSkin, &texture); + if (ddrval != D3DRM_OK) + AfxMessageBox(TraceError(ddrval)); + } + + return TRUE; +} + +/* + * MDL_LoadSkinFromPCX + * + * Reads and creates a texture from a PCX file + * + */ +BOOL MDL_LoadSkinFromPCX(char *filename, mdl_p *model) +{ + unsigned char cur_byte; + int j,run_len; + FILE *f; + int tw,th; + short w,h; + //char *fname; + int offset,size; + + f = fopen(filename, "rb"); + + if (!f) return FALSE; + + offset=0; + fseek(f,0,SEEK_END); + size=ftell(f); + fseek(f,0,SEEK_SET); + + //PCX reading stuff + fseek(f,offset+8,SEEK_SET); + fread(&w,sizeof(short),1,f); + fread(&h,sizeof(short),1,f); + + w++; + h++; + + unsigned char *buf; + + if (useNodes && curNode > -1) + { + node_state[curNode].skin = (unsigned char *) malloc(w*h); + node_state[curNode].skinheight = h; + node_state[curNode].skinwidth = h; + buf = (unsigned char *) node_state[curNode].skin; + } + else + { + if (model->header == NULL) + model->header = new mdl_t; + + model->header->skinwidth = w; + model->header->skinheight = h; + + model->skins = (skin_t *)malloc(sizeof(skin_t)); + if (model->skins==NULL) return Error("Could not allocate skin page"); + memset(model->skins,0,sizeof(skin_t)); + + model->skins[0].skin = (u_char **)malloc(sizeof(unsigned char *)); + if (model->skins[0].skin==NULL) return Error("Could not allocate skin page buffer"); + + model->skins[0].skin[0] = (u_char *)malloc(model->header->skinwidth*model->header->skinheight); + if (model->skins[0].skin[0]==NULL) return Error("Could not do something"); + + buf = (unsigned char *) model->skins[0].skin[0]; + } + + tw = w; + th = h; + + fseek(f,offset+128,SEEK_SET); + j = 0; + + //.pcx decoding loop type thing + while(j < tw*th) + { + cur_byte = fgetc(f); + if((cur_byte & 0xC0) == 0xC0) + { + run_len = cur_byte & 0x3F; + cur_byte = fgetc(f); + for( ;(run_len>0) && (jm_nProgressBar3.SetRange(0, model->header->numtris); + + vertexlist = new D3DRMVERTEX[model->header->numtris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + + curvert = model->header->numtris * 3; + + vertorder = new unsigned[model->header->numtris*3+1]; + if (vertorder == NULL) + return Error("Cannot make vertorder"); + + curvert = model->header->numtris * 3; + + for (i = 0; i < (model->header->numtris * 3); i++) + { + curvert--; + vertorder[i] = curvert; + } + + curvert=0; + + d3drm->CreateMesh( &mesh ); + + MDL_LoadSkin(model, 0); + + triverts = model->frames[0].data[0]; + + for (i = 0; i < model->header->numtris; i++) + { + for (j = 2; j >= 0; j--) + { + v1 = model->tris[i].vertices[j]; + + pt1.x = triverts[v1].x; + pt1.y = triverts[v1].y; + pt1.z = triverts[v1].z; + + s = model->stverts[v1].s; + t = model->stverts[v1].t; + + if (s > model->header->skinwidth) + Error("Invalid skin vertex (S)"); + + if (t > model->header->skinheight) + Error("Invalid skin vertex (T)"); + + if( (model->stverts[v1].onseam) && (!model->tris[i].facesfront)) + s += model->header->skinwidth / 2; + + p[j].x = ( model->header->scale.x * pt1.x ) + model->header->origin.x; + p[j].y = ( model->header->scale.y * pt1.y ) + model->header->origin.y; + p[j].z = ( model->header->scale.z * pt1.z ) + model->header->origin.z; + + vertexlist[curvert].position.x = -p[j].x; + vertexlist[curvert].position.y = -p[j].y; + vertexlist[curvert].position.z = -p[j].z; + + vertexlist[curvert].tu = D3DVALUE(s) / rtx; + vertexlist[curvert].tv = D3DVALUE(t) / rty; + vertexlist[curvert].color = D3DCOLOR(0); + + if (curvert+1 < model->header->numtris*3) curvert++; + } + + D3DRMVectorSubtract(&n2, &p[2], &p[1]); + D3DRMVectorSubtract(&n1, &p[1], &p[0]); + + D3DRMVectorCrossProduct(&n3, &n1, &n2); + D3DRMVectorNormalize(&n3); + + for (j = 0; j < 3; j++) + { + vertexlist[curvert-j+1].normal.x = -n3.x; + vertexlist[curvert-j+1].normal.y = -n3.y; + vertexlist[curvert-j+1].normal.z = -n3.z; + } + + numread++; + //statusDlg->m_nProgressBar3.SetPos(numread); + } + + mesh->AddGroup( model->header->numtris * 3, model->header->numtris, 3, vertorder, &group ); + mesh->SetVertices( group, 0, model->header->numtris * 3, vertexlist ); + + mesh->SetGroupTexture( group, texture ); + mesh->SetGroupMapping( group, D3DRMMAP_PERSPCORRECT ); + mesh->SetGroupQuality( group, D3DRMRENDER_FLAT ); + + //mesh->Scale( D3DVALUE(curscale), D3DVALUE(curscale), D3DVALUE(curscale) ); + + ddrval = frame->AddVisual( mesh ); + if (ddrval != D3DRM_OK) + AfxMessageBox(TraceError(ddrval)); + + if (vertexlist) delete vertexlist; + if (vertorder) delete vertorder; + + return TRUE; +} + +int OpenSkin ( void ) +{ + CFileDialog fdOpenFile(TRUE,"*.pcx",NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST, "PCX Files (*.pcx)|*.pcx||", NULL); + + if (fdOpenFile.DoModal()==IDOK) + { + CString strHelp = fdOpenFile.GetPathName(); + CString strExt = fdOpenFile.GetFileExt(); + + LPSTR szHelp= strHelp.GetBuffer(10); + LPSTR szExt = strExt.GetBuffer(10); + + if (!MDL_LoadSkinFromPCX(szHelp, &mainModel)) + return FALSE; + else + return TRUE; + } + else + { + return 666; + } +} + +/* + * MDL2_Show + * + * Creates the mesh and displays the Quake 2 model + * + */ +BOOL MDL2_Show(mdl_p *mdl) +{ + BOOL ODD = FALSE; + HRESULT ddrval; + D3DRMVERTEX *vertexlist; + unsigned *vertorder; + unsigned numread = 0; + + int i,j,x; + vec5_t p1; + frameinfo2_t *frameinfo1; + long *command; + int num_verts,vert_index; + int command_type; + vec5_t *vertlist; + D3DVECTOR p[3], n1, n2, n3; + BOOL skin_ok = FALSE; + + int realvert = 0; + + if (!MDL_LoadSkinFromPCX("!skin.pcx", mdl)) + { + AfxMessageBox("'!SKIN.PCX' could not be found!\nPlease choose a skin..."); + + while (!skin_ok) + { + skin_ok = OpenSkin(); + if (skin_ok == 666) return FALSE; + } + } + + vertexlist = new D3DRMVERTEX[mdl->header2->num_tris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + + vertPath = new int[mdl->header2->num_tris*3+1]; + + int curvert = mdl->header2->num_tris * 3; + + vertorder = new unsigned[mdl->header2->num_tris*3+1]; + if (vertorder == NULL) + return Error("Cannot make vertorder"); + + for (i = 0; i < (mdl->header2->num_tris * 3); i++) + { + curvert--; + vertorder[i] = curvert; + } + + curvert=0; + + d3drm->CreateMesh( &mesh ); + + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*mdl->header2->num_tris*3); + + frameinfo1 = (frameinfo2_t *)((char *)mdl->frames2); + command = (long *)mdl->glcmds; + + //do the gl commands + while (*command) + { + ODD = TRUE; + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * mdl->header->skinwidth; command++; + p1.t = (*((float *)command)) * mdl->header->skinheight; command++; + + //grab the vertex index + vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[i] = p1; + } + + switch (command_type) + { + case 0: + //tristrip + for (i=0;i -1; j--) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / rtx; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / rty; + vertexlist[curvert].color = D3DCOLOR(2); + vertPath[curvert] = realvert+i+j; + curvert++; + } + ODD = FALSE; + } + else + { + for (j = 0; j < 3; j++) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / rtx; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / rty; + vertexlist[curvert].color = D3DCOLOR(2); + vertPath[curvert] = realvert+i+j; + curvert++; + } + ODD = TRUE; + } + } + break; + + case 1: + //trifan + for (i=0;i -1; j--) + { + if (j == 0) + x = 0; + else + x = i; + + p[j].x = vertlist[x+j].x; + p[j].y = vertlist[x+j].y; + p[j].z = vertlist[x+j].z; + } + + D3DRMVectorSubtract(&n1, &p[1], &p[0]); + D3DRMVectorSubtract(&n2, &p[2], &p[1]); + + D3DRMVectorCrossProduct(&n3, &n1, &n2); + D3DRMVectorNormalize(&n3); + + for (j = 2; j > -1; j--) + { + if (j == 0) + x = 0; + else + x = i; + + vertexlist[curvert].position.x = vertlist[x+j].x; + vertexlist[curvert].position.y = vertlist[x+j].y; + vertexlist[curvert].position.z = vertlist[x+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[x+j].s) / rtx; + vertexlist[curvert].tv = D3DVALUE(vertlist[x+j].t) / rty; + vertexlist[curvert].color = D3DCOLOR(2); + vertPath[curvert] = realvert+x+j; + curvert++; + } + } + break; + } + + realvert += num_verts; + } + + mesh->AddGroup( mdl->header2->num_tris * 3, mdl->header2->num_tris, 3, vertorder, &group ); + mesh->SetVertices( group, 0, mdl->header2->num_tris * 3, vertexlist ); + + mesh->SetGroupTexture( group, texture ); + mesh->SetGroupMapping( group, D3DRMMAP_PERSPCORRECT ); + mesh->SetGroupQuality( group, D3DRMRENDER_FLAT ); + + //mesh->Scale( D3DVALUE(curscale), D3DVALUE(curscale), D3DVALUE(curscale) ); + + ddrval = frame->AddVisual( mesh ); + if (ddrval != D3DRM_OK) + return Error(TraceError(ddrval)); + + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) ); + + if (vertexlist) delete vertexlist; + if (vertorder) delete vertorder; + if (vertlist) free(vertlist); + + return TRUE; +} + +/* + * MDL_LoadPaletteFromFile + * + * Loads the program's palette from a file + * + */ +BOOL MDL_LoadPaletteFromFile(char *filename, DWORD fileType) +{ + FILE *fp; + unsigned size; + char input[128]; + LPDIRECTDRAWPALETTE lpPal; + PALETTEENTRY pe[256]; + + if (fileType == PALTYPE_BMP) + { + } + else if (fileType == PALTYPE_JASC) + { + if ((fp = fopen(filename, "rt"))==NULL) + return Error("Cannot open specified palette"); + } + else + { + if ((fp = fopen(filename, "rb"))==NULL) + return Error("Cannot open specified palette"); + } + + if (fileType == PALTYPE_RAW) + { + fread(&filepal, sizeof(filepal), 1, fp); + } + else if (fileType == PALTYPE_PCX) + { + fseek(fp,0,SEEK_END); + size=ftell(fp); + fseek(fp,0,SEEK_SET); + + fseek(fp, size - 768, SEEK_SET); + fread(&filepal, sizeof(filepal), 1, fp); + } + else if (fileType == PALTYPE_JASC) + { + fgets(input, 128, fp); + if (stricmp(input, "JASC-PAL\n")) + return Error("Invalid JASC Palette File"); + + fgets(input, 128, fp); + fgets(input, 128, fp); + if (stricmp(input, "256\n")) + return Error("Invalid Color Depth"); + + for (int i = 0; i < 256; i++) + { + if (!feof(fp)) + { + fgets(input, 128, fp); + sscanf(input, "%d %d %d", &filepal[i].r, &filepal[i].g, &filepal[i].b); + } + else + return Error("Unexpected EOF"); + } + } + else if (fileType == PALTYPE_MS) + { + return Error("Microsoft Palettes Not Supported"); + } + else if (fileType == PALTYPE_BMP) + { + lpPal = DDLoadPalette(lpDD, filename); + if (lpPal) + { + lpPal->GetEntries(0, 0, 256, pe); + + for (int i = 0; i < 256; i++) + { + filepal[i].r = pe[i].peRed; + filepal[i].g = pe[i].peGreen; + filepal[i].b = pe[i].peBlue; + } + lpPal->Release(); + lpPal = 0; + } + else + return Error("Unable to create palette from BMP"); + } + + fclose(fp); + + return TRUE; +} + +/* + * MDL2_LoadFromFile + * + * Loads Quake 2 model from a file + * + */ +BOOL MDL2_LoadFromFile(char *filename) +{ + FILE *f; + mdl_p *mdl = &mainModel; + + curframe = 0; + curscale = -150; + curSkin = 0; + camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(curscale)); + + playing = FALSE; + + f = fopen(filename, "rb"); + + mdl->header2 = (mdl2header_t *) malloc(sizeof(mdl2header_t)); + fread(mdl->header2,sizeof(mdl2header_t),1,f); + + fseek(f,mdl->header2->ofs_glcmds,SEEK_SET); + mdl->glcmds = (long *)malloc(mdl->header2->num_glcmds * sizeof(long)); + fread(mdl->glcmds,mdl->header2->num_glcmds*sizeof(long),1,f); + + fseek(f,mdl->header2->ofs_frames,SEEK_SET); + mdl->frames2 = (frameinfo2_t *)malloc(mdl->header2->framesize*mdl->header2->num_frames); + fread(mdl->frames2,mdl->header2->framesize*mdl->header2->num_frames,1,f); + + fseek(f,mdl->header2->ofs_skins,SEEK_SET); + fread(mdl->skinname,64,1,f); + + mainModel.modelType = MODEL_QUAKE2; + mainModelType = MODEL_QUAKE2; + palNum = PAL_QUAKE2; + + numframes = mdl->header2->num_frames; + + MDL2_Show(mdl); + + return TRUE; +} + +/* + * MDL_LoadFromFile + * + * Loads a Quake / Hexen 2 model from a file + * + */ +BOOL MDL_LoadFromFile(char *filename) +{ + FILE *infile; + mdl_p *mdl = &mainModel; + mdl_t *header; + int numgroupskins = 0; + int fileread = 0; + int filesize; + + curframe = 0; + curscale = -150; + curSkin = 0; + camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(curscale)); + + playing = FALSE; + + if ((infile = fopen(filename, "rb"))==NULL) return FALSE; + + fseek(infile, 0, SEEK_END); + filesize = ftell(infile); + fseek(infile, 0, SEEK_SET); + + header = new mdl_t; + if (header == NULL) + return Error("Could not init header memory"); + + mdl->header = header; + + fread(header, sizeof(mdl_t), 1, infile); + + fileread += sizeof(mdl_t); + + numframes = header->numframes; + + if (header->id != 0x4F504449) + return Error("Invalid File"); + + if (header->version != 6) + return Error("Invalid MDL Version"); + + fseek(infile,0x54,SEEK_SET); + + mdl->skins = (skin_t *)malloc(header->numskins*sizeof(skin_t)); + if (mdl->skins==NULL) return Error("Could not allocate skin page"); + memset(mdl->skins,0,header->numskins*sizeof(skin_t)); + for (int i=0;inumskins;i++) + { + fread(&(mdl->skins[i].type),sizeof(long),1,infile); + + fileread += sizeof(long); + + if (mdl->skins[i].type==0) + { + mdl->skins[i].numgroupskins = 1; + + mdl->skins[i].skin = (u_char **)malloc(sizeof(unsigned char *)); + if (mdl->skins[i].skin==NULL) return Error("Could not allocate skin page buffer"); + mdl->skins[i].skin[0] = (u_char *)malloc(header->skinwidth*header->skinheight); + if (mdl->skins[i].skin[0]==NULL) return Error("Could not do something"); + memset(mdl->skins[i].skin[0],0,header->skinwidth*header->skinheight); + + fread(mdl->skins[i].skin[0],header->skinwidth*header->skinheight,1,infile); + + fileread += header->skinwidth*header->skinheight; + + mdl->skins[i].interval = (float *)malloc(sizeof(float)); + if (mdl->skins[i].interval==NULL) return Error("Could not allocate intervals"); + *(mdl->skins[i].interval) = (float)0; + + } + else + { + fread(&(mdl->skins[i].numgroupskins),sizeof(long),1,infile); + + fileread += sizeof(long); + + mdl->skins[i].interval = (float *)malloc(sizeof(float)*(mdl->skins[i].numgroupskins)); + if (mdl->skins[i].interval==NULL) Error("Could not load"); + memset(mdl->skins[i].interval,0,sizeof(float)*mdl->skins[i].numgroupskins); + for (int j=0;jskins[i].numgroupskins;j++) + { + fread(&(mdl->skins[i].interval[j]),sizeof(float),1,infile); + + fileread += sizeof(float); + } + + mdl->skins[i].skin = (u_char **)malloc(sizeof(unsigned char *)*(mdl->skins[i].numgroupskins)); + if (mdl->skins[i].skin==NULL) Error("Could not load"); + memset(mdl->skins[i].skin,0,sizeof(unsigned char *)*(mdl->skins[i].numgroupskins)); + for (j=0;jskins[i].numgroupskins;j++) + { + mdl->skins[i].skin[j] = (unsigned char *)malloc(header->skinwidth*header->skinheight); + if (mdl->skins[i].skin[j]==NULL) Error("Could not load"); + memset(mdl->skins[i].skin[j],0,header->skinwidth*header->skinheight); + fread(mdl->skins[i].skin[j],header->skinwidth*header->skinheight,1,infile); + + fileread += header->skinwidth*header->skinheight; + } + } + } + + mdl->stverts = (stvert_t *)malloc(header->numverts*sizeof(stvert_t)); + if (mdl->stverts==NULL) Error("1"); + memset(mdl->stverts,0,header->numverts*sizeof(stvert_t)); + fread(mdl->stverts,header->numverts*sizeof(stvert_t),1,infile); + + fileread += header->numverts*sizeof(stvert_t); + + mdl->tris = (itriangle_t *)malloc(header->numtris*sizeof(itriangle_t)); + if (mdl->tris==NULL) Error("2"); + memset(mdl->tris,0,header->numtris*sizeof(itriangle_t)); + fread(mdl->tris,header->numtris*sizeof(itriangle_t),1,infile); + + fileread += header->numtris * sizeof(itriangle_t); + + mdl->frames = (frame_t *)malloc(header->numframes*sizeof(frame_t)); + if (mdl->frames==NULL) Error("3"); + memset(mdl->frames,0,header->numframes*sizeof(frame_t)); + + for (i=0;inumframes;i++) + { + fread(&(mdl->frames[i].type),sizeof(long),1,infile); + + fileread += sizeof(long); + + if (mdl->frames[i].type==0) + { + mdl->frames[i].numgroupframes = 1; + + mdl->frames[i].info = (frameinfo_t *)malloc(sizeof(frameinfo_t)); + if (mdl->frames[i].info==NULL) Error("4"); + + fread(mdl->frames[i].info,sizeof(frameinfo_t),1,infile); + + fileread += sizeof(frameinfo_t); + + mdl->frames[i].data = (trivertx_t **)malloc(sizeof(u_char *)); + if (mdl->frames[i].data==NULL) Error("5"); + + mdl->frames[i].data[0] = (trivertx_t *)malloc(header->numverts*sizeof(trivertx_t)); + if (mdl->frames[i].data[0]==NULL) Error("6"); + memset(mdl->frames[i].data[0],0,header->numverts*sizeof(trivertx_t)); + fread(mdl->frames[i].data[0],header->numverts*sizeof(trivertx_t),1,infile); + + fileread += header->numverts*sizeof(trivertx_t); + + mdl->frames[i].interval = (float *)malloc(sizeof(float)); + if (mdl->frames[i].interval==NULL) Error("7"); + *(mdl->frames[i].interval) = (float)0; + } + else + { + fread(&(mdl->frames[i].numgroupframes),sizeof(long),1,infile); + fread(&(mdl->frames[i].groupmin),sizeof(trivertx_t),1,infile); + fread(&(mdl->frames[i].groupmax),sizeof(trivertx_t),1,infile); + + fileread += sizeof(long) + (2 * sizeof(trivertx_t)); + + mdl->frames[i].data = (trivertx_t **)malloc(sizeof(u_char *)*(mdl->frames[i].numgroupframes)); + if (mdl->frames[i].data==NULL) Error("8"); + memset(mdl->frames[i].data,0,sizeof(u_char *)*(mdl->frames[i].numgroupframes)); + + mdl->frames[i].info = (frameinfo_t *)malloc(sizeof(frameinfo_t)*(mdl->frames[i].numgroupframes)); + if (mdl->frames[i].info==NULL) Error("9"); + memset(mdl->frames[i].info,0,sizeof(frameinfo_t)*(mdl->frames[i].numgroupframes)); + + mdl->frames[i].interval = (float *)malloc(sizeof(float)*(mdl->frames[i].numgroupframes)); + if (mdl->frames[i].interval==NULL) Error("10"); + memset(mdl->frames[i].interval,0,sizeof(float)*mdl->frames[i].numgroupframes); + for (int j=0;jframes[i].numgroupframes;j++) + { + fread(&(mdl->frames[i].interval[j]),sizeof(float),1,infile); + + fileread += sizeof(float); + } + + for (j=0;jframes[i].numgroupframes;j++) + { + fread(&(mdl->frames[i].info[j]),sizeof(frameinfo_t),1,infile); + + fileread += sizeof(frameinfo_t); + + mdl->frames[i].data[j] = (trivertx_t *)malloc(header->numverts*sizeof(trivertx_t)); + if (mdl->frames[i].data[j]==NULL) Error("11"); + memset(mdl->frames[i].data[j],0,header->numverts*sizeof(trivertx_t)); + fread(mdl->frames[i].data[j],header->numverts*sizeof(trivertx_t),1,infile); + + fileread += header->numverts*sizeof(trivertx_t); + } + } + } + + mainModel.modelType = MODEL_QUAKE; + MDL_Show(&mainModel); + + fclose(infile); + + return TRUE; +} + +/* + * MDL_WritePaletteToFile + * + * Saves the current palette to a file of certain type + * + */ +BOOL MDL_WritePaletteToFile(char *filename, DWORD fileType) +{ + FILE *fp; + char output[128]; + pal_t *ppal; + + switch (palNum) + { + case PAL_QUAKE: ppal = &qpal[0]; + break; + case PAL_HEXEN2: ppal = &h2pal[0]; + break; + //case PAL_QUAKE2: ppal = &q2pal[0]; + // break; + case PAL_FROMFILE: ppal = &filepal[0]; + break; + } + + if (fileType == PALTYPE_JASC) + { + if ((fp = fopen(filename, "w+t"))==NULL) + return Error("Cannot open specified palette"); + } + else + { + if ((fp = fopen(filename, "w+b"))==NULL) + return Error("Cannot open specified palette"); + } + + if (fileType == PALTYPE_RAW) + { + fwrite(ppal, sizeof(pal_t)*256, 1, fp); + } + else if (fileType == PALTYPE_JASC) + { + fputs("JASC-PAL\n", fp); + fputs("0100\n", fp); + fputs("256\n", fp); + + for (int i = 0; i < 256; i++) + { + sprintf(output, "%d %d %d\n", ppal[i].r, ppal[i].g, ppal[i].b); + fputs(output, fp); + } + } + else if (fileType == PALTYPE_PCX) + { + } + + fclose(fp); + + return TRUE; +} + +/* + * MDL_Save + * + * Saves the current model to a file + * + */ +BOOL MDL_Save(char *filename) +{ + FILE *fp; + + fp = fopen(filename, "w+b"); + + if (!fp) return FALSE; + + return TRUE; +} diff --git a/Toolkit/Programming/Tools/qMView/MainFrm.cpp b/Toolkit/Programming/Tools/qMView/MainFrm.cpp new file mode 100644 index 0000000..df26e4e --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/MainFrm.cpp @@ -0,0 +1,699 @@ +// MainFrm.cpp : implementation of the CMainFrame class +// + +#include "stdafx.h" +#include "resource.h" +#include "DDUtil.h" +#include "Matrix.h" + +#include "Model.h" +#include "qMView.h" +#include "QMViewDoc.h" +#include "qMViewView.h" + +#include "treectrlex.h" +#include "frametreectrl.h" +#include "skintreectrl.h" + +#include "SkinPageFrm.h" +#include "JointConstraintDlg.h" +#include "JointAnglesDlg.h" +#include "ManagerTree.h" +#include "FrameManager2.h" +#include "MainFrm.h" + +#include "NodePropertyDlg.h" +//#include "Splash.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame + +IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) + +BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) + ON_COMMAND_EX(CG_ID_VIEW_FRAMEMANAGER2, OnBarCheck) + ON_UPDATE_COMMAND_UI(CG_ID_VIEW_FRAMEMANAGER2, OnUpdateControlBarMenu) + ON_COMMAND_EX(CG_ID_VIEW_FRAMETREEDLG, OnBarCheck) + ON_UPDATE_COMMAND_UI(CG_ID_VIEW_FRAMETREEDLG, OnUpdateControlBarMenu) + //{{AFX_MSG_MAP(CMainFrame) + ON_WM_CREATE() + ON_COMMAND(ID_ANIMATE_PLAY, OnAnimatePlay) + ON_COMMAND(ID_ANIMATE_STOP, OnAnimateStop) + ON_COMMAND(ID_ANIMATE_TYPE_BACK, OnAnimateTypeBack) + ON_UPDATE_COMMAND_UI(ID_ANIMATE_TYPE_BACK, OnUpdateAnimateTypeBack) + ON_COMMAND(ID_ANIMATE_TYPE_FRONT, OnAnimateTypeFront) + ON_UPDATE_COMMAND_UI(ID_ANIMATE_TYPE_FRONT, OnUpdateAnimateTypeFront) + ON_COMMAND(ID_ANIMATE_TYPE_PINGPONG, OnAnimateTypePingpong) + ON_UPDATE_COMMAND_UI(ID_ANIMATE_TYPE_PINGPONG, OnUpdateAnimateTypePingpong) + ON_COMMAND(ID_RENDER_FLAT, OnRenderFlat) + ON_UPDATE_COMMAND_UI(ID_RENDER_FLAT, OnUpdateRenderFlat) + ON_COMMAND(ID_RENDER_GOURAUD, OnRenderGouraud) + ON_UPDATE_COMMAND_UI(ID_RENDER_GOURAUD, OnUpdateRenderGouraud) + ON_COMMAND(ID_RENDER_WIREFRAME, OnRenderWireframe) + ON_UPDATE_COMMAND_UI(ID_RENDER_WIREFRAME, OnUpdateRenderWireframe) + ON_COMMAND(ID_NODE_TOGGLE_VIS, OnNodeToggleVis) + ON_COMMAND(ID_SKIN_SHOWOVERLAY, OnSkinShowoverlay) + ON_UPDATE_COMMAND_UI(ID_SKIN_SHOWOVERLAY, OnUpdateSkinShowoverlay) + ON_COMMAND(ID_MODE_CAMERA, OnModeCamera) + ON_UPDATE_COMMAND_UI(ID_MODE_CAMERA, OnUpdateModeCamera) + ON_COMMAND(ID_MODE_SKELETAL, OnModeSkeletal) + ON_UPDATE_COMMAND_UI(ID_MODE_SKELETAL, OnUpdateModeSkeletal) + ON_COMMAND(ID_SKELETON_SNAP, OnSkeletonSnap) + ON_COMMAND(ID_JOINT_MANUAL_ANGLES, OnJointManualAngles) + ON_COMMAND(ID_USE_JOINTS, OnUseJoints) + ON_UPDATE_COMMAND_UI(ID_USE_JOINTS, OnUpdateUseJoints) + ON_UPDATE_COMMAND_UI(ID_JOINT_MANUAL_ANGLES, OnUpdateJointManualAngles) + ON_UPDATE_COMMAND_UI(ID_JOINT_CONSTRAINTS, OnUpdateJointConstraints) + ON_COMMAND(ID_JOINT_CONSTRAINTS, OnJointConstraints) + ON_COMMAND(ID_WINDOW_SKIN, OnWindowSkin) + ON_UPDATE_COMMAND_UI(ID_WINDOW_SKIN, OnUpdateWindowSkin) + ON_COMMAND(ID_WINDOW_FRAME, OnWindowFrame) + ON_UPDATE_COMMAND_UI(ID_WINDOW_FRAME, OnUpdateWindowFrame) + ON_UPDATE_COMMAND_UI(ID_ANIMATE_STOP, OnUpdateAnimateStop) + ON_WM_DESTROY() + ON_UPDATE_COMMAND_UI(ID_ANIMATE_PLAY, OnUpdateAnimatePlay) + //}}AFX_MSG_MAP + // Global help commands + ON_COMMAND(ID_HELP_FINDER, CFrameWnd::OnHelpFinder) + ON_COMMAND(ID_HELP, CFrameWnd::OnHelp) + ON_COMMAND(ID_CONTEXT_HELP, CFrameWnd::OnContextHelp) + ON_COMMAND(ID_DEFAULT_HELP, CFrameWnd::OnHelpFinder) + + ON_UPDATE_COMMAND_UI_RANGE(ID_RENDER_FLAT, ID_RENDER_GOURAUD, OnUpdateRender) + ON_UPDATE_COMMAND_UI_RANGE(ID_ANIMATE_PLAY, ID_ANIMATE_STOP, OnUpdateAnim) + ON_UPDATE_COMMAND_UI_RANGE(ID_ANIMATE_TYPE_BACK, ID_ANIMATE_TYPE_PINGPONG, OnUpdateAnimType) + +END_MESSAGE_MAP() + +static UINT indicators[] = +{ + ID_SEPARATOR, // status line indicator + ID_INDICATOR_FPS, + ID_INDICATOR_CAPS, + ID_INDICATOR_NUM, + ID_INDICATOR_SCRL, +}; + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame construction/estruction + +CMainFrame::CMainFrame() +{ + m_hItemFirstSel = NULL; + m_jointDlg = NULL; + m_jointConstraintDlg = NULL; + m_wndFrameTreeDlg = NULL; + m_wndFrameManager2 = NULL; + m_model = NULL; + m_currentView = ID_MODELVIEW; + m_skinView = NULL; + m_modelView = NULL; + + m_manipulationType = MANIPULATE_CAMERA; +} + +CMainFrame::~CMainFrame() +{ +} + +void CMainFrame::PickNode(HTREEITEM item) +{ + m_wndFrameManager2->PickNode(item); +} + +void CMainFrame::SetModel(CModel* model) +{ + m_wndFrameTreeDlg->SetModel(model); + m_wndFrameManager2->SetModel(model); + m_model = model; + m_manipulationType = MANIPULATE_CAMERA; +} + +LPDIRECT3DRM2 CMainFrame::GetD3D() +{ + return ((CQMViewView*)m_modelView)->GetD3D(); +} + +CMenu* CMainFrame::GetSkinMenu() +{ + return m_wndFrameTreeDlg->GetSkinMenu(); +} + +CTreeCtrl* CMainFrame::GetSkinTreeCtrl() +{ + return m_wndFrameTreeDlg->GetSkinTreeCtrl(); +} + +CTreeCtrl* CMainFrame::GetNodeTreeCtrl() +{ + return m_wndFrameManager2->GetNodeTreeCtrl(); +} + +void CMainFrame::DeleteContents() +{ + m_wndFrameTreeDlg->DeleteContents(); + m_wndFrameManager2->DeleteContents(); +} + +CModel* CMainFrame::GetModel() +{ + return ((CQMViewDoc*)GetActiveDocument())->GetModel(); +} + +int CMainFrame::GetManipulationType() +{ + return m_manipulationType; +} + +int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CFrameWnd::OnCreate(lpCreateStruct) == -1) + return -1; + + if (!m_wndToolBar.Create(this) || + !m_wndToolBar.LoadToolBar(IDR_QMVIEWTYPE)) + { + TRACE0("Failed to create toolbar\n"); + return -1; // fail to create + } + + if (!m_wndStatusBar.Create(this) || + !m_wndStatusBar.SetIndicators(indicators, + sizeof(indicators)/sizeof(UINT))) + { + TRACE0("Failed to create status bar\n"); + return -1; // fail to create + } + + m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | + CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + + m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); + EnableDocking(CBRS_ALIGN_ANY); + DockControlBar(&m_wndToolBar, AFX_IDW_DOCKBAR_TOP); + + if (!m_wndPosToolBar.Create(this) || + !m_wndPosToolBar.LoadToolBar(IDR_VIEWPOSBAR)) + { + TRACE0("Failed to create toolbar\n"); + return -1; // fail to create + } + + m_wndPosToolBar.SetBarStyle(m_wndPosToolBar.GetBarStyle() | + CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + + m_wndPosToolBar.EnableDocking(CBRS_ALIGN_ANY); + + DockControlBar(&m_wndPosToolBar, AFX_IDW_DOCKBAR_LEFT); + + if (!m_wndAnimToolBar.Create(this) || + !m_wndAnimToolBar.LoadToolBar(IDR_ANIMBAR)) + { + TRACE0("Failed to create toolbar\n"); + return -1; // fail to create + } + + m_wndAnimToolBar.SetBarStyle(m_wndAnimToolBar.GetBarStyle() | + CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + + m_wndAnimToolBar.EnableDocking(CBRS_ALIGN_ANY); + DockControlBar(&m_wndAnimToolBar, AFX_IDW_DOCKBAR_TOP); + + m_wndFrameManager2 = new FrameManager2; + if (!m_wndFrameManager2->Create(this, CBRS_RIGHT | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_HIDE_INPLACE)) + { + TRACE0("Failed to create dialog bar m_wndFrameManager2\n"); + return -1; // fail to create + } + + m_wndFrameTreeDlg = new CManagerTree(); + if (!m_wndFrameTreeDlg->Create(this, CBRS_LEFT | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_HIDE_INPLACE)) + { + TRACE0("Failed to create dialog bar m_wndFrameTreeDlg\n"); + return -1; // fail to create + } + + // TODO: Add a menu item that will toggle the visibility of the + // dialog bar named "Frame Manager2": + // 1. In ResourceView, open the menu resource that is used by + // the CMainFrame class + // 2. Select the View submenu + // 3. Double-click on the blank item at the bottom of the submenu + // 4. Assign the new item an ID: CG_ID_VIEW_FRAMEMANAGER2 + // 5. Assign the item a Caption: Frame Manager2 + + // TODO: Change the value of CG_ID_VIEW_FRAMEMANAGER2 to an appropriate value: + // 1. Open the file resource.h + // CG: The following block was inserted by the 'Dialog Bar' component + + return 0; +} + +BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) +{ + // TODO: Modify the Window class or styles here by modifying + // the CREATESTRUCT cs + + cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE + | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_MAXIMIZE; + + return CFrameWnd::PreCreateWindow(cs); +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame message handlers + +BOOL overlayOn = false; + +//Added so toolbar can function +void CMainFrame::OnAnimatePlay() +{ + if (m_model == NULL) + { + return; + } + m_model->SetPlay(true); + GetActiveDocument()->UpdateAllViews(NULL, QM_RUN_ANIMATION, NULL); +} + +void CMainFrame::OnAnimateStop() +{ + if (m_model == NULL) + { + return; + } + m_model->SetPlay(false); + GetActiveDocument()->UpdateAllViews(NULL, QM_STOP_ANIMATION, NULL); +} + +void CMainFrame::OnAnimateTypeBack() +{ + if (m_model == NULL) + { + return; + } + m_model->SetPlayMode(ANIM_BACKWARD); + m_model->SetPingPong(false); +} + +void CMainFrame::OnUpdateAnimateTypeBack(CCmdUI* pCmdUI) +{ + if (m_model != NULL) + { + pCmdUI->SetCheck((m_model->GetPlayMode()==ANIM_BACKWARD)); + } +} + +void CMainFrame::OnAnimateTypeFront() +{ + if (m_model == NULL) + { + return; + } + m_model->SetPlayMode(ANIM_FORWARD); + m_model->SetPingPong(false); +} + +void CMainFrame::OnUpdateAnimateTypeFront(CCmdUI* pCmdUI) +{ + if (m_model != NULL) + { + pCmdUI->SetCheck((m_model->GetPlayMode()==ANIM_FORWARD)); + } +} + +void CMainFrame::OnAnimateTypePingpong() +{ + if (m_model == NULL) + { + return; + } + m_model->SetPingPong(true); +} + +void CMainFrame::OnUpdateAnimateTypePingpong(CCmdUI* pCmdUI) +{ + if (m_model != NULL) + { + pCmdUI->SetCheck((m_model->GetPlayMode()==ANIM_PINGPONG)); + } +} + +void CMainFrame::OnRenderFlat() +{ + if (m_model == NULL) + { + return; + } + m_model->SetGroupQuality(D3DRMRENDER_FLAT); +// m_model->ShowFrame(); +} + +void CMainFrame::OnUpdateRenderFlat(CCmdUI* pCmdUI) +{ + if (m_model) + { + D3DRMRENDERQUALITY meshquality = m_model->GetGroupQuality(); + pCmdUI->SetCheck(meshquality==D3DRMRENDER_FLAT); + } +} + +void CMainFrame::OnRenderGouraud() +{ + if (m_model) + { + m_model->SetGroupQuality(D3DRMRENDER_GOURAUD); +// m_model->ShowFrame(); + } +} + +void CMainFrame::OnUpdateRenderGouraud(CCmdUI* pCmdUI) +{ + if (m_model) + { + D3DRMRENDERQUALITY meshquality = m_model->GetGroupQuality(); + pCmdUI->SetCheck( meshquality==D3DRMRENDER_GOURAUD ); + } +} + +void CMainFrame::OnRenderWireframe() +{ + if (m_model == NULL) + { + return; + } + m_model->SetGroupQuality(D3DRMRENDER_WIREFRAME); +// m_model->ShowFrame(); +} + +void CMainFrame::OnUpdateRenderWireframe(CCmdUI* pCmdUI) +{ + if (m_model) + { + D3DRMRENDERQUALITY meshquality = m_model->GetGroupQuality(); + pCmdUI->SetCheck( meshquality==D3DRMRENDER_WIREFRAME ); + } +} + +void CMainFrame::OnUpdateRender(CCmdUI* pCmdUI) +{ + pCmdUI->SetRadio(TRUE); +} + +void CMainFrame::OnUpdateAnimType(CCmdUI* pCmdUI) +{ + pCmdUI->SetRadio(TRUE); +} + +void CMainFrame::OnUpdateAnim(CCmdUI* pCmdUI) +{ + pCmdUI->SetRadio(TRUE); +} + +void CMainFrame::OnNodeToggleVis() +{ + HTREEITEM item, parent; + int nodeNum = 0; + CTreeCtrl* pCTree = (CTreeCtrl*)m_wndFrameManager2->GetDlgItem(IDC_NODETREE); + + item = pCTree->GetSelectedItem(); + parent = pCTree->GetParentItem(item); + + if (parent == TVI_ROOT) + { + GetActiveDocument()->UpdateAllViews(NULL, QM_ALLNODES_VISIBLE, (CObject*)m_model); + return; + } + + CString cs = pCTree->GetItemText(item); + LPSTR foo = cs.GetBuffer(10); + + sscanf(foo, "Node %d", &nodeNum); + + m_model->SelectMesh(NULL); + + if (m_model->ToggleNodeVisibility(nodeNum)) + { + GetActiveDocument()->UpdateAllViews(NULL, QM_ADD_VISUAL, (CObject*)nodeNum); + m_model->GetMesh(nodeNum)->SetGroupColorRGB(0, 255, 0, 0); + pCTree->SetItemImage(item, 1, 1); + } + else + { + GetActiveDocument()->UpdateAllViews(NULL, QM_DELETE_VISUAL, (CObject*)nodeNum); + pCTree->SetItemImage(item, 2, 2); + } +} + +void CMainFrame::OnSkinShowoverlay() +{ + overlayOn = !overlayOn; + Invalidate(true); +} + +void CMainFrame::OnUpdateSkinShowoverlay(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(overlayOn); +} + +void CMainFrame::OnModeCamera() +{ + m_manipulationType = MANIPULATE_CAMERA; +} + +void CMainFrame::OnUpdateModeCamera(CCmdUI* pCmdUI) +{ + pCmdUI->SetRadio(m_manipulationType==MANIPULATE_CAMERA); +} + +void CMainFrame::OnModeSkeletal() +{ + if (m_model == NULL) + { + return; + } + m_manipulationType = MANIPULATE_SKELETON; +} + +void CMainFrame::OnUpdateModeSkeletal(CCmdUI* pCmdUI) +{ + pCmdUI->SetRadio(m_manipulationType==MANIPULATE_SKELETON); +} + +void CMainFrame::OnSkeletonSnap() +{ + if (m_model != NULL) + { + m_model->Snap(); + UpdateVisuals(); +// m_model->ShowFrame(); + } +} + +void CMainFrame::OnJointManualAngles() +{ + if (m_jointDlg == NULL) + { + m_jointDlg = new CJointAnglesDlg; + m_jointDlg->Create(IDD_JOINT_ANGLES, this); + } + else + { + m_jointDlg->DestroyWindow(); + delete m_jointDlg; + m_jointDlg = NULL; + } +} + +void CMainFrame::OnUseJoints() +{ + if (m_model != NULL) + { + m_model->ToggleJointOn(); + } +} + +void CMainFrame::OnUpdateUseJoints(CCmdUI* pCmdUI) +{ + if (m_model != NULL) + { + pCmdUI->SetRadio(m_model->IsJointOn()); + } +} + +void CMainFrame::DestroyJointDialogs() +{ + if (m_jointDlg != NULL) + { + m_jointDlg->DestroyWindow(); + delete m_jointDlg; + m_jointDlg = NULL; + } + if (m_jointConstraintDlg != NULL) + { + m_jointConstraintDlg->DestroyWindow(); + delete m_jointConstraintDlg; + m_jointConstraintDlg = NULL; + } +} + +void CMainFrame::UpdateVisuals() +{ + if (m_jointDlg != NULL) + { + m_jointDlg->UpdateVisuals(); + } +} + +void CMainFrame::OnUpdateJointManualAngles(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + pCmdUI->SetCheck(m_jointDlg != NULL); +} + +void CMainFrame::OnUpdateJointConstraints(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + pCmdUI->SetCheck(m_jointConstraintDlg != NULL); +} + +void CMainFrame::OnJointConstraints() +{ + // TODO: Add your command handler code here + if (m_jointConstraintDlg == NULL) + { + m_jointConstraintDlg = new CJointConstraintDlg; + m_jointConstraintDlg->Create(IDD_JOINT_LOCK_ANGLES, this); + } + else + { + m_jointConstraintDlg->DestroyWindow(); + delete m_jointConstraintDlg; + m_jointConstraintDlg = NULL; + } +} + +void CMainFrame::OnWindowFrame() +{ + // TODO: Add your command handler code here + if (m_currentView == ID_MODELVIEW) + { + return; + } + if (m_modelView == NULL) + { + MessageBox("Logic error -- no model view"); + return; + } + m_modelView->SetDlgCtrlID(AFX_IDW_PANE_FIRST); + m_skinView->SetDlgCtrlID(ID_SKINVIEW); + m_modelView->ShowWindow(SW_SHOW); + m_skinView->ShowWindow(SW_HIDE); + SetActiveView(m_modelView); + m_currentView = ID_MODELVIEW; + RecalcLayout(); +} + +void CMainFrame::OnUpdateWindowSkin(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + pCmdUI->SetCheck(m_currentView == ID_SKINVIEW); +} + +void CMainFrame::OnWindowSkin() +{ + // TODO: Add your command handler code here + if (m_currentView == ID_SKINVIEW) + { + return; + } + m_skinView->SetDlgCtrlID(AFX_IDW_PANE_FIRST); + m_modelView->SetDlgCtrlID(ID_MODELVIEW); + m_skinView->ShowWindow(SW_SHOW); + m_modelView->ShowWindow(SW_HIDE); + SetActiveView(m_skinView); + m_currentView = ID_SKINVIEW; + RecalcLayout(); +} + +void CMainFrame::OnUpdateWindowFrame(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + pCmdUI->SetCheck(m_currentView == ID_MODELVIEW); +} + + +void CMainFrame::OnUpdateAnimateStop(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + if (m_model == NULL) + { + return; + } + pCmdUI->SetCheck(!m_model->Playing()); +} + +void CMainFrame::OnUpdateAnimatePlay(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + if (m_model == NULL) + { + return; + } + pCmdUI->SetCheck(m_model->Playing()); +} + +void CMainFrame::OnDestroy() +{ + CFrameWnd::OnDestroy(); + + // TODO: Add your message handler code here + if (m_jointDlg != NULL) + { + m_jointDlg->DestroyWindow(); + delete m_jointDlg; + m_jointDlg = NULL; + } + if (m_jointConstraintDlg != NULL) + { + m_jointConstraintDlg->DestroyWindow(); + delete m_jointConstraintDlg; + m_jointConstraintDlg = NULL; + } + if (m_wndFrameTreeDlg != NULL) + { + m_wndFrameTreeDlg->DestroyWindow(); + delete m_wndFrameTreeDlg; + m_wndFrameTreeDlg = NULL; + } + if (m_wndFrameManager2 != NULL) + { + m_wndFrameManager2->DestroyWindow(); + delete m_wndFrameManager2; + m_wndFrameManager2 = NULL; + } +} + +BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) +{ + // TODO: Add your specialized code here and/or call the base class + + m_modelView = (CView*)CreateView(pContext, AFX_IDW_PANE_FIRST); + m_skinView = new CSkinPageFrm; + m_skinView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, ID_SKINVIEW, NULL); + CDocument* pDoc = pContext->m_pCurrentDoc; + pDoc->AddView(m_skinView); + m_modelView->SetDlgCtrlID(AFX_IDW_PANE_FIRST); + m_skinView->SetDlgCtrlID(ID_SKINVIEW); + m_modelView->ShowWindow(SW_SHOW); + m_skinView->ShowWindow(SW_HIDE); + SetActiveView(m_modelView); + m_currentView = ID_MODELVIEW; + return true; +} diff --git a/Toolkit/Programming/Tools/qMView/MainFrm.h b/Toolkit/Programming/Tools/qMView/MainFrm.h new file mode 100644 index 0000000..26e47fe --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/MainFrm.h @@ -0,0 +1,113 @@ +// MainFrm.h : interface of the CMainFrame class +// +///////////////////////////////////////////////////////////////////////////// + +#define MANIPULATE_CAMERA 0 +#define MANIPULATE_SKELETON 1 + +class CMainFrame : public CFrameWnd +{ + DECLARE_DYNCREATE(CMainFrame) +public: + CMainFrame(); + +// Attributes +public: + void UpdateVisuals(); + CModel* GetModel(); + CMenu* GetSkinMenu(); + CTreeCtrl* GetSkinTreeCtrl(); + CTreeCtrl* GetNodeTreeCtrl(); + LPDIRECT3DRM2 GetD3D(); +// Operations +public: + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CMainFrame) + public: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + protected: + virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CMainFrame(); + + void SetModel(CModel* model); + void DeleteContents(); + void PickNode(HTREEITEM item); + int GetManipulationType(); + + void DestroyJointDialogs(); + +public: // control bar embedded members + HTREEITEM m_hItemFirstSel; + +// Generated message map functions +protected: + CToolBar m_wndToolBar; + CToolBar m_wndPosToolBar; + CToolBar m_wndAnimToolBar; + CStatusBar m_wndStatusBar; + + CJointAnglesDlg* m_jointDlg; + CJointConstraintDlg* m_jointConstraintDlg; + CManagerTree* m_wndFrameTreeDlg; + FrameManager2* m_wndFrameManager2; + CModel* m_model; + + int m_currentView; + CView* m_skinView; + CView* m_modelView; + + int m_manipulationType; + + //{{AFX_MSG(CMainFrame) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnAnimatePlay(); + afx_msg void OnAnimateStop(); + afx_msg void OnAnimateTypeBack(); + afx_msg void OnUpdateAnimateTypeBack(CCmdUI* pCmdUI); + afx_msg void OnAnimateTypeFront(); + afx_msg void OnUpdateAnimateTypeFront(CCmdUI* pCmdUI); + afx_msg void OnAnimateTypePingpong(); + afx_msg void OnUpdateAnimateTypePingpong(CCmdUI* pCmdUI); + afx_msg void OnRenderFlat(); + afx_msg void OnUpdateRenderFlat(CCmdUI* pCmdUI); + afx_msg void OnRenderGouraud(); + afx_msg void OnUpdateRenderGouraud(CCmdUI* pCmdUI); + afx_msg void OnRenderWireframe(); + afx_msg void OnUpdateRenderWireframe(CCmdUI* pCmdUI); + afx_msg void OnNodeToggleVis(); + afx_msg void OnSkinShowoverlay(); + afx_msg void OnUpdateSkinShowoverlay(CCmdUI* pCmdUI); + afx_msg void OnModeCamera(); + afx_msg void OnUpdateModeCamera(CCmdUI* pCmdUI); + afx_msg void OnModeSkeletal(); + afx_msg void OnUpdateModeSkeletal(CCmdUI* pCmdUI); + afx_msg void OnSkeletonSnap(); + afx_msg void OnJointManualAngles(); + afx_msg void OnUseJoints(); + afx_msg void OnUpdateUseJoints(CCmdUI* pCmdUI); + afx_msg void OnUpdateJointManualAngles(CCmdUI* pCmdUI); + afx_msg void OnUpdateJointConstraints(CCmdUI* pCmdUI); + afx_msg void OnJointConstraints(); + afx_msg void OnWindowSkin(); + afx_msg void OnUpdateWindowSkin(CCmdUI* pCmdUI); + afx_msg void OnWindowFrame(); + afx_msg void OnUpdateWindowFrame(CCmdUI* pCmdUI); + afx_msg void OnUpdateAnimateStop(CCmdUI* pCmdUI); + afx_msg void OnDestroy(); + afx_msg void OnUpdateAnimatePlay(CCmdUI* pCmdUI); + //}}AFX_MSG + + afx_msg void OnUpdateAnim(CCmdUI* pCmdUI); + afx_msg void OnUpdateRender(CCmdUI* pCmdUI); + afx_msg void OnUpdateAnimType(CCmdUI* pCmdUI); + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// diff --git a/Toolkit/Programming/Tools/qMView/ManagerTree.cpp b/Toolkit/Programming/Tools/qMView/ManagerTree.cpp new file mode 100644 index 0000000..c81feb4 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/ManagerTree.cpp @@ -0,0 +1,86 @@ +// ManagerTree.cpp : implementation file +// + +#include "stdafx.h" +#include "DDUtil.h" +#include "qMView.h" +#include "Matrix.h" +#include "Model.h" + +#include "JointConstraintDlg.h" +#include "JointAnglesDlg.h" +#include "treectrlex.h" +#include "frametreectrl.h" +#include "skintreectrl.h" + +#include "ManagerTree.h" +#include "NodeTreeCtrl.h" +#include "JointTreeCtrl.h" +#include "FrameManager2.h" +#include "MainFrm.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CManagerTree + +CManagerTree::CManagerTree() +{ +} + +CManagerTree::~CManagerTree() +{ +} + +BOOL CManagerTree::Create(CWnd* pParentWnd, UINT nStyle) +{ + if (!CDialogBar::Create (pParentWnd, CG_IDD_TREEMANAGER, nStyle, CG_IDD_TREEMANAGER)) + return FALSE; + + m_nFrameTree.SubclassDlgItem(IDC_FRAMETREE,this); + m_nSkinTree.SubclassDlgItem(IDC_SKINTREE,this); + CModel* model = GetModel(); + m_nFrameTree.SetModel(model); + m_nSkinTree.SetModel(model); + return TRUE; +} + +CMenu* CManagerTree::GetSkinMenu() +{ + return m_nSkinTree.GetSkinMenu(); +} + +CTreeCtrl* CManagerTree::GetSkinTreeCtrl() +{ + return &m_nSkinTree; +} + +void CManagerTree::DeleteContents() +{ + m_nFrameTree.DeleteContents(); + m_nSkinTree.DeleteContents(); +} + +BEGIN_MESSAGE_MAP(CManagerTree, CDialogBar) + //{{AFX_MSG_MAP(CManagerTree) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CManagerTree message handlers + +CModel* CManagerTree::GetModel() +{ + return ((CMainFrame*)GetParent())->GetModel(); +} + +void CManagerTree::SetModel(CModel* model) +{ + m_nFrameTree.SetModel(model); + m_nSkinTree.SetModel(model); +} diff --git a/Toolkit/Programming/Tools/qMView/ManagerTree.h b/Toolkit/Programming/Tools/qMView/ManagerTree.h new file mode 100644 index 0000000..230b465 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/ManagerTree.h @@ -0,0 +1,45 @@ +// ManagerTree.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CManagerTree window + +class CManagerTree : public CDialogBar +{ +// Construction +public: + CFrameTreeCtrl m_nFrameTree; + CSkinTreeCtrl m_nSkinTree; + CManagerTree(); + BOOL Create(CWnd* pParentWnd, UINT nStyle); + void SetModel(CModel* model); + void DeleteContents(); + CModel* GetModel(); + CMenu* GetSkinMenu(); + CTreeCtrl* GetSkinTreeCtrl(); +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CManagerTree) + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CManagerTree(); + + // Generated message map functions +protected: + //{{AFX_MSG(CManagerTree) + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +///////////////////////////////////////////////////////////////////////////// diff --git a/Toolkit/Programming/Tools/qMView/Martix.cpp b/Toolkit/Programming/Tools/qMView/Martix.cpp new file mode 100644 index 0000000..2b5143f --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Martix.cpp @@ -0,0 +1,794 @@ +#include "stdafx.h" +#include "Matrix.h" +#include "Vector.h" +#include "Angles.h" + +#pragma warning(disable : 4244) // truncation from double to float +#pragma warning(disable : 4056) // overflow in floating-point constant arithmetic +#pragma warning (disable : 4305) + +void CMatrix::Matrix3MultByMartrix3(matrix3_t A, matrix3_t B, matrix3_t C) +{ + C[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + + B[0][2] * A[2][0]; + C[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + + B[0][2] * A[2][1]; + C[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + + B[0][2] * A[2][2]; + C[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + + B[1][2] * A[2][0]; + C[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + + B[1][2] * A[2][1]; + C[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + + B[1][2] * A[2][2]; + C[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + + B[2][2] * A[2][0]; + C[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + + B[2][2] * A[2][1]; + C[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + + B[2][2] * A[2][2]; +} + +void CMatrix::Matrix3dMultByMartrix3d(matrix3d_t A, matrix3d_t B, matrix3d_t C) +{ + C[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + + B[0][2] * A[2][0]; + C[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + + B[0][2] * A[2][1]; + C[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + + B[0][2] * A[2][2]; + C[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + + B[1][2] * A[2][0]; + C[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + + B[1][2] * A[2][1]; + C[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + + B[1][2] * A[2][2]; + C[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + + B[2][2] * A[2][0]; + C[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + + B[2][2] * A[2][1]; + C[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + + B[2][2] * A[2][2]; +} + +void CMatrix::Matrix3MultByVec3(matrix3_t A, vec3a_t B, vec3a_t C) +{ + C[0] = B[0] * A[0][0] + B[1] * A[1][0] + + B[2] * A[2][0]; + C[1] = B[0] * A[0][1] + B[1] * A[1][1] + + B[2] * A[2][1]; + C[2] = B[0] * A[0][2] + B[1] * A[1][2] + + B[2] * A[2][2]; +} + +void CMatrix::Matrix3dMultByVec3(matrix3d_t A, vec3a_t B, vec3a_t *C) +{ + C[0][0] = B[0] * A[0][0] + B[1] * A[1][0] + + B[2] * A[2][0]; + C[0][1] = B[0] * A[0][1] + B[1] * A[1][1] + + B[2] * A[2][1]; + C[0][2] = B[0] * A[0][2] + B[1] * A[1][2] + + B[2] * A[2][2]; +} + +void CMatrix::Matrix3dMultByVec3d(matrix3d_t A, vec3d_t B, vec3d_t C) +{ + C[0] = B[0] * A[0][0] + B[1] * A[1][0] + + B[2] * A[2][0]; + C[1] = B[0] * A[0][1] + B[1] * A[1][1] + + B[2] * A[2][1]; + C[2] = B[0] * A[0][2] + B[1] * A[1][2] + + B[2] * A[2][2]; +} + +void CMatrix::Matrix3FromAngles(vec3a_t angles, matrix3_t rotationMatrix) +{ + matrix3_t yawMatrix; + matrix3_t pitchMatrix; + matrix3_t rollMatrix; + matrix3_t pitchRollMatrix; + +#if 1 + memset(rollMatrix, 0, sizeof(rollMatrix)); + + // Rotation about the x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = cos(angles[PITCH]); + rollMatrix[2][2] = rollMatrix[1][1]; + rollMatrix[1][2] = sin(angles[PITCH]); + rollMatrix[2][1] = -rollMatrix[1][2]; + + // Rotation about the y axis + memset(pitchMatrix, 0, sizeof(pitchMatrix)); + + pitchMatrix[0][0] = cos(angles[YAW]); + pitchMatrix[2][2] = pitchMatrix[0][0]; + pitchMatrix[1][1] = 1; + pitchMatrix[2][0] = sin(angles[YAW]); + pitchMatrix[0][2] = -pitchMatrix[2][0]; + + // Rotation about the z axis + memset(yawMatrix, 0, sizeof(yawMatrix)); + + yawMatrix[0][0] = cos(angles[ROLL]); + yawMatrix[1][1] = yawMatrix[0][0]; + yawMatrix[0][1] = sin(angles[ROLL]); + yawMatrix[1][0] = -yawMatrix[0][1]; + yawMatrix[2][2] = 1; + + Matrix3MultByMartrix3(pitchMatrix, rollMatrix, pitchRollMatrix); + + Matrix3MultByMartrix3(yawMatrix, pitchRollMatrix, rotationMatrix); +#else + // Rotation about the y axis + memset(pitchMatrix, 0, sizeof(pitchMatrix)); + + pitchMatrix[0][0] = cos(angles[YAW]); + pitchMatrix[2][2] = pitchMatrix[0][0]; + pitchMatrix[1][1] = 1; + pitchMatrix[2][0] = sin(angles[YAW]); + pitchMatrix[0][2] = -pitchMatrix[2][0]; + + memset(rollMatrix, 0, sizeof(rollMatrix)); + + // Rotation about the x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = cos(angles[PITCH]); + rollMatrix[2][2] = rollMatrix[1][1]; + rollMatrix[1][2] = sin(angles[PITCH]); + rollMatrix[2][1] = -rollMatrix[1][2]; + + // Rotation about the z axis + memset(yawMatrix, 0, sizeof(yawMatrix)); + + yawMatrix[0][0] = cos(angles[ROLL]); + yawMatrix[1][1] = yawMatrix[0][0]; + yawMatrix[0][1] = sin(angles[ROLL]); + yawMatrix[1][0] = -yawMatrix[0][1]; + yawMatrix[2][2] = 1; + + Matrix3MultByMartrix3(rollMatrix, pitchMatrix, pitchRollMatrix); + + Matrix3MultByMartrix3(yawMatrix, pitchRollMatrix, rotationMatrix); +#endif +} + +void CMatrix::Matrix3dFromAngles(vec3a_t angles, matrix3d_t rotationMatrix) +{ + matrix3d_t yawMatrix; + matrix3d_t pitchMatrix; + matrix3d_t rollMatrix; + matrix3d_t pitchRollMatrix; + + memset(rollMatrix, 0, sizeof(rollMatrix)); + + // Rotation about the x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = cos(angles[ROLL]); + rollMatrix[2][2] = rollMatrix[1][1]; + rollMatrix[1][2] = sin(angles[ROLL]); + rollMatrix[2][1] = -rollMatrix[1][2]; + + // Rotation about the y axis + memset(pitchMatrix, 0, sizeof(pitchMatrix)); + + pitchMatrix[0][0] = cos(-angles[PITCH]); + pitchMatrix[2][2] = pitchMatrix[0][0]; + pitchMatrix[1][1] = 1; + pitchMatrix[2][0] = sin(-angles[PITCH]); + pitchMatrix[0][2] = -pitchMatrix[2][0]; + + // Rotation about the z axis + memset(yawMatrix, 0, sizeof(yawMatrix)); + + yawMatrix[0][0] = cos(angles[YAW]); + yawMatrix[1][1] = yawMatrix[0][0]; + yawMatrix[0][1] = sin(angles[YAW]); + yawMatrix[1][0] = -yawMatrix[0][1]; + yawMatrix[2][2] = 1; + + Matrix3MultByMartrix3(pitchMatrix, rollMatrix, pitchRollMatrix); + + Matrix3MultByMartrix3(yawMatrix, pitchRollMatrix, rotationMatrix); +} + +void CMatrix::Matrixs3FromDirAndUp(vec3a_t direction, vec3a_t up, matrix3_t toLocal, matrix3_t fromLocal) +{ + matrix3d_t pitchYawMatrix; + matrix3d_t rollMatrix; + double r, s, roll; + vec3a_t rotatedUp; + float x, y, z; + + x = 1.0f; + y = 1.0f; + z = 1.0f; + + // need to check for direction == {x, 0, 0} + // ot maybe not. Looks like the math will work out to be the I or -I, + // which seems right; haven't actually seen any problems with it yet. . . + + r = 1-direction[0]; + s = sin(-acos(direction[0])); + +#if 1 + // matrix from direction vector + pitchYawMatrix[0][0] = direction[0]*x; + pitchYawMatrix[1][0] = -direction[1]*s; + pitchYawMatrix[2][0] = -direction[2]*s; + pitchYawMatrix[0][1] = -pitchYawMatrix[1][0]; + pitchYawMatrix[1][1] = direction[2]*direction[2]*r+direction[0]*y; + pitchYawMatrix[2][1] = -direction[1]*direction[2]*r; + pitchYawMatrix[0][2] = direction[2]*s; + pitchYawMatrix[1][2] = pitchYawMatrix[2][1]; + pitchYawMatrix[2][2] = direction[1]*direction[1]*r+direction[0]*z; + +/* pitchYawMatrix[0][0] = direction[0]; + pitchYawMatrix[1][0] = -direction[1]*s; + pitchYawMatrix[2][0] = -direction[2]*s; + pitchYawMatrix[0][1] = -pitchYawMatrix[1][0]; + pitchYawMatrix[1][1] = direction[2]*direction[2]*r+direction[0]; + pitchYawMatrix[2][1] = -direction[1]*direction[2]*r; + pitchYawMatrix[0][2] = direction[2]*s; + pitchYawMatrix[1][2] = pitchYawMatrix[2][1]; + pitchYawMatrix[2][2] = direction[1]*direction[1]*r+direction[0];*/ +#else + pitchYawMatrix[0][0] = 1; + pitchYawMatrix[1][0] = 0; + pitchYawMatrix[2][0] = 0; + pitchYawMatrix[0][1] = 0; + pitchYawMatrix[1][1] = 1; + pitchYawMatrix[2][1] = 0; + pitchYawMatrix[0][2] = 0; + pitchYawMatrix[1][2] = 0; + pitchYawMatrix[2][2] = 1; +#endif + + Matrix3dMultByVec3(pitchYawMatrix, up, &rotatedUp); + +#ifndef NDEBUG + { + vec3a_t temp = { 1, 0, 0 }; + float dot; + dot = Vec3DotProduct(rotatedUp, temp); + } +#endif + + rotatedUp[0] = 0; + + Vec3Normalize(rotatedUp); + + roll = -(atan2(rotatedUp[2], rotatedUp[1])-ANGLE_90); + + memset(rollMatrix, 0, sizeof(rollMatrix)); + +#if 1 + // Rotation about the local x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = cos(roll); + rollMatrix[2][2] = rollMatrix[1][1]; + rollMatrix[1][2] = sin(roll); + rollMatrix[2][1] = -rollMatrix[1][2]; + +#else + // Rotation about the local x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = 1; + rollMatrix[2][2] = 1; +#endif + + Matrix3dMultByMartrix3d(rollMatrix, pitchYawMatrix, fromLocal); + + if(toLocal) + { + roll *= -1; + + memset(rollMatrix, 0, sizeof(rollMatrix)); + +#if 1 + // Rotation about the x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = cos(roll); + rollMatrix[2][2] = rollMatrix[1][1]; + rollMatrix[1][2] = sin(roll); + rollMatrix[2][1] = -rollMatrix[1][2]; +#else + // Rotation about the local x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = 1; + rollMatrix[2][2] = 1; +#endif + +// direction[1] *= -1; +// direction[2] *= -1; + + r = 1-direction[0]; + s = sin(acos(direction[0])); + +#if 1 + // matrix from direction vector + pitchYawMatrix[0][0] = direction[0]*x; + pitchYawMatrix[1][0] = -direction[1]*s; + pitchYawMatrix[2][0] = -direction[2]*s; + pitchYawMatrix[0][1] = -pitchYawMatrix[1][0]; + pitchYawMatrix[1][1] = direction[2]*direction[2]*r+direction[0]*y; + pitchYawMatrix[2][1] = -direction[1]*direction[2]*r; + pitchYawMatrix[0][2] = direction[2]*s; + pitchYawMatrix[1][2] = pitchYawMatrix[2][1]; + pitchYawMatrix[2][2] = direction[1]*direction[1]*r+direction[0]*z; +#else + pitchYawMatrix[0][0] = 1; + pitchYawMatrix[1][0] = 0; + pitchYawMatrix[2][0] = 0; + pitchYawMatrix[0][1] = 0; + pitchYawMatrix[1][1] = 1; + pitchYawMatrix[2][1] = 0; + pitchYawMatrix[0][2] = 0; + pitchYawMatrix[1][2] = 0; + pitchYawMatrix[2][2] = 1; +#endif + + Matrix3dMultByVec3(pitchYawMatrix, up, &rotatedUp); + + Matrix3dMultByMartrix3d(pitchYawMatrix, rollMatrix, toLocal); + +// direction[1] *= -1; +// direction[2] *= -1; + } +} + +#pragma optimize("p", on) + +double CMatrix::Matricies3dFromDirAndUp(vec3a_t direction, vec3a_t up, matrix3d_t fromLocal, matrix3d_t toLocal) +{ + matrix3d_t pitchYawMatrix; + matrix3d_t rollMatrix; + double roll; + vec3d_t rotatedUp, up_d; + vec3d_t dir_d; + +#ifndef NDEBUG + double dot1, dot2; + +#endif + + dir_d[0] = direction[0]; + dir_d[1] = direction[1]; + dir_d[2] = direction[2]; + + up_d[0] = up[0]; + up_d[1] = up[1]; + up_d[2] = up[2]; + +#ifndef NDEBUG + dot1 = Vec3dDotProduct(up_d, dir_d); +#endif + +#if 0 // not sure what's wrong with this + + // need to check for direction == {x, 0, 0} + // ot maybe not. Looks like the math will work out to be the I or -I, + // which seems right; haven't actually seen any problems with it yet. . . + + r = 1-dir_d[0]; + s = sin(-acos(dir_d[0])); + + // matrix from dir_d vector + pitchYawMatrix[0][0] = dir_d[0]; + pitchYawMatrix[1][0] = -dir_d[1]*s; + pitchYawMatrix[2][0] = -dir_d[2]*s; + pitchYawMatrix[0][1] = -pitchYawMatrix[1][0]; + pitchYawMatrix[1][1] = dir_d[2]*dir_d[2]*r+dir_d[0]; + pitchYawMatrix[2][1] = -dir_d[1]*dir_d[2]*r; + pitchYawMatrix[0][2] = dir_d[2]*s; + pitchYawMatrix[1][2] = pitchYawMatrix[2][1]; + pitchYawMatrix[2][2] = dir_d[1]*dir_d[1]*r+dir_d[0]; +#else + { + double yaw, pitch; + matrix3d_t pitchMatrix, yawMatrix; + + yaw = atan2(dir_d[1], dir_d[0]); + pitch = asin(dir_d[2]); + + // Rotation about the y axis + memset(pitchMatrix, 0, sizeof(pitchMatrix)); + + pitchMatrix[0][0] = cos(pitch); + pitchMatrix[2][2] = pitchMatrix[0][0]; + pitchMatrix[1][1] = 1; + pitchMatrix[2][0] = sin(pitch); + pitchMatrix[0][2] = -pitchMatrix[2][0]; + + // Rotation about the z axis + memset(yawMatrix, 0, sizeof(yawMatrix)); + + yawMatrix[0][0] = cos(yaw); + yawMatrix[1][1] = yawMatrix[0][0]; + yawMatrix[0][1] = sin(yaw); + yawMatrix[1][0] = -yawMatrix[0][1]; + yawMatrix[2][2] = 1; + + Matrix3dMultByMartrix3d(pitchMatrix, yawMatrix, pitchYawMatrix); + + } +#endif + + Matrix3dMultByVec3d(pitchYawMatrix, up_d, rotatedUp); + +#ifndef NDEBUG + { + vec3d_t xaxis = { 1, 0, 0 }; + double temp; + +#if 0 + vec3d_t rotatedDir; + double dot3, dot4; + + Matrix3dMultByVec3d(pitchYawMatrix, dir_d, rotatedDir); + + dot3 = Vec3dDotProduct(rotatedDir, xaxis); + + dot3 = acos(dot3); + dot3 *= RAD_TO_ANGLE; + + dot4 = Vec3dDotProduct(dir_d, xaxis); + + dot4 = acos(dot4); + dot4 *= RAD_TO_ANGLE; +#endif + + dot2 = Vec3dDotProduct(rotatedUp, xaxis); + + dot1 = acos(dot1); + dot2 = acos(dot2); + temp = (dot2-dot1)*RAD_TO_ANGLE; + +#if 0 + assert(fabs(temp)/90.0 <= 0.1); // greater than 10% error created by rotation of + // up vector into world coordiantes +#else + temp = fabs(temp); // 0.1 for pelf, 0.024 for beetle +#endif + dot1 *= RAD_TO_ANGLE; + dot2 *= RAD_TO_ANGLE; + } +#endif + + rotatedUp[0] = 0; + + Vec3dNormalize(rotatedUp); + + roll = -(atan2(rotatedUp[2], rotatedUp[1])-ANGLE_90); + + memset(rollMatrix, 0, sizeof(rollMatrix)); + + // Rotation about the local x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = cos(roll); + rollMatrix[2][2] = rollMatrix[1][1]; + rollMatrix[1][2] = sin(roll); + rollMatrix[2][1] = -rollMatrix[1][2]; + + Matrix3dMultByMartrix3d(rollMatrix, pitchYawMatrix, fromLocal); + + // FIXME!!!!!!! + // this is wrong, roll needs to rotate about the new local axis + // I think the pitch yaw matix is still correct though + if(toLocal) + { + roll *= -1; + +#if 0 + + memset(rollMatrix, 0, sizeof(rollMatrix)); + +#if 1 + // Rotation about the x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = cos(roll); + rollMatrix[2][2] = rollMatrix[1][1]; + rollMatrix[1][2] = sin(roll); + rollMatrix[2][1] = -rollMatrix[1][2]; +#else + // Rotation about the local x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = 1; + rollMatrix[2][2] = 1; +#endif + +#endif + +#if 0 // not sure what's wrong with this! + r = 1-direction[0]; + s = sin(acos(direction[0])); + + // matrix from direction vector + pitchYawMatrix[0][0] = direction[0]; + pitchYawMatrix[1][0] = -direction[1]*s; + pitchYawMatrix[2][0] = -direction[2]*s; + pitchYawMatrix[0][1] = -pitchYawMatrix[1][0]; + pitchYawMatrix[1][1] = direction[2]*direction[2]*r+direction[0]; + pitchYawMatrix[2][1] = -direction[1]*direction[2]*r; + pitchYawMatrix[0][2] = direction[2]*s; + pitchYawMatrix[1][2] = pitchYawMatrix[2][1]; + pitchYawMatrix[2][2] = direction[1]*direction[1]*r+direction[0]; +#else + { + double yaw, pitch; + matrix3d_t pitchMatrix, yawMatrix; + + yaw = -atan2(dir_d[1], dir_d[0]); + pitch = -asin(dir_d[2]); + + // Rotation about the y axis + memset(pitchMatrix, 0, sizeof(pitchMatrix)); + + pitchMatrix[0][0] = cos(pitch); + pitchMatrix[2][2] = pitchMatrix[0][0]; + pitchMatrix[1][1] = 1; + pitchMatrix[2][0] = sin(pitch); + pitchMatrix[0][2] = -pitchMatrix[2][0]; + + // Rotation about the z axis + memset(yawMatrix, 0, sizeof(yawMatrix)); + + yawMatrix[0][0] = cos(yaw); + yawMatrix[1][1] = yawMatrix[0][0]; + yawMatrix[0][1] = sin(yaw); + yawMatrix[1][0] = -yawMatrix[0][1]; + yawMatrix[2][2] = 1; + +// Matrix3dMultByMartrix3d(yawMatrix, pitchMatrix, pitchYawMatrix); + Matrix3dMultByMartrix3d(yawMatrix, pitchMatrix, toLocal); + } +#endif + +// Matrix3dMultByMartrix3d(pitchYawMatrix, rollMatrix, toLocal); + } + + return roll; +} + +float CMatrix::Matricies3FromDirAndUp(vec3a_t direction, vec3a_t up, matrix3_t fromLocal, matrix3_t toLocal) +{ + matrix3_t pitchYawMatrix; + matrix3_t rollMatrix; + float roll; + vec3a_t rotatedUp, up_d; + vec3a_t dir_d; + +#ifndef NDEBUG + float dot1, dot2; + +#endif + + dir_d[0] = direction[0]; + dir_d[1] = direction[1]; + dir_d[2] = direction[2]; + + up_d[0] = up[0]; + up_d[1] = up[1]; + up_d[2] = up[2]; + +#ifndef NDEBUG + dot1 = Vec3DotProduct(up_d, dir_d); +#endif + +#if 0 // not sure what's wrong with this + + // need to check for direction == {x, 0, 0} + // ot maybe not. Looks like the math will work out to be the I or -I, + // which seems right; haven't actually seen any problems with it yet. . . + + r = 1-dir_d[0]; + s = sin(-acos(dir_d[0])); + + // matrix from dir_d vector + pitchYawMatrix[0][0] = dir_d[0]; + pitchYawMatrix[1][0] = -dir_d[1]*s; + pitchYawMatrix[2][0] = -dir_d[2]*s; + pitchYawMatrix[0][1] = -pitchYawMatrix[1][0]; + pitchYawMatrix[1][1] = dir_d[2]*dir_d[2]*r+dir_d[0]; + pitchYawMatrix[2][1] = -dir_d[1]*dir_d[2]*r; + pitchYawMatrix[0][2] = dir_d[2]*s; + pitchYawMatrix[1][2] = pitchYawMatrix[2][1]; + pitchYawMatrix[2][2] = dir_d[1]*dir_d[1]*r+dir_d[0]; +#else + { + float yaw, pitch; + matrix3_t pitchMatrix, yawMatrix; + + yaw = atan2(dir_d[1], dir_d[0]); + pitch = asin(dir_d[2]); + + // Rotation about the y axis + memset(pitchMatrix, 0, sizeof(pitchMatrix)); + + pitchMatrix[0][0] = cos(pitch); + pitchMatrix[2][2] = pitchMatrix[0][0]; + pitchMatrix[1][1] = 1; + pitchMatrix[2][0] = sin(pitch); + pitchMatrix[0][2] = -pitchMatrix[2][0]; + + // Rotation about the z axis + memset(yawMatrix, 0, sizeof(yawMatrix)); + + yawMatrix[0][0] = cos(yaw); + yawMatrix[1][1] = yawMatrix[0][0]; + yawMatrix[0][1] = sin(yaw); + yawMatrix[1][0] = -yawMatrix[0][1]; + yawMatrix[2][2] = 1; + + Matrix3MultByMartrix3(pitchMatrix, yawMatrix, pitchYawMatrix); + + } +#endif + + Matrix3MultByVec3(pitchYawMatrix, up_d, rotatedUp); + +#ifndef NDEBUG + { + vec3a_t xaxis = { 1, 0, 0 }; + float temp; + +#if 0 + vec3a_t rotatedDir; + float dot3, dot4; + + Matrix3MultByVec3(pitchYawMatrix, dir_d, rotatedDir); + + dot3 = Vec3DotProduct(rotatedDir, xaxis); + + dot3 = acos(dot3); + dot3 *= RAD_TO_ANGLE; + + dot4 = Vec3DotProduct(dir_d, xaxis); + + dot4 = acos(dot4); + dot4 *= RAD_TO_ANGLE; +#endif + + dot2 = Vec3DotProduct(rotatedUp, xaxis); + + dot1 = acos(dot1); + dot2 = acos(dot2); + temp = (dot2-dot1)*RAD_TO_ANGLE; + +#if 0 + assert(fabs(temp)/90.0 <= 0.1); // greater than 10% error created by rotation of + // up vector into world coordiantes +#else + temp = fabs(temp); // 0.1 for pelf, 0.024 for beetle +#endif + dot1 *= RAD_TO_ANGLE; + dot2 *= RAD_TO_ANGLE; + } +#endif + + rotatedUp[0] = 0; + + Vec3Normalize(rotatedUp); + + roll = -(atan2(rotatedUp[2], rotatedUp[1])-ANGLE_90); + + memset(rollMatrix, 0, sizeof(rollMatrix)); + + // Rotation about the local x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = cos(roll); + rollMatrix[2][2] = rollMatrix[1][1]; + rollMatrix[1][2] = sin(roll); + rollMatrix[2][1] = -rollMatrix[1][2]; + + Matrix3MultByMartrix3(rollMatrix, pitchYawMatrix, fromLocal); + + // FIXME!!!!!!! + // this is wrong, roll needs to rotate about the new local axis + // I think the pitch yaw matix is still correct though + if(toLocal) + { + roll *= -1; + +#if 0 + + memset(rollMatrix, 0, sizeof(rollMatrix)); + +#if 1 + // Rotation about the x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = cos(roll); + rollMatrix[2][2] = rollMatrix[1][1]; + rollMatrix[1][2] = sin(roll); + rollMatrix[2][1] = -rollMatrix[1][2]; +#else + // Rotation about the local x axis + rollMatrix[0][0] = 1; + rollMatrix[1][1] = 1; + rollMatrix[2][2] = 1; +#endif + +#endif + +#if 0 // not sure what's wrong with this! + r = 1-direction[0]; + s = sin(acos(direction[0])); + + // matrix from direction vector + pitchYawMatrix[0][0] = direction[0]; + pitchYawMatrix[1][0] = -direction[1]*s; + pitchYawMatrix[2][0] = -direction[2]*s; + pitchYawMatrix[0][1] = -pitchYawMatrix[1][0]; + pitchYawMatrix[1][1] = direction[2]*direction[2]*r+direction[0]; + pitchYawMatrix[2][1] = -direction[1]*direction[2]*r; + pitchYawMatrix[0][2] = direction[2]*s; + pitchYawMatrix[1][2] = pitchYawMatrix[2][1]; + pitchYawMatrix[2][2] = direction[1]*direction[1]*r+direction[0]; +#else + { + float yaw, pitch; + matrix3_t pitchMatrix, yawMatrix; + + yaw = -atan2(dir_d[1], dir_d[0]); + pitch = -asin(dir_d[2]); + + // Rotation about the y axis + memset(pitchMatrix, 0, sizeof(pitchMatrix)); + + pitchMatrix[0][0] = cos(pitch); + pitchMatrix[2][2] = pitchMatrix[0][0]; + pitchMatrix[1][1] = 1; + pitchMatrix[2][0] = sin(pitch); + pitchMatrix[0][2] = -pitchMatrix[2][0]; + + // Rotation about the z axis + memset(yawMatrix, 0, sizeof(yawMatrix)); + + yawMatrix[0][0] = cos(yaw); + yawMatrix[1][1] = yawMatrix[0][0]; + yawMatrix[0][1] = sin(yaw); + yawMatrix[1][0] = -yawMatrix[0][1]; + yawMatrix[2][2] = 1; + + //Matrix3dMultByMartrix3d(yawMatrix, pitchMatrix, pitchYawMatrix); + Matrix3MultByMartrix3(yawMatrix, pitchMatrix, toLocal); + } +#endif + + //Matrix3dMultByMartrix3d(pitchYawMatrix, rollMatrix, toLocal); + } + + return roll; +} + +#pragma optimize("p", off) + +void CMatrix::RotatePointAboutLocalOrigin(matrix3_t rotation, vec3a_t origin, vec3a_t point) +{ + vec3a_t temp; + + point[0] -= origin[0]; + point[1] -= origin[1]; + point[2] -= origin[2]; + + Matrix3MultByVec3(rotation, point, temp); + + point[0] = temp[0] + origin[0]; + point[1] = temp[1] + origin[1]; + point[2] = temp[2] + origin[2]; +} + +void CMatrix::RotatePointAboutLocalOrigin_d(matrix3d_t rotation, vec3a_t origin, vec3a_t point) +{ + vec3a_t temp; + + point[0] -= origin[0]; + point[1] -= origin[1]; + point[2] -= origin[2]; + + Matrix3dMultByVec3(rotation, point, &temp); + + point[0] = temp[0] + origin[0]; + point[1] = temp[1] + origin[1]; + point[2] = temp[2] + origin[2]; +} diff --git a/Toolkit/Programming/Tools/qMView/Matrix.h b/Toolkit/Programming/Tools/qMView/Matrix.h new file mode 100644 index 0000000..ae18ac1 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Matrix.h @@ -0,0 +1,24 @@ +typedef float vec3a_t[3]; +typedef double vec3d_t[3]; +typedef float matrix3_t[3][3]; +typedef float matrix3d_t[3][3]; + +class CMatrix +{ +public: + + static void Matrix3dMultByVec3(matrix3d_t A, vec3a_t B, vec3a_t *C); + static void Matrix3MultByMartrix3(matrix3_t A, matrix3_t B, matrix3_t C); + static void Matrix3MultByVec3(matrix3_t A, vec3a_t B, vec3a_t C); + static void Matrix3FromAngles(vec3a_t angles, matrix3_t rotationMatrix); + static void Matrixs3FromDirAndUp(vec3a_t direction, vec3a_t up, matrix3_t toLocal, matrix3_t fromLocal); + static void RotatePointAboutLocalOrigin(matrix3_t rotation, vec3a_t origin, vec3a_t point); + + static void Matrix3dMultByMartrix3d(matrix3d_t A, matrix3d_t B, matrix3d_t C); + static void Matrix3dMultByVec3d(matrix3d_t A, vec3d_t B, vec3d_t C); + static void Matrix3dFromAngles(vec3a_t angles, matrix3d_t rotationMatrix); + static double Matricies3dFromDirAndUp(vec3a_t direction, vec3a_t up, matrix3_t toWorld, matrix3_t partialToLocal); + static void RotatePointAboutLocalOrigin_d(matrix3d_t rotation, vec3a_t origin, vec3a_t point); + + static float Matricies3FromDirAndUp(vec3a_t direction, vec3a_t up, matrix3_t fromLocal, matrix3_t toLocal); +}; diff --git a/Toolkit/Programming/Tools/qMView/Mdl.h b/Toolkit/Programming/Tools/qMView/Mdl.h new file mode 100644 index 0000000..62c17b0 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Mdl.h @@ -0,0 +1,90 @@ + +#ifndef __MDL_H__ +#define __MDL_H__ + +typedef struct +{ + long id; + long version; + vec3_t scale; + vec3_t origin; + scalar_t radius; + vec3_t eye; + long numskins ; + long skinwidth; + + long skinheight; + + long numverts; + long numtris; + long numframes; + long sync; + long flags; + float size; +} mdlheader_t; + + +typedef struct +{ + long type; + long numgroupskins; + float *interval; + u_char **skin; +} skin_t; + + +typedef struct +{ + long onseam; + long s; + + long t; + +} stvert_t; + + +typedef struct +{ + long facesfront; + long vertices[3]; + +} itriangle_t; + + +typedef struct +{ + u_char x; + u_char y; + u_char z; + u_char lightnormalindex; +} trivertx_t; + + +typedef struct +{ + trivertx_t min; + trivertx_t max; + char name[16]; +} frameinfo_t; + +typedef struct +{ + vec3_t scale; + vec3_t origin; + char name[16]; + trivertx_t verts[1]; +} frameinfo2_t; + + +typedef struct +{ + long type; + long numgroupframes; + trivertx_t groupmin; + trivertx_t groupmax; + frameinfo_t *info; + float *interval; + trivertx_t **data; +} frame_t; + +#endif diff --git a/Toolkit/Programming/Tools/qMView/Model.cpp b/Toolkit/Programming/Tools/qMView/Model.cpp new file mode 100644 index 0000000..c871faf --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Model.cpp @@ -0,0 +1,1640 @@ +// Model.cpp + +#include "stdafx.h" +#include "ddutil.h" +#include "resource.h" +#include "Matrix.h" +#include "Model.h" +#include "FlexModel.h" +#include "QuakeModel.h" +#include "Quake2Model.h" +#include "FrameManager2.h" + +extern pal_t qpal[]; +extern pal_t h2pal[]; + +// +// CModel +// + +CModel::CModel() +{ +} + +CModel::~CModel() +{ +} + +void CModel::Init() +{ + m_skin_head = NULL; + m_curSkin = NULL; + m_defaultSkin = 0; + + m_framesize = 0; + m_curFrame = 0; + m_filename = NULL; + m_curscale = -150; + m_playing = false; + m_num_glcmds = 0; + m_glcmds = NULL; + m_vertPath = NULL; + m_num_frames = 0; + m_frames = NULL; + m_ident = 0; + m_version = 0; + m_num_skins = 0; + m_pingPong = false; + m_curGroup = -1; + m_num_st = 0; + m_stverts = NULL; + m_num_tris = 0; + m_tris = NULL; + m_num_xyz = 0; + m_group = -1; + m_frameTick = 0; + m_curstep = 0; + m_pcurframe = 0; + m_nUseTicker = true; + m_nTickerDelay = 100; + m_playMode = ANIM_FORWARD; + m_usePunch = false; + // used by frame tree ctrl + m_numGroups = 0; + m_treeInfo = NULL; + m_frameSels.frames = NULL; + m_frameSels.numFrames = 0; + m_frameSels.info = 0; + m_genPropPage = NULL; +} + +void CModel::SetPlayMode(int playmode) +{ + m_playMode = playmode; +} + +int CModel::GetPlayMode() +{ + return m_playMode; +} + +void CModel::SetTimerData(long delay, bool useTimer) +{ + m_nUseTicker = useTimer; + m_nTickerDelay = delay; +} + +void CModel::GetTimerData(long* delay, bool* useTimer) +{ + *delay = m_nTickerDelay; + *useTimer = m_nUseTicker; +} + +CBitmap* CModel::GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC, int skinnum, int& width, int& height) +{ + width = m_curSkin->GetWidth(d3drm, pDC); + height = m_curSkin->GetHeight(d3drm, pDC); + return m_curSkin->GetBitmap(d3drm, pDC); +} + +void CModel::Delete() +{ + if (m_skin_head != NULL) + { + delete m_skin_head; + m_skin_head = NULL; + } + if (m_frames) + { + free(m_frames); + m_frames = NULL; + } + if (m_tris != NULL) + { + free(m_tris); + m_tris = NULL; + } + if (m_stverts != NULL) + { + free(m_stverts); + m_stverts = NULL; + } + if (m_filename != NULL) + { + free(m_filename); + m_filename = NULL; + } + if (m_glcmds) + { + free(m_glcmds); + m_glcmds = NULL; + } + + if (m_vertPath) + { + delete m_vertPath; + m_vertPath = NULL; + } + // used by frame tree ctrl + if (m_treeInfo != NULL) + { + delete m_treeInfo; + m_treeInfo = NULL; + } + if (m_frameSels.frames != NULL) + { + free (m_frameSels.frames); + m_frameSels.frames = NULL; + m_frameSels.numFrames = 0; + } + delete this; +} + +void CModel::Drag(double delta_x, double delta_y) +{ +} + +void CModel::RenderTexture(LPDIRECT3DRM2 d3drm, CDC* pDC, bool useTexture) +{ + LPDIRECT3DRMMESH mesh = GetMesh(); + if (mesh == NULL) + { + return; + } + if ((useTexture) && (m_curSkin != NULL)) + { + mesh->SetGroupTexture(m_group, m_curSkin->GetTexture(d3drm, pDC)); + } + else + { + mesh->SetGroupTexture(m_group, NULL); + } +} + +HRESULT CModel::SetGroupQuality(D3DRMRENDERQUALITY value) +{ + LPDIRECT3DRMMESH mesh = GetMesh(); + if (mesh == NULL) + { + return -1; + } + return mesh->SetGroupQuality(m_group, value); +} + +D3DRMRENDERQUALITY CModel::GetGroupQuality() +{ + LPDIRECT3DRMMESH mesh = GetMesh(); + if (mesh == NULL) + { + return -1; + } + return mesh->GetGroupQuality(m_group); +} + +void CModel::SetPingPong(bool pingPong) +{ + m_pingPong = pingPong; +} + +void CModel::Snap() +{ +} + +long CModel::GetNumGroups() +{ + return m_numGroups; +} + +long CModel::GetNumNodes() +{ + return 0; +} + +void CModel::DeSelectAll() +{ +} + +void CModel::ChangeVisual(LPDIRECT3DRMFRAME frame, int nodeNum) +{ +} + +int CModel::SelectNode(int nodeNum) +{ + return -1; +} + +HTREEITEM CModel::SelectMesh(LPDIRECT3DRMVISUAL selection) +{ + return NULL; +} + +bool CModel::ValidNode() +{ + return false; +} + +void CModel::SetCurGroup(long group) +{ + m_curGroup = group; +} + +long CModel::GetNumFrames() +{ + return m_num_frames; +} + +LPCTSTR CModel::GetFilename() +{ + return m_filename; +} + +void CModel::SetFilename(LPCTSTR filename) +{ + CString fileName = filename; + while (true) + { + int destChar = fileName.Find("/"); + if (destChar < 0) + { + break; + } + fileName.SetAt(destChar, '\\'); + } + + if (m_filename != NULL) + { + free(m_filename); + } + m_filename = (char*)malloc(fileName.GetLength() + 1); + strcpy(m_filename, fileName); +} + +LPDIRECT3DRMMESH CModel::GetMesh(int i) +{ + return NULL; +} + +void CModel::MakeAllNodesVisible(LPDIRECT3DRMFRAME frame) +{ +} + +bool CModel::ToggleNodeVisibility(int node) +{ + return false; +} + +long CModel::GetNumTris() +{ + return m_num_tris; +} + +double CModel::GetCurScale() +{ + return m_curscale; +} + +void CModel::SetCurScale(double curscale) +{ + m_curscale = curscale; +} + +int CModel::GetTriCount() +{ + return m_num_tris; +} + +int CModel::GetCurFrame() +{ + return m_curFrame; +} + +void CModel::SetCurFrame(int curframe) +{ + m_curFrame = curframe; +} + +void CModel::ResetPlay() +{ + m_playing = !m_playing; +} + +void CModel::SetPlay(bool playing) +{ + m_playing = playing; +} + +bool CModel::Playing() +{ + return m_playing; +} + +CModel* CModel::Create(LPCTSTR extension) +{ + CModel* retval; + if (!stricmp(extension, "md2")) + { + retval = new CQuake2Model(); + } + else if (!stricmp(extension, "fm")) + { + retval = new CFlexModel(); + } + else + { + retval = new CQuakeModel(); + } + retval->Init(); + return retval; +} + +void CModel::SetBackOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); +} + +void CModel::SetFrontOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) ); +} + +void CModel::SetLeftOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1) ); +} + +void CModel::SetRightOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1) ); +} + +void CModel::SetTopOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) ); +} + +void CModel::SetBottomOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); +} + +void CModel::SetInitialOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ +} + +long* CModel::GetCommands() +{ + return m_glcmds; +} + +void CModel::SetPunch(bool usePunch) +{ + m_usePunch = usePunch; +} + +BOOL CModel::ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC) +{ + return false; +} + +void CModel::UpdateForward() +{ + m_curFrame++; + int upperLimit; + int lowerLimit; + if (m_curGroup == -1) + { + upperLimit = m_num_frames - 1; + lowerLimit = 0; + } + else + { + upperLimit = m_treeInfo[m_curGroup].eFrame; + lowerLimit = m_treeInfo[m_curGroup].bFrame; + } + if (m_curFrame > upperLimit) + { + if (m_pingPong) + { + m_curFrame -= 2; + } + else + { + m_curFrame = lowerLimit; + } + } +} + +void CModel::UpdateBackward() +{ + m_curFrame--; + int upperLimit; + int lowerLimit; + if (m_curGroup == -1) + { + upperLimit = m_num_frames - 1; + lowerLimit = 0; + } + else + { + upperLimit = m_treeInfo[m_curGroup].eFrame; + lowerLimit = m_treeInfo[m_curGroup].bFrame; + } + if (m_curFrame < lowerLimit) + { + if (m_pingPong) + { + m_curFrame += 2; + } + else + { + m_curFrame = upperLimit; + } + } +} + +BOOL CModel::UpdateFrame(LPDIRECT3DRM2 d3drm, CDC* pDC, int direction, bool interOn) +{ + if (m_num_frames < 2) return TRUE; + + unsigned long thisTick = GetTickCount(); + + if (m_nUseTicker) + { + if (thisTick < m_frameTick) return TRUE; + } + + m_frameTick = thisTick + FRAME_TICK_INCR; + + if (interOn && m_curstep != 0) + { + return CalcInterpolate(d3drm, pDC, m_curstep, INTERPOLATION_STEPS, 0, direction); + } + else m_curstep = 1; + + if (m_usePunch) + { + if (m_pingPong) + { + if (direction == ANIM_FORWARD) + { + if (m_pcurframe > m_frameSels.numFrames-2) + direction = m_playMode = ANIM_BACKWARD; + } + else if (direction == ANIM_BACKWARD) + { + if (m_pcurframe <= 0) + direction = m_playMode = ANIM_FORWARD; + } + } + + if (direction == ANIM_FORWARD) + { + if (m_pcurframe > m_frameSels.numFrames-2) + m_pcurframe = 0; + else + m_pcurframe++; + + m_curFrame = m_frameSels.frames[m_pcurframe]; + + if (m_curFrame < 0) + { + m_curFrame = 0; + } + } + else if (direction == ANIM_BACKWARD) + { + if (m_pcurframe < 0) + m_pcurframe = m_frameSels.numFrames-1; + else + m_pcurframe--; + + m_curFrame = m_frameSels.frames[m_pcurframe]; + + if (m_curFrame < 0) + { + m_curFrame = 0; + } + } + } + if (!m_usePunch || (m_frameSels.numFrames > 1)) + { + + if (direction == ANIM_FORWARD) + { + UpdateForward(); + } + else + { + UpdateBackward(); + } + } + return ShowFrame(d3drm, pDC); +} + +BOOL CModel::CalcInterpolate(LPDIRECT3DRM2 d3drm, CDC* pDC, int step, int numsteps, int intertype, int direction) +{ + return false; +} + +void CModel::BuildMesh(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene, CDC* pDC) +{ +} + +void CModel::DeleteMeshs(LPDIRECT3DRMFRAME frame) +{ +} + +void CModel::DeleteVisuals(LPDIRECT3DRMFRAME frame) +{ +} + +CSkin* CModel::GetSkin(int i) +{ + return NULL; +} + +CSkin* CModel::GetSkin(LPCTSTR skinname) +{ + CSkin* skin = NULL; + if (m_num_skins > 0) + { + if (m_skin_head == NULL) + { + skin = new CSkin(); + skin->SetFilename(skinname); + m_skin_head = skin; + } + else + { + skin = m_skin_head->Find(skinname); + if (skin == NULL) + { + skin = new CSkin(); + skin->SetFilename(skinname); + m_skin_head->InsertSkin(skin); + } + } + } + return skin; +} + +void CModel::FillMenuWithSkins(CMenu* menu) +{ +} + +void CModel::ChangeSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, int nodenum, int skinnum) +{ +} + +void CModel::AddSkin(LPCTSTR skinname) +{ +} + +void CModel::ReplaceSkin(int i, LPCTSTR skinname) +{ +} + +bool CModel::LoadSkin(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, int skinnum, CDC* pDC) +{ + m_defaultSkin = skinnum; + m_curSkin = GetSkin(skinnum); + return true; +} + +void CModel::CreateJointVisuals(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame) +{ +} + +void CModel::Serialize(CArchive & ar) +{ +} + +// info window support +void CModel::AddJoints(CTreeCtrl* pCTree, HTREEITEM rootJoint) +{ +} + +void CModel::AddNodes(CTreeCtrl* pCTree, HTREEITEM rootNode) +{ +} + +void CModel::LoadSkinInfo(CTreeCtrl* pCTree, HTREEITEM rootSkin) +{ + for (int i = 0; i < m_num_skins; i++) + { + CString name; + name.Format("skin%d", i); + HTREEITEM point = pCTree->InsertItem(name, rootSkin, TVI_LAST); + pCTree->SetItemImage(point, 0, 0); + pCTree->SetItemData(point, i); + } +} + +// frame tree ctrl support + +void CModel::LoadFrameInfo(CTreeCtrl* treeDlg, HTREEITEM rootFrame) +{ +} + +frameStruct* CModel::GetFrameSels() +{ + return &m_frameSels; +} + +void CModel::StripGroupName(char *gname) +{ + int len = strlen(gname); + char newname[16]; + + memset(newname, 0, sizeof(newname)); + + for (int i = 0; i < len; i++) + { + if (isdigit((int)gname[i])) break; + else newname[i] = gname[i]; + } + + strcpy(gname, newname); +} + +int CModel::InGroupList(char *test, CTreeGroup* groupList, int numGroups) +{ + for (int i = 0; i < numGroups; i++) + { + if (!strcmp(test, groupList[i].id)) return i; + } + + strcpy(groupList[numGroups].id, test); + return -1; +} + +CTreeHead* CModel::GetTreeInfo(int i) +{ + if (i == 0) + { + return m_treeInfo; + } + return &m_treeInfo[i]; +} + +// skin texturing support + +//void CModel::TextureChanged() +//{ +//} + +void CModel::SetTransparency(LPDIRECT3DRM2 d3drm, CDC* pDC, bool trans) +{ + if (m_curSkin != NULL) + { + m_curSkin->GetTexture(d3drm, pDC)->SetDecalTransparency(trans); + } +} + +// joint support + +void CModel::ToggleJointOn() +{ +} + +bool CModel::IsJointOn() +{ + return false; +} + +void CModel::GetModelAngles(float* x, float* y, float* z) +{ + *x = 0; + *y = 0; + *z = 0; +} + +void CModel::SetModelAngles(float x, float y, float z) +{ +} + +void CModel::GetConstraintAngleMaxs(float* x, float* y, float* z) +{ + *x = 0; + *y = 0; + *z = 0; +} + +void CModel::GetConstraintAngleMins(float* x, float* y, float* z) +{ + *x = 0; + *y = 0; + *z = 0; +} + +void CModel::SetConstraintAngleMaxs(float x, float y, float z) +{ +} + +void CModel::SetConstraintAngleMins(float x, float y, float z) +{ +} + +void CModel::SetCurJoint(long joint) +{ +} + +long CModel::GetCurJoint() +{ + return -1; +} + +// property page support + +void CModel::AddPropPages(CPropertySheet* propSheet) +{ + m_genPropPage = new CGeneralPropPage(); + m_genPropPage->m_frames.Format("%d", m_num_frames); + m_genPropPage->m_glcommands.Format("%d", m_num_glcmds); + m_genPropPage->m_groups.Format("%d", m_numGroups); + m_genPropPage->m_skinheight.Format("%d", m_skinheight); + m_genPropPage->m_skins.Format("%d", m_num_skins); + m_genPropPage->m_skinwidth.Format("%d", m_skinwidth); + m_genPropPage->m_tris.Format("%d", m_num_tris); + m_genPropPage->m_verts.Format("%d", m_num_xyz); + m_genPropPage->m_stverts.Format("%d", m_num_st); + propSheet->AddPage(m_genPropPage); +} + +void CModel::UpdateFromPropPages(CPropertySheet* propSheet) +{ +} + +void CModel::RemovePropPages(CPropertySheet* propSheet) +{ + delete m_genPropPage; + m_genPropPage = NULL; +} + +///////////////////////////////////////////////////////////////////////////// +// CGeneralPropPage property page + +IMPLEMENT_DYNCREATE(CGeneralPropPage, CPropertyPage) + +CGeneralPropPage::CGeneralPropPage() : CPropertyPage(CGeneralPropPage::IDD) +{ + //{{AFX_DATA_INIT(CGeneralPropPage) + m_frames = _T(""); + m_glcommands = _T(""); + m_groups = _T(""); + m_skinheight = _T(""); + m_skins = _T(""); + m_skinwidth = _T(""); + m_tris = _T(""); + m_stverts = _T(""); + m_verts = _T(""); + //}}AFX_DATA_INIT +} + +CGeneralPropPage::~CGeneralPropPage() +{ +} + +void CGeneralPropPage::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CGeneralPropPage) + DDX_Text(pDX, IDC_PPGEN_FRAMES, m_frames); + DDX_Text(pDX, IDC_PPGEN_GLCOMMANDS, m_glcommands); + DDX_Text(pDX, IDC_PPGEN_GROUPS, m_groups); + DDX_Text(pDX, IDC_PPGEN_SKINHEIGHT, m_skinheight); + DDX_Text(pDX, IDC_PPGEN_SKINS, m_skins); + DDX_Text(pDX, IDC_PPGEN_SKINWIDTH, m_skinwidth); + DDX_Text(pDX, IDC_PPGEN_TRIS, m_tris); + DDX_Text(pDX, IDC_PPGEN_STVERTS, m_stverts); + DDX_Text(pDX, IDC_PPGEN_VERTS, m_verts); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CGeneralPropPage, CPropertyPage) + //{{AFX_MSG_MAP(CGeneralPropPage) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGeneralPropPage message handlers + + +// +// CSkin +// + +CRGB16* CSkin::s_rgb16 = NULL; + +CSkin::CSkin() +{ + m_parent = NULL; + m_left = NULL; + m_right = NULL; + m_filename = NULL; + m_bitmap = NULL; + m_texture = NULL; + m_bitDepth = 0; + m_skinWidth = 0; + m_skinHeight = 0; + t_skinBits = NULL; + t_textureBits = NULL; + t_lpDDSkin = NULL; + t_pitch = 0; +} + +CSkin::~CSkin() +{ + if (t_skinBits != NULL) + { + free(t_skinBits); + t_skinBits = NULL; + } + if (m_left != NULL) + { + delete m_left; + m_left = NULL; + } + if (m_right != NULL) + { + delete m_right; + m_right = NULL; + } + m_parent = NULL; + if (m_filename != NULL) + { + free (m_filename); + m_filename = NULL; + } + if (m_bitmap != NULL) + { + delete m_bitmap; + m_bitmap = NULL; + } +// if (m_texture != NULL) +// { +// m_texture->Release(); +// m_texture = NULL; +// } + if (s_rgb16 != NULL) + { + delete s_rgb16; + s_rgb16 = NULL; + } +} + +CSkin* CSkin::GetNext() +{ + CSkin* retval; + + if (m_left != NULL) + { + retval = m_left; + } + else if (m_right != NULL) + { + retval = m_right; + } + else + { + retval = m_parent; + CSkin* curSkin = this; + while (retval != NULL) + { + if ((retval->m_right != NULL) && (retval->m_right != curSkin)) + { + break; + } + curSkin = retval; + retval = retval->m_parent; + } + } + if (retval != NULL) + { + while (retval->m_left != NULL) + { + retval = retval->m_left; + } + } + return retval; +} + +CSkin* CSkin::Find(LPCTSTR filename) +{ + CSkin* curSkin = this; + while (curSkin != NULL) + { + int result = stricmp(filename, curSkin->m_filename); + if (result == 0) + { + break; + } + if (result < 0) + { + curSkin = curSkin->m_left; + } + else + { + curSkin = curSkin->m_right; + } + } + return curSkin; +} + +CSkin* CSkin::InsertSkin(CSkin* newSkin) +{ + CSkin* parent = this; + while(parent != NULL) + { + int result = stricmp(newSkin->m_filename, parent->m_filename); + if (result == 0) + { + return parent; + } + if (result < 0) + { + if (parent->m_left == NULL) + { + parent->m_left = newSkin; + newSkin->m_parent = parent; + return NULL; + } + parent = parent->m_left; + } + else + { + if (parent->m_right == NULL) + { + parent->m_right = newSkin; + newSkin->m_parent = parent; + return NULL; + } + parent = parent->m_right; + } + } + return this; // impossible for properly constructed tree +} + +void CSkin::SetFilename(LPCTSTR filename) +{ + CFile* file = new CFile(filename, CFile::modeRead); + if (file == NULL) + { + CString message; + message.Format("%s not found", filename); + AfxMessageBox(message); + } + delete file; + + if (m_filename != NULL) + { + free(m_filename); + m_filename = NULL; + } + m_filename = (char*)malloc(strlen(filename) + 1); + strcpy(m_filename, filename); +} + +LPCTSTR CSkin::GetFilename() +{ + return m_filename; +} + +int CSkin::GetWidth(LPDIRECT3DRM2 d3drm, CDC* pDC) +{ + Cache(d3drm, pDC); + return m_skinWidth; +} + +int CSkin::GetHeight(LPDIRECT3DRM2 d3drm, CDC* pDC) +{ + Cache(d3drm, pDC); + return m_skinHeight; +} + +LPDIRECT3DRMTEXTURE CSkin::GetTexture(LPDIRECT3DRM2 d3drm, CDC* pDC) +{ + Cache(d3drm, pDC); + return m_texture; +} + +CBitmap* CSkin::GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC) +{ + Cache(d3drm, pDC); + return m_bitmap; +} + +void CSkin::Cache(LPDIRECT3DRM2 d3drm, CDC* pDC) +{ + if (m_bitmap != NULL) + { + return; + } + if ((d3drm == NULL) || (pDC == NULL)) + { + AfxMessageBox("Fatal error trying to cache skin"); + } + int bits = pDC->GetDeviceCaps(BITSPIXEL); + m_bitDepth = bits; + if (bits == 16) + { + CreateRGB16(pDC); + } + + CString ext; + CString path = m_filename; + int loc = path.ReverseFind('.'); + if (loc != -1) + { + ext = path.Right(path.GetLength() - loc - 1); + } + CFile* file = new CFile(m_filename, CFile::modeRead); + if (file == NULL) + { + CString message; + message.Format("%s not found", m_filename); + AfxMessageBox(message); + return; + } + if (!stricmp(ext, "pcx") ) + { + if (!CacheFromPCX(file)) + { + AfxMessageBox("Could not load PCX"); + } + } + else if (!stricmp(ext, "m8")) + { + if (!CacheFromM8(file)) + { + AfxMessageBox("Could not load M8"); + } + } + else if (!stricmp(ext, "m32")) + { + if (!CacheFromM32(file)) + { + AfxMessageBox("Could not load M32"); + } + } + else if (!stricmp(ext, "tga")) + { + if (!CacheFromTGA(file)) + { + AfxMessageBox("Could not load Targa"); + } + } + else + { + AfxMessageBox("Could not load skin"); + delete file; + return; + } + delete file; + + if ((m_bitmap != NULL) && (t_skinBits != NULL)) + { + m_bitmap->SetBitmapBits(m_skinWidth * m_skinHeight * m_bitDepth / 8, t_skinBits); + free(t_skinBits); + t_skinBits = NULL; + } + + if (t_lpDDSkin != NULL) + { + t_lpDDSkin->Unlock(NULL); + d3drm->CreateTextureFromSurface(t_lpDDSkin, &m_texture); + t_lpDDSkin->Release(); + t_lpDDSkin = NULL; + } +} + +void CSkin::CreateRGB16(CDC* pDC) +{ + if (s_rgb16 != NULL) + { + return; + } + DDSURFACEDESC ddsd; + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + IDirectDrawSurface* surface = 0; + + // Create the primary surface. + HRESULT hr = CDDHelper::lpDD->CreateSurface(&ddsd, &surface, 0); + s_rgb16 = CDDHelper::CreateRGB16(surface); + + surface->Release(); +} + +bool CSkin::CacheFromPCX(CFile* file) +{ + file->Seek(8, CFile::begin); + short width; + short height; + file->Read(&width, sizeof(width)); + file->Read(&height, sizeof(height)); + width++; + height++; + if (!SetBitmap(width, height)) + { + return false; + } + + file->Seek(file->GetLength() - 768, CFile::begin); + pal_t palette[256]; + file->Read(palette, sizeof(pal_t) * 256); + + file->Seek(128, CFile::begin); + byte* buf = (byte*)malloc(width); + for (int y = 0; y < height; y++) + { + int x = 0; + while (x < width) + { + byte curByte; + file->Read(&curByte, 1); + if ((curByte & 0xC0) == 0xC0) + { + int runLen = curByte & 0x3F; + file->Read(&curByte, 1); + for(; (runLen > 0) && (x < width); runLen--, x++) + { + buf[x] = curByte; + } + } + else + { + buf[x] = curByte; + x++; + } + } + SetBitmapRow(y, buf, palette); + } + free(buf); + return true; +} + +bool CSkin::CacheFromM8(CFile* file) +{ + int ver; + file->Read(&ver, sizeof(ver)); + char name[32]; + file->Read(name, sizeof(name)); + + unsigned width[MIPLEVELS]; + unsigned height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; + int arraySize = sizeof(unsigned) * MIPLEVELS; + if (ver <= 1) + { + arraySize /= 2; + } + file->Read(width, arraySize); + file->Read(height, arraySize); + file->Read(offsets, arraySize); + + char animname[32]; + pal_t palette[256]; + int flags; + int contents; + int value; + file->Read(animname, sizeof(animname)); + file->Read(palette, sizeof(palette)); + file->Read(&flags, sizeof(flags)); + file->Read(&contents, sizeof(contents)); + file->Read(&value, sizeof(value)); + + if (!SetBitmap(width[0], height[0])) + { + return false; + } + + file->Seek(offsets[0], CFile::begin); + byte* buf = (byte*)malloc(width[0]); + for (int y = 0; y < (int)height[0]; y++) + { + file->Read(buf, width[0]); + SetBitmapRow(y, buf, palette); + } + free(buf); + return true; +} + +bool CSkin::CacheFromM32(CFile* file) +{ + int ver; + file->Read(&ver, sizeof(ver)); + char name[128]; + file->Read(name, sizeof(name)); + + if (ver >= 3) + { + char animname[128]; + char altname[128]; + + file->Read(&altname, sizeof(altname)); + file->Read(&animname, sizeof(animname)); + } + + unsigned width[MIPLEVELS]; + unsigned height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; + int arraySize = sizeof(unsigned) * MIPLEVELS; + file->Read(width, arraySize); + file->Read(height, arraySize); + file->Read(offsets, arraySize); + + int flags; + int contents; + int value; + + if (ver < 3) + { + char animname[32]; + + file->Read(animname, sizeof(animname)); + } + + file->Read(&flags, sizeof(flags)); + file->Read(&contents, sizeof(contents)); + file->Read(&value, sizeof(value)); + + float scale_x; + float scale_y; + file->Read(&scale_x, sizeof(scale_x)); + file->Read(&scale_y, sizeof(scale_y)); + + if (ver >= 3) + { + int mip_scale; + int unused[20]; + + file->Read(&mip_scale, sizeof(mip_scale)); + file->Read(&unused, sizeof(unused)); + } + + if (!SetBitmap(width[0], height[0])) + { + return false; + } + + file->Seek(offsets[0], CFile::begin); + long* buf = (long*)malloc(width[0] * sizeof(long)); + for (int y = 0; y < (int)height[0]; y++) + { + file->Read(buf, width[0] * 4); + SetBitmapRow(y, buf); + } + free(buf); + return true; +} + +bool CSkin::CacheFromTGA(CFile* file) +{ + // read header + byte IDLength; + file->Read(&IDLength, sizeof(IDLength)); + byte ColorMapType; + file->Read(&ColorMapType, sizeof(ColorMapType)); + byte ImageType; + file->Read(&ImageType, sizeof(ImageType)); + short CMapStart; + file->Read(&CMapStart, sizeof(CMapStart)); + short CMapLength; + file->Read(&CMapLength, sizeof(CMapLength)); + byte CMapDepth; + file->Read(&CMapDepth, sizeof(CMapDepth)); + short XOffset; + file->Read(&XOffset, sizeof(XOffset)); + short YOffset; + file->Read(&YOffset, sizeof(YOffset)); + short width; + file->Read(&width, sizeof(width)); + short height; + file->Read(&height, sizeof(height)); + byte PixelDepth; + file->Read(&PixelDepth, sizeof(PixelDepth)); + byte ImageDescriptor; + file->Read(&ImageDescriptor, sizeof(ImageDescriptor)); + if ((ImageType != 2) && (ImageType != 10)) + { + AfxMessageBox ("Only type 2 and 10 targa RGB images supported"); + return false; + } + if (ColorMapType || ((PixelDepth != 32) && (PixelDepth != 24))) + { + AfxMessageBox ("Only 32 or 24 bit images supported (no colormaps)"); + return false; + } + if (!SetBitmap(width, height)) + { + return false; + } + + char* id = (char*)malloc(IDLength + 1); + id[IDLength] = '\0'; + if (IDLength > 0) + { + file->Read(id, IDLength); + } + byte* buf = (byte*)malloc(width * sizeof(long)); + + if (ImageType == 2) + { + int srcRow; + switch (PixelDepth) + { + case 24: + srcRow = 3 * width; + break; + case 32: + srcRow = 4 * width; + break; + } + byte* src = (byte*)malloc(srcRow); + for(int y = 0; y < height; y++) + { + file->Read(src, srcRow); + byte* srcPtr = src; + byte* destPtr = buf; + for(int x = 0; x < width; x++) + { + switch (PixelDepth) + { + case 24: + *destPtr++ = srcPtr[2]; + *destPtr++ = srcPtr[1]; + *destPtr++ = srcPtr[0]; + *destPtr++ = 255; + srcPtr += 3; + break; + case 32: + *destPtr++ = srcPtr[2]; + *destPtr++ = srcPtr[1]; + *destPtr++ = srcPtr[0]; + *destPtr++ = srcPtr[3]; + srcPtr += 4; + break; + } + } + SetBitmapRow(height - y - 1, (long*)buf); + } + free(src); + } + else if (ImageType == 10) + { + byte packetHeader; + int packetSize = 0; + byte blue = 0; + byte green = 0; + byte red = 0; + byte alpha = 255; + bool readEachByte = true; + for(int y = 0; y < height; y++) + { + byte* destPtr = buf; + for(int x = 0; x < width; ) + { + while(packetSize > 0) + { + if (readEachByte) + { + file->Read(&blue, 1); + file->Read(&green, 1); + file->Read(&red, 1); + if (PixelDepth == 32) + { + file->Read(&alpha, 1); + } + else + { + alpha = 255; + } + } + *destPtr++ = red; + *destPtr++ = green; + *destPtr++ = blue; + *destPtr++ = alpha; + x++; + packetSize--; + if(x == width) + { + break; + } + } + if (x == width) + { + break; + } + file->Read(&packetHeader, 1); + packetSize = 1 + (packetHeader & 0x7f); + readEachByte = !(packetHeader & 0x80); + if (!readEachByte) + { // run-length packet + file->Read(&blue, 1); + file->Read(&green, 1); + file->Read(&red, 1); + if (PixelDepth == 32) + { + file->Read(&alpha, 1); + } + else + { + alpha = 255; + } + } + } + SetBitmapRow(height - y - 1, (long*)buf); + } + } + free(buf); + free(id); + return true; +} + +bool CSkin::SetBitmap(int width, int height) +{ + if (((width != 1024) && (width != 512) && (width != 256) && (width != 128) && + (width != 64) && (width != 32) && (width != 16) && (width != 8)) || + ((height != 1024) && (height != 512) && (height != 256) && (height != 128) && + (height != 64) && (height != 32) && (height != 16) && (height != 8))) + { + AfxMessageBox("Improper skin dimensions"); + return false; + } + // create surface and lockdown buffer + DDSURFACEDESC ddsd; + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + ddsd.dwWidth = width; + ddsd.dwHeight = height; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat); + ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; + ddsd.ddpfPixelFormat.dwRGBBitCount = 32; + ddsd.ddpfPixelFormat.dwRBitMask = 0xff0000; + ddsd.ddpfPixelFormat.dwGBitMask = 0xff00; + ddsd.ddpfPixelFormat.dwBBitMask = 0xff; + ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0; + + if (CDDHelper::lpDD->CreateSurface(&ddsd, &t_lpDDSkin, NULL) != DD_OK) + { + AfxMessageBox("Fail on CreateSurface 1"); + return false; + } + + ddsd.dwSize = sizeof(ddsd); + t_lpDDSkin->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + t_textureBits = (byte*)ddsd.lpSurface; + t_pitch = ddsd.lPitch; + + if (m_bitmap != NULL) + { + delete m_bitmap; + m_bitmap = NULL; + } + if (t_skinBits != NULL) + { + free(t_skinBits); + t_skinBits = NULL; + } + m_skinWidth = width; + m_skinHeight = height; + + // create bitmap and buffer + m_bitmap = new CBitmap(); + m_bitmap->CreateBitmap(width, height, 1, m_bitDepth, NULL); + t_skinBits = (byte*)malloc(width * height * m_bitDepth / 8); + return true; +} + +void CSkin::SetBitmapRow(int row, byte* buf, pal_t* palette) +{ + if (t_skinBits == NULL) + { + return; + } + byte* base = (byte*)(t_skinBits + (row * m_skinWidth * m_bitDepth / 8)); + byte* src = buf; + int x; + switch (m_bitDepth) + { + case 16: + if (s_rgb16 == NULL) + { + return; + } + for (x = 0; x < m_skinWidth; x++) + { + ((short*)base)[x] = (short)(((long)(palette[src[x]].r >> 3) << s_rgb16->Position.rgbRed) | + ((long)(palette[src[x]].g >> 3) << s_rgb16->Position.rgbGreen) | + ((long)(palette[src[x]].b >> 3) << s_rgb16->Position.rgbBlue)); + } + break; + case 24: + for (x = 0; x < m_skinWidth; x++) + { + *base++ = palette[src[x]].b; + *base++ = palette[src[x]].g; + *base++ = palette[src[x]].r; + } + break; + case 32: + for (x = 0; x < m_skinWidth; x++) + { + *base++ = palette[src[x]].b; + *base++ = palette[src[x]].g; + *base++ = palette[src[x]].r; + *base++ = 0; + } + break; + } + + // fill in texture + + src = (byte*)buf; + base = (byte*)(t_textureBits + (row * t_pitch)); + for (x = 0; x < m_skinWidth; x++) + { + base[2] = palette[src[x]].r; + base[1] = palette[src[x]].g; + base[0] = palette[src[x]].b; + base[3] = 0; + base += 4; + } +} + +void CSkin::SetBitmapRow(int row, long* buf) +{ + if (t_skinBits == NULL) + { + return; + } + byte* base = (byte*)(t_skinBits + (row * m_skinWidth * m_bitDepth / 8)); + byte* src = (byte*)buf; + int x; + switch (m_bitDepth) + { + case 16: + if (s_rgb16 == NULL) + { + return; + } + for (x = 0; x < m_skinWidth; x++) + { + ((short*)base)[x] = (short)(((long)(src[0] >> 3) << s_rgb16->Position.rgbRed) | + ((long)(src[1] >> 3) << s_rgb16->Position.rgbGreen) | + ((long)(src[2] >> 3) << s_rgb16->Position.rgbBlue)); + src += 4; + } + break; + case 24: + for (x = 0; x < m_skinWidth; x++) + { + *base++ = src[2]; + *base++ = src[1]; + *base++ = src[0]; + src += 4; + } + break; + case 32: + for (x = 0; x < m_skinWidth; x++) + { + *base++ = src[2]; + *base++ = src[1]; + *base++ = src[0]; + *base++ = src[3]; + src += 4; + } + break; + } + + // fill in texture + + src = (byte*)buf; + base = (byte*)(t_textureBits + (row * t_pitch)); + for (x = 0; x < m_skinWidth; x++) + { + base[2] = *src++; + base[1] = *src++; + base[0] = *src++; + base[3] = *src++; + base += 4; + } +} diff --git a/Toolkit/Programming/Tools/qMView/Model.h b/Toolkit/Programming/Tools/qMView/Model.h new file mode 100644 index 0000000..f3e8496 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Model.h @@ -0,0 +1,438 @@ +// Model.h +#define MIPLEVELS 16 +#define MIP_VERSION 2 +#define INTERPOLATION_STEPS 4 +#define FRAME_TICK_INCR 100 + +#define ANIM_FORWARD 0 +#define ANIM_BACKWARD 1 +#define ANIM_PINGPONG 2 +#define ANIM_PUNCH 3 + +#define PALTYPE_RAW 0 +#define PALTYPE_PCX 1 +#define PALTYPE_JASC 2 +#define PALTYPE_MS 3 +#define PALTYPE_BMP 4 + +#define PAL_QUAKE 0 +#define PAL_QUAKE2 1 +#define PAL_HEXEN2 2 +#define PAL_FROMFILE 3 +#define PAL_NONE 4 + +#define PAL_SIZE 256 + +typedef struct +{ + unsigned char r,g,b; +} paletteRGB_t; + +typedef struct Placement_s +{ + vec_t origin; + vec_t direction; + vec_t up; +} Placement_t; + +typedef struct M_SkeletalJoint_s +{ + int children; // must be the first field + Placement_t model; // relative to the model, used for dynamic software rotation + Placement_t parent; // relative to the parent joint (or model in case of root joint), used for + // inverse kinematics + qboolean inUse; +} M_SkeletalJoint_t; + +typedef struct ArrayedListNode_s +{ + int data; + int next; + int inUse; +} ArrayedListNode_t; + +typedef struct ModelSkeleton_s +{ + M_SkeletalJoint_t rootJoint[8]; + ArrayedListNode_t rootNode[64]; +} ModelSkeleton_t; + +typedef struct +{ + unsigned char r; + unsigned char g; + unsigned char b; +} pal_t; + +typedef struct +{ + int numFrames; + int info; + int* frames; +} frameStruct; + +typedef struct miptex_s +{ + //int version; + char name[32]; + unsigned width[MIPLEVELS/2], height[MIPLEVELS/2]; + unsigned offsets[MIPLEVELS/2]; // four mip maps stored + char animname[32]; // next frame in animation chain + paletteRGB_t palette[PAL_SIZE]; + int flags; + int contents; + int value; +} miptex_t; + +typedef struct miptex_v2_s +{ + //int version; + char name[32]; + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + paletteRGB_t palette[PAL_SIZE]; + int flags; + int contents; + int value; +} miptex_v2_t; + +typedef struct +{ + long facesfront; + long vertices[3]; + +} itriangle_t; + +typedef struct +{ + u_char x; + u_char y; + u_char z; + u_char lightnormalindex; +} trivertx_t; + + +typedef struct +{ + trivertx_t min; + trivertx_t max; + char name[16]; +} frameinfo_t; + +typedef struct +{ + vec3_t scale; + vec3_t origin; + char name[16]; + trivertx_t verts[1]; +} frameinfo2_t; + +typedef struct +{ + int type; + int skin_num; + HTREEITEM pointer; +} skinItem; + +typedef struct +{ + int numskins; + skinItem *skins; +} skinStruct; + +// used for tree control maintenance + +class CTreeGroup +{ +public: + HTREEITEM head; + char id[16]; +}; + +class CTreeHead +{ +public: + int bFrame; + int eFrame; +}; + +///////////////////////////////////////////////////////////////////////////// +// CGeneralPropPage dialog + +class CGeneralPropPage : public CPropertyPage +{ + DECLARE_DYNCREATE(CGeneralPropPage) + +// Construction +public: + CGeneralPropPage(); + ~CGeneralPropPage(); + +// Dialog Data + //{{AFX_DATA(CGeneralPropPage) + enum { IDD = IDD_PP_GENERAL }; + CString m_frames; + CString m_glcommands; + CString m_groups; + CString m_skinheight; + CString m_skins; + CString m_skinwidth; + CString m_tris; + CString m_stverts; + CString m_verts; + //}}AFX_DATA + + +// Overrides + // ClassWizard generate virtual function overrides + //{{AFX_VIRTUAL(CGeneralPropPage) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + // Generated message map functions + //{{AFX_MSG(CGeneralPropPage) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +// +// CSkin +// + +typedef struct +{ + long type; + long numgroupskins; + float *interval; + u_char **skin; +} skin_t; + +class CSkin +{ +public: + CSkin(); + ~CSkin(); + + CSkin* GetNext(); + CSkin* InsertSkin(CSkin* newSkin); + CSkin* Find(LPCTSTR filename); + + void SetFilename(LPCTSTR filename); + LPCTSTR GetFilename(); + int GetWidth(LPDIRECT3DRM2 d3drm, CDC* pDC); + int GetHeight(LPDIRECT3DRM2 d3drm, CDC* pDC); + LPDIRECT3DRMTEXTURE GetTexture(LPDIRECT3DRM2 d3drm, CDC* pDC); + CBitmap* GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC); + + +protected: + CSkin* m_parent; + CSkin* m_left; + CSkin* m_right; + + char* m_filename; + CBitmap* m_bitmap; + LPDIRECT3DRMTEXTURE2 m_texture; + int m_bitDepth; + int m_skinWidth; + int m_skinHeight; + + LPDIRECTDRAWSURFACE t_lpDDSkin; + int t_pitch; + byte* t_skinBits; // temporary during build of bitmap + byte* t_textureBits; // temporary during build of texture + + static CRGB16* s_rgb16; + + void Cache(LPDIRECT3DRM2 d3drm, CDC* pDC); + void CreateRGB16(CDC* pDC); + + bool CacheFromPCX(CFile* file); + bool CacheFromM8(CFile* file); + bool CacheFromM32(CFile* file); + bool CacheFromTGA(CFile* file); + + bool SetBitmap(int width, int height); + void SetBitmapRow(int row, byte* buf, pal_t* palette); + void SetBitmapRow(int row, long* buf); +}; + +// +// CModel +// + +class CModel +{ +public: + virtual void Serialize(CArchive& ar); + CModel(); + ~CModel(); + + virtual CBitmap* GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC, int skinnum, int& width, int& height); + virtual CSkin* GetSkin(LPCTSTR skinname); + virtual CSkin* GetSkin(int i); + virtual void ReplaceSkin(int i, LPCTSTR skinname); + virtual void AddSkin(LPCTSTR skinname); + virtual void FillMenuWithSkins(CMenu* menu); + virtual void ChangeSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, int nodenum, int skinnum); + + void SetPunch(bool usePunch); + int GetPlayMode(); + void SetPlayMode(int playmode); + void SetTimerData(long delay, bool useTimer); + void GetTimerData(long* delay, bool* useTimer); + virtual void RenderTexture(LPDIRECT3DRM2 d3drm, CDC* pDC, bool useTexture); + virtual void DeleteVisuals(LPDIRECT3DRMFRAME frame); + void SetFilename(LPCTSTR filename); + LPCTSTR GetFilename(); + static CModel* Create(LPCTSTR extension); + virtual void Delete(); + virtual void DeleteMeshs(LPDIRECT3DRMFRAME frame); + + virtual LPDIRECT3DRMMESH GetMesh(int i = -1); + virtual bool ToggleNodeVisibility(int node); + virtual void MakeAllNodesVisible(LPDIRECT3DRMFRAME frame); + virtual HTREEITEM SelectMesh(LPDIRECT3DRMVISUAL selection); + virtual int SelectNode(int nodeNum); + virtual void ChangeVisual(LPDIRECT3DRMFRAME frame, int nodeNum); + virtual void DeSelectAll(); + virtual HRESULT SetGroupQuality(D3DRMRENDERQUALITY value); + virtual D3DRMRENDERQUALITY GetGroupQuality(); + virtual bool ValidNode(); + virtual long GetNumFrames(); + void SetCurGroup(long group); + long GetNumGroups(); + virtual long GetNumNodes(); + void SetPingPong(bool pingPong); + virtual void BuildMesh(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene, CDC* pDC); + virtual long* GetCommands(); + virtual void CreateJointVisuals(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame); + virtual void SetCurJoint(long joint); + virtual long GetCurJoint(); + virtual long GetNumTris(); + virtual int GetTriCount(); + int GetCurFrame(); + void SetCurFrame(int curframe); + double GetCurScale(); + void SetCurScale(double curscale); + void ResetPlay(); + void SetPlay(bool playing); + bool Playing(); + + virtual void SetBackOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetFrontOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetLeftOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetRightOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetTopOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetBottomOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetInitialOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + + virtual bool LoadSkin(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, int skinnum, CDC* pDC); + + virtual BOOL ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC); + virtual BOOL UpdateFrame(LPDIRECT3DRM2 d3drm, CDC* pDC, int direction, bool interOn); + virtual void UpdateForward(); + virtual void UpdateBackward(); + + virtual void Drag(double delta_x, double delta_y); + virtual void Snap(); + + virtual BOOL CalcInterpolate(LPDIRECT3DRM2 d3drm, CDC* pDC, int step, int numsteps, int intertype, int direction); + +// info window support + virtual void LoadSkinInfo(CTreeCtrl* pCTree, HTREEITEM rootSkin); + virtual void AddNodes (CTreeCtrl*pCTree, HTREEITEM rootNode); + virtual void AddJoints(CTreeCtrl* pCTree, HTREEITEM rootJoint); + +protected: +// header info + char* m_filename; + long m_ident; + long m_version; + long m_framesize; + long m_num_glcmds; + long m_num_frames; + long m_num_tris; + long m_num_xyz; + long m_num_st; + long m_num_skins; + + long m_skinwidth; + long m_skinheight; +// skin_t* m_skins; + CSkin* m_skin_head; + CSkin* m_curSkin; + int m_defaultSkin; + + long m_curFrame; + double m_curscale; + long m_curGroup; + int m_curstep; + + void* m_frames; + void* m_stverts; + void* m_tris; + long* m_glcmds; + long* m_vertPath; + D3DRMGROUPINDEX m_group; + int m_pcurframe; + + unsigned long m_frameTick; + bool m_nUseTicker; + long m_nTickerDelay; + + bool m_pingPong; + bool m_playing; + bool m_usePunch; + int m_playMode; + + virtual void Init(); + +// used for support of frame tree view---------------------------------------------- +protected: + frameStruct m_frameSels; // passes back tree selections + CTreeHead* m_treeInfo; // one entry for each animation group + long m_numGroups; // number of treeinfo entries + +public: // called by frame tree ctrl + virtual void LoadFrameInfo(CTreeCtrl* treeDlg, HTREEITEM rootFrame); + frameStruct* GetFrameSels(); + CTreeHead* GetTreeInfo(int i); + +protected: + void StripGroupName(char *gname); + int InGroupList(char *test, CTreeGroup* groupList, int numGroups); +//------------------------------------------------------------------------------------- + +// skin texturing support + +public: +// virtual void TextureChanged(); + virtual void SetTransparency(LPDIRECT3DRM2 d3drm, CDC* pDC, bool trans); + +// joint support +public: + virtual bool IsJointOn(); + virtual void ToggleJointOn(); + virtual void GetModelAngles(float* x, float* y, float* z); + virtual void SetModelAngles(float x, float y, float z); + virtual void GetConstraintAngleMaxs(float* x, float* y, float* z); + virtual void GetConstraintAngleMins(float* x, float* y, float* z); + virtual void SetConstraintAngleMaxs(float x, float y, float z); + virtual void SetConstraintAngleMins(float x, float y, float z); + +// property sheet support +public: + virtual void AddPropPages(CPropertySheet* propSheet); + virtual void UpdateFromPropPages(CPropertySheet* propSheet); + virtual void RemovePropPages(CPropertySheet* propSheet); +protected: + CGeneralPropPage* m_genPropPage; +}; + diff --git a/Toolkit/Programming/Tools/qMView/NodePropertyDlg.cpp b/Toolkit/Programming/Tools/qMView/NodePropertyDlg.cpp new file mode 100644 index 0000000..6b2a0b5 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/NodePropertyDlg.cpp @@ -0,0 +1,79 @@ +// NodePropertyDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "DDUtil.h" +#include "qMView.h" + +#include "Matrix.h" +#include "Model.h" + +#include "NodePropertyDlg.h" +#include "treectrlex.h" +#include "frametreectrl.h" +#include "skintreectrl.h" + +#include "ManagerTree.h" +#include "FrameManager2.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CNodePropertyDlg dialog + + +CNodePropertyDlg::CNodePropertyDlg(CWnd* pParent /*=NULL*/) + : CDialog(CNodePropertyDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CNodePropertyDlg) + m_tris = _T(""); + //}}AFX_DATA_INIT +} + + +void CNodePropertyDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CNodePropertyDlg) + DDX_Text(pDX, IDC_EDIT1, m_tris); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CNodePropertyDlg, CDialog) + //{{AFX_MSG_MAP(CNodePropertyDlg) + ON_BN_CLICKED(IDAPPLY, OnApply) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CNodePropertyDlg message handlers + +void CNodePropertyDlg::OnApply() +{ + +} + +BOOL CNodePropertyDlg::PreCreateWindow(CREATESTRUCT& cs) +{ + // TODO: Add your specialized code here and/or call the base class + + return CDialog::PreCreateWindow(cs); +} + +BOOL CNodePropertyDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CNodePropertyDlg::OnOK() +{ + CDialog::OnOK(); +} diff --git a/Toolkit/Programming/Tools/qMView/NodePropertyDlg.h b/Toolkit/Programming/Tools/qMView/NodePropertyDlg.h new file mode 100644 index 0000000..d7d988a --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/NodePropertyDlg.h @@ -0,0 +1,49 @@ +#if !defined(AFX_NODEPROPERTYDLG_H__4BAEFDE1_C304_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_NODEPROPERTYDLG_H__4BAEFDE1_C304_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// NodePropertyDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CNodePropertyDlg dialog + +class CNodePropertyDlg : public CDialog +{ +// Construction +public: + CNodePropertyDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CNodePropertyDlg) + enum { IDD = IDD_NODE_PROP }; + CString m_tris; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CNodePropertyDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CNodePropertyDlg) + afx_msg void OnApply(); + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_NODEPROPERTYDLG_H__4BAEFDE1_C304_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/NodeTreeCtrl.cpp b/Toolkit/Programming/Tools/qMView/NodeTreeCtrl.cpp new file mode 100644 index 0000000..f68a6ea --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/NodeTreeCtrl.cpp @@ -0,0 +1,207 @@ +// NodeTreeCtrl.cpp : implementation file +// + +#include "stdafx.h" +#include "DDUtil.h" +#include "qMView.h" + +#include "Matrix.h" +#include "Model.h" +#include "resource.h" +#include "NodeTreeCtrl.h" +#include "JointTreeCtrl.h" +#include "FrameManager2.h" + +#include "NodePropertyDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CNodeTreeCtrl + +CNodeTreeCtrl::CNodeTreeCtrl() +{ + m_rootNode = NULL; +} + +CNodeTreeCtrl::~CNodeTreeCtrl() +{ +} + +void CNodeTreeCtrl::DeleteContents() +{ + DeleteAllItems(); + m_rootNode = InsertItem("Nodes", TVI_ROOT, TVI_FIRST); + SetItemImage(m_rootNode, 0, 0); +} + +CModel* CNodeTreeCtrl::GetModel() +{ + return ((FrameManager2*)GetParent())->GetModel(); +} + +void CNodeTreeCtrl::SetModel(CModel* model) +{ + DeleteContents(); + if (model != NULL) + { + model->AddNodes(this, m_rootNode); + } +} + +BEGIN_MESSAGE_MAP(CNodeTreeCtrl, CTreeCtrl) + ON_WM_CONTEXTMENU() + //{{AFX_MSG_MAP(CNodeTreeCtrl) + ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged) + ON_COMMAND(ID_NODE_TOGGLE_VIS, OnNodeToggleVis) + ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CNodeTreeCtrl message handlers + +void CNodeTreeCtrl::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_TREEVIEW *pNMTreeView = (NM_TREEVIEW*)pNMHDR; + int nodeNum = 0; + HTREEITEM item, parent; + + CModel* model = GetModel(); + if (model == NULL) + { + return; + } + if (model->GetMesh(0) == NULL) + return; + + item = GetSelectedItem(); + parent = GetParentItem(item); + + if (item==m_rootNode) + { + model->DeSelectAll(); + *pResult = 0; + return; + } + + CString cs = GetItemText(item); + LPSTR foo = cs.GetBuffer(10); + + sscanf(foo, "Node %d", &nodeNum); + + ((CFrameWnd*)AfxGetMainWnd())->GetActiveDocument()->UpdateAllViews(NULL, QM_CHANGE_VISUAL, (CObject*)nodeNum); + + model->SelectNode(nodeNum); + + *pResult = 0; +} + +void CNodeTreeCtrl::OnContextMenu(CWnd*, CPoint point) +{ + { + if (point.x == -1 && point.y == -1){ + //keystroke invocation + CRect rect; + GetClientRect(rect); + ClientToScreen(rect); + + point = rect.TopLeft(); + point.Offset(5, 5); + } + + CMenu menu; + VERIFY(menu.LoadMenu(CG_IDR_POPUP_NODE_TREE_CTRL)); + + CMenu* pPopup = menu.GetSubMenu(0); + ASSERT(pPopup != NULL); + CWnd* pWndPopupOwner = this; + + while (pWndPopupOwner->GetStyle() & WS_CHILD) + pWndPopupOwner = pWndPopupOwner->GetParent(); + + pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, + pWndPopupOwner); + } +} + +void CNodeTreeCtrl::OnNodeToggleVis() +{ + HTREEITEM item, parent; + int nodeNum = 0; + + CModel* model = GetModel(); + if (model == NULL) + { + return; + } + item = GetSelectedItem(); + parent = GetParentItem(item); + + if (item==m_rootNode) + return; + + CString cs = GetItemText(item); + LPSTR foo = cs.GetBuffer(10); + + sscanf(foo, "Node %d", &nodeNum); + + for (int i = 0; i < model->GetNumNodes(); i++) + { + model->GetMesh(i)->SetGroupColorRGB( 0, D3DVALUE(255), + D3DVALUE(255), + D3DVALUE(255) ); + } + + model->GetMesh(nodeNum)->SetGroupColorRGB( 0, D3DVALUE(0), + D3DVALUE(0), + D3DVALUE(0) ); +} + +void CNodeTreeCtrl::OnRclick(NMHDR* pNMHDR, LRESULT* pResult) +{ + POINT point; + + GetCursorPos(&point); + UINT flags; + POINT hitpoint = point; + ScreenToClient(&hitpoint); + HTREEITEM item = HitTest(hitpoint, &flags); + SelectItem(item); + if ((item == m_rootNode) || (item == NULL)) + { + return; + } + CModel* model = GetModel(); + if (model != NULL) + { + CMenu menu; + VERIFY(menu.LoadMenu(CG_IDR_POPUP_NODE_TREE_CTRL)); + + CMenu* pPopup = menu.GetSubMenu(0); + ASSERT(pPopup != NULL); + model->FillMenuWithSkins(pPopup); + CWnd* pWndPopupOwner = this; + + while (pWndPopupOwner->GetStyle() & WS_CHILD) + pWndPopupOwner = pWndPopupOwner->GetParent(); + + + pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, + pWndPopupOwner); + } + *pResult = 0; +} + +void CNodeTreeCtrl::PreSubclassWindow() +{ + // TODO: Add your specialized code here and/or call the base class + + CTreeCtrl::PreSubclassWindow(); + m_image.Create(IDB_BITMAP3, 13, 2, RGB(255,255,255)); + SetImageList(&(m_image), TVSIL_NORMAL); +} diff --git a/Toolkit/Programming/Tools/qMView/NodeTreeCtrl.h b/Toolkit/Programming/Tools/qMView/NodeTreeCtrl.h new file mode 100644 index 0000000..95ba1ff --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/NodeTreeCtrl.h @@ -0,0 +1,58 @@ +#if !defined(AFX_NODETREECTRL_H__358B2D85_C279_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_NODETREECTRL_H__358B2D85_C279_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// NodeTreeCtrl.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CNodeTreeCtrl window + +class CNodeTreeCtrl : public CTreeCtrl +{ +// Construction +public: + CNodeTreeCtrl(); + void SetModel(CModel* model); + void DeleteContents(); + CModel* GetModel(); +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CNodeTreeCtrl) + protected: + virtual void PreSubclassWindow(); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CNodeTreeCtrl(); + + // Generated message map functions +protected: + afx_msg void OnContextMenu(CWnd*, CPoint point); + //{{AFX_MSG(CNodeTreeCtrl) + afx_msg void OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnNodeToggleVis(); + afx_msg void OnRclick(NMHDR* pNMHDR, LRESULT* pResult); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() + + HTREEITEM m_rootNode; + CImageList m_image; +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_NODETREECTRL_H__358B2D85_C279_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/PDA.cpp b/Toolkit/Programming/Tools/qMView/PDA.cpp new file mode 100644 index 0000000..606e7a5 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/PDA.cpp @@ -0,0 +1,48 @@ +// PDA.cpp : implementation file +// + +#include "stdafx.h" +#include "qMView.h" +#include "PDA.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPDA dialog + + +CPDA::CPDA(CWnd* pParent /*=NULL*/) + : CDialog(CPDA::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPDA) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CPDA::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPDA) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CPDA, CDialog) + //{{AFX_MSG_MAP(CPDA) + ON_WM_PAINT() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPDA message handlers + +void CPDA::OnPaint() +{ + CPaintDC dc(this); // device context for painting +} diff --git a/Toolkit/Programming/Tools/qMView/PDA.h b/Toolkit/Programming/Tools/qMView/PDA.h new file mode 100644 index 0000000..5e1ee64 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/PDA.h @@ -0,0 +1,46 @@ +#if !defined(AFX_PDA_H__F0330641_CF89_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_PDA_H__F0330641_CF89_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// PDA.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CPDA dialog + +class CPDA : public CDialog +{ +// Construction +public: + CPDA(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CPDA) + enum { IDD = IDD_PDA }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPDA) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CPDA) + afx_msg void OnPaint(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PDA_H__F0330641_CF89_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/PrefDlg.cpp b/Toolkit/Programming/Tools/qMView/PrefDlg.cpp new file mode 100644 index 0000000..6dd9189 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/PrefDlg.cpp @@ -0,0 +1,74 @@ +// PrefDlg.cpp : implementation file +// + +#include "generalpref.h" + +#include "stdafx.h" +#include "qMView.h" +#include "PrefDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPrefDlg dialog + + +CPrefDlg::CPrefDlg(CWnd* pParent /*=NULL*/) + : CDialog(CPrefDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPrefDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CPrefDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPrefDlg) + DDX_Control(pDX, IDDEFAULT, m_nDefault); + DDX_Control(pDX, IDC_OPTIONTAB, m_nTabCtrl); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CPrefDlg, CDialog) + //{{AFX_MSG_MAP(CPrefDlg) + ON_BN_CLICKED(IDDEFAULT, OnDefault) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPrefDlg message handlers + +void CPrefDlg::OnDefault() +{ + // TODO: Add your control notification handler code here + +} + +void CPrefDlg::OnCancel() +{ + // TODO: Add extra cleanup here + + CDialog::OnCancel(); +} + +void CPrefDlg::OnOK() +{ + // TODO: Add extra validation here + + CDialog::OnOK(); +} + +BOOL CPrefDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} diff --git a/Toolkit/Programming/Tools/qMView/PrefDlg.h b/Toolkit/Programming/Tools/qMView/PrefDlg.h new file mode 100644 index 0000000..581b25f --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/PrefDlg.h @@ -0,0 +1,39 @@ +// PrefDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CPrefDlg dialog + +class CPrefDlg : public CDialog +{ +// Construction +public: + CPrefDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CPrefDlg) + enum { IDD = IDD_OPTIONS }; + CButton m_nDefault; + CTabCtrl m_nTabCtrl; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPrefDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CPrefDlg) + afx_msg void OnDefault(); + virtual void OnCancel(); + virtual void OnOK(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; diff --git a/Toolkit/Programming/Tools/qMView/Quake2Model.cpp b/Toolkit/Programming/Tools/qMView/Quake2Model.cpp new file mode 100644 index 0000000..d63ab31 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Quake2Model.cpp @@ -0,0 +1,594 @@ +// Quake2Model +// + +#include "stdafx.h" +#include "resource.h" +#include "DDUtil.h" +#include "Matrix.h" +#include "Model.h" +#include "FrameManager2.h" +#include "Quake2Model.h" + +// +// CQuake2Model +// + +CQuake2Model::CQuake2Model() +{ +} + +CQuake2Model::~CQuake2Model() +{ +} + +void CQuake2Model::Init() +{ + m_mesh = NULL; + m_skinname = NULL; + CModel::Init(); +} + +void CQuake2Model::DeleteMeshs(LPDIRECT3DRMFRAME frame) +{ + if (m_mesh != NULL) + { + frame->DeleteVisual(m_mesh); + m_mesh->Release(); + m_mesh = NULL; + } +} + +void CQuake2Model::Delete() +{ + if (m_skinname != NULL) + { + free (m_skinname); + m_skinname = NULL; + } + CModel::Delete(); +} + +void CQuake2Model::Serialize(CArchive& ar) +{ + long ofs_skins; // each skin is a MAX_SKINNAME string + long ofs_st; // byte offset from start for stverts + long ofs_tris; // offset for dtriangles + long ofs_frames; // offset for first frame + long ofs_glcmds; + long ofs_end; // end of file + m_curFrame = 0; + m_curscale = -150; + m_playing = FALSE; + + ar >> m_ident >> m_version >> m_skinwidth >> m_skinheight >> + m_framesize >> m_num_skins >> m_num_xyz >> m_num_st >> + m_num_tris >> m_num_glcmds >> m_num_frames >> ofs_skins >> + ofs_st >> ofs_tris >> ofs_frames >> ofs_glcmds >> + ofs_end; + + if (m_glcmds) + { + free(m_glcmds); + m_glcmds = NULL; + } + + CFile* file = ar.GetFile(); + file->Seek(ofs_glcmds, CFile::begin); + m_glcmds = (long*)malloc(m_num_glcmds * sizeof(long)); + file->Read(m_glcmds, m_num_glcmds * sizeof(long)); + + if (m_frames != NULL) + { + free(m_frames); + m_frames = NULL; + } + file->Seek(ofs_frames, CFile::begin); + m_frames = (void*)malloc(m_framesize * m_num_frames); + file->Read(m_frames, m_framesize * m_num_frames); + + file->Seek(ofs_skins, CFile::begin); + char tempskinname[64]; + file->Read(tempskinname, 64); + CString skinname = tempskinname; + int pos = skinname.ReverseFind('.'); + if (pos > -1) + { + skinname = skinname.Left(pos); + } + skinname += ".pcx"; + CString filePath = m_filename; + int destChar = filePath.ReverseFind('\\'); + if (destChar > -1) + { + filePath = filePath.Left(destChar); + } + + while(true) + { + destChar = skinname.Find("/"); + if (destChar < 0) + { + break; + } + skinname.SetAt(destChar, '\\'); + } + + CString namePart; + CString partialPath = skinname; + destChar = partialPath.ReverseFind('\\'); + if (destChar > -1) + { + namePart = partialPath.Right(partialPath.GetLength() - destChar); + partialPath = partialPath.Left(destChar); + } + + if (partialPath.CompareNoCase(filePath.Right(partialPath.GetLength())) == 0) + { + partialPath = filePath; + } + partialPath = partialPath + namePart; + + m_skinname = (char*)malloc(partialPath.GetLength() + 1); + strcpy(m_skinname, partialPath); +} + +void CQuake2Model::BuildMesh(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene, CDC* pDC) +{ + int realvert = 0; + + D3DRMVERTEX* vertexlist = new D3DRMVERTEX[m_num_tris*3+1]; + if (vertexlist == NULL) + { + AfxMessageBox("Cannot make vertexlist"); + return; + } + + if (m_vertPath != NULL) + { + delete m_vertPath; + } + m_vertPath = new long[m_num_tris*3+1]; + + int curvert = m_num_tris * 3; + + unsigned* vertorder = new unsigned[m_num_tris*3+1]; + if (vertorder == NULL) + { + AfxMessageBox("Cannot make vertorder"); + return; + } + + for (int i = 0; i < (m_num_tris * 3); i++) + { + curvert--; + vertorder[i] = curvert; + } + + curvert=0; + + d3drm->CreateMesh(&m_mesh); + + vec5_t* vertlist = (vec5_t*)malloc(sizeof(vec5_t)*m_num_tris*3); + + frameinfo2_t* frameinfo1 = (frameinfo2_t*)m_frames; + long* command = m_glcmds; + BOOL ODD = FALSE; + int num_verts; + int command_type; + + //do the gl commands + while (*command) + { + ODD = TRUE; + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + vec5_t p1; + //grab the floating point s and t + p1.s = (*((float *)command)) * m_skinwidth; command++; + p1.t = (*((float *)command)) * m_skinheight; command++; + + //grab the vertex index + int vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[i] = p1; + } + + D3DVECTOR p[3], n1, n2, n3; + switch (command_type) + { + case 0: + //tristrip + for (i=0;i -1; j--) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / m_skinwidth; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / m_skinheight; + vertexlist[curvert].color = D3DCOLOR(2); + m_vertPath[curvert] = realvert+i+j; + curvert++; + } + ODD = FALSE; + } + else + { + for (int j = 0; j < 3; j++) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / m_skinwidth; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / m_skinheight; + vertexlist[curvert].color = D3DCOLOR(2); + m_vertPath[curvert] = realvert+i+j; + curvert++; + } + ODD = TRUE; + } + } + break; + + case 1: + //trifan + for (i=0;i -1; j--) + { + if (j == 0) + x = 0; + else + x = i; + + p[j].x = vertlist[x+j].x; + p[j].y = vertlist[x+j].y; + p[j].z = vertlist[x+j].z; + } + + D3DRMVectorSubtract(&n1, &p[1], &p[0]); + D3DRMVectorSubtract(&n2, &p[2], &p[1]); + + D3DRMVectorCrossProduct(&n3, &n1, &n2); + D3DRMVectorNormalize(&n3); + + for (j = 2; j > -1; j--) + { + if (j == 0) + x = 0; + else + x = i; + + vertexlist[curvert].position.x = vertlist[x+j].x; + vertexlist[curvert].position.y = vertlist[x+j].y; + vertexlist[curvert].position.z = vertlist[x+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[x+j].s) / m_skinwidth; + vertexlist[curvert].tv = D3DVALUE(vertlist[x+j].t) / m_skinheight; + vertexlist[curvert].color = D3DCOLOR(2); + m_vertPath[curvert] = realvert+x+j; + curvert++; + } + } + break; + } + + realvert += num_verts; + } + + m_mesh->AddGroup( m_num_tris * 3, m_num_tris, 3, vertorder, &m_group ); + m_mesh->SetVertices(m_group, 0, m_num_tris * 3, vertexlist ); + + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) ); + + if (vertexlist) delete vertexlist; + if (vertorder) delete vertorder; + if (vertlist) free(vertlist); +} + +BOOL CQuake2Model::ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC) +{ + int curvert = 0; + D3DRMVERTEX *vertexlist; + vec5_t *vertlist; + int i; + vec5_t p1; + frameinfo2_t *frameinfo1; + long *command; + int num_verts,vert_index; + int command_type; + + vertexlist = new D3DRMVERTEX[m_num_tris*3+1]; + if (vertexlist == NULL) + return AfxMessageBox("Cannot make vertexlist"); + + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*m_num_tris*3); + + frameinfo1 = (frameinfo2_t*)((char*)m_frames + m_curFrame * m_framesize); + command = m_glcmds; + + curvert = 0; + //do the gl commands + while (*command) + { + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * m_skinwidth; command++; + p1.t = (*((float *)command)) * m_skinheight; command++; + + //grab the vertex index + vert_index = *command; + command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[curvert] = p1; + curvert++; + } + + } + + for (i = 0; i < m_num_tris*3; i++) + { + vertexlist[i].position.x = vertlist[m_vertPath[i]].x; + vertexlist[i].position.y = vertlist[m_vertPath[i]].y; + vertexlist[i].position.z = vertlist[m_vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[m_vertPath[i]].s) / m_skinwidth; + vertexlist[i].tv = D3DVALUE(vertlist[m_vertPath[i]].t) / m_skinheight; + } + + m_mesh->SetVertices(m_group, 0, m_num_tris*3, vertexlist ); + + free(vertlist); + + delete (vertexlist); + + return TRUE; +} + +BOOL CQuake2Model::CalcInterpolate(LPDIRECT3DRM2 d3drm, CDC* pDC, int step, int numsteps, int intertype, int direction) +{ + D3DVECTOR delta; + int curvert = 0; + D3DRMVERTEX *vertexlist; + int lastframe, i; + + vec5_t p1,p2; + frameinfo2_t *frameinfo1, *frameinfo2; + long *command; + int num_verts,vert_index; + int command_type; + vec5_t *vertlist; + BOOL ODD; + + vertexlist = new D3DRMVERTEX[m_num_tris*3+1]; + if (vertexlist == NULL) + return AfxMessageBox("Cannot make vertexlist"); + if (direction == ANIM_FORWARD) + { + if (m_curGroup == -1) + { + if (m_curFrame + 1 > m_num_frames-1) + lastframe = 0; + else + lastframe = m_curFrame + 1; + } + else + { + if (m_curFrame + 1 > m_treeInfo[m_curGroup].eFrame) + lastframe = m_treeInfo[m_curGroup].bFrame; + else + lastframe = m_curFrame + 1; + } + } + + curvert = 0; + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*m_num_tris*3); + + frameinfo1 = (frameinfo2_t*)((char*)m_frames + m_curFrame * m_framesize); + frameinfo2 = (frameinfo2_t*)((char*)m_frames + lastframe * m_framesize); + command = m_glcmds; + + //do the gl commands + while (*command) + { + ODD = TRUE; + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * m_skinwidth; command++; + p1.t = (*((float *)command)) * m_skinheight; command++; + + //grab the vertex index + vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + p2.z = -((frameinfo2->verts[vert_index].x * frameinfo2->scale.x) + frameinfo2->origin.x); + p2.y = ((frameinfo2->verts[vert_index].y * frameinfo2->scale.y) + frameinfo2->origin.y); + p2.x = -((frameinfo2->verts[vert_index].z * frameinfo2->scale.z) + frameinfo2->origin.z); + + delta.x = (p2.x - p1.x) / numsteps; + delta.y = (p2.y - p1.y) / numsteps; + delta.z = (p2.z - p1.z) / numsteps; + + p1.x += delta.x * step; + p1.y += delta.y * step; + p1.z += delta.z * step; + + vertlist[curvert] = p1; + curvert++; + } + + } + + for (i = 0; i < m_num_tris*3; i++) + { + vertexlist[i].position.x = vertlist[m_vertPath[i]].x; + vertexlist[i].position.y = vertlist[m_vertPath[i]].y; + vertexlist[i].position.z = vertlist[m_vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[m_vertPath[i]].s) / m_skinwidth; + vertexlist[i].tv = D3DVALUE(vertlist[m_vertPath[i]].t) / m_skinheight; + } + + m_mesh->SetVertices(m_group, 0, m_num_tris*3, vertexlist ); + + free(vertlist); + delete (vertexlist); + + if (step + 1 > numsteps) m_curstep = 0; + else m_curstep++; + + return TRUE; +} + +LPDIRECT3DRMMESH CQuake2Model::GetMesh(int i) +{ + return m_mesh; +} + +CSkin* CQuake2Model::GetSkin(int i) +{ + return CModel::GetSkin(m_skinname); +} + +void CQuake2Model::FillMenuWithSkins(CMenu* menu) +{ + if (m_skinname != NULL) + { + menu->AppendMenu(MF_ENABLED | MF_UNCHECKED | MF_STRING, IDR_SKIN_SELECT_START, m_skinname); + } +} + +void CQuake2Model::AddSkin(LPCTSTR skinname) +{ +} + +void CQuake2Model::ReplaceSkin(int i, LPCTSTR skinname) +{ + if (m_skinname != NULL) + { + free(m_skinname); + m_skinname = NULL; + } + m_skinname = (char*)malloc(strlen(skinname) + 1); + strcpy(m_skinname, skinname); +} + +// frame tree ctrl support + +void CQuake2Model::LoadFrameInfo(CTreeCtrl* treeDlg, HTREEITEM rootFrame) +{ + if (m_num_frames > 0) + { + m_numGroups = 0; + + m_treeInfo = new CTreeHead[m_num_frames]; + if (m_treeInfo == NULL) AfxMessageBox("Null tree"); + + CTreeGroup* groupList = new CTreeGroup[m_num_frames]; + if (groupList == NULL) AfxMessageBox("Null groupList"); + + for (int i = 0; i < m_num_frames; i++) + { + frameinfo2_t* frameinfo1 = (frameinfo2_t*)((char*)m_frames + i * m_framesize); + char name[16]; + strcpy(name , frameinfo1->name); + char* newname = name; + StripGroupName(newname); + int thisgroup = InGroupList(newname, groupList, m_numGroups); + if (thisgroup == -1) + { + thisgroup = m_numGroups; + groupList[thisgroup].head = treeDlg->InsertItem(newname, rootFrame, TVI_LAST); + treeDlg->SetItemData(groupList[thisgroup].head, thisgroup); + m_treeInfo[m_numGroups].bFrame = i; + m_numGroups++; + } + m_treeInfo[thisgroup].eFrame = i; + HTREEITEM item = treeDlg->InsertItem(frameinfo1->name, groupList[thisgroup].head); + treeDlg->SetItemData(item, i); + treeDlg->SetItemImage(item, 1, 1); + } + if (groupList) + { + delete groupList; + groupList = NULL; + } + treeDlg->Expand(rootFrame, TVE_EXPAND); + } +} + diff --git a/Toolkit/Programming/Tools/qMView/Quake2Model.h b/Toolkit/Programming/Tools/qMView/Quake2Model.h new file mode 100644 index 0000000..37a735d --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Quake2Model.h @@ -0,0 +1,35 @@ +// QuakeModel2.h + +class CQuake2Model : public CModel +{ +public: + CQuake2Model(); + ~CQuake2Model(); + + virtual void Delete(); + + virtual CSkin* GetSkin(int i); + virtual void ReplaceSkin(int i, LPCTSTR skinname); + virtual void AddSkin(LPCTSTR skinname); + virtual void FillMenuWithSkins(CMenu* menu); + + virtual void DeleteMeshs(LPDIRECT3DRMFRAME frame); + virtual LPDIRECT3DRMMESH GetMesh(int i = -1); + virtual void Serialize(CArchive& ar); + // tris and sts are not read in - only first skin name read in + + virtual void BuildMesh(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene, CDC* pDC); + virtual BOOL ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC); + + virtual BOOL CalcInterpolate(LPDIRECT3DRM2 d3drm, CDC* pDC, int step, int numsteps, int intertype, int direction); +// frame tree control support + virtual void LoadFrameInfo(CTreeCtrl* treeDlg, HTREEITEM rootFrame); + +protected: + char* m_skinname; // eventually goes away + + virtual void Init(); + + LPDIRECT3DRMMESH m_mesh; +}; + diff --git a/Toolkit/Programming/Tools/qMView/QuakeModel.cpp b/Toolkit/Programming/Tools/qMView/QuakeModel.cpp new file mode 100644 index 0000000..7d24c82 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/QuakeModel.cpp @@ -0,0 +1,658 @@ +// QuakeModel.cpp + +#include "stdafx.h" +#include "resource.h" +#include "DDUtil.h" +#include "Matrix.h" +#include "Model.h" +#include "FrameManager2.h" +#include "QuakeModel.h" + +// +// CQuakeModel +// + +CQuakeModel::CQuakeModel() +{ +} + +CQuakeModel::~CQuakeModel() +{ +} + +void CQuakeModel::Init() +{ + m_mesh = NULL; + m_scale.x = 0; + m_scale.y = 0; + m_scale.z = 0; + m_origin.x = 0; + m_origin.y = 0; + m_origin.z = 0; + m_radius = 0; + m_eye.x = 0; + m_eye.y = 0; + m_eye.z = 0; + m_sync = 0; + m_flags = 0; + m_size = 0; + CModel::Init(); +} + +void CQuakeModel::DeleteMeshs(LPDIRECT3DRMFRAME frame) +{ + if (m_mesh != NULL) + { + frame->DeleteVisual(m_mesh); + m_mesh->Release(); + m_mesh = NULL; + } +} + +void CQuakeModel::Delete() +{ + if (m_frames!=NULL) + { + for (int i=0;iSetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0) ); +} + +void CQuakeModel::SetFrontOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); +} + +void CQuakeModel::SetLeftOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1) ); +} + +void CQuakeModel::SetRightOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1) ); +} + +void CQuakeModel::SetTopOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0) ); +} + +void CQuakeModel::SetBottomOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1), + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0) ); +} + +void CQuakeModel::SetInitialOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene) +{ + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); +} + +typedef struct +{ + long onseam; + long s; + long t; +} stvert_t; + +void CQuakeModel::Serialize(CArchive& ar) +{ + m_curFrame = 0; + m_curscale = -150; + m_playing = false; + + ar >> m_ident >> m_version; + ar.Read(&m_scale, sizeof(m_scale)); + ar.Read(&m_origin, sizeof(m_origin)); + ar.Read(&m_radius, sizeof(m_radius)); + ar.Read(&m_eye, sizeof(m_eye)); + ar >> m_num_skins >> m_skinwidth >> + m_skinheight >> m_num_xyz >> m_num_tris >> m_num_frames >> + m_sync >> m_flags >> m_size; + m_num_st = m_num_xyz; + if (m_ident != 0x4F504449) + { + AfxMessageBox("Invalid File"); + return; + } + + if (m_version != 6) + { + AfxMessageBox("Invalid MDL Version"); + return; + } + + CFile* file = ar.GetFile(); + AfxMessageBox("not currently reading quake models properly"); + if (true) + { + return; + } +/* file->Seek(0x54, CFile::begin); + + m_skins = (skin_t *)malloc(m_num_skins*sizeof(skin_t)); + if (m_skins==NULL) + { + AfxMessageBox("Could not allocate skin page"); + return; + } + memset(m_skins,0,m_num_skins*sizeof(skin_t)); + for (int i=0;iRead(&(m_skins[i].type),sizeof(long)); + + if (m_skins[i].type==0) + { + m_skins[i].numgroupskins = 1; + + m_skins[i].skin = (u_char **)malloc(sizeof(unsigned char *)); + if (m_skins[i].skin==NULL) + { + AfxMessageBox("Could not allocate skin page buffer"); + return; + } + m_skins[i].skin[0] = (u_char *)malloc(m_skinwidth*m_skinheight); + if (m_skins[i].skin[0]==NULL) + { + AfxMessageBox("Could not do something"); + return; + } + memset(m_skins[i].skin[0],0,m_skinwidth*m_skinheight); + + file->Read(m_skins[i].skin[0],m_skinwidth*m_skinheight); + + m_skins[i].interval = (float *)malloc(sizeof(float)); + if (m_skins[i].interval==NULL) + { + AfxMessageBox("Could not allocate intervals"); + return; + } + *(m_skins[i].interval) = (float)0; + + } + else + { + file->Read(&(m_skins[i].numgroupskins),sizeof(long)); + + m_skins[i].interval = (float *)malloc(sizeof(float)*(m_skins[i].numgroupskins)); + if (m_skins[i].interval==NULL) AfxMessageBox("Could not load"); + memset(m_skins[i].interval,0,sizeof(float)*m_skins[i].numgroupskins); + for (int j=0;jRead(&(m_skins[i].interval[j]),sizeof(float)); + } + + m_skins[i].skin = (u_char **)malloc(sizeof(unsigned char *)*(m_skins[i].numgroupskins)); + if (m_skins[i].skin==NULL) AfxMessageBox("Could not load"); + memset(m_skins[i].skin,0,sizeof(unsigned char *)*(m_skins[i].numgroupskins)); + for (j=0;jRead(m_skins[i].skin[j],m_skinwidth*m_skinheight); + } + } + } + +*/ if (m_stverts != NULL) + { + free(m_stverts); + } + m_stverts = (void*)malloc(m_num_st*sizeof(stvert_t)); + if (m_stverts==NULL) AfxMessageBox("1"); + memset(m_stverts,0,m_num_st*sizeof(stvert_t)); + file->Read(m_stverts,m_num_st*sizeof(stvert_t)); + m_tris = (void*)malloc(m_num_tris*sizeof(itriangle_t)); + if (m_tris==NULL) AfxMessageBox("2"); + memset(m_tris,0,m_num_tris*sizeof(itriangle_t)); + file->Read(m_tris,m_num_tris*sizeof(itriangle_t)); + + m_frames = (void*)malloc(m_num_frames*sizeof(frame_t)); + if (m_frames==NULL) AfxMessageBox("3"); + memset(m_frames,0,m_num_frames*sizeof(frame_t)); + + for (int i=0;iRead(&(((frame_t*)m_frames)[i].type),sizeof(long)); + if (((frame_t*)m_frames)[i].type==0) + { + ((frame_t*)m_frames)[i].numgroupframes = 1; + + ((frame_t*)m_frames)[i].info = (frameinfo_t *)malloc(sizeof(frameinfo_t)); + if (((frame_t*)m_frames)[i].info==NULL) AfxMessageBox("4"); + + file->Read(((frame_t*)m_frames)[i].info,sizeof(frameinfo_t)); + ((frame_t*)m_frames)[i].data = (trivertx_t **)malloc(sizeof(u_char *)); + if (((frame_t*)m_frames)[i].data==NULL) AfxMessageBox("5"); + + ((frame_t*)m_frames)[i].data[0] = (trivertx_t *)malloc(m_num_xyz*sizeof(trivertx_t)); + if (((frame_t*)m_frames)[i].data[0]==NULL) AfxMessageBox("6"); + memset(((frame_t*)m_frames)[i].data[0],0,m_num_xyz*sizeof(trivertx_t)); + file->Read(((frame_t*)m_frames)[i].data[0],m_num_xyz*sizeof(trivertx_t)); + + ((frame_t*)m_frames)[i].interval = (float *)malloc(sizeof(float)); + if (((frame_t*)m_frames)[i].interval==NULL) AfxMessageBox("7"); + *(((frame_t*)m_frames)[i].interval) = (float)0; + } + else + { + file->Read(&(((frame_t*)m_frames)[i].numgroupframes),sizeof(long)); + file->Read(&(((frame_t*)m_frames)[i].groupmin),sizeof(trivertx_t)); + file->Read(&(((frame_t*)m_frames)[i].groupmax),sizeof(trivertx_t)); + + ((frame_t*)m_frames)[i].data = (trivertx_t **)malloc(sizeof(u_char *)*(((frame_t*)m_frames)[i].numgroupframes)); + if (((frame_t*)m_frames)[i].data==NULL) AfxMessageBox("8"); + memset(((frame_t*)m_frames)[i].data,0,sizeof(u_char *)*(((frame_t*)m_frames)[i].numgroupframes)); + + ((frame_t*)m_frames)[i].info = (frameinfo_t *)malloc(sizeof(frameinfo_t)*(((frame_t*)m_frames)[i].numgroupframes)); + if (((frame_t*)m_frames)[i].info==NULL) AfxMessageBox("9"); + memset(((frame_t*)m_frames)[i].info,0,sizeof(frameinfo_t)*(((frame_t*)m_frames)[i].numgroupframes)); + + ((frame_t*)m_frames)[i].interval = (float *)malloc(sizeof(float)*(((frame_t*)m_frames)[i].numgroupframes)); + if (((frame_t*)m_frames)[i].interval==NULL) AfxMessageBox("10"); + memset(((frame_t*)m_frames)[i].interval,0,sizeof(float)*((frame_t*)m_frames)[i].numgroupframes); + for (int j=0;j<((frame_t*)m_frames)[i].numgroupframes;j++) + { + file->Read(&(((frame_t*)m_frames)[i].interval[j]),sizeof(float)); + } + + for (j=0;j<((frame_t*)m_frames)[i].numgroupframes;j++) + { + file->Read(&(((frame_t*)m_frames)[i].info[j]),sizeof(frameinfo_t)); + + ((frame_t*)m_frames)[i].data[j] = (trivertx_t *)malloc(m_num_xyz*sizeof(trivertx_t)); + if (((frame_t*)m_frames)[i].data[j]==NULL) AfxMessageBox("11"); + memset(((frame_t*)m_frames)[i].data[j],0,m_num_xyz*sizeof(trivertx_t)); + file->Read(((frame_t*)m_frames)[i].data[j],m_num_xyz*sizeof(trivertx_t)); + } + } + } +} + +void CQuakeModel::BuildMesh(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene, CDC* pDC) +{ + D3DVECTOR p[3], n1, n2, n3; + int i,j; + trivertx_t *triverts; + int v1, curvert; + vec3_t pt1; + long s, t; + D3DRMVERTEX *vertexlist; + unsigned *vertorder; + unsigned numread = 0; + + vertexlist = new D3DRMVERTEX[m_num_tris*3+1]; + if (vertexlist == NULL) + { + AfxMessageBox("Cannot make vertexlist"); + return; + } + + curvert = m_num_tris * 3; + + vertorder = new unsigned[m_num_tris*3+1]; + if (vertorder == NULL) + { + AfxMessageBox("Cannot make vertorder"); + return; + } + + curvert = m_num_tris * 3; + + for (i = 0; i < (m_num_tris * 3); i++) + { + curvert--; + vertorder[i] = curvert; + } + + curvert=0; + + d3drm->CreateMesh(&m_mesh); + + triverts = ((frame_t*)m_frames)[0].data[0]; + + for (i = 0; i < m_num_tris; i++) + { + for (j = 2; j >= 0; j--) + { + v1 = ((itriangle_t*)m_tris)[i].vertices[j]; + + pt1.x = triverts[v1].x; + pt1.y = triverts[v1].y; + pt1.z = triverts[v1].z; + + s = ((stvert_t*)m_stverts)[v1].s; + t = ((stvert_t*)m_stverts)[v1].t; + + if (s > m_skinwidth) + AfxMessageBox("Invalid skin vertex (S)"); + + if (t > m_skinheight) + AfxMessageBox("Invalid skin vertex (T)"); + + if( (((stvert_t*)m_stverts)[v1].onseam) && (!((itriangle_t*)m_tris)[i].facesfront)) + s += m_skinwidth / 2; + + p[j].x = ( m_scale.x * pt1.x ) + m_origin.x; + p[j].y = ( m_scale.y * pt1.y ) + m_origin.y; + p[j].z = ( m_scale.z * pt1.z ) + m_origin.z; + + vertexlist[curvert].position.x = -p[j].x; + vertexlist[curvert].position.y = -p[j].y; + vertexlist[curvert].position.z = -p[j].z; + + vertexlist[curvert].tu = D3DVALUE(s) / m_skinwidth; + vertexlist[curvert].tv = D3DVALUE(t) / m_skinheight; + vertexlist[curvert].color = D3DCOLOR(0); + + if (curvert+1 < m_num_tris*3) curvert++; + } + + D3DRMVectorSubtract(&n2, &p[2], &p[1]); + D3DRMVectorSubtract(&n1, &p[1], &p[0]); + + D3DRMVectorCrossProduct(&n3, &n1, &n2); + D3DRMVectorNormalize(&n3); + + for (j = 0; j < 3; j++) + { + vertexlist[curvert-j+1].normal.x = -n3.x; + vertexlist[curvert-j+1].normal.y = -n3.y; + vertexlist[curvert-j+1].normal.z = -n3.z; + } + + numread++; + //statusDlg->m_nProgressBar3.SetPos(numread); + } + + m_mesh->AddGroup( m_num_tris * 3, m_num_tris, 3, vertorder, &m_group ); + m_mesh->SetVertices(m_group, 0, m_num_tris * 3, vertexlist ); + +// m_mesh->SetGroupTexture(m_group, m_texture); +// m_mesh->SetGroupMapping(m_group, D3DRMMAP_PERSPCORRECT); +// m_mesh->SetGroupQuality(m_group, D3DRMRENDER_FLAT); + +// ddrval = frame->AddVisual(m_mesh); +// if (ddrval != D3DRM_OK) +// AfxMessageBox(CDDHelper::TraceError(ddrval)); + + if (vertexlist) delete vertexlist; + if (vertorder) delete vertorder; + +} + +BOOL CQuakeModel::ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC) +{ + long s,t; + D3DVECTOR p[3], v; + int curvert = 0; + trivertx_t *triverts; + int v1; + D3DRMVERTEX *vertexlist; + int i,j; + + vertexlist = new D3DRMVERTEX[m_num_tris*3+1]; + if (vertexlist == NULL) + return AfxMessageBox("Cannot make vertexlist"); + + m_mesh->GetVertices(m_group, 0, m_num_tris*3, vertexlist); + triverts = ((frame_t*)m_frames)[m_curFrame].data[0]; + + for (i = 0; i < m_num_tris; i++) + { + for (j = 2; j >= 0; j--) + { + v1 = ((itriangle_t*)m_tris)[i].vertices[j]; + + v.x = triverts[v1].x; + v.y = triverts[v1].y; + v.z = triverts[v1].z; + + s = ((stvert_t*)m_stverts)[v1].s; + t = ((stvert_t*)m_stverts)[v1].t; + + if (s > m_skinwidth) + s = m_skinwidth;; + + if (t > m_skinheight) + t = m_skinheight; + + if( (((stvert_t*)m_stverts)[v1].onseam) && (!((itriangle_t*)m_tris)[i].facesfront)) + s += m_skinwidth / 2; + + p[j].x = ( m_scale.x * v.x ) + m_origin.x; + p[j].y = ( m_scale.y * v.y ) + m_origin.y; + p[j].z = ( m_scale.z * v.z ) + m_origin.z; + + vertexlist[curvert].position.x = -p[j].x; + vertexlist[curvert].position.y = -p[j].y; + vertexlist[curvert].position.z = -p[j].z; + + vertexlist[curvert].tu = D3DVALUE(s) / m_skinwidth; + vertexlist[curvert].tv = D3DVALUE(t) / m_skinheight; + + curvert++; + } + } + m_mesh->SetVertices(m_group, 0, m_num_tris*3, vertexlist ); + + delete (vertexlist); + + return TRUE; +} + +BOOL CQuakeModel::CalcInterpolate(LPDIRECT3DRM2 d3drm, CDC* pDC, int step, int numsteps, int intertype, int direction) +{ + D3DVECTOR delta; + D3DVECTOR d1,d2; + D3DVECTOR p[3]; + int curvert = 0; + trivertx_t *triverts, *triverts2; + int v1; + D3DRMVERTEX *vertexlist; + int lastframe, i, j; + + long s, t; + + vertexlist = new D3DRMVERTEX[m_num_tris*3+1]; + if (vertexlist == NULL) + return AfxMessageBox("Cannot make vertexlist"); + if (direction == ANIM_FORWARD) + { + if (m_curGroup == -1) + { + if (m_curFrame + 1 > m_num_frames-1) + lastframe = 0; + else + lastframe = m_curFrame + 1; + } + else + { + if (m_curFrame + 1 > m_treeInfo[m_curGroup].eFrame) + lastframe = m_treeInfo[m_curGroup].bFrame; + else + lastframe = m_curFrame + 1; + } + } + //mesh->GetVertices( group, 0, mainModel.header->numtris*3, vertexlist); + + triverts = ((frame_t*)m_frames)[m_curFrame].data[0]; + triverts2 = ((frame_t*)m_frames)[lastframe].data[0]; + + for (i = 0; i < m_num_tris; i++) + { + for (j = 2; j >= 0; j--) + { + + v1 = ((itriangle_t*)m_tris)[i].vertices[j]; + + s = ((stvert_t*)m_stverts)[v1].s; + t = ((stvert_t*)m_stverts)[v1].t; + + if (s > m_skinwidth) + AfxMessageBox("Invalid skin vertex (S)"); + + if (t > m_skinheight) + AfxMessageBox("Invalid skin vertex (T)"); + + if( (((stvert_t*)m_stverts)[v1].onseam) && (!((itriangle_t*)m_tris)[i].facesfront)) + s += m_skinwidth / 2; + + d1.x = triverts[v1].x; + d1.y = triverts[v1].y; + d1.z = triverts[v1].z; + + d2.x = triverts2[v1].x; + d2.y = triverts2[v1].y; + d2.z = triverts2[v1].z; + + delta.x = (d1.x - d2.x) / numsteps; + delta.y = (d1.y - d2.y) / numsteps; + delta.z = (d1.z - d2.z) / numsteps; + + d1.x -= delta.x * step; + d1.y -= delta.y * step; + d1.z -= delta.z * step; + + p[j].x = ( m_scale.x * d1.x ) + m_origin.x; + p[j].y = ( m_scale.y * d1.y ) + m_origin.y; + p[j].z = ( m_scale.z * d1.z ) + m_origin.z; + + vertexlist[curvert].position.x = -p[j].x; + vertexlist[curvert].position.y = -p[j].y; + vertexlist[curvert].position.z = -p[j].z; + + vertexlist[curvert].tu = D3DVALUE(s) / m_skinwidth; + vertexlist[curvert].tv = D3DVALUE(t) / m_skinheight; + + curvert++; + } + } + + m_mesh->SetVertices(m_group, 0, m_num_tris*3, vertexlist ); + + delete (vertexlist); + + if (step + 1 > numsteps) m_curstep = 0; + else m_curstep++; + + return TRUE; +} + +void CQuakeModel::FillMenuWithSkins(CMenu* menu) +{ +} + +void CQuakeModel::AddSkin(LPCTSTR skinname) +{ +} + +void CQuakeModel::ReplaceSkin(int i, LPCTSTR skinname) +{ +} + +CSkin* CQuakeModel::GetSkin(int i) +{ + return NULL; +} + +LPDIRECT3DRMMESH CQuakeModel::GetMesh(int i) +{ + return m_mesh; +} + +// info window support + +void CQuakeModel::LoadFrameInfo(CTreeCtrl* treeDlg, HTREEITEM rootFrame) +{ + int thisgroup = 0; + char name[16], *newname; + HTREEITEM point; + int groupcount = 0; + + if (m_num_frames < 1) return; + + m_numGroups = 0; + + m_treeInfo = new CTreeHead[m_num_frames]; + if (m_treeInfo == NULL) AfxMessageBox("Null tree"); + + CTreeGroup* groupList = new CTreeGroup[m_num_frames]; + if (groupList == NULL) AfxMessageBox("Null groupList"); + + for (int i = 0; i < m_num_frames; i++) + { + if (((frame_t*)m_frames)[i].type == 1) + { + AfxMessageBox("Tricky Frames not supported!\n"); + } + else + { + strcpy(name , ((frame_t*)m_frames)[i].info->name); + newname = (char *)&name; + StripGroupName(newname); + + if ((thisgroup = InGroupList(newname, groupList, m_numGroups)) == -1) + { + point = treeDlg->InsertItem(newname, rootFrame, TVI_LAST); + groupList[thisgroup].head = point; + treeDlg->SetItemData(point, m_numGroups); + m_treeInfo[m_numGroups].bFrame = i; + m_treeInfo[m_numGroups].eFrame = i; + point = treeDlg->InsertItem(((frame_t*)m_frames)[i].info->name, point, TVI_LAST); + treeDlg->SetItemData(point, i); + m_numGroups++; + } + else + { + if (i > m_treeInfo[thisgroup].eFrame) + m_treeInfo[thisgroup].eFrame = i; + + point = treeDlg->InsertItem(((frame_t*)m_frames)[i].info->name, groupList[thisgroup].head, TVI_LAST); + treeDlg->SetItemData(point, i); + } + treeDlg->SetItemImage(point, 1, 1); + } + } + if (groupList) + { + delete groupList; + groupList = NULL; + } + + treeDlg->Expand(rootFrame, TVE_EXPAND); +} + diff --git a/Toolkit/Programming/Tools/qMView/QuakeModel.h b/Toolkit/Programming/Tools/qMView/QuakeModel.h new file mode 100644 index 0000000..add59b9 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/QuakeModel.h @@ -0,0 +1,58 @@ +// QuakeModel.h + +typedef struct +{ + long type; + long numgroupframes; + trivertx_t groupmin; + trivertx_t groupmax; + frameinfo_t *info; + float *interval; + trivertx_t **data; +} frame_t; + +class CQuakeModel : public CModel +{ +public: + CQuakeModel(); + ~CQuakeModel(); + virtual void Serialize(CArchive& ar); + virtual void BuildMesh(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene, CDC* pDC); + + virtual void Delete(); + + virtual CSkin* GetSkin(int i); + virtual void ReplaceSkin(int i, LPCTSTR skinname); + virtual void AddSkin(LPCTSTR skinname); + virtual void FillMenuWithSkins(CMenu* menu); + + virtual void DeleteMeshs(LPDIRECT3DRMFRAME frame); + virtual LPDIRECT3DRMMESH GetMesh(int i = -1); + virtual void SetBackOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetFrontOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetLeftOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetRightOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetTopOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetBottomOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + virtual void SetInitialOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene); + + virtual BOOL ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC); + + virtual BOOL CalcInterpolate(LPDIRECT3DRM2 d3drm, CDC* pDC, int step, int numsteps, int intertype, int direction); +// frame tree ctrl support + virtual void LoadFrameInfo(CTreeCtrl* treeDlg, HTREEITEM rootFrame); + + +protected: + virtual void Init(); + + vec3_t m_scale; + vec3_t m_origin; + scalar_t m_radius; + vec3_t m_eye; + long m_sync; + long m_flags; + float m_size; + LPDIRECT3DRMMESH m_mesh; +}; + diff --git a/Toolkit/Programming/Tools/qMView/ReadMe.txt b/Toolkit/Programming/Tools/qMView/ReadMe.txt new file mode 100644 index 0000000..3b7c9e4 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/ReadMe.txt @@ -0,0 +1,120 @@ +======================================================================== + MICROSOFT FOUNDATION CLASS LIBRARY : qMView +======================================================================== + + +AppWizard has created this qMView application for you. This application +not only demonstrates the basics of using the Microsoft Foundation classes +but is also a starting point for writing your application. + +This file contains a summary of what you will find in each of the files that +make up your qMView application. + +qMView.h + This is the main header file for the application. It includes other + project specific headers (including Resource.h) and declares the + CQMViewApp application class. + +qMView.cpp + This is the main application source file that contains the application + class CQMViewApp. + +qMView.rc + This is a listing of all of the Microsoft Windows resources that the + program uses. It includes the icons, bitmaps, and cursors that are stored + in the RES subdirectory. This file can be directly edited in Microsoft + Developer Studio. + +res\qMView.ico + This is an icon file, which is used as the application's icon. This + icon is included by the main resource file qMView.rc. + +res\qMView.rc2 + This file contains resources that are not edited by Microsoft + Developer Studio. You should place all resources not + editable by the resource editor in this file. + +qMView.clw + This file contains information used by ClassWizard to edit existing + classes or add new classes. ClassWizard also uses this file to store + information needed to create and edit message maps and dialog data + maps and to create prototype member functions. + +///////////////////////////////////////////////////////////////////////////// + +For the main frame window: + +MainFrm.h, MainFrm.cpp + These files contain the frame class CMainFrame, which is derived from + CMDIFrameWnd and controls all MDI frame features. + +res\Toolbar.bmp + This bitmap file is used to create tiled images for the toolbar. + The initial toolbar and status bar are constructed in the + CMainFrame class. Edit this toolbar bitmap along with the + array in MainFrm.cpp to add more toolbar buttons. + +///////////////////////////////////////////////////////////////////////////// + +AppWizard creates one document type and one view: + +qMViewDoc.h, qMViewDoc.cpp - the document + These files contain your CQMViewDoc class. Edit these files to + add your special document data and to implement file saving and loading + (via CQMViewDoc::Serialize). + +qMViewView.h, qMViewView.cpp - the view of the document + These files contain your CQMViewView class. + CQMViewView objects are used to view CQMViewDoc objects. + +res\qMViewDoc.ico + This is an icon file, which is used as the icon for MDI child windows + for the CQMViewDoc class. This icon is included by the main + resource file qMView.rc. + +///////////////////////////////////////////////////////////////////////////// + +Help Support: + +MakeHelp.bat + Use this batch file to create your application's Help file, qMView.hLP. + +qMView.hpj + This file is the Help Project file used by the Help compiler to create + your application's Help file. + +hlp\*.bmp + These are bitmap files required by the standard Help file topics for + Microsoft Foundation Class Library standard commands. + +hlp\*.rtf + This file contains the standard help topics for standard MFC + commands and screen objects. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named qMView.pch and a precompiled types file named StdAfx.obj. + +Resource.h + This is the standard header file, which defines new resource IDs. + Microsoft Developer Studio reads and updates this file. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +If your application uses MFC in a shared DLL, and your application is +in a language other than the operating system's current language, you +will need to copy the corresponding localized resources MFC40XXX.DLL +from the Microsoft Visual C++ CD-ROM onto the system or system32 directory, +and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation. +For example, MFC40DEU.DLL contains resources translated to German.) If you +don't do this, some of the UI elements of your application will remain in the +language of the operating system. + +///////////////////////////////////////////////////////////////////////////// diff --git a/Toolkit/Programming/Tools/qMView/SkinPageFrm.cpp b/Toolkit/Programming/Tools/qMView/SkinPageFrm.cpp new file mode 100644 index 0000000..65b113d --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/SkinPageFrm.cpp @@ -0,0 +1,388 @@ +// SkinPageFrm.cpp : implementation file +// + +#include "stdafx.h" +#include "Resource.h" +#include "Matrix.h" + +#include "DDUtil.h" +#include "Model.h" + +#include "qMView.h" +#include "qMViewDoc.h" +#include "treectrlex.h" +#include "frametreectrl.h" +#include "skintreectrl.h" + +#include "SkinPageFrm.h" +#include "JointConstraintDlg.h" +#include "JointAnglesDlg.h" +#include "ManagerTree.h" +#include "FrameManager2.h" + +#include "MainFrm.h" + +#include "TickerDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#pragma warning(disable : 4244) // truncation from double to float + +///////////////////////////////////////////////////////////////////////////// +// CSkinPageFrm + +IMPLEMENT_DYNCREATE(CSkinPageFrm, CView) + +CSkinPageFrm::CSkinPageFrm() +{ + m_skinScale = 1.0; + m_skinBitmap = NULL; + m_vertexlist = NULL; + m_num_tris = 0; +} + +CSkinPageFrm::~CSkinPageFrm() +{ +} + +CQMViewDoc* CSkinPageFrm::GetDocument() // non-debug version is inline +{ + ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CQMViewDoc))); + return (CQMViewDoc*)m_pDocument; +} + +void CSkinPageFrm::SetModel(CModel* model) +{ + if (model == NULL) + { + return; + } + int skinwidth; + int skinheight; + CDC *pDC = GetDC(); + m_skinBitmap = model->GetBitmap(GetDocument()->GetD3D(), pDC, 0, skinwidth, skinheight); + ReleaseDC(pDC); + if (m_vertexlist != NULL) + { + delete m_vertexlist; + m_vertexlist = NULL; + } + m_num_tris = model->GetTriCount(); + long* command = model->GetCommands(); + + int curvert = m_num_tris * 3; + + m_vertexlist = new D3DRMVERTEX[curvert + 1]; + if (m_vertexlist == NULL) + { + m_num_tris = 0; + return; + } + + unsigned* vertorder = new unsigned[curvert + 1]; + if (vertorder == NULL) + { + delete m_vertexlist; + m_vertexlist = NULL; + m_num_tris = 0; + return; + } + + vec5_t* vertlist = (vec5_t*)malloc(sizeof(vec5_t) * curvert); + if (vertlist == NULL) + { + delete vertorder; + delete m_vertexlist; + m_vertexlist = NULL; + m_num_tris = 0; + return; + } + curvert=0; + + //do the gl commands + while (*command) + { + int num_verts; + int command_type; + bool ODD = true; + if (*command>0) + { + //triangle strip + num_verts = *command++; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command++); + command_type = 1; + } + + int vert_index; + vec5_t p1; + for (int i = 0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command++)) * skinwidth; + p1.t = (*((float *)command++)) * skinheight; + + //grab the vertex index + vert_index = *command++; + + vertlist[i] = p1; + } + + switch (command_type) + { + case 0: + //tristrip + for (i=0;i -1; j--) + { + m_vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s); + m_vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t); + curvert++; + } + } + else + { + for (int j = 0; j < 3; j++) + { + m_vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s); + m_vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t); + curvert++; + } + } + ODD = !ODD; + } + break; + + case 1: + //trifan + for (i=0;i -1; j--) + { + int x; + if (j == 0) + x = 0; + else + x = i; + + m_vertexlist[curvert].tu = D3DVALUE(vertlist[x+j].s); + m_vertexlist[curvert].tv = D3DVALUE(vertlist[x+j].t); + curvert++; + } + } + break; + } + } + delete vertorder; + free(vertlist); + + Invalidate(true); +} + +BEGIN_MESSAGE_MAP(CSkinPageFrm, CView) + //{{AFX_MSG_MAP(CSkinPageFrm) + ON_WM_ERASEBKGND() + ON_WM_LBUTTONDOWN() + ON_WM_RBUTTONDOWN() + ON_WM_DRAWITEM() + ON_WM_HSCROLL() + ON_WM_VSCROLL() + ON_WM_CREATE() + ON_WM_DESTROY() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSkinPageFrm message handlers + +extern BOOL overlayOn; + +void CSkinPageFrm::AdjustScrollers(int width, int height) +{ + SetScrollRange(SB_HORZ, 0, width, true); + SetScrollRange(SB_VERT, 0, height, true); + + SetScrollPos(SB_HORZ, 0); + SetScrollPos(SB_VERT, 0); +} + +BOOL CSkinPageFrm::PreCreateWindow(CREATESTRUCT& cs) +{ + // TODO: Modify the Window class or styles here by modifying + // the CREATESTRUCT cs + + cs.style = WS_CHILD | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_HSCROLL | WS_VSCROLL + | FWS_ADDTOTITLE | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_MAXIMIZE; + + return CView::PreCreateWindow(cs); +} + +void CSkinPageFrm::Register() +{ + LPCTSTR lpszChildClass = + AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, + LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_MAGNIFIER)), + 0, + LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_SKIN))); +} + +extern BOOL overlayOn; + +void CSkinPageFrm::DrawSTOverlay(void) +{ + CDC* pDC = GetDC(); + + CPen penStroke; + if (!penStroke.CreatePen(PS_SOLID, 1, RGB(255,255,255))) + return; + + CPen* pOldPen = pDC->SelectObject(&penStroke); + + for (int i = 0; i < m_num_tris; i++) + { + pDC->MoveTo((int) m_vertexlist[i*3].tu * m_skinScale, (int) m_vertexlist[i*3].tv * m_skinScale); + pDC->LineTo((int) m_vertexlist[i*3+1].tu * m_skinScale, (int) m_vertexlist[i*3+1].tv * m_skinScale); + + pDC->MoveTo((int) m_vertexlist[i*3+1].tu * m_skinScale, (int) m_vertexlist[i*3+1].tv * m_skinScale); + pDC->LineTo((int) m_vertexlist[i*3+2].tu * m_skinScale, (int) m_vertexlist[i*3+2].tv * m_skinScale); + + pDC->MoveTo((int) m_vertexlist[i*3+2].tu * m_skinScale, (int) m_vertexlist[i*3+2].tv * m_skinScale); + pDC->LineTo((int) m_vertexlist[i*3].tu * m_skinScale, (int) m_vertexlist[i*3].tv * m_skinScale); + } + + pDC->SelectObject(pOldPen); + + return; +} + +void CSkinPageFrm::OnLButtonDown(UINT nFlags, CPoint point) +{ + if (m_skinScale < 4) + { + m_skinScale += (float) 0.2; + Invalidate(true); + } + + CView::OnLButtonDown(nFlags, point); +} + +void CSkinPageFrm::OnRButtonDown(UINT nFlags, CPoint point) +{ + if (m_skinScale > 1) + { + m_skinScale -= (float) 0.2; + Invalidate(true); + } + + CView::OnRButtonDown(nFlags, point); +} + +void CSkinPageFrm::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + CDC *pDC = GetDC(); + + pDC->OffsetViewportOrg(nPos, 0); + CView::OnHScroll(nSBCode, nPos, pScrollBar); +} + +void CSkinPageFrm::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + CView::OnVScroll(nSBCode, nPos, pScrollBar); + if (pScrollBar != NULL) + { + pScrollBar->SetScrollPos(pScrollBar->GetScrollPos() + 10); + } +} + +void CSkinPageFrm::OnDraw(CDC* pDC) +{ + // TODO: Add your specialized code here and/or call the base class + if (m_skinBitmap == NULL) + { + return; + } + CDC dcCompatible; + dcCompatible.CreateCompatibleDC(pDC); + + BITMAP bmInfo; + + m_skinBitmap->GetObject(sizeof(bmInfo), &bmInfo); + + dcCompatible.SelectObject(m_skinBitmap); + + BOOL res = pDC->StretchBlt(0, 0, (int)bmInfo.bmWidth*m_skinScale, (int)bmInfo.bmHeight*m_skinScale, &dcCompatible, 0, 0, bmInfo.bmWidth, bmInfo.bmHeight, SRCCOPY); + dcCompatible.DeleteDC(); + + if (overlayOn) + DrawSTOverlay(); + + AdjustScrollers((int)bmInfo.bmWidth*m_skinScale, (int)bmInfo.bmHeight*m_skinScale); +} + +void CSkinPageFrm::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) +{ + // TODO: Add your specialized code here and/or call the base class + CModel* theModel; + + switch(lHint) + { + case QM_IDLE: + break; + case QM_NEW_SKIN: + theModel = GetDocument()->GetModel(); + SetModel(theModel); + if (theModel != NULL) + { + int skinwidth; + int skinheight; + m_skinBitmap = theModel->GetBitmap(GetDocument()->GetD3D(), GetDC(), (int)pHint, skinwidth, skinheight); + } + break; + break; + case QM_CHANGE_SKIN: + theModel = GetDocument()->GetModel(); + if (theModel != NULL) + { + int skinwidth; + int skinheight; + m_skinBitmap = theModel->GetBitmap(GetDocument()->GetD3D(), GetDC(), (int)pHint, skinwidth, skinheight); + } + break; + case QM_NEW_MODEL: + theModel = (CModel*)pHint; + SetModel(theModel); + break; + } +} + +int CSkinPageFrm::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CView::OnCreate(lpCreateStruct) == -1) + return -1; + return 0; +} + +void CSkinPageFrm::OnDestroy() +{ + CView::OnDestroy(); + + // TODO: Add your message handler code here + + if (m_vertexlist != NULL) + { + delete m_vertexlist; + m_vertexlist = NULL; + m_num_tris = 0; + } +} diff --git a/Toolkit/Programming/Tools/qMView/SkinPageFrm.h b/Toolkit/Programming/Tools/qMView/SkinPageFrm.h new file mode 100644 index 0000000..4e1a012 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/SkinPageFrm.h @@ -0,0 +1,64 @@ +#if !defined(AFX_SKINPAGEFRM_H__80CBF401_CA1C_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_SKINPAGEFRM_H__80CBF401_CA1C_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// SkinPageFrm.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSkinPageFrm frame + +class CSkinPageFrm : public CView +{ + DECLARE_DYNCREATE(CSkinPageFrm) +protected: +// Attributes +public: + CSkinPageFrm(); // protected constructor used by dynamic creation + virtual ~CSkinPageFrm(); + void SetModel(CModel* model); + CQMViewDoc* GetDocument(); + +// Operations +public: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + + void DrawSTOverlay(void); + void AdjustScrollers(int width, int height); + static void Register(); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSkinPageFrm) + protected: + virtual void OnDraw(CDC* pDC); + virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); + //}}AFX_VIRTUAL + +// Implementation +protected: + float m_skinScale; + CBitmap* m_skinBitmap; + long m_num_tris; + D3DRMVERTEX* m_vertexlist; + + // Generated message map functions + //{{AFX_MSG(CSkinPageFrm) + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnDestroy(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SKINPAGEFRM_H__80CBF401_CA1C_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/SkinScrollView.cpp b/Toolkit/Programming/Tools/qMView/SkinScrollView.cpp new file mode 100644 index 0000000..4dbd20c --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/SkinScrollView.cpp @@ -0,0 +1,69 @@ +// SkinScrollView.cpp : implementation file +// + +#include "stdafx.h" +#include "qMView.h" +#include "SkinScrollView.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSkinScrollView + +IMPLEMENT_DYNCREATE(CSkinScrollView, CScrollView) + +CSkinScrollView::CSkinScrollView() +{ +} + +CSkinScrollView::~CSkinScrollView() +{ +} + + +BEGIN_MESSAGE_MAP(CSkinScrollView, CScrollView) + //{{AFX_MSG_MAP(CSkinScrollView) + // NOTE - the ClassWizard will add and remove mapping macros here. + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSkinScrollView drawing + +void CSkinScrollView::OnInitialUpdate() +{ + CScrollView::OnInitialUpdate(); + + CSize sizeTotal; + // TODO: calculate the total size of this view + sizeTotal.cx = sizeTotal.cy = 100; + SetScrollSizes(MM_TEXT, sizeTotal); +} + +void CSkinScrollView::OnDraw(CDC* pDC) +{ + CDocument* pDoc = GetDocument(); + // TODO: add draw code here +} + +///////////////////////////////////////////////////////////////////////////// +// CSkinScrollView diagnostics + +#ifdef _DEBUG +void CSkinScrollView::AssertValid() const +{ + CScrollView::AssertValid(); +} + +void CSkinScrollView::Dump(CDumpContext& dc) const +{ + CScrollView::Dump(dc); +} +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// CSkinScrollView message handlers diff --git a/Toolkit/Programming/Tools/qMView/SkinScrollView.h b/Toolkit/Programming/Tools/qMView/SkinScrollView.h new file mode 100644 index 0000000..ea91260 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/SkinScrollView.h @@ -0,0 +1,53 @@ +#if !defined(AFX_SKINSCROLLVIEW_H__72280EA1_CB13_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_SKINSCROLLVIEW_H__72280EA1_CB13_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// SkinScrollView.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSkinScrollView view + +class CSkinScrollView : public CScrollView +{ +protected: + CSkinScrollView(); // protected constructor used by dynamic creation + DECLARE_DYNCREATE(CSkinScrollView) + +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSkinScrollView) + protected: + virtual void OnDraw(CDC* pDC); // overridden to draw this view + virtual void OnInitialUpdate(); // first time after construct + //}}AFX_VIRTUAL + +// Implementation +protected: + virtual ~CSkinScrollView(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + + // Generated message map functions + //{{AFX_MSG(CSkinScrollView) + // NOTE - the ClassWizard will add and remove member functions here. + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SKINSCROLLVIEW_H__72280EA1_CB13_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/SkinTreeCtrl.cpp b/Toolkit/Programming/Tools/qMView/SkinTreeCtrl.cpp new file mode 100644 index 0000000..3763846 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/SkinTreeCtrl.cpp @@ -0,0 +1,220 @@ +// SkinTreeCtrl.cpp : implementation file +// + +#include "stdafx.h" +#include "qMView.h" +#include "Matrix.h" + +#include "DDUtil.h" +#include "Model.h" + +#include "qMViewDoc.h" +#include "SkinPageFrm.h" + +#include "SkinTreeCtrl.h" +#include "FrameTreeCtrl.h" +#include "ManagerTree.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSkinTreeCtrl + +CSkinTreeCtrl::CSkinTreeCtrl() +{ + m_rootSkin = NULL; + m_menu = NULL; +} + +CSkinTreeCtrl::~CSkinTreeCtrl() +{ + if (m_menu != NULL) + { + delete m_menu; + m_menu = NULL; + } +} + +BEGIN_MESSAGE_MAP(CSkinTreeCtrl, CTreeCtrl) + //{{AFX_MSG_MAP(CSkinTreeCtrl) + ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick) + ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSkinTreeCtrl message handlers + +void CSkinTreeCtrl::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; + if ((pNMTreeView->itemOld.hItem != NULL) && (pNMTreeView->itemNew.hItem == pNMTreeView->itemOld.hItem)) + { + return; + } + HTREEITEM item, parent; + + CModel* model = GetModel(); + if (model == NULL) + { + return; + } + + item = pNMTreeView->itemNew.hItem; + parent =GetParentItem(item); + + if (parent == TVI_ROOT) + { + *pResult = 0; + return; + } + CString cs,strPath; + + strPath = cs = GetItemText(item); + + int destChar = cs.ReverseFind('.'); + int strLen = cs.GetLength(); + + if (destChar > -1) + { + cs = strPath.Right(strLen - destChar - 1); + } + + ((CFrameWnd*)GetParent()->GetParent())->GetActiveDocument()->UpdateAllViews(NULL, QM_NEW_SKIN, (CObject*)GetItemData(item)); + *pResult = 0; +} + +void CSkinTreeCtrl::DeleteContents() +{ + DeleteAllItems(); + m_rootSkin = InsertItem("Skins", TVI_ROOT, TVI_FIRST); + SetItemImage(m_rootSkin, 0, 0); + if (m_menu != NULL) + { + delete m_menu; + m_menu = NULL; + } +} + +CMenu* CSkinTreeCtrl::GetSkinMenu() +{ + if (m_menu == NULL) + { + return NULL; + } + return m_menu->GetSubMenu(0); +} + +CModel* CSkinTreeCtrl::GetModel() +{ + return ((CManagerTree*)GetParent())->GetModel(); +} + +void CSkinTreeCtrl::SetModel(CModel* model) +{ + DeleteContents(); + if (model != NULL) + { + model->LoadSkinInfo(this, m_rootSkin); + + char tempStr[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, tempStr); + if (m_menu != NULL) + { + delete m_menu; + m_menu = NULL; + } + m_menu = new CMenu(); + m_menu->LoadMenu(IDR_SKIN_POPUP_MENU); + CMenu* pPopup = m_menu->GetSubMenu(0); + + CString path = model->GetFilename(); + int loc = path.ReverseFind('/'); + int loc2 = path.ReverseFind('\\'); + if (loc2 > loc) + { + loc = loc2; + } + if (loc != -1) + { + path = path.Left(loc + 1); + } + SetCurrentDirectory(path); + int curID = IDR_SKIN_FROM_FILE_START; + + CString extensions; + extensions.LoadString(ID_FILE_EXTENSIONS); + CFileFind findFile; + while (extensions.GetLength() > 0) + { + CString thisExtension; + loc = extensions.Find(';'); + if (loc > -1) + { + thisExtension = extensions.Left(loc); + extensions = extensions.Right(extensions.GetLength() - loc - 1); + } + else + { + thisExtension = extensions; + extensions.Empty(); + } + BOOL process = findFile.FindFile(thisExtension, 0); + while(process) + { + process = findFile.FindNextFile(); + pPopup->AppendMenu(MF_ENABLED | MF_UNCHECKED | MF_STRING, curID++, findFile.GetFilePath()); + } + } + SetCurrentDirectory(tempStr); + + Expand(m_rootSkin, TVE_EXPAND); + } +} + +void CSkinTreeCtrl::PreSubclassWindow() +{ + // TODO: Add your specialized code here and/or call the base class + + CTreeCtrl::PreSubclassWindow(); + m_image.Create( IDB_BITMAP2, 13, 1, RGB(255,255,255)); + SetImageList(&(m_image), TVSIL_NORMAL); +} + +void CSkinTreeCtrl::OnRclick(NMHDR* pNMHDR, LRESULT* pResult) +{ + // TODO: Add your control notification handler code here + + if (m_menu == NULL) + { + *pResult = 0; + return; + } + + POINT point; + + GetCursorPos(&point); + POINT hitpoint = point; + ScreenToClient(&hitpoint); + UINT flags; + HTREEITEM item = HitTest(hitpoint, &flags); + SelectItem(item); + + { + CMenu* pPopup = m_menu->GetSubMenu(0); + ASSERT(pPopup != NULL); + CWnd* pWndPopupOwner = this; + + while (pWndPopupOwner->GetStyle() & WS_CHILD) + pWndPopupOwner = pWndPopupOwner->GetParent(); + + + pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, + pWndPopupOwner); + } + *pResult = 0; +} diff --git a/Toolkit/Programming/Tools/qMView/SkinTreeCtrl.h b/Toolkit/Programming/Tools/qMView/SkinTreeCtrl.h new file mode 100644 index 0000000..d9a82c3 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/SkinTreeCtrl.h @@ -0,0 +1,47 @@ +// SkinTreeCtrl.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSkinTreeCtrl window + +class CSkinTreeCtrl : public CTreeCtrl +{ +// Construction +public: + CSkinTreeCtrl(); + void DeleteContents(); + void SetModel(CModel* model); + CModel* GetModel(); + CMenu* GetSkinMenu(); +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSkinTreeCtrl) + protected: + virtual void PreSubclassWindow(); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CSkinTreeCtrl(); + + // Generated message map functions +protected: + //{{AFX_MSG(CSkinTreeCtrl) + afx_msg void OnRclick(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() + + CImageList m_image; + HTREEITEM m_rootSkin; + CMenu* m_menu; +}; + +///////////////////////////////////////////////////////////////////////////// diff --git a/Toolkit/Programming/Tools/qMView/SkinView.cpp b/Toolkit/Programming/Tools/qMView/SkinView.cpp new file mode 100644 index 0000000..7bc7bec --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/SkinView.cpp @@ -0,0 +1,59 @@ +// SkinView.cpp : implementation file +// + +#include "stdafx.h" +#include "qMView.h" +#include "SkinView.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSkinView + +IMPLEMENT_DYNCREATE(CSkinView, CView) + +CSkinView::CSkinView() +{ +} + +CSkinView::~CSkinView() +{ +} + + +BEGIN_MESSAGE_MAP(CSkinView, CView) + //{{AFX_MSG_MAP(CSkinView) + // NOTE - the ClassWizard will add and remove mapping macros here. + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSkinView drawing + +void CSkinView::OnDraw(CDC* pDC) +{ + CDocument* pDoc = GetDocument(); + // TODO: add draw code here +} + +///////////////////////////////////////////////////////////////////////////// +// CSkinView diagnostics + +#ifdef _DEBUG +void CSkinView::AssertValid() const +{ + CView::AssertValid(); +} + +void CSkinView::Dump(CDumpContext& dc) const +{ + CView::Dump(dc); +} +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// CSkinView message handlers diff --git a/Toolkit/Programming/Tools/qMView/SkinView.h b/Toolkit/Programming/Tools/qMView/SkinView.h new file mode 100644 index 0000000..634903a --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/SkinView.h @@ -0,0 +1,53 @@ +#if !defined(AFX_SKINVIEW_H__D23DA741_CD62_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_SKINVIEW_H__D23DA741_CD62_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// SkinView.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSkinView view + +class CSkinView : public CView +{ +protected: + CSkinView(); // protected constructor used by dynamic creation + DECLARE_DYNCREATE(CSkinView) + +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSkinView) + protected: + virtual void OnDraw(CDC* pDC); // overridden to draw this view + //}}AFX_VIRTUAL + +// Implementation +protected: + virtual ~CSkinView(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + + // Generated message map functions +protected: + //{{AFX_MSG(CSkinView) + // NOTE - the ClassWizard will add and remove member functions here. + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SKINVIEW_H__D23DA741_CD62_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/Splash.cpp b/Toolkit/Programming/Tools/qMView/Splash.cpp new file mode 100644 index 0000000..60b7758 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Splash.cpp @@ -0,0 +1,98 @@ +// CG: This file was added by the Splash Screen component. +// Splash.cpp : implementation file +// + +#include "stdafx.h" // e. g. stdafx.h +#include "resource.h" // e.g. resource.h + +#include "Splash.h" // e.g. splash.h + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char BASED_CODE THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Splash Screen class + +CSplashWnd::CSplashWnd(CWnd* pParentWnd /*= NULL*/) +{ + if (!m_bitmap.LoadBitmap(IDB_SPLASH)) + return; + + BITMAP bm; + m_bitmap.GetBitmap(&bm); + + CreateEx(0, + AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)), + NULL, WS_POPUP | WS_VISIBLE, 0, 0, bm.bmWidth, bm.bmHeight, pParentWnd->GetSafeHwnd(), NULL); +} + +CSplashWnd::~CSplashWnd() +{ + // Clear the static window pointer. + m_bitmap.DeleteObject(); +} + +BEGIN_MESSAGE_MAP(CSplashWnd, CWnd) + //{{AFX_MSG_MAP(CSplashWnd) + ON_WM_CREATE() + ON_WM_PAINT() + ON_WM_TIMER() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +BOOL CSplashWnd::PreTranslateMessage(MSG* pMsg) +{ + // If we get a keyboard or mouse message, hide the splash screen. + if (pMsg->message == WM_KEYDOWN || + pMsg->message == WM_SYSKEYDOWN || + pMsg->message == WM_LBUTTONDOWN || + pMsg->message == WM_RBUTTONDOWN || + pMsg->message == WM_MBUTTONDOWN || + pMsg->message == WM_NCLBUTTONDOWN || + pMsg->message == WM_NCRBUTTONDOWN || + pMsg->message == WM_NCMBUTTONDOWN) + { + DestroyWindow(); + delete this; + return true; + } + return false; +} + +int CSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CWnd::OnCreate(lpCreateStruct) == -1) + return -1; + + // Set a timer to destroy the splash screen. + SetTimer(1, 2000, NULL); + + return 0; +} + +void CSplashWnd::OnPaint() +{ + CPaintDC dc(this); + + CDC dcImage; + if (!dcImage.CreateCompatibleDC(&dc)) + return; + + BITMAP bm; + m_bitmap.GetBitmap(&bm); + + // Paint the image. + CBitmap* pOldBitmap = dcImage.SelectObject(&m_bitmap); + dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCCOPY); + dcImage.SelectObject(pOldBitmap); +} + +void CSplashWnd::OnTimer(UINT nIDEvent) +{ + // Destroy the splash screen window. + DestroyWindow(); + delete this; +} diff --git a/Toolkit/Programming/Tools/qMView/Splash.h b/Toolkit/Programming/Tools/qMView/Splash.h new file mode 100644 index 0000000..b8a94ca --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Splash.h @@ -0,0 +1,44 @@ +// CG: This file was added by the Splash Screen component. + +#ifndef _SPLASH_SCRN_ +#define _SPLASH_SCRN_ + +// Splash.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// Splash Screen class + +class CSplashWnd : public CWnd +{ +// Construction +public: + CSplashWnd(CWnd* pParentWnd = NULL); + +// Attributes: + CBitmap m_bitmap; + +// Operations + virtual BOOL PreTranslateMessage(MSG* pMsg); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSplashWnd) + //}}AFX_VIRTUAL + +// Implementation +public: + ~CSplashWnd(); + +// Generated message map functions +protected: + //{{AFX_MSG(CSplashWnd) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnPaint(); + afx_msg void OnTimer(UINT nIDEvent); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +#endif diff --git a/Toolkit/Programming/Tools/qMView/StdAfx.cpp b/Toolkit/Programming/Tools/qMView/StdAfx.cpp new file mode 100644 index 0000000..607f22c --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/StdAfx.cpp @@ -0,0 +1,6 @@ +// stdafx.cpp : source file that includes just the standard includes +// qMView.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + diff --git a/Toolkit/Programming/Tools/qMView/StdAfx.h b/Toolkit/Programming/Tools/qMView/StdAfx.h new file mode 100644 index 0000000..0f147c4 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/StdAfx.h @@ -0,0 +1,27 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows 95 Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +//#include +//#include + + + diff --git a/Toolkit/Programming/Tools/qMView/TickerDlg.cpp b/Toolkit/Programming/Tools/qMView/TickerDlg.cpp new file mode 100644 index 0000000..06db09e --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/TickerDlg.cpp @@ -0,0 +1,67 @@ +// TickerDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "qMView.h" +#include "TickerDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTickerDlg dialog + + +CTickerDlg::CTickerDlg(CWnd* pParent /*=NULL*/) + : CDialog(CTickerDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTickerDlg) + m_nUseTicker = FALSE; + m_nTickerDelay = 0; + //}}AFX_DATA_INIT +} + + +void CTickerDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTickerDlg) + DDX_Control(pDX, IDC_SPIN1, m_nSpinCtrl); + DDX_Check(pDX, IDC_TICKTOG, m_nUseTicker); + DDX_Text(pDX, IDC_EDIT1, m_nTickerDelay); + DDV_MinMaxLong(pDX, m_nTickerDelay, 0, 10000); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTickerDlg, CDialog) + //{{AFX_MSG_MAP(CTickerDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CTickerDlg message handlers + +BOOL CTickerDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + UDACCEL acc[3]; + + acc[0].nSec = 1; + acc[0].nInc = 2; + + acc[1].nSec = 2; + acc[1].nInc = 10; + + acc[2].nSec = 3; + acc[2].nInc = 50; + + m_nSpinCtrl.SetAccel(3, acc); + m_nSpinCtrl.SetRange(0, 1000); + + return TRUE; +} diff --git a/Toolkit/Programming/Tools/qMView/TickerDlg.h b/Toolkit/Programming/Tools/qMView/TickerDlg.h new file mode 100644 index 0000000..465e854 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/TickerDlg.h @@ -0,0 +1,48 @@ +#if !defined(AFX_TICKERDLG_H__4514B041_C559_11D1_82DF_0080C82BD965__INCLUDED_) +#define AFX_TICKERDLG_H__4514B041_C559_11D1_82DF_0080C82BD965__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// TickerDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CTickerDlg dialog + +class CTickerDlg : public CDialog +{ +// Construction +public: + CTickerDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CTickerDlg) + enum { IDD = IDD_TICKER }; + CSpinButtonCtrl m_nSpinCtrl; + BOOL m_nUseTicker; + long m_nTickerDelay; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTickerDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CTickerDlg) + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_TICKERDLG_H__4514B041_C559_11D1_82DF_0080C82BD965__INCLUDED_) diff --git a/Toolkit/Programming/Tools/qMView/TreeCtrlEx.cpp b/Toolkit/Programming/Tools/qMView/TreeCtrlEx.cpp new file mode 100644 index 0000000..ed1f409 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/TreeCtrlEx.cpp @@ -0,0 +1,593 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// CTreeCtrlEx - Multiple selection tree control (MFC 4.2) +// +// Bendik Engebretsen (c) 1997 +// bendik@techsoft.no +// http://www.techsoft.no/bendik/ +// +// Oct 9, 1997 : Fixed problem with notification to parent (TVN_BEGINDRAG) +// Oct 17, 1997 : Fixed bug with deselection when collapsing node with no sibling +// Nov 5, 1997 : Fixed problem with label editing +// Feb 17, 1998 : Fixed another notfication to parent (TVN_KEYDOWN) +// + +#include "stdafx.h" +#include "TreeCtrlEx.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTreeCtrlEx + +BEGIN_MESSAGE_MAP(CTreeCtrlEx, CTreeCtrl) + //{{AFX_MSG_MAP(CTreeCtrlEx) + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_MOUSEMOVE() + ON_WM_KEYDOWN() + ON_NOTIFY_REFLECT_EX(TVN_ITEMEXPANDING, OnItemexpanding) + ON_NOTIFY_REFLECT_EX(NM_SETFOCUS, OnSetfocus) + ON_NOTIFY_REFLECT_EX(NM_KILLFOCUS, OnKillfocus) + ON_WM_RBUTTONDOWN() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +IMPLEMENT_DYNAMIC(CTreeCtrlEx, CTreeCtrl) + +BOOL CTreeCtrlEx::Create(DWORD dwStyle, DWORD dwExStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) +{ + return CreateEx( dwExStyle, WC_TREEVIEW, NULL, dwStyle, + rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, + pParentWnd->GetSafeHwnd(), (HMENU)nID ); +} + +///////////////////////////////////////////////////////////////////////////// +// CTreeCtrlEx message handlers + + +/////////////////////////////////////////////////////////////////////////////// +// The tree control dosn't support multiple selection. However we can simulate +// it by taking control of the left mouse click and arrow key press before the +// control gets them, and setting/clearing the TVIS_SELECTED style on the items + +void CTreeCtrlEx::OnLButtonDown( UINT nFlags, CPoint point ) +{ + + UINT nHitFlags = 0; + HTREEITEM hClickedItem = HitTest( point, &nHitFlags ); + + // Must invoke label editing explicitly. The base class OnLButtonDown would normally + // do this, but we can't call it here because of the multiple selection... + if( nHitFlags & LVHT_ONITEMLABEL ) + if ( hClickedItem == GetSelectedItem() ) + { + EditLabel( hClickedItem ); + return; + } + + if( nHitFlags & LVHT_ONITEM ) + { + SetFocus(); + + m_hClickedItem = hClickedItem; + + // Is the clicked item already selected ? + BOOL bIsClickedItemSelected = GetItemState( hClickedItem, TVIS_SELECTED ) & TVIS_SELECTED; + + if ( bIsClickedItemSelected ) + { + // Maybe user wants to drag/drop multiple items! + // So, wait until OnLButtonUp() to do the selection stuff. + m_bSelectPending=TRUE; + m_ptClick=point; + } + else + { + SelectMultiple( hClickedItem, nFlags ); + m_bSelectPending=FALSE; + } + } + else + CTreeCtrl::OnLButtonDown( nFlags, point ); +} + +void CTreeCtrlEx::OnLButtonUp( UINT nFlags, CPoint point ) +{ + if ( m_bSelectPending ) + { + // A select has been waiting to be performed here + SelectMultiple( m_hClickedItem, nFlags ); + m_bSelectPending=FALSE; + } + + m_hClickedItem=NULL; + + CTreeCtrl::OnLButtonUp( nFlags, point ); +} + + +void CTreeCtrlEx::OnMouseMove( UINT nFlags, CPoint point ) +{ + // If there is a select pending, check if cursor has moved so much away from the + // down-click point that we should cancel the pending select and initiate + // a drag/drop operation instead! + + if ( m_hClickedItem ) + { + CSize sizeMoved = m_ptClick-point; + + if ( abs(sizeMoved.cx) > GetSystemMetrics( SM_CXDRAG ) || abs(sizeMoved.cy) > GetSystemMetrics( SM_CYDRAG ) ) + { + m_bSelectPending=FALSE; + + // Notify parent that he may begin drag operation + // Since we have taken over OnLButtonDown(), the default handler doesn't + // do the normal work when clicking an item, so we must provide our own + // TVN_BEGINDRAG notification for the parent! + + CWnd* pWnd = GetParent(); + if ( pWnd ) + { + NM_TREEVIEW tv; + + tv.hdr.hwndFrom = GetSafeHwnd(); + tv.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID ); + tv.hdr.code = TVN_BEGINDRAG; + + tv.itemNew.hItem = m_hClickedItem; + tv.itemNew.state = GetItemState( m_hClickedItem, 0xffffffff ); + tv.itemNew.lParam = GetItemData( m_hClickedItem ); + + tv.ptDrag.x = point.x; + tv.ptDrag.y = point.y; + + pWnd->SendMessage( WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv ); + } + + m_hClickedItem=NULL; + } + } + + CTreeCtrl::OnMouseMove( nFlags, point ); +} + + +void CTreeCtrlEx::SelectMultiple( HTREEITEM hClickedItem, UINT nFlags ) +{ + // Action depends on whether the user holds down the Shift or Ctrl key + if ( nFlags & MK_SHIFT ) + { + // Select from first selected item to the clicked item + if ( !m_hFirstSelectedItem ) + m_hFirstSelectedItem=GetSelectedItem(); + + SelectItems( m_hFirstSelectedItem, hClickedItem ); + } + else if ( nFlags & MK_CONTROL ) + { + // Find which item is currently selected + HTREEITEM hSelectedItem = GetSelectedItem(); + + // Is the clicked item already selected ? + BOOL bIsClickedItemSelected = GetItemState( hClickedItem, TVIS_SELECTED ) & TVIS_SELECTED; + BOOL bIsSelectedItemSelected = GetItemState( hSelectedItem, TVIS_SELECTED ) & TVIS_SELECTED; + + // Select the clicked item (this will also deselect the previous one!) + SelectItem( hClickedItem ); + + // If the previously selected item was selected, re-select it + if ( bIsSelectedItemSelected ) + SetItemState( hSelectedItem, TVIS_SELECTED, TVIS_SELECTED ); + + // We want the newly selected item to toggle its selected state, + // so unselect now if it was already selected before + if ( bIsClickedItemSelected ) + SetItemState( hClickedItem, 0, TVIS_SELECTED ); + else + SetItemState( hClickedItem, TVIS_SELECTED, TVIS_SELECTED ); + + // Store as first selected item (if not already stored) + if ( m_hFirstSelectedItem==NULL ) + m_hFirstSelectedItem = hClickedItem; + } + else + { + // Clear selection of all "multiple selected" items first + ClearSelection(); + + // Then select the clicked item + SelectItem( hClickedItem ); + SetItemState( hClickedItem, TVIS_SELECTED, TVIS_SELECTED ); + + // Store as first selected item + m_hFirstSelectedItem = hClickedItem; + } +} + +void CTreeCtrlEx::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags ) +{ + if ( nChar==VK_UP || nChar==VK_DOWN ) + { + if ( !( GetKeyState( VK_SHIFT )&0x8000 ) ) + { + // User pressed arrow key without holding 'Shift': + // Clear multiple selection and let base class do normal + // selection work! + ClearSelection( TRUE ); + CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags ); + return; + } + + // Find which item is currently selected + HTREEITEM hSelectedItem = GetSelectedItem(); + + HTREEITEM hNextItem; + if ( nChar==VK_UP ) + hNextItem = GetPrevVisibleItem( hSelectedItem ); + else + hNextItem = GetNextVisibleItem( hSelectedItem ); + + if ( hNextItem ) + { + // If the next item is already selected, we assume user is + // "moving back" in the selection, and thus we should clear + // selection on the previous one + BOOL bSelect = !( GetItemState( hNextItem, TVIS_SELECTED ) & TVIS_SELECTED ); + + // Select the next item (this will also deselect the previous one!) + SelectItem( hNextItem ); + + // Now, re-select the previously selected item + if ( bSelect ) + SetItemState( hSelectedItem, TVIS_SELECTED, TVIS_SELECTED ); + } + + // Notify parent that he may begin drag operation + // Since the base class' OnKeyDown() isn't called in this case, + // we must provide our own TVN_KEYDOWN notification to the parent + + CWnd* pWnd = GetParent(); + if ( pWnd ) + { + /*NM_KEYDOWN tvk; + + tvk.hdr.hwndFrom = GetSafeHwnd(); + tvk.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID ); + tvk.hdr.code = TVN_KEYDOWN; + + tvk.wVKey = nChar; + tvk.flags = 0;*/ + + pWnd->SendMessage( WM_NOTIFY, 0, TVN_KEYDOWN ); + } + } + else + // Behave normally + CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags ); +} + + +/////////////////////////////////////////////////////////////////////////////// +// I want clicking on an item with the right mouse button to select the item, +// but not if there is currently a multiple selection + +void CTreeCtrlEx::OnRButtonDown( UINT nFlags, CPoint point ) +{ + UINT nHitFlags = 0; + HTREEITEM hClickedItem = HitTest( point, &nHitFlags ); + + if( nHitFlags&LVHT_ONITEM ) + if ( GetSelectedCount()<2 ) + SelectItem( hClickedItem ); + + CTreeCtrl::OnRButtonDown( nFlags, point ); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Get number of selected items + +UINT CTreeCtrlEx::GetSelectedCount() const +{ + // Only visible items should be selected! + UINT uCount=0; + for ( HTREEITEM hItem = GetRootItem(); hItem!=NULL; hItem = GetNextVisibleItem( hItem ) ) + if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) + uCount++; + + return uCount; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Helpers to list out selected items. (Use similar to GetFirstVisibleItem(), +// GetNextVisibleItem() and GetPrevVisibleItem()!) + +HTREEITEM CTreeCtrlEx::GetFirstSelectedItem() +{ + for ( HTREEITEM hItem = GetRootItem(); hItem!=NULL; hItem = GetNextVisibleItem( hItem ) ) + if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) + return hItem; + + return NULL; +} + +HTREEITEM CTreeCtrlEx::GetNextSelectedItem( HTREEITEM hItem ) +{ + for ( hItem = GetNextVisibleItem( hItem ); hItem!=NULL; hItem = GetNextVisibleItem( hItem ) ) + if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) + return hItem; + + return NULL; +} + +HTREEITEM CTreeCtrlEx::GetPrevSelectedItem( HTREEITEM hItem ) +{ + for ( hItem = GetPrevVisibleItem( hItem ); hItem!=NULL; hItem = GetPrevVisibleItem( hItem ) ) + if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) + return hItem; + + return NULL; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Select/unselect item without unselecting other items + +BOOL CTreeCtrlEx::SelectItemEx(HTREEITEM hItem, BOOL bSelect/*=TRUE*/) +{ + HTREEITEM hSelItem = GetSelectedItem(); + + if ( hItem==hSelItem ) + { + if ( !bSelect ) + { + SelectItem(NULL); + return TRUE; + } + + return FALSE; + } + + SelectItem( hItem ); + m_hFirstSelectedItem=hItem; + + // Reselect previous "real" selected item which was unselected byt SelectItem() + if ( hSelItem ) + SetItemState( hSelItem, TVIS_SELECTED, TVIS_SELECTED ); + + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// Select visible items between specified 'from' and 'to' item (including these!) +// If the 'to' item is above the 'from' item, it traverses the tree in reverse +// direction. Selection on other items is cleared! + +BOOL CTreeCtrlEx::SelectItems( HTREEITEM hFromItem, HTREEITEM hToItem ) +{ + // Determine direction of selection + // (see what item comes first in the tree) + HTREEITEM hItem = GetRootItem(); + + while ( hItem && hItem!=hFromItem && hItem!=hToItem ) + hItem = GetNextVisibleItem( hItem ); + + if ( !hItem ) + return FALSE; // Items not visible in tree + + BOOL bReverse = hItem==hToItem; + + // "Really" select the 'to' item (which will deselect + // the previously selected item) + + SelectItem( hToItem ); + + // Go through all visible items again and select/unselect + + hItem = GetRootItem(); + BOOL bSelect = FALSE; + + while ( hItem ) + { + if ( hItem == ( bReverse ? hToItem : hFromItem ) ) + bSelect = TRUE; + + if ( bSelect ) + { + if ( !( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) ) + SetItemState( hItem, TVIS_SELECTED, TVIS_SELECTED ); + } + else + { + if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) + SetItemState( hItem, 0, TVIS_SELECTED ); + } + + if ( hItem == ( bReverse ? hFromItem : hToItem ) ) + bSelect = FALSE; + + hItem = GetNextVisibleItem( hItem ); + } + + return TRUE; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Clear selected state on all visible items + +void CTreeCtrlEx::ClearSelection(BOOL bMultiOnly/*=FALSE*/) +{ + if ( !bMultiOnly ) + SelectItem( NULL ); + + for ( HTREEITEM hItem=GetRootItem(); hItem!=NULL; hItem=GetNextVisibleItem( hItem ) ) + if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) + SetItemState( hItem, 0, TVIS_SELECTED ); +} + + +/////////////////////////////////////////////////////////////////////////////// +// If a node is collapsed, we should clear selections of its child items + +BOOL CTreeCtrlEx::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; + + if ( pNMTreeView->action == TVE_COLLAPSE ) + { + HTREEITEM hItem = GetChildItem( pNMTreeView->itemNew.hItem ); + + while ( hItem ) + { + if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) + SetItemState( hItem, 0, TVIS_SELECTED ); + + // Get the next node: First see if current node has a child + HTREEITEM hNextItem = GetChildItem( hItem ); + if ( !hNextItem ) + { + // No child: Get next sibling item + if ( !( hNextItem = GetNextSiblingItem( hItem ) ) ) + { + HTREEITEM hParentItem = hItem; + while ( !hNextItem ) + { + // No more children: Get parent + if ( !( hParentItem = GetParentItem( hParentItem ) ) ) + break; + + // Quit when parent is the collapsed node + // (Don't do anything to siblings of this) + if ( hParentItem == pNMTreeView->itemNew.hItem ) + break; + + // Get next sibling to parent + hNextItem = GetNextSiblingItem( hParentItem ); + } + + // Quit when parent is the collapsed node + if ( hParentItem == pNMTreeView->itemNew.hItem ) + break; + } + } + + hItem = hNextItem; + } + } + + *pResult = 0; + return FALSE; // Allow parent to handle this notification as well +} + + +/////////////////////////////////////////////////////////////////////////////// +// Ensure the multiple selected items are drawn correctly when loosing/getting +// the focus + +BOOL CTreeCtrlEx::OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult) +{ + Invalidate(); + *pResult = 0; + return FALSE; +} + +BOOL CTreeCtrlEx::OnKillfocus(NMHDR* pNMHDR, LRESULT* pResult) +{ + Invalidate(); + *pResult = 0; + return FALSE; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Retreives a tree ctrl item given the item's data + +HTREEITEM CTreeCtrlEx::ItemFromData(DWORD dwData, HTREEITEM hStartAtItem/*=NULL*/) const +{ + // Traverse all items in tree control + HTREEITEM hItem; + if ( hStartAtItem ) + hItem = hStartAtItem; + else + hItem = GetRootItem(); + + while ( hItem ) + { + if ( dwData == (DWORD)GetItemData( hItem ) ) + return hItem; + + // Get first child node + HTREEITEM hNextItem = GetChildItem( hItem ); + + if ( !hNextItem ) + { + // Get next sibling child + hNextItem = GetNextSiblingItem( hItem ); + + if ( !hNextItem ) + { + HTREEITEM hParentItem=hItem; + while ( !hNextItem && hParentItem ) + { + // No more children: Get next sibling to parent + hParentItem = GetParentItem( hParentItem ); + hNextItem = GetNextSiblingItem( hParentItem ); + } + } + } + + hItem = hNextItem; + } + + return NULL; +} + + +///////////////////////////////////////////////////////////////////////////// +// Global function to retreive a HTREEITEM from a tree control, given the +// item's itemdata. + +HTREEITEM GetTreeItemFromData(CTreeCtrl& treeCtrl, DWORD dwData, HTREEITEM hStartAtItem /*=NULL*/) +{ + // Traverse from given item (or all items if hFromItem is NULL) + HTREEITEM hItem; + if ( hStartAtItem ) + hItem=hStartAtItem; + else + hItem = treeCtrl.GetRootItem(); + + while ( hItem ) + { + if ( dwData == (DWORD)treeCtrl.GetItemData( hItem ) ) + return hItem; + + // Get first child node + HTREEITEM hNextItem = treeCtrl.GetChildItem( hItem ); + + if ( !hNextItem ) + { + // Get next sibling child + hNextItem = treeCtrl.GetNextSiblingItem( hItem ); + + if ( !hNextItem ) + { + HTREEITEM hParentItem=hItem; + while ( !hNextItem && hParentItem ) + { + // No more children: Get next sibling to parent + hParentItem = treeCtrl.GetParentItem( hParentItem ); + hNextItem = treeCtrl.GetNextSiblingItem( hParentItem ); + } + } + } + hItem = hNextItem; + } + return NULL; +} diff --git a/Toolkit/Programming/Tools/qMView/Vector.h b/Toolkit/Programming/Tools/qMView/Vector.h new file mode 100644 index 0000000..7585108 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/Vector.h @@ -0,0 +1,81 @@ +typedef float vec3a_t[3]; +typedef double vec3d_t[3]; + +// angle indexes +#define PITCH 0 // up / down +#define YAW 1 // left / right +#define ROLL 2 // fall over + +void DirAndUpFromAngles(vec3a_t angles, vec3a_t direction, vec3a_t up); +void AnglesFromDir(vec3a_t direction, vec3a_t angles); +void AnglesFromDirAndUp(vec3a_t direction, vec3a_t up, vec3a_t angles); + +_inline void Vec3SubtractAssign(vec3a_t value, vec3a_t subFrom) +{ + subFrom[0] -= value[0]; + subFrom[1] -= value[1]; + subFrom[2] -= value[2]; +} + +_inline void Vec3AddAssign(vec3a_t value, vec3a_t addTo) +{ + addTo[0] += value[0]; + addTo[1] += value[1]; + addTo[2] += value[2]; +} + +_inline float Vec3DotProduct(vec3a_t v1, vec3a_t v2) +{ + return (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]); +} + +_inline float Vec3Normalize(vec3a_t v1) +{ + float mag; + float imag = 1; + + mag = Vec3DotProduct(v1, v1); + + if(!mag) + { + return 0; + } + + mag = (float)sqrt(mag); + + imag /= mag; + + v1[0] *= imag; + v1[1] *= imag; + v1[2] *= imag; + + return mag; +} + +_inline double Vec3dDotProduct(vec3d_t v1, vec3d_t v2) +{ + return (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]); +} + +_inline double Vec3dNormalize(vec3d_t v1) +{ + double mag; + double imag = 1; + + mag = Vec3dDotProduct(v1, v1); + + if(!mag) + { + return 0; + } + + mag = (float)sqrt(mag); + + imag /= mag; + + v1[0] *= imag; + v1[1] *= imag; + v1[2] *= imag; + + return mag; +} \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qMView/d3dglobal.h b/Toolkit/Programming/Tools/qMView/d3dglobal.h new file mode 100644 index 0000000..5b9216f --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/d3dglobal.h @@ -0,0 +1,137 @@ +#ifndef __D3DGLOBAL__ +#define __D3DGLOBAL__ + +#define PI 3.141592654 + +#define ANIM_FORWARD 0 +#define ANIM_BACKWARD 1 +#define ANIM_PINGPONG 2 +#define ANIM_PUNCH 3 + +#define PALTYPE_RAW 0 +#define PALTYPE_PCX 1 +#define PALTYPE_JASC 2 +#define PALTYPE_MS 3 +#define PALTYPE_BMP 4 + +#define PAL_QUAKE 0 +#define PAL_QUAKE2 1 +#define PAL_HEXEN2 2 +#define PAL_FROMFILE 3 + +typedef unsigned char u_char; + +typedef float scalar_t; +typedef BOOL qboolean; + +typedef struct +{ + scalar_t x; + scalar_t y; + scalar_t z; +} vec3_t; + +typedef struct +{ + scalar_t x; + scalar_t y; + scalar_t z; + scalar_t s; + scalar_t t; +} vec5_t; + +extern LPDIRECTDRAW lpDD; +//extern LPDIRECT3DRM2 d3drm2; +extern LPDIRECT3DRMFRAME scene; + +extern LPDIRECT3DRMMESH bBox; + +extern HTREEITEM master; +//unsigned int interOptions = 0; +extern double interThresh; +//UINT interCalcState = 0; +extern BOOL interNext; + +typedef struct +{ + HTREEITEM head; + int bFrame, eFrame; +} treehead_t; + +typedef struct +{ + char id[16]; +} framegroup_t; + +extern int playMode; + +//Multiple Selection Frame Structures + +typedef struct +{ + int frameIndex; + BOOL start, end; +} frameMember; + +typedef struct +{ + int numFrames; + int info; + frameMember *frames; +} frameStruct; + +extern frameStruct frameSels; +extern BOOL usePunch; + +extern BOOL PICK_ON; + +typedef struct +{ + unsigned char r; + unsigned char g; + unsigned char b; +} pal_t; + +typedef float vec_t[3]; + +typedef struct Placement_s +{ + vec_t origin; + vec_t direction; + vec_t up; +} Placement_t; + +typedef struct M_SkeletalJoint_s +{ + int children; // must be the first field + Placement_t model; // relative to the model, used for dynamic software rotation + Placement_t parent; // relative to the parent joint (or model in case of root joint), used for + // inverse kinematics + qboolean inUse; +} M_SkeletalJoint_t; + +typedef struct ArrayedListNode_s +{ + int data; + int next; + int inUse; +} ArrayedListNode_t; + +typedef struct ModelSkeleton_s +{ + M_SkeletalJoint_t rootJoint[8]; + ArrayedListNode_t rootNode[64]; +} ModelSkeleton_t; + +#define PAL_SIZE 256 + +typedef struct +{ + unsigned char r,g,b; +} paletteRGB_t; + +extern BOOL LSHFT_DN, ZOOM_ON, PICK_ON; + +#endif + +//__D3DGLOBAL__ \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qMView/flexmdl.cpp b/Toolkit/Programming/Tools/qMView/flexmdl.cpp new file mode 100644 index 0000000..a33f51f --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/flexmdl.cpp @@ -0,0 +1,1456 @@ +//Flex Model Loading / Handling routines + +#include "stdafx.h" +#include "qMView.h" + +#include "d3dGlobal.h" +#include "flex.h" +#include "mdl2.h" + +#include "FrameManager2.h" + +extern FrameManager2 m_wndFrameManager2; + +node_info_t node_info[MAX_FM_MESH_NODES]; +int numnodes; + +LPDIRECT3DRMMESH node_mesh[MAX_FM_MESH_NODES]; +LPDIRECT3DRMTEXTURE node_texture[MAX_FM_MESH_NODES]; + +char *buffer; +char *buf; + +fmdl_t fmodel; + +M_SkeletalCluster_t SkeletalClusters[256]; + + + +BOOL FM_LoadSkinFromFile(char *filename) +{ + FILE *in; + miptex_t mt; + DDSURFACEDESC ddsd; + BYTE *src; + BYTE *dest; + int curpos = 0; + int x,y; + int mx, my, tx, ty; + int pos; + BYTE r, g, b; + BYTE color; + long yofs, yofs2; + //pal_t *usepal; + HRESULT ddrval; + + mdl_p *model = &mainModel; + + if ((in = fopen(filename, "rb"))==NULL) + return FALSE; + + fread(&mt, sizeof(mt), 1, in); + + unsigned char *buf; + + if (useNodes && curNode > -1) + { + node_state[curNode].skin = (unsigned char *)malloc(mt.width[0]*mt.height[0]); + node_state[curNode].skinwidth = mt.width[0]; + node_state[curNode].skinheight = mt.height[0]; + + fseek(in, mt.offsets[0], SEEK_SET); + + fread(node_state[curNode].skin, mt.width[0]*mt.height[0], 1, in); + + buf = (BYTE *)node_state[curNode].skin; + } + else + { + model->skins = (skin_t *)malloc(sizeof(skin_t)); + if (model->skins==NULL) return Error("Could not allocate skin page"); + memset(model->skins,0,sizeof(skin_t)); + + model->skins[0].skin = (u_char **)malloc(sizeof(unsigned char *)); + if (model->skins[0].skin==NULL) return Error("Could not allocate skin page buffer"); + + model->skins[0].skin[0] = (u_char *)malloc(mt.width[0]*mt.height[0]); + if (model->skins[0].skin[0]==NULL) return Error("Could not do something"); + + fseek(in, mt.offsets[0], SEEK_SET); + + fread(*model->skins[0].skin, mt.width[0]*mt.height[0], 1, in); + + buf = model->skins->skin[0]; + } + + rtx = fmodel.header.skinwidth; + rty = fmodel.header.skinheight; + + fclose(in); + + if (lpDDSSkin) + { + lpDDSSkin->Release(); + lpDDSSkin = 0; + } + + if (texture) + { + texture->Release(); + texture = 0; + } + + mx = mt.width[0]; + my = mt.height[0]; + + tx = 256; + ty = 256; + + if (mx>512) { tx=1024;} + else if (mx>256){ tx=512; } + else if (mx>128){ tx=256; } + else if (mx>64) { tx=128; } + else if (mx>32) { tx=64; } + else if (mx>16) { tx=32; } + else if (mx>8) { tx=16; } + else if (mx>4) { tx=8; } + else if (mx>2) { tx=4; } + else if (mx>1) { tx=2; } + else Error("Bad texture width"); + + if (my>512) { ty=1024;} + else if (my>256){ ty=512; } + else if (my>128){ ty=256; } + else if (my>64) { ty=128; } + else if (my>32) { ty=64; } + else if (my>16) { ty=32; } + else if (my>8) { ty=16; } + else if (my>4) { ty=8; } + else if (my>2) { ty=4; } + else if (my>1) { ty=2; } + else Error("Bad texture height"); + + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + ddsd.dwWidth = tx; + ddsd.dwHeight = ty; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat); + ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; + ddsd.ddpfPixelFormat.dwRGBBitCount = 32; + ddsd.ddpfPixelFormat.dwRBitMask = 0xff0000; + ddsd.ddpfPixelFormat.dwGBitMask = 0xff00; + ddsd.ddpfPixelFormat.dwBBitMask = 0xff; + ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0; + + ddrval = lpDD->CreateSurface( &ddsd, &lpDDSSkin, NULL ); + if( ddrval != DD_OK ) + return Error("Fail on CreateSurface 1"); + + (BYTE *) src = (BYTE *)buf; + + ddsd.dwSize = sizeof(ddsd); + ddrval = lpDDSSkin->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + + (BYTE *) dest = (BYTE *)ddsd.lpSurface; + + if (ddrval == DD_OK) + { + for (y = 0; y < my; y++) + { + yofs = y * (ddsd.lPitch); + yofs2 = y * mx; + + for (x = 0; x < mx; x++) + { + color = (BYTE) src[x + yofs2]; + + r = mt.palette[color].r; + g = mt.palette[color].g; + b = mt.palette[color].b; + + pos = (x << 2) + yofs; + + dest[pos] = b; + dest[pos+1] = g; + dest[pos+2] = r; + dest[pos+3] = 0; + } + } + + lpDDSSkin->Unlock(NULL); + } + else + Error("No go"); + + if (useNodes && curNode > -1) + { + ddrval = d3drm->CreateTextureFromSurface(lpDDSSkin, &node_texture[curNode]); + if (ddrval != D3DRM_OK) + AfxMessageBox(TraceError(ddrval)); + } + else + { + ddrval = d3drm->CreateTextureFromSurface(lpDDSSkin, &texture); + if (ddrval != D3DRM_OK) + AfxMessageBox(TraceError(ddrval)); + } + + return true; +} + +qboolean fmLoadHeader(fmdl_t *fmodel, int version, int length, void *buffer) +{ + int i; + + void *foo = (void *)buf; + + if (version != FM_HEADER_VER) + return Error("Invalid header version for block\n"); + + for (i=0 ; iheader)[i] = LittleLong (((int *)buffer)[i]); + + if (fmodel->header.skinheight > MAX_LBM_HEIGHT) + return Error("Model has a skin taller than max LBM height\n"); + + if (fmodel->header.num_xyz <= 0) + return Error("Model has no verts\n"); + + if (fmodel->header.num_xyz > MAX_FM_VERTS) + return Error("Model has too many vertices\n"); + + if (fmodel->header.num_st <= 0) + return Error("Model has no st verts\n"); + + if (fmodel->header.num_tris <= 0) + return Error("Model has no tris\n"); + + if (fmodel->header.num_frames <= 0) + return Error("Model has no frames\n"); + + return true; +} + +qboolean fmLoadSkin(fmdl_t *fmodel, int version, int length, void *buffer) +{ + int size, i; + + if (version != FM_SKIN_VER) + { + //ri.Sys_Error (ERR_DROP, "invalid SKIN version for block %s: %d != %d\n", FM_SKIN_NAME, FM_SKIN_VER, version); + return false; + } + + size = MAX_FM_SKINNAME * fmodel->header.num_skins; + if (size != length) + { + //ri.Con_Printf (PRINT_ALL, "skin sizes do not match: %d != %d\n", length, size); + return false; + } + + fmodel->skin_names = (char *) malloc(size); + memcpy(fmodel->skin_names, buffer, size); + + for (i=0 ; iheader.num_skins ; i++) + { + /*if (!FM_LoadSkinFromFile(fmodel->skin_names)) + { + AfxMessageBox("Could not properly load skin file!\n"); + }*/ + + //mod->skins[i] = GL_FindImage ((char *)fmodel->skin_names + i*MAX_FM_SKINNAME, it_skin); + } + + return true; +} + + +qboolean fmLoadST(fmdl_t *fmodel, int version, int length, void *buffer) +{ + int i; + fmstvert_t *pinst, *poutst; + + if (version != FM_ST_VER) + { + //ri.Sys_Error (ERR_DROP, "invalid ST version for block %s: %d != %d\n", FM_ST_NAME, FM_ST_VER, version); + + return Error("Invalid ST version\n"); + } + + pinst = (fmstvert_t *) buffer; + poutst = fmodel->st_verts = (fmstvert_t *) malloc(sizeof(fmstvert_t) * fmodel->header.num_st); + + for (i=0 ; iheader.num_st ; i++) + { + poutst[i].s = LittleShort (pinst[i].s); + poutst[i].t = LittleShort (pinst[i].t); + } + + return true; +} + +qboolean fmLoadTris(fmdl_t *fmodel, int version, int length, void *buffer) +{ + int i,j; + fmtriangle_t *pintri, *pouttri; + + if (version != FM_TRI_VER) + { + //ri.Sys_Error (ERR_DROP, "invalid TRIS version for block %s: %d != %d\n", FM_TRI_NAME, FM_TRI_VER, version); + return false; + } + + pintri = (fmtriangle_t *) ((byte *)buffer); + pouttri = fmodel->tris = (fmtriangle_t *) malloc (sizeof(fmtriangle_t) * fmodel->header.num_tris); + + for (i=0 ; iheader.num_tris ; i++) + { + for (j=0 ; j<3 ; j++) + { + pouttri[i].index_xyz[j] = LittleShort(pintri[i].index_xyz[j]); + pouttri[i].index_st[j] = LittleShort(pintri[i].index_st[j]); + } + } + + return true; +} + +qboolean fmLoadFrames(fmdl_t *fmodel, int version, int length, void *buffer) +{ + int i,j; + fmaliasframe_t *pinframe, *poutframe; + + if (version != FM_FRAME_VER) + { + //ri.Sys_Error (ERR_DROP, "invalid FRAMES version for block %s: %d != %d\n", FM_FRAME_NAME, FM_FRAME_VER, version); + return false; + } + + fmodel->frames = (fmaliasframe_t *) malloc(fmodel->header.num_frames * fmodel->header.framesize); + + for (i=0 ; iheader.num_frames ; i++) + { + pinframe = (fmaliasframe_t *) ((byte *)buffer + i * fmodel->header.framesize); + poutframe = (fmaliasframe_t *) ((byte *)fmodel->frames + i * fmodel->header.framesize); + + memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name)); + for (j=0 ; j<3 ; j++) + { + poutframe->scale[j] = LittleFloat(pinframe->scale[j]); + poutframe->translate[j] = LittleFloat(pinframe->translate[j]); + } + // verts are all 8 bit, so no swapping needed + memcpy (poutframe->verts, pinframe->verts, fmodel->header.num_xyz*sizeof(fmtrivertx_t)); + } + + return true; +} + +qboolean fmLoadGLCmds(fmdl_t *fmodel, int version, int length, void *buffer) +{ + int i; + int *pincmd, *poutcmd; + + if (version != FM_GLCMDS_VER) + { + //ri.Sys_Error (ERR_DROP, "invalid GLCMDS version for block %s: %d != %d\n", FM_GLCMDS_NAME, FM_GLCMDS_VER, version); + return false; + } + + poutcmd = fmodel->glcmds = (int *) malloc(sizeof(int) * fmodel->header.num_glcmds); + pincmd = (int *) ((byte *)buffer); + for (i=0 ; iheader.num_glcmds ; i++) + poutcmd[i] = (pincmd[i]); + + return true; +} + +qboolean fmLoadMeshNodes(fmdl_t *fmodel, int version, int length, void *buffer) +{ + int i; + fmmeshnode_t *node; + + if (version != FM_MESH_VER) + { + //ri.Sys_Error (ERR_DROP, "invalid MESH version for block %s: %d != %d\n", FM_MESH_NAME, FM_MESH_VER, version); + return false; + } + + if (fmodel->header.num_mesh_nodes) + { + fmodel->mesh_nodes = (fmmeshnode_t *) malloc (sizeof(fmmeshnode_t) * fmodel->header.num_mesh_nodes); + + for(i=0,node = (fmmeshnode_t *)buffer;iheader.num_mesh_nodes;i++,node++) + { + memcpy(fmodel->mesh_nodes[i].tris, node->tris, sizeof(fmodel->mesh_nodes[i].tris)); + memcpy(fmodel->mesh_nodes[i].verts, node->verts, sizeof(fmodel->mesh_nodes[i].verts)); + fmodel->mesh_nodes[i].start_glcmds = LittleShort(node->start_glcmds); + fmodel->mesh_nodes[i].num_glcmds = LittleShort(node->num_glcmds); + } + } + + return true; +} + +qboolean fmLoadShortFrames(fmdl_t *fmodel, int version, int length, void *buffer) +{ + if (version != FM_SHORT_FRAME_VER) + { + //ri.Sys_Error (ERR_DROP, "invalid SHORTFRAMES version for block %s: %d != %d\n", FM_SHORT_FRAME_NAME, FM_SHORT_FRAME_VER, version); + return false; + } + + fmodel->frames=NULL; + fmodel->framenames=(char *) (fmodel->header.num_frames*FRAME_NAME_LEN); + memcpy(fmodel->framenames,buffer,fmodel->header.num_frames*FRAME_NAME_LEN); + return true; +} + +qboolean fmLoadNormal(fmdl_t *fmodel, int version, int length, void *buffer) +{ + if (version != FM_NORMAL_VER) + { + //ri.Sys_Error (ERR_DROP, "invalid NORMAL version for block %s: %d != %d\n", FM_NORMAL_NAME, FM_NORMAL_VER, version); + return false; + } + fmodel->lightnormalindex=(byte *)malloc(fmodel->header.num_xyz*sizeof(byte)); + memcpy(fmodel->lightnormalindex,buffer,fmodel->header.num_xyz*sizeof(byte)); + + return true; +} + +qboolean fmLoadComp(fmdl_t *fmodel, int version, int length, void *buff) +{ + fmgroup_t *g; + char *buffer; + + buffer= (char *)buff; + g=&fmodel->compdata; + + if (version != FM_COMP_VER) + { + //ri.Sys_Error (ERR_DROP, "invalid COMP version for block %s: %d != %d\n", FM_COMP_NAME, FM_COMP_VER, version); + return false; + } + + g->start_frame=LittleLong(*(int *)buffer); + buffer+=sizeof(int); + g->num_frames= LittleLong(*(int *)buffer); + buffer+=sizeof(int); + g->degrees=LittleLong(*(int *)buffer); + buffer+=sizeof(int); + + g->mat= (char *)malloc(fmodel->header.num_xyz*3*g->degrees*sizeof(char)); + g->ccomp= (char *)malloc(g->num_frames*g->degrees*sizeof(char)); + g->cbase= (unsigned char*)malloc(fmodel->header.num_xyz*3*sizeof(unsigned char)); + g->cscale= (float *)malloc(g->degrees*sizeof(float)); + g->coffset= (float *)malloc(g->degrees*sizeof(float)); + g->complerp=(float *)malloc(g->degrees*sizeof(float)); + + memcpy(g->mat,buffer,fmodel->header.num_xyz*3*g->degrees*sizeof(char)); + buffer+=fmodel->header.num_xyz*3*g->degrees*sizeof(char); + memcpy(g->ccomp,buffer,g->num_frames*g->degrees*sizeof(char)); + buffer+=g->num_frames*g->degrees*sizeof(char); + memcpy(g->cbase,buffer,fmodel->header.num_xyz*3*sizeof(unsigned char)); + buffer+=fmodel->header.num_xyz*3*sizeof(unsigned char); + memcpy(g->cscale,buffer,g->degrees*sizeof(float)); + buffer+=g->degrees*sizeof(float); + memcpy(g->coffset,buffer,g->degrees*sizeof(float)); + buffer+=g->degrees*sizeof(float); + memcpy(g->trans,buffer,3*sizeof(float)); + buffer+=3*sizeof(float); + memcpy(g->scale,buffer,3*sizeof(float)); + buffer+=3*sizeof(float); + memcpy(g->bmin,buffer,3*sizeof(float)); + buffer+=3*sizeof(float); + memcpy(g->bmax,buffer,3*sizeof(float)); + buffer+=3*sizeof(float); + + return true; +} + +qboolean fmLoadSkeleton(fmdl_t *fmodel, int version, int length, void *buffer) +{ + int i, j, k; + int *basei; + int numClusters, runningTotalVertices = 0; + int indexBase = 0; + float *basef; + + if (version != FM_SKELETON_VER) + { + //ri.Con_Printf (PRINT_ALL, "invalid SKELETON version for block %s: %d != %d\n", FM_SKELETON_NAME, FM_SKELETON_VER, version); + return false; + } + + basei = (int *)buffer; + + fmodel->skeletalType = *basei; + +//FIXME!!! fmodel->rootCluster = CreateSkeleton(fmodel->skeletalType); + + numClusters = *(++basei); + + for(i = numClusters - 1; i >= 0; --i) + { + runningTotalVertices += *(++basei); + SkeletalClusters[fmodel->rootCluster + i].numVerticies = runningTotalVertices; + SkeletalClusters[fmodel->rootCluster + i].verticies = (int*)malloc(SkeletalClusters[fmodel->rootCluster + i].numVerticies*sizeof(int)); + } + + for(j = numClusters - 1; j >= 0; --j) + { + for(i = indexBase; i < SkeletalClusters[fmodel->rootCluster + j].numVerticies; ++i) + { + ++basei; + + for(k = 0; k <= j; ++ k) + { + SkeletalClusters[fmodel->rootCluster + k].verticies[i] = *basei; + } + } + + indexBase = SkeletalClusters[fmodel->rootCluster + j].numVerticies; + } + + for(i = 0; i < numClusters; ++i) + { + for(j = 0; j < SkeletalClusters[fmodel->rootCluster + i].numVerticies; ++j) + { + int index; + index = SkeletalClusters[fmodel->rootCluster + i].verticies[j]; + + for(k = j+1; k < SkeletalClusters[fmodel->rootCluster + i].numVerticies; ++k) + { +// assert(index != SkeletalClusters[fmodel->rootCluster + i].verticies[k]); + if(index == SkeletalClusters[fmodel->rootCluster + i].verticies[k]) + { + AfxMessageBox("Warning duplicate vertex\n"); + } + // duplicate vertex in cluster vertex list + } + } + } + + if(*(++basei)) + { + basef = (float *)++basei; + + fmodel->skeletons = (ModelSkeleton_t*) malloc(fmodel->header.num_frames*sizeof(ModelSkeleton_t)); + + for (i = 0; i < fmodel->header.num_frames; ++i) + { + //CreateSkeletonAsHunk(fmodel->skeletalType, fmodel->skeletons + i); + + for(j = 0; j < numClusters; ++j) + { + fmodel->skeletons[i].rootJoint[j].model.origin[0] = *(basef++); + fmodel->skeletons[i].rootJoint[j].model.origin[1] = *(basef++); + fmodel->skeletons[i].rootJoint[j].model.origin[2] = *(basef++); + + fmodel->skeletons[i].rootJoint[j].model.direction[0] = *(basef++); + fmodel->skeletons[i].rootJoint[j].model.direction[1] = *(basef++); + fmodel->skeletons[i].rootJoint[j].model.direction[2] = *(basef++); + + fmodel->skeletons[i].rootJoint[j].model.up[0] = *(basef++); + fmodel->skeletons[i].rootJoint[j].model.up[1] = *(basef++); + fmodel->skeletons[i].rootJoint[j].model.up[2] = *(basef++); + } + } + } + else + { + fmodel->header.num_xyz -= numClusters*3; + } + + fmodel->jointed = true; + + return TRUE; +} + +qboolean fmLoadNull(fmdl_t *fmodel, int version, int length, void *buff) +{ + AfxMessageBox("Null\n"); + return true; +} + +fmblock_t fmblocks[] = +{ + { FM_HEADER_NAME, fmLoadHeader }, + { FM_SKIN_NAME, fmLoadSkin }, + { FM_ST_NAME, fmLoadST }, + { FM_TRI_NAME, fmLoadTris }, + { FM_FRAME_NAME , fmLoadFrames }, + { FM_GLCMDS_NAME, fmLoadGLCmds }, + { FM_MESH_NAME, fmLoadMeshNodes }, + { FM_SHORT_FRAME_NAME, fmLoadShortFrames }, + { FM_NORMAL_NAME, fmLoadNormal }, + { FM_COMP_NAME, fmLoadComp }, + { FM_SKELETON_NAME, fmLoadNull }, + { "", NULL} +}; + + +/* + * FM_ShowNodeFrame + * + * Shows the frame + * + */ + +BOOL FM_ShowNodeFrame(mdl_p *mdl, int frame, int nodeNum) +{ + D3DRMVERTEX *vertexlist; + vec5_t *vertlist; + vec5_t p1; + frameinfo2_t *frameinfo1; + long *command; + int i; + int curvert = 0; + int num_verts,vert_index; + int command_type; + int realvert = 0; + int cur_glcmnd; + BOOL ODD; + + fmdl_t *model = &mdl->flex; + + vertexlist = new D3DRMVERTEX[model->header.num_tris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*model->header.num_tris*3); + + frameinfo1 = (frameinfo2_t *)((char *)model->frames + model->header.framesize * curframe); + command = (long *)model->glcmds + model->mesh_nodes[nodeNum].start_glcmds; + + cur_glcmnd = model->mesh_nodes[nodeNum].num_glcmds; + + //do the gl commands + while (*command && cur_glcmnd) + { + cur_glcmnd--; + + ODD = TRUE; + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * model->header.skinwidth; command++; + p1.t = (*((float *)command)) * model->header.skinheight; command++; + + //grab the vertex index + vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[realvert] = p1; + realvert++; + } + } + + for (i = 0; i < node_info[nodeNum].numVerts; i++) + { + vertexlist[i].position.x = vertlist[node_info[nodeNum].vertPath[i]].x; + vertexlist[i].position.y = vertlist[node_info[nodeNum].vertPath[i]].y; + vertexlist[i].position.z = vertlist[node_info[nodeNum].vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[node_info[nodeNum].vertPath[i]].s) / rtx; + vertexlist[i].tv = D3DVALUE(vertlist[node_info[nodeNum].vertPath[i]].t) / rty; + } + + node_mesh[nodeNum]->SetVertices( group, 0, node_info[nodeNum].numVerts, vertexlist ); + + free(vertlist); + + delete (vertexlist); + + frameChanged = FALSE; + return TRUE; +} + +BOOL FM_ShowInterNodeFrame(mdl_p *model, int frame, int nextframe, int nodeNum, int step, int numsteps) +{ + D3DVECTOR delta; + int curvert = 0; + D3DRMVERTEX *vertexlist; + int lastframe, i; + vec5_t p1,p2; + frameinfo2_t *frameinfo1, *frameinfo2; + long *command; + int num_verts,vert_index; + int command_type; + vec5_t *vertlist; + BOOL ODD; + int realvert = 0; + + lastframe = nextframe; + curframe = frame; + + vertexlist = new D3DRMVERTEX[model->flex.header.num_tris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*model->flex.header.num_tris*3); + + frameinfo1 = (frameinfo2_t *)((char *)model->flex.frames + model->flex.header.framesize * curframe); + frameinfo2 = (frameinfo2_t *)((char *)model->flex.frames + model->flex.header.framesize * lastframe); + + if (useNodes) + command = (long *)model->flex.glcmds + model->flex.mesh_nodes[nodeNum].start_glcmds; + else + command = (long *)model->flex.glcmds; + + int cur_glcmnd; + + if (useNodes) + cur_glcmnd = model->flex.mesh_nodes[nodeNum].num_glcmds; + else + cur_glcmnd = 1; + + //do the gl commands + while (*command && (!useNodes || cur_glcmnd)) + { + cur_glcmnd--; + + ODD = TRUE; + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * model->flex.header.skinwidth; command++; + p1.t = (*((float *)command)) * model->flex.header.skinheight; command++; + + //grab the vertex index + vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + p2.z = -((frameinfo2->verts[vert_index].x * frameinfo2->scale.x) + frameinfo2->origin.x); + p2.y = ((frameinfo2->verts[vert_index].y * frameinfo2->scale.y) + frameinfo2->origin.y); + p2.x = -((frameinfo2->verts[vert_index].z * frameinfo2->scale.z) + frameinfo2->origin.z); + + delta.x = (p2.x - p1.x) / numsteps; + delta.y = (p2.y - p1.y) / numsteps; + delta.z = (p2.z - p1.z) / numsteps; + + p1.x += delta.x * step; + p1.y += delta.y * step; + p1.z += delta.z * step; + + vertlist[realvert] = p1; + realvert++; + } + } + + if (useNodes) + { + for (i = 0; i < node_info[nodeNum].numVerts; i++) + { + vertexlist[i].position.x = vertlist[node_info[nodeNum].vertPath[i]].x; + vertexlist[i].position.y = vertlist[node_info[nodeNum].vertPath[i]].y; + vertexlist[i].position.z = vertlist[node_info[nodeNum].vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[node_info[nodeNum].vertPath[i]].s) / rtx; + vertexlist[i].tv = D3DVALUE(vertlist[node_info[nodeNum].vertPath[i]].t) / rty; + } + } + else + { + for (i = 0; i < model->flex.header.num_tris*3; i++) + { + vertexlist[i].position.x = vertlist[vertPath[i]].x; + vertexlist[i].position.y = vertlist[vertPath[i]].y; + vertexlist[i].position.z = vertlist[vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[vertPath[i]].s) / rtx; + vertexlist[i].tv = D3DVALUE(vertlist[vertPath[i]].t) / rty; + } + } + + if (useNodes) + node_mesh[nodeNum]->SetVertices( group, 0, node_info[nodeNum].numVerts, vertexlist ); + else + mesh->SetVertices( group, 0, model->flex.header.num_tris*3, vertexlist ); + + free(vertlist); + + delete (vertexlist); + + return true; +} + +/* + * FM_ShowNode + * + * Creates one node mesh and displays the node + * + */ + +BOOL FM_ShowNode(fmdl_t *mdl, int nodeNum) +{ + BOOL ODD = FALSE; + HRESULT ddrval; + D3DRMVERTEX *vertexlist; + unsigned *vertorder; + unsigned numread = 0; + + int i,j,x; + vec5_t p1; + frameinfo2_t *frameinfo1; + long *command; + int num_verts,vert_index; + int command_type; + vec5_t *vertlist; + D3DVECTOR p[3], n1, n2, n3; + BOOL skin_ok = FALSE; + int realvert = 0, realTris = 0; + + curNode = nodeNum; + + FM_LoadSkinFromFile("!skin.m8"); + + vertexlist = new D3DRMVERTEX[mdl->header.num_tris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + + int curvert; + + curvert=0; + + d3drm->CreateMesh( &node_mesh[nodeNum] ); + + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*mdl->header.num_tris*3); + + node_info[nodeNum].vertPath = new int[mdl->header.num_tris*3]; + + frameinfo1 = (frameinfo2_t *)((char *)mdl->frames); + command = (long *)mdl->glcmds + mdl->mesh_nodes[nodeNum].start_glcmds; + + int cur_glcmnd = mdl->mesh_nodes[nodeNum].num_glcmds; + + //do the gl commands + while (*command && cur_glcmnd) + { + cur_glcmnd--; + + ODD = TRUE; + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * mdl->header.skinwidth; command++; + p1.t = (*((float *)command)) * mdl->header.skinheight; command++; + + //grab the vertex index + vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[i] = p1; + } + + switch (command_type) + { + case 0: + //tristrip + for (i=0;i -1; j--) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / rtx; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / rty; + node_info[nodeNum].vertPath[curvert] = realvert+i+j; + curvert++; + } + realTris++; + ODD = FALSE; + } + else + { + for (j = 0; j < 3; j++) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / rtx; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / rty; + node_info[nodeNum].vertPath[curvert] = realvert+i+j; + curvert++; + } + realTris++; + ODD = TRUE; + } + } + break; + + case 1: + //trifan + for (i=0;i -1; j--) + { + if (j == 0) + x = 0; + else + x = i; + + p[j].x = vertlist[x+j].x; + p[j].y = vertlist[x+j].y; + p[j].z = vertlist[x+j].z; + } + + D3DRMVectorSubtract(&n1, &p[1], &p[0]); + D3DRMVectorSubtract(&n2, &p[2], &p[1]); + + D3DRMVectorCrossProduct(&n3, &n1, &n2); + D3DRMVectorNormalize(&n3); + + for (j = 2; j > -1; j--) + { + if (j == 0) + x = 0; + else + x = i; + + vertexlist[curvert].position.x = vertlist[x+j].x; + vertexlist[curvert].position.y = vertlist[x+j].y; + vertexlist[curvert].position.z = vertlist[x+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[x+j].s) / rtx; + vertexlist[curvert].tv = D3DVALUE(vertlist[x+j].t) / rty; + node_info[nodeNum].vertPath[curvert] = realvert+x+j; + curvert++; + } + realTris++; + } + break; + } + + realvert += num_verts; + } + + int tempvert = curvert; + + vertorder = new unsigned[curvert]; + if (vertorder == NULL) + return Error("Cannot make vertorder"); + + for (i = 0; i < (curvert); i++) + { + tempvert--; + vertorder[i] = tempvert; + } + + node_info[nodeNum].numTris = realTris; + node_info[nodeNum].numVerts = curvert; + + node_mesh[nodeNum]->AddGroup( curvert, realTris, 3, vertorder, &group ); + node_mesh[nodeNum]->SetVertices( group, 0, curvert, vertexlist ); + + node_mesh[nodeNum]->SetGroupTexture( group, node_texture[nodeNum]); + node_mesh[nodeNum]->SetGroupMapping( group, D3DRMMAP_PERSPCORRECT ); + + node_mesh[nodeNum]->SetGroupQuality( group, D3DRMRENDER_FLAT ); + + ddrval = frame->AddVisual( node_mesh[nodeNum] ); + if (ddrval != D3DRM_OK) + return Error(TraceError(ddrval)); + + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) ); + + if (vertexlist) delete vertexlist; + if (vertorder) delete vertorder; + if (vertlist) free(vertlist); + + return true; +} + +/* + * FM_Show + * + * Creates the mesh and displays the Flex model + * + */ + +BOOL FM_Show(fmdl_t *mdl) +{ + BOOL ODD = FALSE; + HRESULT ddrval; + D3DRMVERTEX *vertexlist; + unsigned *vertorder; + unsigned numread = 0; + + int i,j,x; + vec5_t p1; + frameinfo2_t *frameinfo1; + long *command; + int num_verts,vert_index; + int command_type; + vec5_t *vertlist; + D3DVECTOR p[3], n1, n2, n3; + BOOL skin_ok = FALSE; + int realvert = 0; + + FM_LoadSkinFromFile("!skin.m8"); + + vertexlist = new D3DRMVERTEX[mdl->header.num_tris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + + vertPath = new int[mdl->header.num_tris*3+1]; + + int curvert = mdl->header.num_tris * 3; + + vertorder = new unsigned[mdl->header.num_tris*3+1]; + if (vertorder == NULL) + return Error("Cannot make vertorder"); + + for (i = 0; i < (mdl->header.num_tris * 3); i++) + { + curvert--; + vertorder[i] = curvert; + } + + curvert=0; + + d3drm->CreateMesh( &mesh ); + + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*mdl->header.num_tris*3); + + frameinfo1 = (frameinfo2_t *)((char *)mdl->frames); + command = (long *)mdl->glcmds; + + //do the gl commands + while (*command) + { + ODD = TRUE; + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * mdl->header.skinwidth; command++; + p1.t = (*((float *)command)) * mdl->header.skinheight; command++; + + //grab the vertex index + vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[i] = p1; + } + + switch (command_type) + { + case 0: + //tristrip + for (i=0;i -1; j--) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / rtx; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / rty; + vertexlist[curvert].color = D3DCOLOR(2); + vertPath[curvert] = realvert+i+j; + curvert++; + } + ODD = FALSE; + } + else + { + for (j = 0; j < 3; j++) + { + vertexlist[curvert].position.x = vertlist[i+j].x; + vertexlist[curvert].position.y = vertlist[i+j].y; + vertexlist[curvert].position.z = vertlist[i+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[i+j].s) / rtx; + vertexlist[curvert].tv = D3DVALUE(vertlist[i+j].t) / rty; + vertexlist[curvert].color = D3DCOLOR(2); + vertPath[curvert] = realvert+i+j; + curvert++; + } + ODD = TRUE; + } + } + break; + + case 1: + //trifan + for (i=0;i -1; j--) + { + if (j == 0) + x = 0; + else + x = i; + + p[j].x = vertlist[x+j].x; + p[j].y = vertlist[x+j].y; + p[j].z = vertlist[x+j].z; + } + + D3DRMVectorSubtract(&n1, &p[1], &p[0]); + D3DRMVectorSubtract(&n2, &p[2], &p[1]); + + D3DRMVectorCrossProduct(&n3, &n1, &n2); + D3DRMVectorNormalize(&n3); + + for (j = 2; j > -1; j--) + { + if (j == 0) + x = 0; + else + x = i; + + vertexlist[curvert].position.x = vertlist[x+j].x; + vertexlist[curvert].position.y = vertlist[x+j].y; + vertexlist[curvert].position.z = vertlist[x+j].z; + vertexlist[curvert].tu = D3DVALUE(vertlist[x+j].s) / rtx; + vertexlist[curvert].tv = D3DVALUE(vertlist[x+j].t) / rty; + vertexlist[curvert].color = D3DCOLOR(2); + vertPath[curvert] = realvert+x+j; + curvert++; + } + } + break; + } + realvert += num_verts; + } + + mesh->AddGroup( mdl->header.num_tris * 3, mdl->header.num_tris, 3, vertorder, &group ); + mesh->SetVertices( group, 0, mdl->header.num_tris * 3, vertexlist ); + + mesh->SetGroupTexture( group, texture ); + mesh->SetGroupMapping( group, D3DRMMAP_PERSPCORRECT ); + mesh->SetGroupQuality( group, D3DRMRENDER_FLAT ); + + ddrval = frame->AddVisual( mesh ); + if (ddrval != D3DRM_OK) + return Error(TraceError(ddrval)); + + frame->SetOrientation( scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1), + D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) ); + + if (vertexlist) delete vertexlist; + if (vertorder) delete vertorder; + if (vertlist) free(vertlist); + + return true; +} + +/* + * FM_ShowFrame + * + * Shows the frame + * + */ + +BOOL FM_ShowFrame(mdl_p *mdl, int frame) +{ + int curvert = 0; + D3DRMVERTEX *vertexlist; + vec5_t *vertlist; + int i; + vec5_t p1; + frameinfo2_t *frameinfo1; + long *command; + int num_verts,vert_index; + int command_type; + BOOL ODD; + + fmdl_t *model = &mdl->flex; + + if (useNodes) + { + for (i = 1; i < numnodes; i++) + { + FM_ShowNodeFrame(mdl, frame, i); + } + + return true; + } + + vertexlist = new D3DRMVERTEX[model->header.num_tris*3+1]; + if (vertexlist == NULL) + return Error("Cannot make vertexlist"); + + vertlist = (vec5_t *)malloc(sizeof(vec5_t)*model->header.num_tris*3); + + frameinfo1 = (frameinfo2_t *)((char *)model->frames + model->header.framesize * curframe); + command = (long *)model->glcmds; + + //do the gl commands + while (*command) + { + ODD = TRUE; + if (*command>0) + { + //triangle strip + num_verts = *command; + command_type = 0; + } + else + { + //triangle fan + num_verts = -(*command); + command_type = 1; + } + + command++; + + for (i=0; i < num_verts; i++) + { + //grab the floating point s and t + p1.s = (*((float *)command)) * model->header.skinwidth; command++; + p1.t = (*((float *)command)) * model->header.skinheight; command++; + + //grab the vertex index + vert_index = *command; command++; + + p1.z = -((frameinfo1->verts[vert_index].x * frameinfo1->scale.x) + frameinfo1->origin.x); + p1.y = ((frameinfo1->verts[vert_index].y * frameinfo1->scale.y) + frameinfo1->origin.y); + p1.x = -((frameinfo1->verts[vert_index].z * frameinfo1->scale.z) + frameinfo1->origin.z); + + vertlist[curvert] = p1; + curvert++; + } + } + + for (i = 0; i < model->header.num_tris*3; i++) + { + vertexlist[i].position.x = vertlist[vertPath[i]].x; + vertexlist[i].position.y = vertlist[vertPath[i]].y; + vertexlist[i].position.z = vertlist[vertPath[i]].z; + vertexlist[i].tu = D3DVALUE(vertlist[vertPath[i]].s) / rtx; + vertexlist[i].tv = D3DVALUE(vertlist[vertPath[i]].t) / rty; + } + + mesh->SetVertices( group, 0, model->header.num_tris*3, vertexlist ); + + free(vertlist); + + delete (vertexlist); + + frameChanged = FALSE; + return TRUE; +} + +void FM_AddNode (int nodeNum) +{ + CString foo; + LPSTR foostr; + CTreeCtrl *pCTree = (CTreeCtrl*)m_wndFrameManager2.GetDlgItem(IDC_NODETREE); + + foo.Format("Node %d", nodeNum); + + foostr = foo.GetBuffer(10); + + HTREEITEM point = pCTree->InsertItem(foo, rootNode, TVI_LAST); + + nodes[nodeNum] = point; + + pCTree->SetItemImage(point, 1, 1); + + pCTree->Expand(rootNode, TVE_EXPAND); +} + +BOOL FM_LoadFromFile(char *filename) +{ + FILE *infile; + long filesize; + mdl_p *mdl = &mainModel; + + int i=0; + qboolean found; + fheader_t *block; + + curframe = 0; + curscale = -150; + curSkin = 0; + camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(curscale)); + + playing = FALSE; + + mainModel.modelType = MODEL_FLEX; + mainModelType = MODEL_FLEX; + palNum = PAL_FROMFILE; + + if ((infile = fopen(filename, "rb"))==NULL) return FALSE; + + fseek(infile, 0, SEEK_END); + filesize = ftell(infile); + fseek(infile, 0, SEEK_SET); + + //mainModel->header; + buffer = (char *) malloc(filesize); + + fread(buffer, filesize, 1, infile); + + while(filesize > 0) + { + block = (fheader_t *) buffer; + + for(i=0,found=false;fmblocks[i].ident[0];i++) + { + if (strcmpi(block->ident, fmblocks[i].ident)==0) + { + filesize -= sizeof(fheader_t); + buffer += sizeof(fheader_t); + + fmblocks[i].LoadBlock(&fmodel, block->version, block->size, buffer); + + found = true; + break; + } + } + + if (!found) + { + filesize -= sizeof(fheader_t); + buffer += sizeof(fheader_t); + + CString foo; + + foo.Format("Unknown block %s\n", block->ident); + AfxMessageBox(foo); + } + + filesize -= block->size; + buffer += block->size; + i=0; + } + + numframes = fmodel.header.num_frames; + numnodes = fmodel.header.num_mesh_nodes; + + fclose(infile); + + mainModel.flex = fmodel; + + if (fmodel.header.num_mesh_nodes > 1) + { + useNodes = true; + + node_state[0].visible = true; + node_state[0].hasSkin = false; + node_state[0].skinNum = 0; + + for (int i = 1; i < fmodel.header.num_mesh_nodes; i++) + { + node_state[i].visible = true; + node_state[i].skinNum = 0; + + FM_ShowNode(&fmodel, i); + FM_AddNode(i); + } + + curNode = -1; + } + else + FM_Show(&fmodel); + + return true; +} diff --git a/Toolkit/Programming/Tools/qMView/logo.BMP b/Toolkit/Programming/Tools/qMView/logo.BMP new file mode 100644 index 0000000..f06ac63 Binary files /dev/null and b/Toolkit/Programming/Tools/qMView/logo.BMP differ diff --git a/Toolkit/Programming/Tools/qMView/mdl2.h b/Toolkit/Programming/Tools/qMView/mdl2.h new file mode 100644 index 0000000..922fa2c --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/mdl2.h @@ -0,0 +1,22 @@ +//MDL2.H Header File + +char *TraceError(HRESULT ddrval); +BOOL Error(char *msg); + +BOOL MDL_Free( mdl_p *mdl ); +BOOL MDL_CalcInterpolate(mdl_p *model, int step, int numsteps, int intertype, int direction); +BOOL MDL_ShowFrame(mdl_p *model, int frame); +BOOL MDL_UpdateFrame(mdl_p *model, int direction); +BOOL MDL_LoadSkin(mdl_p *model, int skinnum); +BOOL MDL_LoadSkinFromPCX(char *filename, mdl_p *model); +BOOL MDL_Show(mdl_p *model); +BOOL MDL_LoadPaletteFromFile(char *filename, DWORD fileType); +BOOL MDL_LoadFromFile(char *filename); + +BOOL MDL2_Show(mdl_p *mdl); +BOOL MDL2_LoadFromFile(char *filename); + +BOOL FM_ShowNodeFrame(mdl_p *mdl, int frame, int nodeNum); +BOOL FM_LoadSkinFromFile(char *filename); +BOOL FM_ShowFrame(mdl_p *mdl, int frame); + diff --git a/Toolkit/Programming/Tools/qMView/pal.h b/Toolkit/Programming/Tools/qMView/pal.h new file mode 100644 index 0000000..d9cacc7 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/pal.h @@ -0,0 +1,521 @@ +#ifndef __PAL__ +#define __PAL__ + +pal_t qpal[] = { + 0,0,0, + 15,15,15, + 31,31,31, + 47,47,47, + 63,63,63, + 75,75,75, + 91,91,91, + 107,107,107, + 123,123,123, + 139,139,139, + 155,155,155, + 171,171,171, + 187,187,187, + 203,203,203, + 219,219,219, + 235,235,235, + 15,11,7, + 23,15,11, + 31,23,11, + 39,27,15, + 47,35,19, + 55,43,23, + 63,47,23, + 75,55,27, + 83,59,27, + 91,67,31, + 99,75,31, + 107,83,31, + 115,87,31, + 123,95,35, + 131,103,35, + 143,111,35, + 11,11,15, + 19,19,27, + 27,27,39, + 39,39,51, + 47,47,63, + 55,55,75, + 63,63,87, + 71,71,103, + 79,79,115, + 91,91,127, + 99,99,139, + 107,107,151, + 115,115,163, + 123,123,175, + 131,131,187, + 139,139,203, + 0,0,0, + 7,7,0, + 11,11,0, + 19,19,0, + 27,27,0, + 35,35,0, + 43,43,7, + 47,47,7, + 55,55,7, + 63,63,7, + 71,71,7, + 75,75,11, + 83,83,11, + 91,91,11, + 99,99,11, + 107,107,15, + 7,0,0, + 15,0,0, + 23,0,0, + 31,0,0, + 39,0,0, + 47,0,0, + 55,0,0, + 63,0,0, + 71,0,0, + 79,0,0, + 87,0,0, + 95,0,0, + 103,0,0, + 111,0,0, + 119,0,0, + 127,0,0, + 19,19,0, + 27,27,0, + 35,35,0, + 47,43,0, + 55,47,0, + 67,55,0, + 75,59,7, + 87,67,7, + 95,71,7, + 107,75,11, + 119,83,15, + 131,87,19, + 139,91,19, + 151,95,27, + 163,99,31, + 175,103,35, + 35,19,7, + 47,23,11, + 59,31,15, + 75,35,19, + 87,43,23, + 99,47,31, + 115,55,35, + 127,59,43, + 143,67,51, + 159,79,51, + 175,99,47, + 191,119,47, + 207,143,43, + 223,171,39, + 239,203,31, + 255,243,27, + 11,7,0, + 27,19,0, + 43,35,15, + 55,43,19, + 71,51,27, + 83,55,35, + 99,63,43, + 111,71,51, + 127,83,63, + 139,95,71, + 155,107,83, + 167,123,95, + 183,135,107, + 195,147,123, + 211,163,139, + 227,179,151, + 171,139,163, + 159,127,151, + 147,115,135, + 139,103,123, + 127,91,111, + 119,83,99, + 107,75,87, + 95,63,75, + 87,55,67, + 75,47,55, + 67,39,47, + 55,31,35, + 43,23,27, + 35,19,19, + 23,11,11, + 15,7,7, + 187,115,159, + 175,107,143, + 163,95,131, + 151,87,119, + 139,79,107, + 127,75,95, + 115,67,83, + 107,59,75, + 95,51,63, + 83,43,55, + 71,35,43, + 59,31,35, + 47,23,27, + 35,19,19, + 23,11,11, + 15,7,7, + 219,195,187, + 203,179,167, + 191,163,155, + 175,151,139, + 163,135,123, + 151,123,111, + 135,111,95, + 123,99,83, + 107,87,71, + 95,75,59, + 83,63,51, + 67,51,39, + 55,43,31, + 39,31,23, + 27,19,15, + 15,11,7, + 111,131,123, + 103,123,111, + 95,115,103, + 87,107,95, + 79,99,87, + 71,91,79, + 63,83,71, + 55,75,63, + 47,67,55, + 43,59,47, + 35,51,39, + 31,43,31, + 23,35,23, + 15,27,19, + 11,19,11, + 7,11,7, + 255,243,27, + 239,223,23, + 219,203,19, + 203,183,15, + 187,167,15, + 171,151,11, + 155,131,7, + 139,115,7, + 123,99,7, + 107,83,0, + 91,71,0, + 75,55,0, + 59,43,0, + 43,31,0, + 27,15,0, + 11,7,0, + 0,0,255, + 11,11,239, + 19,19,223, + 27,27,207, + 35,35,191, + 43,43,175, + 47,47,159, + 47,47,143, + 47,47,127, + 47,47,111, + 47,47,95, + 43,43,79, + 35,35,63, + 27,27,47, + 19,19,31, + 11,11,15, + 43,0,0, + 59,0,0, + 75,7,0, + 95,7,0, + 111,15,0, + 127,23,7, + 147,31,7, + 163,39,11, + 183,51,15, + 195,75,27, + 207,99,43, + 219,127,59, + 227,151,79, + 231,171,95, + 239,191,119, + 247,211,139, + 167,123,59, + 183,155,55, + 199,195,55, + 231,227,87, + 127,191,255, + 171,231,255, + 215,255,255, + 103,0,0, + 139,0,0, + 179,0,0, + 215,0,0, + 255,0,0, + 255,243,147, + 255,247,199, + 255,255,255, + 159,91,83 +}; + +pal_t h2pal[] = { + 0,0,0, + 0,0,0, + 8,8,8, + 17,17,17, + 25,25,25, + 33,33,33, + 42,42,42, + 50,50,50, + 59,59,59, + 67,67,67, + 74,74,74, + 80,80,80, + 87,87,87, + 91,91,91, + 99,99,99, + 105,105,105, + 112,112,112, + 121,121,121, + 131,131,131, + 139,139,139, + 149,149,149, + 159,159,159, + 168,168,168, + 183,183,183, + 187,187,187, + 196,196,196, + 205,205,205, + 215,215,215, + 224,224,224, + 233,233,233, + 243,243,243, + 252,252,252, + 11,11,15, + 18,18,23, + 24,25,30, + 31,32,38, + 38,39,45, + 44,45,53, + 51,52,60, + 57,59,68, + 64,66,75, + 76,79,89, + 92,95,107, + 110,115,129, + 129,135,154, + 152,159,179, + 168,175,199, + 191,199,223, + 32,24,20, + 40,32,28, + 48,36,32, + 52,44,40, + 60,52,44, + 68,56,52, + 76,64,56, + 84,72,64, + 92,76,72, + 100,84,76, + 108,92,84, + 112,96,88, + 120,104,96, + 128,112,100, + 136,116,108, + 144,124,112, + 23,25,23, + 29,32,29, + 34,38,34, + 40,45,40, + 46,51,46, + 51,58,51, + 57,64,57, + 64,71,64, + 71,79,71, + 85,92,85, + 105,113,104, + 122,130,121, + 140,148,137, + 157,165,154, + 174,182,170, + 191,199,187, + 49,33,8, + 60,40,8, + 72,48,16, + 84,56,20, + 92,64,28, + 100,72,36, + 108,80,44, + 120,92,52, + 136,104,60, + 148,116,72, + 160,128,84, + 168,136,92, + 180,144,100, + 188,152,108, + 196,160,116, + 204,168,124, + 17,22,17, + 21,28,21, + 25,34,25, + 29,39,29, + 33,45,33, + 36,51,36, + 40,57,40, + 44,62,44, + 48,68,48, + 55,77,54, + 63,85,61, + 70,94,67, + 78,102,73, + 85,111,79, + 93,119,86, + 100,128,92, + 24,12,8, + 34,17,10, + 43,22,11, + 53,26,13, + 62,31,14, + 71,35,15, + 79,39,17, + 84,44,20, + 92,48,24, + 100,56,28, + 112,64,32, + 120,72,36, + 128,80,44, + 146,95,57, + 171,115,73, + 192,132,88, + 24,5,5, + 39,4,4, + 49,3,3, + 60,3,3, + 70,2,2, + 81,2,2, + 91,1,1, + 102,1,1, + 112,0,0, + 132,0,0, + 153,0,0, + 173,0,0, + 194,0,0, + 214,0,0, + 235,0,0, + 252,0,0, + 18,15,32, + 31,23,51, + 35,31,59, + 43,39,71, + 55,47,83, + 63,59,95, + 71,67,107, + 83,75,119, + 91,87,131, + 103,99,143, + 111,111,155, + 123,119,167, + 135,135,179, + 147,147,191, + 159,159,203, + 175,175,215, + 36,20,4, + 54,27,5, + 68,32,4, + 83,41,2, + 103,49,4, + 124,60,4, + 140,74,6, + 156,89,9, + 172,103,11, + 188,117,13, + 204,131,15, + 220,146,18, + 236,160,20, + 252,184,56, + 248,200,80, + 248,220,120, + 21,18,6, + 29,25,8, + 37,33,10, + 45,42,12, + 52,51,16, + 59,59,18, + 65,67,22, + 70,74,25, + 74,82,29, + 80,95,34, + 86,106,41, + 91,119,46, + 93,131,52, + 92,141,54, + 94,150,59, + 98,163,66, + 61,16,16, + 74,24,24, + 87,31,31, + 101,39,37, + 115,44,44, + 126,55,51, + 143,67,59, + 155,77,67, + 47,23,11, + 59,31,15, + 75,35,19, + 87,43,23, + 99,47,31, + 115,55,35, + 127,59,43, + 143,67,51, + 26,22,17, + 36,29,22, + 46,38,29, + 56,44,33, + 66,52,38, + 75,60,44, + 83,68,49, + 92,76,55, + 102,85,61, + 113,93,68, + 123,102,74, + 134,112,81, + 146,121,89, + 154,130,97, + 162,139,105, + 171,148,113, + 39,27,15, + 47,34,18, + 55,40,20, + 63,47,23, + 73,55,26, + 83,62,28, + 88,68,31, + 104,79,35, + 151,99,59, + 160,108,64, + 175,116,74, + 180,126,81, + 192,135,91, + 204,143,93, + 218,157,111, + 63,23,93, + 103,39,119, + 168,75,166, + 205,108,192, + 4,85,4, + 5,134,5, + 3,182,3, + 2,219,2, + 7,7,146, + 17,71,206, + 36,135,225, + 89,171,235, + 216,5,5, + 247,74,0, + 255,129,2, + 255,174,27, + 255,255,255 +}; +#endif \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qMView/qMView.cpp b/Toolkit/Programming/Tools/qMView/qMView.cpp new file mode 100644 index 0000000..7ece3f0 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/qMView.cpp @@ -0,0 +1,203 @@ +// qMView.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "resource.h" +#include "DDUtil.h" +#include "Matrix.h" + +#include "Model.h" +#include "qMView.h" + +#include "treectrlex.h" +#include "frametreectrl.h" +#include "skintreectrl.h" + +#include "JointConstraintDlg.h" +#include "JointAnglesDlg.h" +#include "ManagerTree.h" +#include "FrameManager2.h" +#include "MainFrm.h" +#include "qMViewDoc.h" +#include "SkinPageFrm.h" +#include "qMViewView.h" + +#include "Splash.h" +#include "pal.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CQMViewApp + +BEGIN_MESSAGE_MAP(CQMViewApp, CWinApp) + //{{AFX_MSG_MAP(CQMViewApp) + ON_COMMAND(ID_APP_ABOUT, OnAppAbout) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG_MAP + // Standard file based document commands + ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) + ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) + ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CQMViewApp construction + +CQMViewApp::CQMViewApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CQMViewApp object + +CQMViewApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CQMViewApp initialization + +BOOL CQMViewApp::InitInstance() +{ +// AfxEnableControlContainer(); + +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif + + LoadStdProfileSettings(16); // Load standard INI file options (including MRU) + + // Register the application's document templates. Document templates + // serve as the connection between documents, frame windows and views. + + CSingleDocTemplate* pDocTemplate; + pDocTemplate = new CSingleDocTemplate( + IDR_QMVIEWTYPE, + RUNTIME_CLASS(CQMViewDoc), + RUNTIME_CLASS(CMainFrame), + RUNTIME_CLASS(CQMViewView)); + AddDocTemplate(pDocTemplate); + +/* pDocTemplate = new CSingleDocTemplate( + IDR_QUAKE, + RUNTIME_CLASS(CQMViewDoc), + RUNTIME_CLASS(CMainFrame), + RUNTIME_CLASS(CQMViewView)); + AddDocTemplate(pDocTemplate); + + pDocTemplate = new CSingleDocTemplate( + IDR_QUAKE2, + RUNTIME_CLASS(CQMViewDoc), + RUNTIME_CLASS(CMainFrame), + RUNTIME_CLASS(CQMViewView)); + AddDocTemplate(pDocTemplate); +*/ + + HRESULT ddrval = DirectDrawCreate(NULL, &CDDHelper::lpDD, NULL ); + if( ddrval != DD_OK ) + { + return FALSE; + } + + EnableShellOpen(); + RegisterShellFileTypes(TRUE); + CSkinPageFrm::Register(); + + // Parse command line for standard shell commands, DDE, file open + CCommandLineInfo cmdInfo; + ParseCommandLine(cmdInfo); + + if (cmdInfo.m_nShellCommand != CCommandLineInfo::FileNew) + { + CCommandLineInfo newcmdInfo; + + if (!ProcessShellCommand(newcmdInfo)) + { + return FALSE; + } + } + + if (!ProcessShellCommand(cmdInfo)) + { + return FALSE; + } + + m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED); + m_pMainWnd->UpdateWindow(); + + m_pMainWnd->DragAcceptFiles(); + + if (cmdInfo.m_nShellCommand != CCommandLineInfo::FileOpen) + { + CSplashWnd* splash = new CSplashWnd(m_pMainWnd); + splash->CenterWindow(m_pMainWnd); + splash->ShowWindow(SW_SHOW); + splash->UpdateWindow(); + } + + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// Dialog Data + //{{AFX_DATA(CAboutDlg) + enum { IDD = IDD_ABOUTBOX }; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + //{{AFX_MSG(CAboutDlg) + // No message handlers + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDlg) + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) + //{{AFX_MSG_MAP(CAboutDlg) + // No message handlers + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +// App command to run the dialog +void CQMViewApp::OnAppAbout() +{ + CAboutDlg aboutDlg; + aboutDlg.DoModal(); +} + +///////////////////////////////////////////////////////////////////////////// +// CQMViewApp commands diff --git a/Toolkit/Programming/Tools/qMView/qMView.dsp b/Toolkit/Programming/Tools/qMView/qMView.dsp new file mode 100644 index 0000000..8c87e49 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/qMView.dsp @@ -0,0 +1,438 @@ +# Microsoft Developer Studio Project File - Name="qMView" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=qMView - Win32 Release +!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 "qMView.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 "qMView.mak" CFG="qMView - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qMView - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "qMView - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Q2 Utilities/qMView", LBHAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qMView - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /Yu"stdafx.h" /c +# ADD CPP /nologo /MD /W3 /Gm /GX /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /Fr /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /i "dx5sdk\sdk\inc" /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 d3drm.lib ddraw.lib dxguid.lib winmm.lib /nologo /subsystem:windows /debug /machine:I386 + +!ELSEIF "$(CFG)" == "qMView - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /Yu"stdafx.h" /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FR /FD /c +# SUBTRACT CPP /WX /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 +# ADD LINK32 d3drm.lib ddraw.lib dxguid.lib winmm.lib /nologo /subsystem:windows /debug /machine:IX86 +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "qMView - Win32 Release" +# Name "qMView - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\ddutil.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\FlexModel.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\FrameManager2.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\FrameTreeCtrl.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\JointAnglesDlg.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\JointConstraintDlg.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\JointTreeCtrl.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\MainFrm.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\ManagerTree.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\Martix.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\Model.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\NodePropertyDlg.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\NodeTreeCtrl.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\qMView.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\qMViewDoc.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\qMViewView.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\Quake2Model.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\QuakeModel.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\SkinPageFrm.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\SkinTreeCtrl.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\Splash.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\TickerDlg.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\TreeCtrlEx.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\Angles.h +# End Source File +# Begin Source File + +SOURCE=.\Ddutil.h +# End Source File +# Begin Source File + +SOURCE=.\FlexModel.h +# End Source File +# Begin Source File + +SOURCE=.\FrameManager2.h +# End Source File +# Begin Source File + +SOURCE=.\FrameTreeCtrl.h +# End Source File +# Begin Source File + +SOURCE=.\JointAnglesDlg.h +# End Source File +# Begin Source File + +SOURCE=.\JointConstraintDlg.h +# End Source File +# Begin Source File + +SOURCE=.\JointTreeCtrl.h +# End Source File +# Begin Source File + +SOURCE=.\MainFrm.h +# End Source File +# Begin Source File + +SOURCE=.\ManagerTree.h +# End Source File +# Begin Source File + +SOURCE=.\Matrix.h +# End Source File +# Begin Source File + +SOURCE=.\Model.h +# End Source File +# Begin Source File + +SOURCE=.\NodePropertyDlg.h +# End Source File +# Begin Source File + +SOURCE=.\NodeTreeCtrl.h +# End Source File +# Begin Source File + +SOURCE=.\pal.h +# End Source File +# Begin Source File + +SOURCE=.\qMView.h +# End Source File +# Begin Source File + +SOURCE=.\qMViewDoc.h +# End Source File +# Begin Source File + +SOURCE=.\qMViewView.h +# End Source File +# Begin Source File + +SOURCE=.\Quake2Model.h +# End Source File +# Begin Source File + +SOURCE=.\QuakeModel.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\SkinPageFrm.h +# End Source File +# Begin Source File + +SOURCE=.\SkinTreeCtrl.h +# End Source File +# Begin Source File + +SOURCE=.\Splash.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\TickerDlg.h +# End Source File +# Begin Source File + +SOURCE=.\treectrlex.h +# End Source File +# Begin Source File + +SOURCE=.\Vector.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\animbar1.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\bitmap1.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\bitmap2.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\bitmap3.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\bitmap4.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\bmp00001.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\cur00001.cur +# End Source File +# Begin Source File + +SOURCE=.\res\cur00002.cur +# End Source File +# Begin Source File + +SOURCE=.\res\cursor1.cur +# End Source File +# Begin Source File + +SOURCE=.\res\cursor2.cur +# End Source File +# Begin Source File + +SOURCE=.\logo.BMP +# End Source File +# Begin Source File + +SOURCE=.\res\qMView.ico +# End Source File +# Begin Source File + +SOURCE=.\qMView.rc +# End Source File +# Begin Source File + +SOURCE=.\res\qMView.rc2 +# End Source File +# Begin Source File + +SOURCE=.\res\qMViewDoc.ico +# End Source File +# Begin Source File + +SOURCE=.\res\raven.bmp +# End Source File +# Begin Source File + +SOURCE=.\splash.BMP +# End Source File +# Begin Source File + +SOURCE=.\res\Toolbar.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\toolbar1.bmp +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# Begin Source File + +SOURCE=.\worklog.txt +# End Source File +# End Target +# End Project +# Section qMView : {0AF79815-1187-11D0-A71A-444553540000} +# 0:8:Splash.h:C:\qMView_MDI\Splash.h +# 0:10:Splash.cpp:C:\qMView_MDI\Splash.cpp +# 1:10:IDB_SPLASH:102 +# 2:10:ResHdrName:resource.h +# 2:11:ProjHdrName:stdafx.h +# 2:10:WrapperDef:_SPLASH_SCRN_ +# 2:12:SplClassName:CSplashWnd +# 2:21:SplashScreenInsertKey:4.0 +# 2:10:HeaderName:Splash.h +# 2:10:ImplemName:Splash.cpp +# 2:7:BmpID16:IDB_SPLASH +# End Section +# Section qMView : {00000000-0000-0000-0000-000000000000} +# 1:27:CG_IDR_POPUP_NODE_TREE_CTRL:108 +# End Section diff --git a/Toolkit/Programming/Tools/qMView/qMView.dsw b/Toolkit/Programming/Tools/qMView/qMView.dsw new file mode 100644 index 0000000..25c2d80 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/qMView.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "qMView"=.\qMView.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Toolkit/Programming/Tools/qMView/qMView.h b/Toolkit/Programming/Tools/qMView/qMView.h new file mode 100644 index 0000000..05fc112 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/qMView.h @@ -0,0 +1,56 @@ +// qMView.h : main header file for the QMVIEW application +// + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CQMViewApp: +// See qMView.cpp for the implementation of this class +// + +class CQMViewApp : public CWinApp +{ +public: + CQMViewApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CQMViewApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CQMViewApp) + afx_msg void OnAppAbout(); + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +enum +{ + QM_NEW_MODEL = 1, + QM_DELETE_MODEL, + QM_CHANGE_VISUAL, + QM_ALLNODES_VISIBLE, + QM_ADD_VISUAL, + QM_DELETE_VISUAL, + QM_IDLE, + QM_STOP_ANIMATION, + QM_RUN_ANIMATION, + QM_NEW_SKIN, + QM_CHANGE_SKIN, + QM_UPDATE_MODEL, +}; + +#define ID_SKINVIEW AFX_IDW_PANE_FIRST + 1 +#define ID_MODELVIEW AFX_IDW_PANE_FIRST + 2 + +///////////////////////////////////////////////////////////////////////////// diff --git a/Toolkit/Programming/Tools/qMView/qMView.rc b/Toolkit/Programming/Tools/qMView/qMView.rc new file mode 100644 index 0000000..af04d9b --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/qMView.rc @@ -0,0 +1,990 @@ +//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 + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif\r\n" + "#include ""res\\qMView.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_SKIN ICON DISCARDABLE "res\\qMView.ico" +IDR_QMVIEWTYPE ICON DISCARDABLE "res\\qMViewDoc.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDR_QMVIEWTYPE BITMAP MOVEABLE PURE "res\\Toolbar.bmp" +IDB_SPLASH BITMAP DISCARDABLE "splash.BMP" +IDB_LOGO BITMAP DISCARDABLE "logo.BMP" +IDB_RAVEN BITMAP DISCARDABLE "res\\raven.bmp" +IDR_VIEWPOSBAR BITMAP DISCARDABLE "res\\toolbar1.bmp" +IDR_ANIMBAR BITMAP DISCARDABLE "res\\bmp00001.bmp" +IDB_BITMAP1 BITMAP DISCARDABLE "res\\bitmap1.bmp" +IDB_BITMAP2 BITMAP DISCARDABLE "res\\bitmap2.bmp" +IDB_BITMAP3 BITMAP DISCARDABLE "res\\bitmap3.bmp" +IDB_BITMAP4 BITMAP DISCARDABLE "res\\bitmap4.bmp" +IDR_ANIMBAR1 BITMAP DISCARDABLE "res\\animbar1.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Toolbar +// + +IDR_QMVIEWTYPE TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_FILE_OPEN + SEPARATOR + BUTTON ID_SKIN_IMPORT + SEPARATOR + BUTTON ID_MODE_CAMERA + SEPARATOR + BUTTON ID_APP_ABOUT +END + +IDR_VIEWPOSBAR TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_GOTOPOS_BACK + BUTTON ID_GOTOPOS_FRONT + BUTTON ID_GOTOPOS_RIGHT + BUTTON ID_GOTOPOS_LEFT + BUTTON ID_GOTOPOS_TOP + BUTTON ID_GOTOPOS_BOTTOM + SEPARATOR + BUTTON ID_LOCK_ROT_X + BUTTON ID_LOCK_ROT_Y + BUTTON ID_LOCK_ROT_Z + SEPARATOR + BUTTON ID_LOCK_TRAN_X + BUTTON ID_LOCK_TRAN_Y + BUTTON ID_LOCK_TRAN_Z +END + +IDR_ANIMBAR TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_ANIMATE_STEP_BACK + BUTTON ID_ANIMATE_STOP + BUTTON ID_ANIMATE_PLAY + BUTTON ID_ANIMATE_STEP_FORE + SEPARATOR + BUTTON ID_ANIMATE_TYPE_BACK + BUTTON ID_ANIMATE_TYPE_PINGPONG + BUTTON ID_ANIMATE_TYPE_FRONT + SEPARATOR + BUTTON ID_RENDER_WIREFRAME + BUTTON ID_RENDER_FLAT + SEPARATOR + BUTTON ID_RENDER_TEXTURE + SEPARATOR + BUTTON ID_RENDER_TRANS + SEPARATOR + BUTTON ID_ANIM_INTERTOGGLE + SEPARATOR + BUTTON ID_TICKER_OPTIONS + SEPARATOR + BUTTON ID_WINDOW_FRAME + BUTTON ID_WINDOW_SKIN + SEPARATOR + BUTTON ID_SKIN_SHOWOVERLAY +END + +IDR_ANIMBAR1 TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_ANIMATE_STEP_BACK + BUTTON ID_ANIMATE_STOP + BUTTON ID_ANIMATE_PLAY + BUTTON ID_ANIMATE_STEP_FORE + SEPARATOR + BUTTON ID_ANIMATE_TYPE_BACK + BUTTON ID_ANIMATE_TYPE_PINGPONG + BUTTON ID_ANIMATE_TYPE_FRONT + SEPARATOR + BUTTON ID_RENDER_WIREFRAME + BUTTON ID_RENDER_FLAT + SEPARATOR + BUTTON ID_RENDER_TEXTURE + SEPARATOR + BUTTON ID_RENDER_TRANS + SEPARATOR + BUTTON ID_ANIM_INTERTOGGLE + SEPARATOR + BUTTON ID_TICKER_OPTIONS + SEPARATOR + BUTTON ID_WINDOW_FRAME + BUTTON ID_WINDOW_SKIN + SEPARATOR + BUTTON ID_SKIN_SHOWOVERLAY + SEPARATOR + BUTTON ID_SKELETON_SNAP + BUTTON ID_JOINT_MANUAL_ANGLES + BUTTON ID_JOINT_CONSTRAINTS +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_QMVIEWTYPE MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN + MENUITEM "&Close", ID_FILE_CLOSE + MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE + MENUITEM "Save &As...", ID_FILE_SAVE_AS + MENUITEM SEPARATOR + MENUITEM "Import S&kin", ID_SKIN_IMPORT + MENUITEM "Ex&port Skin", ID_SKIN_EXPORT, GRAYED + MENUITEM SEPARATOR + MENUITEM "I&mport Frame", ID_FRAME_IMPORT, GRAYED + MENUITEM "Export &Frame", ID_FRAME_EXPORT, GRAYED + MENUITEM SEPARATOR + MENUITEM "&Preferences", ID_PREF + MENUITEM SEPARATOR + MENUITEM "Recent File", ID_FILE_MRU_FILE1, GRAYED + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_APP_EXIT + END + POPUP "&Render" + BEGIN + MENUITEM "Wireframe", ID_RENDER_WIREFRAME + MENUITEM "Flat", ID_RENDER_FLAT + MENUITEM "Gouraud", ID_RENDER_GOURAUD + MENUITEM SEPARATOR + MENUITEM "Textures", ID_RENDER_TEXTURE + MENUITEM "Transparency", ID_RENDER_TRANS + END + POPUP "&Animation" + BEGIN + MENUITEM "&Play", ID_ANIMATE_PLAY, CHECKED + MENUITEM "&Stop", ID_ANIMATE_STOP + MENUITEM "Step &>>", ID_ANIMATE_STEP_FORE + MENUITEM "&<< Step", ID_ANIMATE_STEP_BACK + MENUITEM SEPARATOR + POPUP "Play &Mode" + BEGIN + MENUITEM "&Forward", ID_ANIMATE_TYPE_FRONT + MENUITEM "&Backward", ID_ANIMATE_TYPE_BACK + MENUITEM "Pin&g Pong", ID_ANIMATE_TYPE_PINGPONG + END + END + POPUP "&View" + BEGIN + POPUP "&Toolbar" + BEGIN + MENUITEM "Animation", ID_VIEW_ANIMBAR + MENUITEM "Position", ID_VIEW_POS + MENUITEM "General", ID_VIEW_TOOLBAR + END + MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR + MENUITEM "Frame / Skin Manager", CG_ID_VIEW_FRAMETREEDLG + MENUITEM "Node / Joint Manager", CG_IDD_TREEMANAGER + MENUITEM SEPARATOR + POPUP "Lock &Rotation" + BEGIN + MENUITEM "&X", ID_LOCK_ROT_X + MENUITEM "&Y", ID_LOCK_ROT_Y + MENUITEM "&Z", ID_LOCK_ROT_Z + END + POPUP "Lock Trans&lation" + BEGIN + MENUITEM "&X", ID_LOCK_TRAN_X + MENUITEM "&Y", ID_LOCK_TRAN_Y + MENUITEM "&Z", ID_LOCK_TRAN_Z + END + POPUP "&All" + BEGIN + MENUITEM "&Lock", ID_ALL_LOCK + MENUITEM "&Unlock", ID_ALL_UNLOCK + END + MENUITEM SEPARATOR + POPUP "&Go To View" + BEGIN + MENUITEM "&Top", ID_GOTOPOS_TOP + MENUITEM "&Bottom", ID_GOTOPOS_BOTTOM + MENUITEM "&Left", ID_GOTOPOS_LEFT + MENUITEM "&Right", ID_GOTOPOS_RIGHT + MENUITEM "&Front", ID_GOTOPOS_FRONT + MENUITEM "Bac&k", ID_GOTOPOS_BACK + END + MENUITEM SEPARATOR + MENUITEM "Properties...", ID_VIEW_PROPS + END + POPUP "&Window" + BEGIN + MENUITEM "&Cascade", ID_WINDOW_CASCADE + MENUITEM "&Tile", ID_WINDOW_TILE_HORZ + MENUITEM "&Arrange Icons", ID_WINDOW_ARRANGE + END + POPUP "&Help" + BEGIN + MENUITEM "&Help Topics", ID_HELP_FINDER + MENUITEM SEPARATOR + MENUITEM "&About qMView...", ID_APP_ABOUT + END +END + +CG_IDR_POPUP_NODE_TREE_CTRL MENU DISCARDABLE +BEGIN + POPUP "_POPUP_" + BEGIN + MENUITEM "Visible", ID_NODE_TOGGLE_VIS + MENUITEM SEPARATOR + MENUITEM "Properties", ID_NODE_PROP, GRAYED + MENUITEM SEPARATOR + END +END + +IDR_SKIN_POPUP_MENU MENU DISCARDABLE +BEGIN + POPUP "_POPUP_" + BEGIN + MENUITEM "&Replace Skin...", ID_REPLACE_SKIN + MENUITEM SEPARATOR + END +END + +IDR_QMVIEWTYPE1 MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN + MENUITEM "&Close", ID_FILE_CLOSE + MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE + MENUITEM "Save &As...", ID_FILE_SAVE_AS + MENUITEM SEPARATOR + MENUITEM "&Import Palette", ID_PALETTE_IMPORT + MENUITEM "&Export Palette", ID_PALETTE_EXPORT + MENUITEM SEPARATOR + MENUITEM "Import S&kin", ID_SKIN_IMPORT + MENUITEM "Ex&port Skin", ID_SKIN_EXPORT, GRAYED + MENUITEM SEPARATOR + MENUITEM "I&mport Frame", ID_FRAME_IMPORT, GRAYED + MENUITEM "Export &Frame", ID_FRAME_EXPORT, GRAYED + MENUITEM SEPARATOR + MENUITEM "&Preferences", ID_PREF + MENUITEM SEPARATOR + MENUITEM "Recent File", ID_FILE_MRU_FILE1, GRAYED + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_APP_EXIT + END + POPUP "&Render" + BEGIN + MENUITEM "Wireframe", ID_RENDER_WIREFRAME + MENUITEM "Flat", ID_RENDER_FLAT + MENUITEM "Gouraud", ID_RENDER_GOURAUD + MENUITEM SEPARATOR + MENUITEM "Textures", ID_RENDER_TEXTURE + MENUITEM "Transparency", ID_RENDER_TRANS + END + POPUP "&Animation" + BEGIN + MENUITEM "&Play", ID_ANIMATE_PLAY, CHECKED + MENUITEM "&Stop", ID_ANIMATE_STOP + MENUITEM "Step &>>", ID_ANIMATE_STEP_FORE + MENUITEM "&<< Step", ID_ANIMATE_STEP_BACK + MENUITEM SEPARATOR + POPUP "Play &Mode" + BEGIN + MENUITEM "&Forward", ID_ANIMATE_TYPE_FRONT + MENUITEM "&Backward", ID_ANIMATE_TYPE_BACK + MENUITEM "Pin&g Pong", ID_ANIMATE_TYPE_PINGPONG + END + END + POPUP "Skeleton" + BEGIN + MENUITEM "Snap to Original", ID_SKELETON_SNAP + MENUITEM "Joint Angles", ID_JOINT_MANUAL_ANGLES + MENUITEM "Joint Constraints", ID_JOINT_CONSTRAINTS, GRAYED + END + POPUP "&View" + BEGIN + POPUP "&Toolbar" + BEGIN + MENUITEM "Animation", ID_VIEW_ANIMBAR + MENUITEM "Position", ID_VIEW_POS + MENUITEM "General", ID_VIEW_TOOLBAR + END + MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR + MENUITEM "Frame / Skin Manager", CG_ID_VIEW_FRAMETREEDLG + MENUITEM "Node / Joint Manager", CG_IDD_TREEMANAGER + MENUITEM SEPARATOR + POPUP "Lock &Rotation" + BEGIN + MENUITEM "&X", ID_LOCK_ROT_X + MENUITEM "&Y", ID_LOCK_ROT_Y + MENUITEM "&Z", ID_LOCK_ROT_Z + END + POPUP "Lock Trans&lation" + BEGIN + MENUITEM "&X", ID_LOCK_TRAN_X + MENUITEM "&Y", ID_LOCK_TRAN_Y + MENUITEM "&Z", ID_LOCK_TRAN_Z + END + POPUP "&All" + BEGIN + MENUITEM "&Lock", ID_ALL_LOCK + MENUITEM "&Unlock", ID_ALL_UNLOCK + END + MENUITEM SEPARATOR + POPUP "&Go To View" + BEGIN + MENUITEM "&Top", ID_GOTOPOS_TOP + MENUITEM "&Bottom", ID_GOTOPOS_BOTTOM + MENUITEM "&Left", ID_GOTOPOS_LEFT + MENUITEM "&Right", ID_GOTOPOS_RIGHT + MENUITEM "&Front", ID_GOTOPOS_FRONT + MENUITEM "Bac&k", ID_GOTOPOS_BACK + END + MENUITEM SEPARATOR + MENUITEM "Properties...", ID_VIEW_PROPS + END + POPUP "&Window" + BEGIN + MENUITEM "&Cascade", ID_WINDOW_CASCADE + MENUITEM "&Tile", ID_WINDOW_TILE_HORZ + MENUITEM "&Arrange Icons", ID_WINDOW_ARRANGE + END + POPUP "&Help" + BEGIN + MENUITEM "&Help Topics", ID_HELP_FINDER + MENUITEM SEPARATOR + MENUITEM "&About qMView...", ID_APP_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_QMVIEWTYPE ACCELERATORS PRELOAD MOVEABLE PURE +BEGIN + "I", ID_SKIN_IMPORT, VIRTKEY, CONTROL, NOINVERT + "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT + "P", ID_PALETTE_IMPORT, VIRTKEY, CONTROL, NOINVERT + "V", ID_NODE_TOGGLE_VIS, VIRTKEY, CONTROL, NOINVERT + VK_F1, ID_HELP, VIRTKEY, NOINVERT + VK_F1, ID_CONTEXT_HELP, VIRTKEY, SHIFT, NOINVERT + VK_F10, ID_GOTOPOS_BOTTOM, VIRTKEY, NOINVERT + VK_F11, ID_WINDOW_FRAME, VIRTKEY, NOINVERT + VK_F12, ID_WINDOW_SKIN, VIRTKEY, NOINVERT + VK_F12, ID_SKIN_SHOWOVERLAY, VIRTKEY, CONTROL, NOINVERT + VK_F2, ID_MODE_CAMERA, VIRTKEY, NOINVERT + VK_F3, ID_MODE_SKELETAL, VIRTKEY, NOINVERT + VK_F4, ID_SKELETON_SNAP, VIRTKEY, NOINVERT + VK_F5, ID_GOTOPOS_FRONT, VIRTKEY, NOINVERT + VK_F6, ID_GOTOPOS_BACK, VIRTKEY, NOINVERT + VK_F7, ID_GOTOPOS_LEFT, VIRTKEY, NOINVERT + VK_F8, ID_GOTOPOS_RIGHT, VIRTKEY, NOINVERT + VK_F9, ID_GOTOPOS_TOP, VIRTKEY, NOINVERT + VK_LEFT, ID_ANIMATE_STEP_BACK, VIRTKEY, NOINVERT + VK_RETURN, ID_VIEW_PROPS, VIRTKEY, ALT, NOINVERT + VK_RIGHT, ID_ANIMATE_STEP_FORE, VIRTKEY, NOINVERT + VK_SPACE, ID_ANIMATE_PLAY, VIRTKEY, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 326, 246 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About qMView" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "qMView Version 2.0ß",IDC_STATIC,128,177,68,8, + SS_NOPREFIX + DEFPUSHBUTTON "This button is far too large for just ""OK""",IDOK,7, + 228,312,14,WS_GROUP + CONTROL 131,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,7,7,313, + 151 + GROUPBOX "Special Thanks",IDC_STATIC,247,163,64,57,BS_CENTER + LTEXT "Trey Harisson",IDC_STATIC,257,176,44,8 + LTEXT "Stan Trujillo",IDC_STATIC,260,194,38,8 + LTEXT "Louis Solomon",IDC_STATIC,257,203,47,8 + LTEXT "Chris Carollo",IDC_STATIC,260,185,40,8 + LTEXT "by Josh Weier",IDC_STATIC,139,187,46,8 + LTEXT "jweier@mail.ravensoft.com",IDC_STATIC,120,200,85,8 + GROUPBOX "Created For",IDC_STATIC,14,163,64,57,BS_CENTER + CONTROL 132,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,30,176,30, + 35 + GROUPBOX "",IDC_STATIC,84,163,157,57 +END + +CG_IDD_TREEMANAGER DIALOGEX 0, 0, 99, 276 +STYLE WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "Tree1",IDC_SKINTREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | + WS_BORDER | WS_TABSTOP,7,7,85,53,WS_EX_NOPARENTNOTIFY | + WS_EX_TRANSPARENT | WS_EX_CLIENTEDGE + CONTROL "Tree2",IDC_FRAMETREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | + TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,63,85,206, + WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT | + WS_EX_CLIENTEDGE +END + +CG_IDD_FRAMEMANAGER2 DIALOGEX 0, 0, 99, 274 +STYLE WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "Tree1",IDC_NODETREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | + WS_BORDER | WS_TABSTOP,7,7,85,123,WS_EX_NOPARENTNOTIFY | + WS_EX_TRANSPARENT | WS_EX_CLIENTEDGE + CONTROL "Tree2",IDC_JOINTTREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | + TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,133,85,134, + WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT | + WS_EX_CLIENTEDGE +END + +IDD_NODE_PROP DIALOG DISCARDABLE 0, 0, 186, 71 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Node Properties" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,9,48,50,14 + PUSHBUTTON "Cancel",IDCANCEL,68,48,50,14 + PUSHBUTTON "Apply",IDAPPLY,127,48,50,14 + LTEXT "Triangles:",IDC_STATIC,55,22,32,8 + EDITTEXT IDC_EDIT1,90,20,40,14,ES_AUTOHSCROLL | ES_READONLY | + ES_NUMBER +END + +IDD_TICKER DIALOG DISCARDABLE 0, 0, 186, 79 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Ticker Options" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Use Ticker",IDC_TICKTOG,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,67,12,51,10 + EDITTEXT IDC_EDIT1,72,30,66,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,140,30,10, + 14 + DEFPUSHBUTTON "OK",IDOK,35,58,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,58,50,14 + LTEXT "Time Delay",IDC_STATIC,33,33,36,8 +END + +IDD_JOINT_ANGLES DIALOG DISCARDABLE 0, 0, 160, 53 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Manual Joint Angles" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_XVAL,15,9,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_YVAL,58,9,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_ZVAL,101,9,40,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "Apply",IDC_APPLY,7,32,150,14 +END + +IDD_JOINT_LOCK_ANGLES DIALOG DISCARDABLE 0, 0, 164, 88 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Joint Constraints" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_XVAL,18,16,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_YVAL,61,16,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_ZVAL,104,16,40,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "Apply",IDC_APPLY,7,67,150,14 + EDITTEXT IDC_XVAL2,18,44,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_YVAL2,61,44,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_ZVAL2,104,44,40,14,ES_AUTOHSCROLL + LTEXT "Maximum",IDC_STATIC,18,7,30,8 + LTEXT "Minimum",IDC_STATIC,18,35,28,8 +END + +IDD_PP_GENERAL DIALOG DISCARDABLE 0, 0, 235, 156 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "General" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Frames:",IDC_STATIC,6,21,26,8 + LTEXT "gl Commands:",IDC_STATIC,6,35,45,8 + LTEXT "Skins:",IDC_STATIC,6,49,20,8 + LTEXT "Tris:",IDC_STATIC,6,91,14,8 + LTEXT "Groups:",IDC_STATIC,6,7,26,8 + LTEXT "Skinwidth:",IDC_STATIC,6,63,34,8 + LTEXT "Skinheight:",IDC_STATIC,6,77,36,8 + LTEXT "",IDC_PPGEN_FRAMES,91,21,45,8 + LTEXT "",IDC_PPGEN_GLCOMMANDS,91,35,45,8 + LTEXT "",IDC_PPGEN_SKINS,91,49,45,8 + LTEXT "",IDC_PPGEN_TRIS,91,91,45,8 + LTEXT "",IDC_PPGEN_GROUPS,91,7,45,8 + LTEXT "",IDC_PPGEN_SKINWIDTH,91,63,45,8 + LTEXT "",IDC_PPGEN_SKINHEIGHT,91,77,45,8 + LTEXT "STVerts:",IDC_STATIC,6,105,28,8 + LTEXT "",IDC_PPGEN_STVERTS,91,105,45,8 + LTEXT "Verts:",IDC_STATIC,6,119,19,8 + LTEXT "",IDC_PPGEN_VERTS,91,119,45,8 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Written by Josh Weier\0" + VALUE "CompanyName", "Raven Software\0" + VALUE "FileDescription", "qMView Model Visualization Utility\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "QMVIEW\0" + VALUE "LegalCopyright", "Copyright © 1998, Raven Software\0" + VALUE "OriginalFilename", "QMVIEW.EXE\0" + VALUE "ProductName", "qMView\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 319 + TOPMARGIN, 7 + BOTTOMMARGIN, 242 + END + + CG_IDD_TREEMANAGER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 92 + TOPMARGIN, 7 + BOTTOMMARGIN, 269 + END + + CG_IDD_FRAMEMANAGER2, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 92 + TOPMARGIN, 7 + BOTTOMMARGIN, 267 + END + + IDD_NODE_PROP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 64 + END + + IDD_TICKER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 72 + END + + IDD_JOINT_ANGLES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 153 + TOPMARGIN, 7 + BOTTOMMARGIN, 46 + END + + IDD_JOINT_LOCK_ANGLES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 157 + TOPMARGIN, 7 + BOTTOMMARGIN, 81 + END + + IDD_PP_GENERAL, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Cursor +// + +IDC_HAND_OPEN CURSOR DISCARDABLE "res\\cursor1.cur" +IDC_HAND_CLOSED CURSOR DISCARDABLE "res\\cursor2.cur" +IDC_HAND_ROTATE CURSOR DISCARDABLE "res\\cur00001.cur" +IDC_MAGNIFIER CURSOR DISCARDABLE "res\\cur00002.cur" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + IDR_SKIN "Skin" + IDR_QMVIEWTYPE "QMView\nQMView\nQMView\nFlex Models (*.fm)\n.fm\nFlexModels\nQMView Document" +END + +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + AFX_IDS_APP_TITLE "qMView" + AFX_IDS_IDLEMESSAGE "qMView Ready" + AFX_IDS_HELPMODEMESSAGE "Select an object on which to get Help" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_INDICATOR_CAPS "CAP" + ID_INDICATOR_NUM "NUM" + ID_INDICATOR_SCRL "SCRL" + ID_INDICATOR_OVR "OVR" + ID_INDICATOR_REC "REC" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_FILE_NEW "Create a new document\nNew" + ID_FILE_OPEN "Open an existing model\nOpen" + ID_FILE_CLOSE "Close the active document\nClose" + ID_FILE_SAVE "Save the active document\nSave" + ID_FILE_SAVE_AS "Save the active document with a new name\nSave As" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_APP_ABOUT "Display program information, version number and copyright\nAbout" + ID_APP_EXIT "Quit the application; prompts to save documents\nExit" + ID_HELP_INDEX "Opens Help\nHelp Topics" + ID_HELP_FINDER "List Help topics\nHelp Topics" + ID_HELP_USING "Display instructions about how to use help\nHelp" + ID_CONTEXT_HELP "Display help for clicked on buttons, menus and windows\nHelp" + ID_HELP "Display help for current task or command\nHelp" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_FILE_MRU_FILE1 "Open this document" + ID_FILE_MRU_FILE2 "Open this document" + ID_FILE_MRU_FILE3 "Open this document" + ID_FILE_MRU_FILE4 "Open this document" + ID_FILE_MRU_FILE5 "Open this document" + ID_FILE_MRU_FILE6 "Open this document" + ID_FILE_MRU_FILE7 "Open this document" + ID_FILE_MRU_FILE8 "Open this document" + ID_FILE_MRU_FILE9 "Open this document" + ID_FILE_MRU_FILE10 "Open this document" + ID_FILE_MRU_FILE11 "Open this document" + ID_FILE_MRU_FILE12 "Open this document" + ID_FILE_MRU_FILE13 "Open this document" + ID_FILE_MRU_FILE14 "Open this document" + ID_FILE_MRU_FILE15 "Open this document" + ID_FILE_MRU_FILE16 "Open this document" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_NEXT_PANE "Switch to the next window pane\nNext Pane" + ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_WINDOW_NEW "Open another window for the active document\nNew Window" + ID_WINDOW_ARRANGE "Arrange icons at the bottom of the window\nArrange Icons" + ID_WINDOW_CASCADE "Arrange windows so they overlap\nCascade Windows" + ID_WINDOW_TILE_HORZ "Arrange windows as non-overlapping tiles\nTile Windows" + ID_WINDOW_TILE_VERT "Arrange windows as non-overlapping tiles\nTile Windows" + ID_WINDOW_SPLIT "Split the active window into panes\nSplit" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_EDIT_CLEAR "Erase the selection\nErase" + ID_EDIT_CLEAR_ALL "Erase everything\nErase All" + ID_EDIT_COPY "Copy the selection and put it on the Clipboard\nCopy" + ID_EDIT_CUT "Cut the selection and put it on the Clipboard\nCut" + ID_EDIT_FIND "Find the specified text\nFind" + ID_EDIT_PASTE "Insert Clipboard contents\nPaste" + ID_EDIT_REPEAT "Repeat the last action\nRepeat" + ID_EDIT_REPLACE "Replace specific text with different text\nReplace" + ID_EDIT_SELECT_ALL "Select the entire document\nSelect All" + ID_EDIT_UNDO "Undo the last action\nUndo" + ID_EDIT_REDO "Redo the previously undone action\nRedo" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_VIEW_TOOLBAR "Show or hide the toolbar\nToggle ToolBar" + ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar" +END + +STRINGTABLE DISCARDABLE +BEGIN + AFX_IDS_SCSIZE "Change the window size" + AFX_IDS_SCMOVE "Change the window position" + AFX_IDS_SCMINIMIZE "Reduce the window to an icon" + AFX_IDS_SCMAXIMIZE "Enlarge the window to full size" + AFX_IDS_SCNEXTWINDOW "Switch to the next document window" + AFX_IDS_SCPREVWINDOW "Switch to the previous document window" + AFX_IDS_SCCLOSE "Close the active window and prompts to save the documents" +END + +STRINGTABLE DISCARDABLE +BEGIN + AFX_IDS_SCRESTORE "Restore the window to normal size" + AFX_IDS_SCTASKLIST "Activate Task List" + AFX_IDS_MDICHILD "Activate this window" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_PALETTE_IMPORT "Import a palette from a file\nImport Palette" + ID_PALETTE_EXPORT "Export the palette to a file\nExport Palette" + ID_SKIN_IMPORT "Import skin from file\nImport Skin" + ID_SKIN_EXPORT "Export skin to file\nExport Skin" + ID_FRAME_IMPORT "Import frame from file\nImport Frame" + ID_FRAME_EXPORT "Export frame to file\nExport Frame" + ID_ANIMATE_PLAY "Play animation\nPlay" + ID_ANIMATE_STOP "Stops animation\nStop" + ID_ANIMATE_STEP_FORE "Steps forward one frame in animation\nStep Forward" + ID_BUTTON32781 "Step back one frame in animation\nStep Back" + ID_ANIMATE_TYPE_FRONT "Sets animation playback to forward\nPlay Forward" + ID_ANIMATE_TYPE_BACK "Set animation playback to backwards\nReverse Play" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_ANIMATE_TYPE_PINGPONG "Sets animation playback to ping-pong\nPing-Pong" + ID_ANIMATE_STEP_BACK "Step backwards one frame in animation\nStep Backward" + ID_LOCK_ROT_X "Lock rotation on the X axis\nLock X Rotation" + ID_LOCK_ROT_Y "Lock rotation on the Y axis\nLock Y Rotation" + ID_LOCK_ROT_Z "Lock rotation on the Z axis\nLock Z Rotation" + ID_LOCK_TRAN_X "Lock translation on the X axis\nLock X Translation" + ID_LOCK_TRAN_Y "Lock translation on the Y axis\nLock Y Translation" + ID_LOCK_TRAN_Z "Lock translation on the Z axis\nLock Z Translation" + ID_LOCK_SCALE_X "Lock scaling on the X axis\nLock X Scale" + ID_LOCK_SCALE_Y "Lock scaling on the Y axis\nLock Y Scale" + ID_LOCK_SCALE_Z "Lock scaling on the Z axis\nLock Z Scale" + ID_ALL_UNLOCK "Unlock all axis\nUnlock All" + ID_ALL_LOCK "Lock all axis\nLock All" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_RENDER_WIREFRAME "Display model as a wireframe\nWireframe" + ID_RENDER_FLAT "Render model with flat shading\nFlat" + ID_RENDER_GOURAUD "Render model with Gouraud shading\nGouraud" + ID_RENDER_TEXTURE "Toggle texture display on/off\nTextures" + ID_RENDER_TRANS "Toggle texture transparency on/off\nTransparency" + ID_GOTOPOS_TOP "View model from top\nTop" + ID_GOTOPOS_BOTTOM "View model from bottom\nBottom" + ID_GOTOPOS_LEFT "View model from left\nLeft" + ID_GOTOPOS_RIGHT "View model from right\nRight" + ID_GOTOPOS_FRONT "View model from front\nFront" + ID_GOTOPOS_BACK "View model from back\nBack" + ID_ANIMATE_INTER "Interpolation\nToggles frame interpolation on/off" +END + +STRINGTABLE DISCARDABLE +BEGIN + CG_ID_VIEW_FRAMETREEDLG "Show or hide Frame / Skin manager\nToggle Frame / Skin Manager" + CG_ID_VIEW_FRAMEMANAGER2 + "Show or hide Frame Manager2\nToggle Frame Manager2" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_ANIMATE_GOTOSTART "Goto Start\nSkip to the first frame of the set" + ID_ANIMATE_GOTOEND "Goto End\nSkip to the last frame of the set" + ID_VIEW_ANIMBAR "Toggle the visibility of the Animation Toolbar\nAnimation Toolbar" + ID_VIEW_POS "Toggle the visibility of the Position Toolbar\nAnimation Toolbar" + ID_PREF "View/Modify program options" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_INDICATOR_FPS "xxFPS: xx/xxxx" + ID_ANIM_INTERTOGGLE "Turn frame interpolation on/off\nInterpolation Toggle" + ID_GOTOPOS_WEAPON "Simulate in game weapon view" + ID_NODE_TOGGLE_VIS "Toggle the visibility of this node\nToggle Visibilty" + ID_TIME_CLAMP "Clamp the current FPS\nTime Clamp" + ID_TICKER_OPTIONS "Change the delay per frame\nTicker Options" + ID_TICK_TOGGLE "Toggle the ticker delay on or off\nTicker Toggle" + ID_SKIN_SHOWOVERLAY "Shows the model's skin vertices over the skin\nToggle Skin Overlay" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_WINDOW_SKIN "Switch to skin window\nSkin Window" + ID_WINDOW_FRAME "Switch animation preview window\nAnimation Window" + ID_MODE_CAMERA "Camera Manipulation Mode\nManipulate Camera" + ID_MODE_SKELETAL "Skeleton Manipulation Mode\nManipulate Skeleton" + ID_SKELETON_SNAP "Return joint angles to original position\nReset Joint Angles" + ID_JOINT_MANUAL_ANGLES "Manually set the angles of the selected joint\nManual Joint Angles" + ID_JOINT_CONSTRAINTS "Constrain the current joint's angles\nConstrain Joint" + ID_USE_JOINTS "Use Joints\nTurn joint use on and off" + ID_VIEW_PROPS "View model properties\nModel properties" + ID_USE_SKIN "Open skin to replace model skin\nReplaces model skin" + ID_REPLACE_SKIN "Replaces model skin\nOpen file to replace model skin" +END + +STRINGTABLE DISCARDABLE +BEGIN + CG_IDD_TREEMANAGER "Show or hide Node / Joint manager\nToggle Node / Joint Manager" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDR_QUAKE "QMView\nQMView\nQMView\nQuake Models (*.md)\n.md\nQuakeModels\nQuake Document" + IDR_QUAKE2 "QMView\\nQMView\\nQMView\\nQuake2 Models (*.md2)\\n.md2\\nQuake2Models\\nQuake2 Document" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDC_SKINTREE "Skins\nSkins for the model" + IDC_FRAMETREE "Animations/Frames\nAnimations/frames for the model" + IDC_NODETREE "Node hierarchy\nNodes for the model" + IDC_JOINTTREE "Joint hierarchy\nJoints in the model" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDR_SKIN_FROM_FILE_START + "Replaces model skin from file\nReplace skin from file" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDR_SKIN_FROM_FILE_END "Replaces model skin from file\nReplace skin from file" + ID_FILE_EXTENSIONS "*.pcx;*.m8;*.m32;*.tga" + ID_SUPPORTED_FORMATS "Supported Formats|*.pcx;*.m8;*.m32;*.tga|PCX File (*.pcx)|*.pcx|M8 File (*.m8)|*.m8|M32 File (*.m32)|*.m32|Targa (*.tga)|*.tga||" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif +#include "res\qMView.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Toolkit/Programming/Tools/qMView/qMViewDoc.cpp b/Toolkit/Programming/Tools/qMView/qMViewDoc.cpp new file mode 100644 index 0000000..01b568d --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/qMViewDoc.cpp @@ -0,0 +1,347 @@ +// qMViewDoc.cpp : implementation of the CQMViewDoc class +// + +#include "stdafx.h" +#include "resource.h" +#include "DDUtil.h" +#include "Matrix.h" +#include "Model.h" +#include "qMView.h" + +#include "qMViewDoc.h" +#include "treectrlex.h" +#include "frametreectrl.h" +#include "skintreectrl.h" + +#include "SkinPageFrm.h" +#include "JointConstraintDlg.h" +#include "JointAnglesDlg.h" +#include "ManagerTree.h" +#include "FrameManager2.h" +#include "MainFrm.h" + +#include "SkinPageFrm.h" +#include "NodePropertyDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CQMViewDoc + +IMPLEMENT_DYNCREATE(CQMViewDoc, CDocument) + +BEGIN_MESSAGE_MAP(CQMViewDoc, CDocument) + ON_UPDATE_COMMAND_UI_RANGE(IDR_SKIN_FROM_FILE_START, IDR_SKIN_FROM_FILE_END, OnUpdateSkinFromFile) + ON_COMMAND_RANGE(IDR_SKIN_FROM_FILE_START, IDR_SKIN_FROM_FILE_END, OnSkinFromFile) + ON_UPDATE_COMMAND_UI_RANGE(IDR_SKIN_SELECT_START, IDR_SKIN_SELECT_END, OnUpdateSkinSelect) + ON_COMMAND_RANGE(IDR_SKIN_SELECT_START, IDR_SKIN_SELECT_END, OnSkinSelect) + //{{AFX_MSG_MAP(CQMViewDoc) + ON_COMMAND(ID_NODE_PROP, OnNodeProp) + ON_UPDATE_COMMAND_UI(ID_VIEW_PROPS, OnUpdateViewProps) + ON_COMMAND(ID_VIEW_PROPS, OnViewProps) + ON_COMMAND(ID_REPLACE_SKIN, OnReplaceSkin) + ON_UPDATE_COMMAND_UI(ID_REPLACE_SKIN, OnUpdateReplaceSkin) + ON_COMMAND(ID_SKIN_IMPORT, OnSkinImport) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CQMViewDoc construction/destruction + +CQMViewDoc::CQMViewDoc() +{ + // TODO: add one-time construction code here + + m_spec_dwFps = 0; + m_spec_dwFramesRendered = 0; + m_spec_dwCurTime = 0; + m_spec_dwDeltaTime = 0; + m_spec_dwLastTime = 0; + m_spec_dwFpsTime = 0; + m_model = NULL; +} + +CQMViewDoc::~CQMViewDoc() +{ +} + +BOOL CQMViewDoc::OnNewDocument() +{ + if (!CDocument::OnNewDocument()) + return FALSE; + + // TODO: add reinitialization code here + // (SDI documents will reuse this document) + + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////// +// CQMViewDoc serialization + +void CQMViewDoc::Serialize(CArchive& ar) +{ + if (ar.IsStoring()) + { + // TODO: add storing code here + } + else + { + CString filename = ar.GetFile()->GetFilePath(); + CString szExt = filename.Right(filename.GetLength() - 1 - filename.ReverseFind('.')); + if (m_model != NULL) + { + UpdateAllViews(NULL, QM_DELETE_MODEL, (CObject*)m_model); + } + m_model = CModel::Create(szExt); + m_model->SetFilename(filename); + m_model->Serialize(ar); + UpdateAllViews(NULL, QM_NEW_MODEL, (CObject*)m_model); + m_spec_dwFps = 0; + m_spec_dwFramesRendered = 0; + m_spec_dwCurTime = 0; + m_spec_dwDeltaTime = 0; + m_spec_dwLastTime = 0; + m_spec_dwFpsTime = 0; + } +} + +///////////////////////////////////////////////////////////////////////////// +// CQMViewDoc diagnostics + +#ifdef _DEBUG +void CQMViewDoc::AssertValid() const +{ + CDocument::AssertValid(); +} + +void CQMViewDoc::Dump(CDumpContext& dc) const +{ + CDocument::Dump(dc); +} +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// CQMViewDoc commands + +LPDIRECT3DRM2 CQMViewDoc::GetD3D() +{ + CMainFrame* mainframe = (CMainFrame*)AfxGetApp()->m_pMainWnd; + return mainframe->GetD3D(); +} + +CModel* CQMViewDoc::GetModel() +{ + return m_model; +} + +void CQMViewDoc::DeleteContents() +{ + // TODO: Add your specialized code here and/or call the base class + if (m_model != NULL) + { + UpdateAllViews(NULL, QM_DELETE_MODEL, (CObject*)m_model); + m_model->Delete(); + m_model = NULL; + } + + m_spec_dwFps = 0; + m_spec_dwFramesRendered = 0; + m_spec_dwCurTime = 0; + m_spec_dwDeltaTime = 0; + m_spec_dwLastTime = 0; + m_spec_dwFpsTime = 0; + CDocument::DeleteContents(); +} + +/* +void CQMViewDoc::OnIdle() +{ + LPSTR szText = "xxFPS: xx/20xx"; + +// if (m_active) + { + m_spec_dwCurTime = timeGetTime(); + m_spec_dwDeltaTime = m_spec_dwCurTime - m_spec_dwLastTime; + m_spec_dwLastTime = m_spec_dwCurTime; + m_spec_dwFpsTime += m_spec_dwDeltaTime; + + if (m_spec_dwFpsTime > 250) + { + m_spec_dwFps = m_spec_dwFramesRendered * 4; + m_spec_dwFramesRendered = 0; + m_spec_dwFpsTime = 0; + + sprintf(szText, "FPS: %2d/20\n", m_spec_dwFps); +// m_wndStatusBar.SetPaneText(1, szText, 1); + } + +// UpdateAllViews(NULL, QM_IDLE, (CObject*)m_model); + m_spec_dwFramesRendered++; + } + +} +*/ + +void CQMViewDoc::OnNodeProp() +{ + // TODO: Add your command handler code here + if (m_model == NULL) + { + return; + } + CNodePropertyDlg nodePropDlg; + nodePropDlg.m_tris.Format("&d", m_model->GetNumTris()); + int ret = nodePropDlg.DoModal(); +} + +void CQMViewDoc::OnCloseDocument() +{ + // TODO: Add your specialized code here and/or call the base class + if (m_model != NULL) + { + UpdateAllViews(NULL, QM_DELETE_MODEL, (CObject*)m_model); + m_model->Delete(); + m_model = NULL; + } + CDocument::OnCloseDocument(); +} + +void CQMViewDoc::OnUpdateViewProps(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + pCmdUI->Enable(m_model != NULL); +} + +void CQMViewDoc::OnViewProps() +{ + // TODO: Add your command handler code here + if (m_model == NULL) + { + return; + } + CPropertySheet* propSheet = new CPropertySheet(m_model->GetFilename()); + m_model->AddPropPages(propSheet); + if (propSheet->DoModal() == IDOK) + { + m_model->UpdateFromPropPages(propSheet); + } + m_model->RemovePropPages(propSheet); + delete propSheet; +} + +void CQMViewDoc::OnUpdateSkinFromFile(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + pCmdUI->Enable(true); +} + +void CQMViewDoc::OnSkinFromFile(UINT nID) +{ + // TODO: Add your command handler code here + CMainFrame* mainframe = (CMainFrame*)AfxGetApp()->m_pMainWnd; + CMenu* popup = mainframe->GetSkinMenu(); + CString filename; + popup->GetMenuString(nID, filename, MF_BYCOMMAND); + ReplaceSkin(filename); +} + +void CQMViewDoc::OnUpdateReplaceSkin(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + pCmdUI->Enable(true); +} + +void CQMViewDoc::OnReplaceSkin() +{ + // TODO: Add your command handler code here + CString extensions; + CString formats; + extensions.LoadString(ID_FILE_EXTENSIONS); + formats.LoadString(ID_SUPPORTED_FORMATS); + CFileDialog fdOpenFile(TRUE,extensions,NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST, formats, NULL); + + if (fdOpenFile.DoModal()==IDOK) + { + ReplaceSkin(fdOpenFile.GetPathName()); + } +} + +void CQMViewDoc::ReplaceSkin(LPCTSTR skinname) +{ + if (m_model == NULL) + { + return; + } + CMainFrame* mainframe = (CMainFrame*)AfxGetApp()->m_pMainWnd; + CTreeCtrl* tree = mainframe->GetSkinTreeCtrl(); + if (tree == NULL) + { + return; + } + HTREEITEM item = tree->GetSelectedItem(); + if (item == NULL) + { + return; + } + if (tree->GetParentItem(item) == TVI_ROOT) + { + return; + } + tree->SetItemText(item, skinname); + + int skinnum = tree->GetItemData(item); + m_model->ReplaceSkin(skinnum, skinname); + UpdateAllViews(NULL, QM_NEW_SKIN, (CObject*)skinnum); +} + + +void CQMViewDoc::OnSkinImport() +{ + // TODO: Add your command handler code here + if (m_model == NULL) + { + return; + } + CString extensions; + CString formats; + extensions.LoadString(ID_FILE_EXTENSIONS); + formats.LoadString(ID_SUPPORTED_FORMATS); + CFileDialog fdOpenFile(TRUE,extensions,NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST, formats, NULL); + + if (fdOpenFile.DoModal()==IDOK) + { + m_model->AddSkin(fdOpenFile.GetPathName()); + CMainFrame* mainframe = (CMainFrame*)AfxGetApp()->m_pMainWnd; + CSkinTreeCtrl* tree = (CSkinTreeCtrl*)mainframe->GetSkinTreeCtrl(); + tree->SetModel(m_model); + ReplaceSkin(fdOpenFile.GetPathName()); + } +} + +void CQMViewDoc::OnUpdateSkinSelect(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here + pCmdUI->Enable(true); +} + +void CQMViewDoc::OnSkinSelect(UINT nID) +{ + // TODO: Add your command handler code here + if (m_model == NULL) + { + return; + } + int skinnum = nID - IDR_SKIN_SELECT_START; + UpdateAllViews(NULL, QM_CHANGE_SKIN, (CObject*)skinnum); +} + +void CQMViewDoc::SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU) +{ + CDocument::SetPathName(lpszPathName, bAddToMRU); + SetTitle(lpszPathName); +} diff --git a/Toolkit/Programming/Tools/qMView/qMViewDoc.h b/Toolkit/Programming/Tools/qMView/qMViewDoc.h new file mode 100644 index 0000000..256dff3 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/qMViewDoc.h @@ -0,0 +1,66 @@ +// qMViewDoc.h : interface of the CQMViewDoc class +// +///////////////////////////////////////////////////////////////////////////// + +class CQMViewDoc : public CDocument +{ +protected: // create from serialization only + CQMViewDoc(); + DECLARE_DYNCREATE(CQMViewDoc) + +// Attributes +public: + +// Operations +public: +// virtual void OnIdle(); + virtual void SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU = TRUE); + CModel* GetModel(); + LPDIRECT3DRM2 GetD3D(); +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CQMViewDoc) + public: + virtual BOOL OnNewDocument(); + virtual void Serialize(CArchive& ar); + virtual void DeleteContents(); + virtual void OnCloseDocument(); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CQMViewDoc(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +protected: + DWORD m_spec_dwFps; + DWORD m_spec_dwFramesRendered; + DWORD m_spec_dwCurTime; + DWORD m_spec_dwDeltaTime; + DWORD m_spec_dwLastTime; + DWORD m_spec_dwFpsTime; + +// Generated message map functions +protected: + void ReplaceSkin(LPCTSTR skinname); + afx_msg void OnSkinFromFile(UINT nID); + afx_msg void OnUpdateSkinFromFile(CCmdUI* pCmdUI); + afx_msg void OnSkinSelect(UINT nID); + afx_msg void OnUpdateSkinSelect(CCmdUI* pCmdUI); + //{{AFX_MSG(CQMViewDoc) + afx_msg void OnNodeProp(); + afx_msg void OnUpdateViewProps(CCmdUI* pCmdUI); + afx_msg void OnViewProps(); + afx_msg void OnReplaceSkin(); + afx_msg void OnUpdateReplaceSkin(CCmdUI* pCmdUI); + afx_msg void OnSkinImport(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + CModel* m_model; +}; + +///////////////////////////////////////////////////////////////////////////// diff --git a/Toolkit/Programming/Tools/qMView/qMViewView.cpp b/Toolkit/Programming/Tools/qMView/qMViewView.cpp new file mode 100644 index 0000000..c56d82e --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/qMViewView.cpp @@ -0,0 +1,1472 @@ +// qMViewView.cpp : implementation of the CQMViewView class +// + +#include "stdafx.h" +#include "resource.h" +#include "DDUtil.h" +#include "Matrix.h" +#include "Model.h" +#include "FlexModel.h" +#include "qMView.h" + +#include "qMViewDoc.h" +#include "qMViewView.h" +#include "treectrlex.h" +#include "frametreectrl.h" +#include "skintreectrl.h" + +#include "SkinPageFrm.h" +#include "JointConstraintDlg.h" +#include "JointAnglesDlg.h" +#include "ManagerTree.h" +#include "FrameManager2.h" + +#include "MainFrm.h" +#include "TickerDlg.h" + +extern pal_t qpal[]; +extern pal_t h2pal[]; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CQMViewView + +IMPLEMENT_DYNCREATE(CQMViewView, CView) + +BEGIN_MESSAGE_MAP(CQMViewView, CView) + //{{AFX_MSG_MAP(CQMViewView) + ON_WM_CREATE() + ON_WM_PAINT() + ON_WM_SIZE() + ON_WM_ERASEBKGND() + ON_COMMAND(ID_ALL_LOCK, OnAllLock) + ON_COMMAND(ID_ALL_UNLOCK, OnAllUnlock) + ON_COMMAND(ID_GOTOPOS_BACK, OnGotoposBack) + ON_COMMAND(ID_GOTOPOS_BOTTOM, OnGotoposBottom) + ON_COMMAND(ID_GOTOPOS_FRONT, OnGotoposFront) + ON_COMMAND(ID_GOTOPOS_LEFT, OnGotoposLeft) + ON_COMMAND(ID_GOTOPOS_RIGHT, OnGotoposRight) + ON_COMMAND(ID_GOTOPOS_TOP, OnGotoposTop) + ON_COMMAND(ID_LOCK_ROT_X, OnLockRotX) + ON_UPDATE_COMMAND_UI(ID_LOCK_ROT_X, OnUpdateLockRotX) + ON_COMMAND(ID_LOCK_ROT_Y, OnLockRotY) + ON_UPDATE_COMMAND_UI(ID_LOCK_ROT_Y, OnUpdateLockRotY) + ON_COMMAND(ID_LOCK_ROT_Z, OnLockRotZ) + ON_UPDATE_COMMAND_UI(ID_LOCK_ROT_Z, OnUpdateLockRotZ) + ON_COMMAND(ID_LOCK_SCALE_X, OnLockScaleX) + ON_UPDATE_COMMAND_UI(ID_LOCK_SCALE_X, OnUpdateLockScaleX) + ON_COMMAND(ID_LOCK_SCALE_Y, OnLockScaleY) + ON_UPDATE_COMMAND_UI(ID_LOCK_SCALE_Y, OnUpdateLockScaleY) + ON_COMMAND(ID_LOCK_SCALE_Z, OnLockScaleZ) + ON_UPDATE_COMMAND_UI(ID_LOCK_SCALE_Z, OnUpdateLockScaleZ) + ON_COMMAND(ID_LOCK_TRAN_X, OnLockTranX) + ON_UPDATE_COMMAND_UI(ID_LOCK_TRAN_X, OnUpdateLockTranX) + ON_COMMAND(ID_LOCK_TRAN_Y, OnLockTranY) + ON_UPDATE_COMMAND_UI(ID_LOCK_TRAN_Y, OnUpdateLockTranY) + ON_COMMAND(ID_LOCK_TRAN_Z, OnLockTranZ) + ON_UPDATE_COMMAND_UI(ID_LOCK_TRAN_Z, OnUpdateLockTranZ) + ON_COMMAND(ID_RENDER_TRANS, OnRenderTrans) + ON_UPDATE_COMMAND_UI(ID_RENDER_TRANS, OnUpdateRenderTrans) + ON_COMMAND(ID_RENDER_TEXTURE, OnRenderTexture) + ON_UPDATE_COMMAND_UI(ID_RENDER_TEXTURE, OnUpdateRenderTexture) + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_RBUTTONDOWN() + ON_WM_RBUTTONUP() + ON_COMMAND(ID_GOTOPOS_WEAPON, OnGotoposWeapon) + ON_COMMAND(ID_TICKER_OPTIONS, OnTickerOptions) + ON_WM_TIMER() + ON_WM_DESTROY() + ON_COMMAND(ID_ANIMATE_STEP_BACK, OnAnimateStepBack) + ON_COMMAND(ID_ANIMATE_STEP_FORE, OnAnimateStepFore) + ON_COMMAND(ID_ANIM_INTERTOGGLE, OnAnimIntertoggle) + ON_UPDATE_COMMAND_UI(ID_ANIM_INTERTOGGLE, OnUpdateAnimIntertoggle) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CQMViewView construction/destruction + +CQMViewView::CQMViewView() +{ + // TODO: add construction code here + m_clipper = NULL; + m_device = NULL; + m_frame = NULL; + m_camera = NULL; + m_viewport = NULL; + m_scene = NULL; + m_transtate = false; + m_curstate = true; + m_drag = false; + m_r_drag = false; + m_globalField = 0.5; + m_interOn = false; + m_last_x = 0; + m_last_y = 0; + m_r_last_x = 0; + m_r_last_y = 0; + + m_lock_rot_x = false; + m_lock_rot_y = false; + m_lock_rot_z = false; + m_lock_scale_x = false; + m_lock_scale_y = false; + m_lock_scale_z = false; + m_lock_trans_x = false; + m_lock_trans_y = false; + m_lock_trans_z = false; + m_d3drm_up = false; + m_d3drm = NULL; +} + +CQMViewView::~CQMViewView() +{ +} + +BOOL CQMViewView::PreCreateWindow(CREATESTRUCT& cs) +{ + // TODO: Modify the Window class or styles here by modifying + // the CREATESTRUCT cs +// cs.style = WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU +// | FWS_ADDTOTITLE | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_MAXIMIZE; + + return CView::PreCreateWindow(cs); +} + +///////////////////////////////////////////////////////////////////////////// +// CQMViewView drawing + +void CQMViewView::OnDraw(CDC* pDC) +{ + CQMViewDoc* pDoc = GetDocument(); + ASSERT_VALID(pDoc); + + // TODO: add draw code for native data here +} + +///////////////////////////////////////////////////////////////////////////// +// CQMViewView diagnostics + +#ifdef _DEBUG +void CQMViewView::AssertValid() const +{ + CView::AssertValid(); +} + +void CQMViewView::Dump(CDumpContext& dc) const +{ + CView::Dump(dc); +} + +CQMViewDoc* CQMViewView::GetDocument() // non-debug version is inline +{ + ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CQMViewDoc))); + return (CQMViewDoc*)m_pDocument; +} + +#endif //_DEBUG + +LPDIRECT3DRM2 CQMViewView::GetD3D() +{ + return m_d3drm; +} + +///////////////////////////////////////////////////////////////////////////// +// CQMViewView message handlers +BOOL CQMViewView::CreateDevice() +{ + HRESULT r = DirectDrawCreateClipper(0, &m_clipper, NULL ); + if (r != D3DRM_OK) + { + TRACE("failed to create D3D clipper\n"); + return FALSE; + } + + r = m_clipper->SetHWnd( NULL, m_hWnd ); + if (r != D3DRM_OK) + { + TRACE("failed in SetHWnd call\n"); + return FALSE; + } + + RECT rect; + ::GetClientRect( m_hWnd, &rect ); +// GetGUID(); + r = m_d3drm->CreateDeviceFromClipper(m_clipper, NULL, //&guid, + rect.right, rect.bottom, + &m_device ); + + if (r!=D3DRM_OK) + { + AfxMessageBox("CreateDeviceFromClipper() failed"); + return FALSE; + } + + m_device->SetQuality( D3DRMRENDER_FLAT ); + + HDC hdc = ::GetDC( m_hWnd ); + int bpp = ::GetDeviceCaps( hdc, BITSPIXEL ); + ::ReleaseDC( m_hWnd, hdc ); + + switch ( bpp ) + { + case 1: + m_device->SetShades( 4 ); + m_d3drm->SetDefaultTextureShades( 4 ); + m_device->SetDither( TRUE ); + break; + case 8: + m_device->SetDither( FALSE ); + break; + case 16: + m_device->SetShades( 32 ); + m_d3drm->SetDefaultTextureColors( 64 ); + m_d3drm->SetDefaultTextureShades( 32 ); + m_device->SetDither( FALSE ); + break; + case 24: + case 32: + m_device->SetShades( 256 ); + m_d3drm->SetDefaultTextureColors( 64 ); + m_d3drm->SetDefaultTextureShades( 256 ); + m_device->SetDither( FALSE ); + break; + } + + m_d3drm->CreateFrame( 0, &m_scene ); + + if (CreateScene()==FALSE) + { + AfxMessageBox("CreateScene() failed"); + return FALSE; + } + + ASSERT(m_camera); + ASSERT(m_viewport); + m_viewport->SetBack( D3DVALUE(8000) ); + + CDDHelper::lpDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL ); + +// r = d3drm->QueryInterface(IID_IDirect3DRM2, (LPVOID *) &d3drm2); + +// if (r != D3D_OK) +// AfxMessageBox("Cannot create reference to IID_IDirect3DRM2!\n"); + + return TRUE; +} + +D3DVALUE CQMViewView::ScaleMesh( LPDIRECT3DRMMESHBUILDER mesh, D3DVALUE dim) +{ + D3DRMBOX box; + mesh->GetBox( &box ); + D3DVALUE sizex = box.max.x - box.min.x; + D3DVALUE sizey = box.max.y - box.min.y; + D3DVALUE sizez = box.max.z - box.min.z; + D3DVALUE largedim=D3DVALUE(0); + if (sizex>largedim) + largedim=sizex; + if (sizey>largedim) + largedim=sizey; + if (sizez>largedim) + largedim=sizez; + D3DVALUE scalefactor = dim/largedim; + mesh->Scale( scalefactor, scalefactor, scalefactor ); + return scalefactor; +} + + +/*GUID* CQMViewView::GetGUID() +{ + HRESULT r; + + D3DFINDDEVICESEARCH searchdata; + memset(&searchdata, 0, sizeof searchdata); + searchdata.dwSize = sizeof searchdata; + searchdata.dwFlags = D3DFDS_COLORMODEL; + searchdata.dcmColorModel = colormodel; + + D3DFINDDEVICERESULT resultdata; + memset( &resultdata, 0, sizeof resultdata ); + resultdata.dwSize = sizeof resultdata; + + LPDIRECTDRAW ddraw; + r = DirectDrawCreate( 0, &ddraw, 0 ); + if (r!=DD_OK) + { + AfxMessageBox("DirectDrawCreate() failed"); + return 0; + } + + LPDIRECT3D d3d; + r = ddraw->QueryInterface( IID_IDirect3D, (void**)&d3d ); + if ( r != D3DRM_OK ) + { + AfxMessageBox("d3drm->QueryInterface() failed\n"); + ddraw->Release(); + ddraw = NULL; + return 0; + } + + r=d3d->FindDevice( &searchdata, &resultdata ); + if ( r==D3D_OK ) + guid = resultdata.guid; + else + { + AfxMessageBox("FindDevice() failed"); + } + + d3d->Release(); + d3d = NULL; + ddraw->Release(); + ddraw = NULL; + + return &guid; +}*/ + +BOOL CQMViewView::CreateScene() +{ + m_scene->SetSceneBackgroundRGB( D3DVALUE(.3), D3DVALUE(.3), D3DVALUE(.3) ); + + m_d3drm->CreateFrame (m_scene, &m_frame); + m_frame->SetOrientation(m_scene, + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), + D3DVALUE(0), D3DVALUE(0), D3DVALUE(1) ); + + m_frame->AddMoveCallback( UpdateDrag, (void*)this); + + // ---------DIRECTIONAL LIGHT-------- + LPDIRECT3DRMLIGHT dlight; + m_d3drm->CreateLightRGB( D3DRMLIGHT_AMBIENT, + D3DVALUE(1.00), D3DVALUE(1.00), D3DVALUE(1.00), + &dlight); + + LPDIRECT3DRMFRAME2 dlightframe; + m_d3drm->CreateFrame(m_scene, &dlightframe ); + dlightframe->AddLight( dlight ); + dlightframe->SetOrientation(m_scene, + D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1), + D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); + + dlight->Release(); + dlight=0; + dlightframe->Release(); + dlightframe=0; + + //------ CAMERA----------- + m_d3drm->CreateFrame(m_scene, &m_camera); + m_camera->SetPosition(m_scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(1.0)); + m_d3drm->CreateViewport(m_device, m_camera, 0, 0, + m_device->GetWidth(),m_device->GetHeight(), + &m_viewport); + + m_d3drm_up = true; + + return TRUE; +} + +void CQMViewView::CreateDot(vec3_t origin, int r, int g , int b) +{ + D3DRMGROUPINDEX group; + LPDIRECT3DRMMESH m_originMesh; + D3DRMVERTEX vertexlist[12]; + + unsigned vertorder[24]; + unsigned numread = 0; + + vertexlist[0].position.x = origin.x - 1; + vertexlist[0].position.y = origin.y; + vertexlist[0].position.z = origin.z; + + vertexlist[2].position.x = origin.x + 1; + vertexlist[2].position.y = origin.y; + vertexlist[2].position.z = origin.z; + + vertexlist[1].position.x = origin.x; + vertexlist[1].position.y = origin.y; + vertexlist[1].position.z = origin.z + 1; + + vertexlist[3].position.x = origin.x; + vertexlist[3].position.y = origin.y; + vertexlist[3].position.z = origin.z - 1; + + vertexlist[4].position.x = origin.x; + vertexlist[4].position.y = origin.y + 1; + vertexlist[4].position.z = origin.z; + + vertexlist[5].position.x = origin.x; + vertexlist[5].position.y = origin.y - 1; + vertexlist[5].position.z = origin.z; + + vertorder[0] = 1; + vertorder[1] = 4; + vertorder[2] = 0; + + vertorder[3] = 4; + vertorder[4] = 3; + vertorder[5] = 0; + + vertorder[6] = 1; + vertorder[7] = 2; + vertorder[8] = 4; + + vertorder[9] = 2; + vertorder[10] = 3; + vertorder[11] = 4; + + ////////////////// + + vertorder[12] = 3; + vertorder[13] = 5; + vertorder[14] = 0; + + vertorder[15] = 5; + vertorder[16] = 1; + vertorder[17] = 0; + + vertorder[18] = 3; + vertorder[19] = 2; + vertorder[20] = 5; + + vertorder[21] = 2; + vertorder[22] = 1; + vertorder[23] = 5; + + m_d3drm->CreateMesh(&m_originMesh); + + m_originMesh->AddGroup( 24, 8, 3, vertorder, &group ); + m_originMesh->SetVertices(group, 0, 23, vertexlist ); + + m_originMesh->SetGroupQuality(group, D3DRMRENDER_FLAT ); + m_originMesh->SetGroupColorRGB(group, D3DVALUE( r ), D3DVALUE( g ), D3DVALUE( b )); + + HRESULT ddrval = m_frame->AddVisual(m_originMesh); + if (ddrval != D3DRM_OK) + AfxMessageBox(CDDHelper::TraceError(ddrval)); + + m_originMesh->Release(); +} + +void CQMViewView::CreateOriginVisual() +{ + vec3_t org; + + org.z = 0; + org.y = 0; + org.x = 0; + + CreateDot( org, 255, 0, 0 ); + + org.x = -10; + org.y = 0; + org.z = 0; + + CreateDot( org, 0, 255, 0 ); + + org.x = 0; + org.y = -10; + org.z = 0; + + CreateDot( org, 0, 0, 255 ); + + org.x = 0; + org.y = 0; + org.z = -10; + + CreateDot( org, 255, 255, 0 ); +} + +int CQMViewView::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CView::OnCreate(lpCreateStruct) == -1) + return -1; + + m_drag = false; + m_r_drag = false; + + m_last_x = 0; + m_last_y = 0; + m_r_last_x = 0; + m_r_last_y = 0; + + //Setup the D3DDevice + HRESULT r = Direct3DRMCreate((LPDIRECT3DRM*)&m_d3drm); + if (r != D3DRM_OK) + { + TRACE("failed to create D3DRM object\n"); + return -1; + } + SetColorModel(D3DCOLOR_RGB); + return 0; +} + +void CQMViewView::OnPaint() +{ + if (m_device == NULL) + { + if (!CreateDevice()) + { + PostQuitMessage(0); + } + } + if (GetUpdateRect( 0, FALSE )==FALSE) + return; + + if (m_device) + { + LPDIRECT3DRMWINDEVICE windev; + PAINTSTRUCT ps; + BeginPaint(&ps); + if (m_device->QueryInterface(IID_IDirect3DRMWinDevice, (void**)&windev)==0) + { + if (windev->HandlePaint(ps.hdc)!=0) + AfxMessageBox("windev->HandlePaint() failure"); + windev->Release(); + windev = NULL; + } + else + AfxMessageBox("Failed to create Windows device to handle WM_PAINT"); + + EndPaint(&ps); + } +} + +void CQMViewView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView) +{ + // TODO: Add your specialized code here and/or call the base class + CModel* theModel = GetDocument()->GetModel(); + if (theModel != NULL) + { + bool useTimer; + long timerDelay; + theModel->GetTimerData(&timerDelay, &useTimer); + if (useTimer) + { + if (bActivate) + { + SetTimer(1, timerDelay, NULL); + } + else + { + KillTimer(1); + } + } + } + + LPDIRECT3DRMWINDEVICE windev; + if (m_device) + { + if (m_device->QueryInterface( IID_IDirect3DRMWinDevice, (void**)&windev)==0) + { + if (windev->HandleActivate((WPARAM)bActivate) ) + AfxMessageBox("windev->HandleActivate() failure"); + windev->Release(); + windev = NULL; + } + else + AfxMessageBox("device->QueryInterface(WinDevice) failure"); + } + CView::OnActivateView(bActivate, pActivateView, pDeactiveView); +} + +void CQMViewView::OnSize(UINT nType, int cx, int cy) +{ + CView::OnSize(nType, cx, cy); + + if (!m_device) + return; + + int width = cx; + int height = cy; + + if (width && height) + { + int view_width = m_viewport->GetWidth(); + int view_height = m_viewport->GetHeight(); + int dev_width = m_device->GetWidth(); + int dev_height = m_device->GetHeight(); + + if (view_width == width && view_height == height) + return; + + int old_dither = m_device->GetDither(); + D3DRMRENDERQUALITY old_quality = m_device->GetQuality(); + int old_shades = m_device->GetShades(); + + m_viewport->Release(); + m_viewport = NULL; + m_device->Release(); + m_device = NULL; +// GetGUID(); + m_d3drm->CreateDeviceFromClipper(m_clipper, NULL,/*&guid,*/ width, height, &m_device ); + + m_device->SetDither(old_dither); + m_device->SetQuality(old_quality); + m_device->SetShades(old_shades); + + width = m_device->GetWidth(); + height = m_device->GetHeight(); + m_d3drm->CreateViewport(m_device, m_camera, 0, 0, width, height, &m_viewport); + + m_viewport->SetBack( D3DVALUE(8000) ); + } +} + +BOOL CQMViewView::OnEraseBkgnd(CDC* pDC) +{ + COLORREF bgcolor; + if (m_scene) + { + D3DCOLOR scenecolor=m_scene->GetSceneBackground(); + bgcolor=D3DCOLOR_2_COLORREF(scenecolor); + } + else + bgcolor=RGB(0,0,0); + + CBrush br( bgcolor ); + CRect rc; + GetClientRect(&rc); + pDC->FillRect(&rc, &br); + + return TRUE; +} + +/* + * UpdateDrag + * + * Mesh animation callback function + * + */ +void CQMViewView::UpdateDrag(LPDIRECT3DRMFRAME frame, void* data, D3DVALUE) +{ + D3DVECTOR dv; + + CQMViewView* view = (CQMViewView*)data; + CModel* model = view->GetDocument()->GetModel(); + + POINT curMouse; + GetCursorPos(&curMouse); + view->ScreenToClient(&curMouse); + + if (view->m_drag) + { + double delta_x = curMouse.x - view->m_last_x; + double delta_y = curMouse.y - view->m_last_y; + + if (delta_x || delta_y) view->m_has_moved = TRUE; + + if (view->m_lock_rot_x) delta_x = 0; + if (view->m_lock_rot_y) delta_y = 0; + + view->m_last_x = curMouse.x; + view->m_last_y = curMouse.y; + double delta_r = sqrt(delta_x * delta_x + delta_y * delta_y); + double radius = 50; + double denom= sqrt(radius * radius + delta_r * delta_r); + if (fabs(delta_r) > 1) + { + if (((CMainFrame*)view->GetParent())->GetManipulationType() == MANIPULATE_CAMERA) + { + if (!(delta_r == 0 || denom == 0)) + { + if (GetKeyState(VK_SHIFT)&0x8000) + { + frame->SetRotation( 0, + D3DVALUE(0.0), + D3DVALUE(0.0), + D3DVALUE(1.0), + D3DVALUE(-delta_x / 100) ); + frame->SetVelocity(0,0,0,0,true); + } + else + { + frame->SetRotation( 0, + D3DDivide(-delta_y, delta_r), + D3DDivide(-delta_x, delta_r), + D3DVALUE(0.0), + D3DDivide(delta_r, denom) ); + frame->SetVelocity(0,0,0,0,true); + } + } + } + else + { + if (model != NULL) + { + model->Drag(delta_x, delta_y); + model->ShowFrame(view->m_d3drm, view->GetDC()); + } + } + } + else + { + frame->SetRotation( 0, 0, 0, D3DVALUE(0.0), 0); + frame->SetVelocity(0,0,0,0,true); + } + } + + if (view->m_r_drag) + { + double delta_x = curMouse.x - view->m_r_last_x; + double delta_y = curMouse.y - view->m_r_last_y; + + if (delta_x || delta_y) view->m_r_has_moved = TRUE; + + view->m_r_last_x = curMouse.x; + view->m_r_last_y = curMouse.y; + + frame->GetPosition(view->m_scene, &dv ); + + if (!view->m_lock_trans_x) dv.x += D3DVALUE(delta_x / 10); + if (!view->m_lock_trans_y) dv.y -= D3DVALUE(delta_y / 10); + dv.z = D3DVALUE(0.0); + + frame->SetPosition(view->m_scene, D3DVALUE(dv.x), D3DVALUE(dv.y), D3DVALUE(0) ); + + if ((GetKeyState(VK_CONTROL)&0x8000) && (model != NULL)) + { + model->SetCurScale(model->GetCurScale() + delta_y); + view->m_camera->SetPosition(view->m_scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(model->GetCurScale())); + } + } + +} + +void CQMViewView::OnAllLock() +{ + m_lock_rot_x = true; + m_lock_rot_y = true; + m_lock_rot_z = true; + m_lock_scale_x = true; + m_lock_scale_y = true; + m_lock_scale_z = true; + m_lock_trans_x = true; + m_lock_trans_y = true; + m_lock_trans_z = true; +} + +void CQMViewView::OnAllUnlock() +{ + m_lock_rot_x = false; + m_lock_rot_y = false; + m_lock_rot_z = false; + m_lock_scale_x = false; + m_lock_scale_y = false; + m_lock_scale_z = false; + m_lock_trans_x = false; + m_lock_trans_y = false; + m_lock_trans_z = false; +} + +void CQMViewView::OnGotoposBack() +{ + m_frame->SetPosition(m_scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + m_frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + m_frame->SetVelocity(0,0,0,0,true); + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + model->SetBackOrientation(m_frame, m_scene); +} + +void CQMViewView::OnGotoposBottom() +{ + m_frame->SetPosition(m_scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + m_frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + m_frame->SetVelocity(0,0,0,0,true); + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + model->SetBottomOrientation(m_frame, m_scene); +} + +void CQMViewView::OnGotoposFront() +{ + m_frame->SetPosition(m_scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + m_frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + m_frame->SetVelocity(0,0,0,0,true); + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + model->SetFrontOrientation(m_frame, m_scene); +} + +void CQMViewView::OnGotoposLeft() +{ + m_frame->SetPosition(m_scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + m_frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + m_frame->SetVelocity(0,0,0,0,true); + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + model->SetLeftOrientation(m_frame, m_scene); +} + +void CQMViewView::OnGotoposRight() +{ + m_frame->SetPosition(m_scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + m_frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + m_frame->SetVelocity(0,0,0,0,true); + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + model->SetRightOrientation(m_frame, m_scene); +} + +void CQMViewView::OnGotoposTop() +{ + m_frame->SetPosition(m_scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(0) ); + + m_frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + m_frame->SetVelocity(0,0,0,0,true); + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + model->SetTopOrientation(m_frame, m_scene); +} + +void CQMViewView::OnLockRotX() +{ + m_lock_rot_x = !m_lock_rot_x; +} + +void CQMViewView::OnUpdateLockRotX(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_lock_rot_x); +} + +void CQMViewView::OnLockRotY() +{ + m_lock_rot_y = !m_lock_rot_y; +} + +void CQMViewView::OnUpdateLockRotY(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_lock_rot_y); +} + +void CQMViewView::OnLockRotZ() +{ + m_lock_rot_z = !m_lock_rot_z; +} + +void CQMViewView::OnUpdateLockRotZ(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_lock_rot_z); +} + +void CQMViewView::OnLockScaleX() +{ + m_lock_scale_x = !m_lock_scale_x; +} + +void CQMViewView::OnUpdateLockScaleX(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_lock_scale_x); +} + +void CQMViewView::OnLockScaleY() +{ + m_lock_scale_y = !m_lock_scale_y; +} + +void CQMViewView::OnUpdateLockScaleY(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_lock_scale_y); +} + +void CQMViewView::OnLockScaleZ() +{ + m_lock_scale_z = !m_lock_scale_z; +} + +void CQMViewView::OnUpdateLockScaleZ(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_lock_scale_z); +} + +void CQMViewView::OnLockTranX() +{ + m_lock_trans_x = !m_lock_trans_x; +} + +void CQMViewView::OnUpdateLockTranX(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_lock_trans_x); +} + +void CQMViewView::OnLockTranY() +{ + m_lock_trans_y = !m_lock_trans_y; +} + +void CQMViewView::OnUpdateLockTranY(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_lock_trans_y); +} + +void CQMViewView::OnLockTranZ() +{ + m_lock_trans_z = !m_lock_trans_z; +} + +void CQMViewView::OnUpdateLockTranZ(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_lock_trans_z); +} + +void CQMViewView::OnRenderTexture() +{ + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + m_curstate = !m_curstate; + model->RenderTexture(m_d3drm, GetDC(), m_curstate); + GetDocument()->GetModel()->ShowFrame(m_d3drm, GetDC()); +} + +void CQMViewView::OnUpdateRenderTexture(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_curstate); +} + +void CQMViewView::OnRenderTrans() +{ + m_transtate = !m_transtate; + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + model->SetTransparency(m_d3drm, GetDC(), m_transtate); + + model->ShowFrame(m_d3drm, GetDC()); +} + +void CQMViewView::OnUpdateRenderTrans(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_transtate); +} + +int CQMViewView::PickFace( const CPoint &point) +{ + HRESULT r; + LPDIRECT3DRMPICKEDARRAY pickarray; + + m_viewport->Pick(point.x, point.y, &pickarray); + + int faceindex=-1; + DWORD numpicks=pickarray->GetSize(); + + if(numpicks>0) + { + LPDIRECT3DRMVISUAL visual; + LPDIRECT3DRMFRAMEARRAY framearray; + D3DRMPICKDESC pickdesc; + + r=pickarray->GetPick( 0, &visual, &framearray, &pickdesc ); + if(r==D3DRM_OK) + { + faceindex=pickdesc.ulFaceIdx; + visual->Release(); + visual = NULL; + framearray->Release(); + framearray = NULL; + } + } + pickarray->Release(); + pickarray = NULL; + + return faceindex; +} + +void CQMViewView::PickMesh(CPoint point) +{ + HRESULT r; + LPDIRECT3DRMPICKEDARRAY pickarray; + + m_viewport->Pick(point.x, point.y, &pickarray); + + int faceindex=-1; + DWORD numpicks=pickarray->GetSize(); + + if(numpicks>0) + { + LPDIRECT3DRMVISUAL visual; + LPDIRECT3DRMFRAMEARRAY framearray; + D3DRMPICKDESC pickdesc; + + r=pickarray->GetPick( 0, &visual, &framearray, &pickdesc ); + + if(r==D3DRM_OK) + { + HTREEITEM item = GetDocument()->GetModel()->SelectMesh(visual); + if (item != NULL) + { + ((CMainFrame*)GetParent())->PickNode(item); + } + visual->Release(); + visual = NULL; + framearray->Release(); + framearray = NULL; + } + } + pickarray->Release(); + pickarray = NULL; +} + +void CQMViewView::DrawOnSkin(UINT nFlags, CPoint point) +{ + LPDIRECT3D2 d3d; + HRESULT r = CDDHelper::lpDD->QueryInterface(IID_IDirect3D2, (void**)&d3d); + if (r != D3DRM_OK) + { + return ; + } + d3d->Release(); + + LPDIRECT3DRMPICKED2ARRAY pickedArray = NULL; + DWORD flags; + D3DRMRAY ray; + + flags = D3DRMRAYPICK_IGNOREFURTHERPRIMITIVES | D3DRMRAYPICK_INTERPOLATEUV; + + ray.dvDir.x = 0.0f; + ray.dvDir.y = 0.0f; + ray.dvDir.z = 1.0f; + + ray.dvPos.x = 0.0f; + ray.dvPos.y = 0.0f; + ray.dvPos.z = 0.0f; + + HRESULT ret = m_scene->RayPick(m_camera, &ray, flags, &pickedArray); + + if (ret != D3DRM_OK) + { + AfxMessageBox(CDDHelper::TraceError(ret)); + return; + } + + if (!pickedArray) + { + AfxMessageBox("Hit fail\n"); + return; + } + + DWORD numpicks=pickedArray->GetSize(); +// LPDIRECT3DRMVISUAL visual; +// LPDIRECT3DRMFRAMEARRAY framearray; +// D3DRMPICKDESC2 pickdesc; +// char out[128]; +// D3DRMVECTOR4D sv; +} + +void CQMViewView::OnLButtonDown(UINT nFlags, CPoint point) +{ + SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_HAND_CLOSED))); + if ((GetKeyState(VK_CONTROL)&0x8000) && (GetKeyState(VK_SHIFT)&0x8000)) + { + PickMesh(point); + CView::OnLButtonDown(nFlags, point); + return; + } +/* + if (GetKeyState(VK_CONTROL)&0x8000) + { + DrawOnSkin(nFlags, point); + } +*/ + if (!m_drag) + { + m_drag=true; + m_last_x = point.x; + m_last_y = point.y; + SetCapture(); + //ShowCursor(FALSE); + } + + CView::OnLButtonDown(nFlags, point); +} + +void CQMViewView::OnLButtonUp(UINT nFlags, CPoint point) +{ + SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_HAND_OPEN))); + + if (m_drag) + { + m_drag = false; + ReleaseCapture(); + double delta_x = point.x - m_last_x; + double delta_y = point.y - m_last_y; + + if (!delta_x && !delta_y) + { + if (!m_has_moved && GetDocument()->GetModel()) + { + GetDocument()->GetModel()->SetCurScale(GetDocument()->GetModel()->GetCurScale() + 5); + m_camera->SetPosition(m_scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(GetDocument()->GetModel()->GetCurScale())); + } + } + m_has_moved = FALSE; + } + + CView::OnLButtonUp(nFlags, point); +} + +void CQMViewView::OnRButtonDown(UINT nFlags, CPoint point) +{ + SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_HAND_CLOSED))); + + if (!m_r_drag) + { + m_r_drag=true; + m_r_last_x = point.x; + m_r_last_y = point.y; + SetCapture(); + //ShowCursor(FALSE); + } + + CView::OnRButtonDown(nFlags, point); +} + +void CQMViewView::OnRButtonUp(UINT nFlags, CPoint point) +{ + SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_HAND_OPEN))); + + if (m_r_drag) + { + m_r_drag = false; + ReleaseCapture(); + double delta_x = point.x - m_r_last_x; + double delta_y = point.y - m_r_last_y; + + if (!delta_x && !delta_y) + { + if (!m_r_has_moved && GetDocument()->GetModel()) + { + GetDocument()->GetModel()->SetCurScale(GetDocument()->GetModel()->GetCurScale() - 5); + m_camera->SetPosition(m_scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(GetDocument()->GetModel()->GetCurScale())); + } + } + m_r_has_moved = FALSE; + } + + CView::OnRButtonUp(nFlags, point); +} + +void CQMViewView::OnGotoposWeapon() +{ + m_frame->SetPosition(m_scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-50) ); + + m_frame->SetRotation( 0, + D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), + D3DVAL(0.0) ); + + m_frame->SetVelocity(0,0,0,0,true); + m_frame->SetOrientation(m_scene, + D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1), + D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) ); + + m_viewport->SetField(D3DVALUE(m_globalField)); +} + +void CQMViewView::OnTickerOptions() +{ + CModel* theModel = GetDocument()->GetModel(); + if (theModel == NULL) + { + return; + } + + CTickerDlg tDlg; + bool useTimer; + theModel->GetTimerData(&tDlg.m_nTickerDelay, &useTimer); + tDlg.m_nUseTicker = useTimer; + + if (tDlg.DoModal()==IDOK) + { + useTimer = (tDlg.m_nUseTicker != 0); + theModel->SetTimerData(tDlg.m_nTickerDelay, useTimer); + } +} + +void CQMViewView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) +{ + // TODO: Add your specialized code here and/or call the base class + CModel* theModel; + long timerDelay; + bool useTimer; + switch(lHint) + { + case QM_IDLE: + break; + case QM_NEW_MODEL: + { + CDC *pDC; +//code stolen from the onPaint method to make sure this stuff is created before we go loading into it! + if (m_device == NULL) + { + if (!CreateDevice()) + { + PostQuitMessage(0); + } + } +//prolly not the best place for it, but it works for now. + theModel = (CModel*)pHint; + ((CMainFrame*)GetParent())->SetModel(theModel); + theModel->CreateJointVisuals(m_d3drm, m_frame); + pDC = GetDC(); + theModel->BuildMesh(m_d3drm, m_frame, m_scene, pDC); + ReleaseDC(pDC); + m_camera->SetPosition(m_scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(theModel->GetCurScale())); + CreateOriginVisual(); + theModel->SetInitialOrientation(m_frame, m_scene); + m_transtate = false; + theModel->GetTimerData(&timerDelay, &useTimer); + if (useTimer) + { + SetTimer(1, timerDelay, NULL); + } + } + break; + case QM_UPDATE_MODEL: + theModel = GetDocument()->GetModel(); + if (theModel != NULL) + { + theModel->ShowFrame(m_d3drm, GetDC()); + } + break; + case QM_RUN_ANIMATION: + theModel = GetDocument()->GetModel(); + if (theModel == NULL) + { + break; + } +// theModel->GetTimerData(&timerDelay, &useTimer); +// if (useTimer) +// { +// SetTimer(1, timerDelay, NULL); +// } + break; + case QM_STOP_ANIMATION: +// KillTimer(1); + break; + case QM_DELETE_MODEL: + KillTimer(1); + theModel = (CModel*)pHint; + if (theModel != NULL) + { + theModel->DeleteVisuals(m_frame); + } + ((CMainFrame*)GetParent())->SetModel(NULL); + ((CMainFrame*)GetParent())->DestroyJointDialogs(); + if (theModel != NULL) + { + theModel->DeleteMeshs(m_frame); + } + break; + case QM_CHANGE_VISUAL: + theModel = GetDocument()->GetModel(); + if (theModel != NULL) + { + theModel->ChangeVisual(m_frame, (int)pHint); + } + break; + case QM_ALLNODES_VISIBLE: + theModel = (CModel*)pHint; + if (theModel != NULL) + { + theModel->MakeAllNodesVisible(m_frame); + } + break; + case QM_ADD_VISUAL: + theModel = GetDocument()->GetModel(); + if (theModel != NULL) + { + m_frame->AddVisual(theModel->GetMesh((int)pHint)); + } + break; + case QM_DELETE_VISUAL: + theModel = GetDocument()->GetModel(); + if (theModel != NULL) + { + m_frame->DeleteVisual(theModel->GetMesh((int)pHint)); + } + break; + case QM_NEW_SKIN: + theModel = GetDocument()->GetModel(); + theModel->LoadSkin(m_d3drm, m_frame, (int)pHint, GetDC()); + theModel->ShowFrame(m_d3drm, GetDC()); +// theModel->TextureChanged(); + break; + case QM_CHANGE_SKIN: + theModel = GetDocument()->GetModel(); + if (theModel != NULL) + { + CMainFrame* mainframe = (CMainFrame*)AfxGetApp()->m_pMainWnd; + CNodeTreeCtrl* tree = (CNodeTreeCtrl*)mainframe->GetNodeTreeCtrl(); + if (tree == NULL) + { + break; + } + HTREEITEM item = tree->GetSelectedItem(); + if (item == NULL) + { + break; + } + int nodenum = tree->GetItemData(item); + theModel->ChangeSkin(m_d3drm, GetDC(), nodenum, (int)pHint); + theModel->ShowFrame(m_d3drm, GetDC()); + } + break; + } +} + +void CQMViewView::OnTimer(UINT nIDEvent) +{ + // TODO: Add your message handler code here and/or call default + CModel* theModel = GetDocument()->GetModel(); + if ((theModel == NULL) || !m_d3drm_up) + { + return; + } + if (theModel->Playing()) + { + theModel->UpdateFrame(m_d3drm, GetDC(), theModel->GetPlayMode(), m_interOn); + } + m_d3drm->Tick(D3DVALUE(1)); + CView::OnTimer(nIDEvent); +} + +void CQMViewView::OnDestroy() +{ + m_d3drm_up = false; + + CView::OnDestroy(); + + // TODO: Add your message handler code here + + CModel* model = GetDocument()->GetModel(); + if (model != NULL) + { + model->DeleteVisuals(m_frame); + } + if (m_scene) + { + m_scene->Release(); + m_scene=0; + } + + if (m_device) + { + m_device->Release(); + m_device=0; + } + + if (m_clipper) + { + m_clipper->Release(); + m_clipper=NULL; + } + + if (m_frame) + { + m_frame->Release(); + m_frame = NULL; + } + + if (m_d3drm) + { + m_d3drm->Release(); + m_d3drm=0; + } + + if (CDDHelper::lpDD) + { + CDDHelper::lpDD->Release(); + CDDHelper::lpDD = 0; + } +} + + +void CQMViewView::OnAnimateStepBack() +{ + // TODO: Add your command handler code here + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + model->UpdateFrame(m_d3drm, GetDC(), ANIM_BACKWARD, m_interOn); +} + +void CQMViewView::OnAnimateStepFore() +{ + // TODO: Add your command handler code here + CModel* model = GetDocument()->GetModel(); + if (model == NULL) + { + return; + } + model->UpdateFrame(m_d3drm, GetDC(), ANIM_FORWARD, m_interOn); +} + +void CQMViewView::OnAnimIntertoggle() +{ + m_interOn = !m_interOn; +} + +void CQMViewView::OnUpdateAnimIntertoggle(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_interOn); +} + diff --git a/Toolkit/Programming/Tools/qMView/qMViewView.h b/Toolkit/Programming/Tools/qMView/qMViewView.h new file mode 100644 index 0000000..b530ec1 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/qMViewView.h @@ -0,0 +1,171 @@ +// qMViewView.h : interface of the CQMViewView class +// +///////////////////////////////////////////////////////////////////////////// + +class CQMViewView : public CView +{ +protected: // create from serialization only + CQMViewView(); + DECLARE_DYNCREATE(CQMViewView) + +// Attributes +public: + CQMViewDoc* GetDocument(); + LPDIRECT3DRM2 GetD3D(); + +// Operations +public: + BOOL CreateDevice(); + void CreateDot(vec3_t origin, int r, int g , int b); + + static void UpdateDrag(LPDIRECT3DRMFRAME frame, void* data, D3DVALUE); + +// GUID* GetGUID(); + BOOL CreateScene(); + D3DVALUE ScaleMesh( LPDIRECT3DRMMESHBUILDER mesh, D3DVALUE dim); + + void PickMesh(CPoint point); + + void SetColorModel( D3DCOLORMODEL cm ) { m_colormodel=cm; } + inline COLORREF D3DCOLOR_2_COLORREF(D3DCOLOR d3dclr); + inline D3DCOLOR COLORREF_2_D3DCOLOR(COLORREF cref); + + D3DCOLORMODEL m_colormodel; + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CQMViewView) + public: + virtual void OnDraw(CDC* pDC); // overridden to draw this view + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + protected: + virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); + virtual void OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CQMViewView(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +protected: + void DrawOnSkin(UINT nFlags, CPoint point); + +// Generated message map functions +protected: + LPDIRECTDRAWCLIPPER m_clipper; + LPDIRECT3DRMDEVICE2 m_device; + LPDIRECT3DRMFRAME2 m_frame; + LPDIRECT3DRMFRAME2 m_camera; + LPDIRECT3DRMVIEWPORT m_viewport; + LPDIRECT3DRMFRAME2 m_scene; + bool m_transtate; + bool m_curstate; + bool m_d3drm_up; + LPDIRECT3DRM2 m_d3drm; + double m_globalField; + +// mouse movements + BOOL m_drag; + BOOL m_r_drag; + + BOOL m_has_moved; + BOOL m_r_has_moved; + + int m_last_x; + int m_last_y; + int m_r_last_x; + int m_r_last_y; + +// locks + bool m_lock_rot_x; + bool m_lock_rot_y; + bool m_lock_rot_z; + bool m_lock_scale_x; + bool m_lock_scale_y; + bool m_lock_scale_z; + bool m_lock_trans_x; + bool m_lock_trans_y; + bool m_lock_trans_z; + + bool m_interOn; + + void CreateOriginVisual(); + int PickFace(const CPoint &point); + + //{{AFX_MSG(CQMViewView) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnPaint(); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnAllLock(); + afx_msg void OnAllUnlock(); + afx_msg void OnGotoposBack(); + afx_msg void OnGotoposBottom(); + afx_msg void OnGotoposFront(); + afx_msg void OnGotoposLeft(); + afx_msg void OnGotoposRight(); + afx_msg void OnGotoposTop(); + afx_msg void OnLockRotX(); + afx_msg void OnUpdateLockRotX(CCmdUI* pCmdUI); + afx_msg void OnLockRotY(); + afx_msg void OnUpdateLockRotY(CCmdUI* pCmdUI); + afx_msg void OnLockRotZ(); + afx_msg void OnUpdateLockRotZ(CCmdUI* pCmdUI); + afx_msg void OnLockScaleX(); + afx_msg void OnUpdateLockScaleX(CCmdUI* pCmdUI); + afx_msg void OnLockScaleY(); + afx_msg void OnUpdateLockScaleY(CCmdUI* pCmdUI); + afx_msg void OnLockScaleZ(); + afx_msg void OnUpdateLockScaleZ(CCmdUI* pCmdUI); + afx_msg void OnLockTranX(); + afx_msg void OnUpdateLockTranX(CCmdUI* pCmdUI); + afx_msg void OnLockTranY(); + afx_msg void OnUpdateLockTranY(CCmdUI* pCmdUI); + afx_msg void OnLockTranZ(); + afx_msg void OnUpdateLockTranZ(CCmdUI* pCmdUI); + afx_msg void OnRenderTrans(); + afx_msg void OnUpdateRenderTrans(CCmdUI* pCmdUI); + afx_msg void OnRenderTexture(); + afx_msg void OnUpdateRenderTexture(CCmdUI* pCmdUI); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnRButtonUp(UINT nFlags, CPoint point); + afx_msg void OnGotoposWeapon(); + afx_msg void OnTickerOptions(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnDestroy(); + afx_msg void OnAnimateStepBack(); + afx_msg void OnAnimateStepFore(); + afx_msg void OnAnimIntertoggle(); + afx_msg void OnUpdateAnimIntertoggle(CCmdUI* pCmdUI); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#ifndef _DEBUG // debug version in qMViewView.cpp +inline CQMViewDoc* CQMViewView::GetDocument() + { return (CQMViewDoc*)m_pDocument; } +#endif + +///////////////////////////////////////////////////////////////////////////// +inline D3DCOLOR CQMViewView::COLORREF_2_D3DCOLOR(COLORREF cref) +{ + D3DVALUE r=D3DVALUE(GetRValue(cref))/D3DVALUE(255); + D3DVALUE g=D3DVALUE(GetGValue(cref))/D3DVALUE(255); + D3DVALUE b=D3DVALUE(GetBValue(cref))/D3DVALUE(255); + return D3DRMCreateColorRGB( r, g, b ); +} + +inline COLORREF CQMViewView::D3DCOLOR_2_COLORREF(D3DCOLOR d3dclr) +{ + D3DVALUE red=D3DVALUE(255)*D3DRMColorGetRed(d3dclr); + D3DVALUE green=D3DVALUE(255)*D3DRMColorGetGreen( d3dclr ); + D3DVALUE blue=D3DVALUE(255)*D3DRMColorGetBlue( d3dclr ); + return RGB((int)red,(int)green,(int)blue); +} + diff --git a/Toolkit/Programming/Tools/qMView/resource.h b/Toolkit/Programming/Tools/qMView/resource.h new file mode 100644 index 0000000..9e29f9e --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/resource.h @@ -0,0 +1,139 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by qMView.rc +// +#define IDAPPLY 3 +#define IDD_ABOUTBOX 100 +#define CG_ID_VIEW_FRAMETREEDLG 104 +#define CG_IDD_FRAMEMANAGER2 105 +#define CG_ID_VIEW_FRAMEMANAGER2 106 +#define IDD_PP_GENERAL 107 +#define CG_IDR_POPUP_NODE_TREE_CTRL 108 +#define IDR_SKIN 128 +#define IDR_QMVIEWTYPE 129 +#define IDB_SPLASH 130 +#define IDB_LOGO 131 +#define IDB_RAVEN 132 +#define IDR_VIEWPOSBAR 139 +#define IDR_ANIMBAR 145 +#define IDR_ANIMBAR1 146 +#define IDB_BITMAP1 147 +#define IDC_HAND_OPEN 151 +#define IDC_HAND_CLOSED 152 +#define IDC_HAND_ROTATE 153 +#define CG_IDD_TREEMANAGER 155 +#define IDB_BITMAP2 157 +#define IDB_BITMAP3 158 +#define IDB_BITMAP4 159 +#define IDD_NODE_PROP 160 +#define IDD_TICKER 164 +#define IDC_MAGNIFIER 166 +#define IDD_JOINT_ANGLES 168 +#define IDD_JOINT_LOCK_ANGLES 169 +#define IDR_SKIN_POPUP_MENU 176 +#define IDR_QMVIEWTYPE1 177 +#define IDC_SKINTREE 1000 +#define IDC_FRAMETREE 1001 +#define IDC_NODETREE 1005 +#define IDC_JOINTTREE 1006 +#define IDC_TICKTOG 1009 +#define IDC_EDIT1 1010 +#define IDC_SPIN1 1011 +#define IDC_YVAL 1014 +#define IDC_ZVAL 1015 +#define IDC_XVAL 1016 +#define IDC_APPLY 1017 +#define IDC_XVAL2 1018 +#define IDC_PPGEN_FRAMES 1018 +#define IDC_YVAL2 1019 +#define IDC_PPGEN_GLCOMMANDS 1019 +#define IDC_ZVAL2 1020 +#define IDC_PPGEN_SKINS 1020 +#define IDC_PPGEN_TRIS 1021 +#define IDC_PPGEN_GROUPS 1022 +#define IDC_PPGEN_SKINWIDTH 1023 +#define IDC_PPGEN_SKINHEIGHT 1024 +#define IDC_PPGEN_STVERTS 1025 +#define IDC_PPGEN_VERTS 1026 +#define ID_PALETTE_IMPORT 32772 +#define ID_PALETTE_EXPORT 32773 +#define ID_SKIN_IMPORT 32774 +#define ID_SKIN_EXPORT 32775 +#define ID_FRAME_IMPORT 32776 +#define ID_FRAME_EXPORT 32777 +#define ID_ANIMATE_PLAY 32778 +#define ID_ANIMATE_STOP 32779 +#define ID_ANIMATE_STEP_FORE 32780 +#define ID_BUTTON32781 32781 +#define ID_ANIMATE_TYPE_FRONT 32782 +#define ID_ANIMATE_TYPE_BACK 32783 +#define ID_ANIMATE_TYPE_PINGPONG 32784 +#define ID_ANIMATE_STEP_BACK 32785 +#define ID_LOCK_ROT_X 32786 +#define ID_LOCK_ROT_Y 32787 +#define ID_LOCK_ROT_Z 32788 +#define ID_LOCK_TRAN_X 32789 +#define ID_LOCK_TRAN_Y 32790 +#define ID_LOCK_TRAN_Z 32791 +#define ID_LOCK_SCALE_X 32792 +#define ID_LOCK_SCALE_Y 32793 +#define ID_LOCK_SCALE_Z 32794 +#define ID_ALL_UNLOCK 32798 +#define ID_ALL_LOCK 32799 +#define ID_RENDER_WIREFRAME 32800 +#define ID_RENDER_FLAT 32801 +#define ID_RENDER_GOURAUD 32802 +#define ID_RENDER_TEXTURE 32803 +#define ID_RENDER_TRANS 32804 +#define ID_GOTOPOS_TOP 32806 +#define ID_GOTOPOS_BOTTOM 32807 +#define ID_GOTOPOS_LEFT 32808 +#define ID_GOTOPOS_RIGHT 32809 +#define ID_GOTOPOS_FRONT 32810 +#define ID_GOTOPOS_BACK 32811 +#define ID_ANIMATE_INTER 32812 +#define ID_ANIMATE_GOTOSTART 32826 +#define ID_ANIMATE_GOTOEND 32827 +#define ID_VIEW_ANIMBAR 32828 +#define ID_VIEW_POS 32829 +#define ID_PREF 32831 +#define ID_INDICATOR_FPS 32832 +#define ID_ANIM_INTERTOGGLE 32833 +#define ID_GOTOPOS_WEAPON 32835 +#define ID_NODE_TOGGLE_VIS 32838 +#define ID_NODE_PROP 32840 +#define ID_TIME_CLAMP 32843 +#define ID_TICKER_OPTIONS 32844 +#define ID_TICK_TOGGLE 32845 +#define ID_SKIN_SHOWOVERLAY 32847 +#define ID_WINDOW_SKIN 32848 +#define ID_WINDOW_FRAME 32849 +#define ID_MODE_CAMERA 32851 +#define ID_MODE_SKELETAL 32852 +#define ID_SKELETON_SNAP 32853 +#define ID_JOINT_MANUAL_ANGLES 32854 +#define ID_JOINT_CONSTRAINTS 32855 +#define ID_USE_JOINTS 32856 +#define ID_VIEW_PROPS 32857 +#define ID_USE_SKIN 32858 +#define ID_REPLACE_SKIN 32859 +#define IDR_QUAKE 61216 +#define IDR_QUAKE2 61217 +#define IDR_SKIN_FROM_FILE_START 62000 +#define IDR_SKIN_FROM_FILE_END 62100 +#define IDR_SKIN_SELECT_START 62101 +#define ID_FILE_EXTENSIONS 62101 +#define ID_SUPPORTED_FORMATS 62102 +#define IDR_SKIN_SELECT_END 62200 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_3D_CONTROLS 1 +#define _APS_NEXT_RESOURCE_VALUE 177 +#define _APS_NEXT_COMMAND_VALUE 32860 +#define _APS_NEXT_CONTROL_VALUE 1025 +#define _APS_NEXT_SYMED_VALUE 115 +#endif +#endif diff --git a/Toolkit/Programming/Tools/qMView/skeleton.cpp b/Toolkit/Programming/Tools/qMView/skeleton.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Toolkit/Programming/Tools/qMView/splash.BMP b/Toolkit/Programming/Tools/qMView/splash.BMP new file mode 100644 index 0000000..ad00bd1 Binary files /dev/null and b/Toolkit/Programming/Tools/qMView/splash.BMP differ diff --git a/Toolkit/Programming/Tools/qMView/treectrlex.h b/Toolkit/Programming/Tools/qMView/treectrlex.h new file mode 100644 index 0000000..8785d0d --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/treectrlex.h @@ -0,0 +1,79 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// CTreeCtrlEx - Multiple selection tree control (MFC 4.2) +// +// Bendik Engebretsen (c) 1997 +// bendik@techsoft.no +// http://www.techsoft.no/bendik/ +// +// + +#ifndef __TREECTRLEX_H +#define __TREECTRLEX_H + +///////////////////////////////////////////////////////////////////////////// +// CTreeCtrlEx window + +class CTreeCtrlEx : public CTreeCtrl +{ + DECLARE_DYNAMIC(CTreeCtrlEx) + +// Construction +public: + CTreeCtrlEx() : m_bSelectPending(FALSE), m_hClickedItem(NULL), m_hFirstSelectedItem(NULL) {} + BOOL Create(DWORD dwStyle, DWORD dwExStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + +// Attributes +public: + UINT GetSelectedCount() const; + HTREEITEM GetFirstSelectedItem(); + HTREEITEM GetNextSelectedItem(HTREEITEM hItem); + HTREEITEM GetPrevSelectedItem(HTREEITEM hItem); + HTREEITEM ItemFromData(DWORD dwData, HTREEITEM hStartAtItem=NULL) const; + + BOOL SelectItemEx(HTREEITEM hItem, BOOL bSelect=TRUE); + + BOOL SelectItems(HTREEITEM hFromItem, HTREEITEM hToItem); + void ClearSelection(BOOL bMultiOnly=FALSE); + +protected: + void SelectMultiple( HTREEITEM hClickedItem, UINT nFlags ); + +private: + BOOL m_bSelectPending; + CPoint m_ptClick; + HTREEITEM m_hClickedItem; + HTREEITEM m_hFirstSelectedItem; + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTreeCtrlEx) + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CTreeCtrlEx() {} + + // Generated message map functions +protected: + //{{AFX_MSG(CTreeCtrlEx) + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg BOOL OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg BOOL OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg BOOL OnKillfocus(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + + +HTREEITEM GetTreeItemFromData(CTreeCtrl& treeCtrl, DWORD dwData, HTREEITEM hStartAtItem=NULL); + +#endif diff --git a/Toolkit/Programming/Tools/qMView/worklog.txt b/Toolkit/Programming/Tools/qMView/worklog.txt new file mode 100644 index 0000000..80b6597 --- /dev/null +++ b/Toolkit/Programming/Tools/qMView/worklog.txt @@ -0,0 +1,122 @@ +qMView ver 1.5 Work Log (c) 1998, Josh Weier +---------------------------------------------- + +TODO: +---------------------------------------------- + + ground plane + axis + drag and drop frame placement (insert before / after) + scale (scoped) + translate (scoped) + rotate (scoped) + file save (Quake) + file save (Quake2) + model bitfield editing + label editing (frame) + undo / redo + import frame (3DS / DXF / COB) + export frame (3DS / DXF / COB) + export skin (BMP / PCX / RAW) + skin view + on model painting + dodge tool + burn tool + on skin page painting + palette swatches + other paint tools + dynamic interpolation + frame rate locking (clamping / acceling) + preferences dialog + palette on status bar + on the fly frame import and model colallation + optimize Quake2 frame updates (vert paths) + add tri-outline skin + frame sequencing + snap to vertex + +---------------------------------------------- + +[1/24/98] + + * surrenders processor time when not active (minimized, not visible) + * 'z' spin toggle + * fix model loading error + * fix Quake models + * frame rate display (in status bar) + * updated to DirectX v5.0 (SDK / End User) + - Fixed ambient light problem + - Fixed transparency error (has palette error now) + - Minor speed increase + * ambient lighting mode + * removed Quake2 model light normal calculations (4 FPS opt) + * re-added frame interpolation (manditory 4 IFPF) + + +[1/25/98] + + * added interpolation toggle to menu and toolbar + +[1/26/98] + + * fix Quake texture vertex loss bug + * fix palette import bug + +[1/29/98] + + * Models are loadable from command line or double click + * fix Quake model scale bug + * fix Quake frame group bug + * fix interpolation error (interpolating to next frame in full list) + * moved to version 1.4ß + * tweaked splash screen + +[1/31/98] + + * really fixed z-spin + * re-did dialog bar + +[2/14/98] + + * spent Valentine's day coding + * added multi-selection + * fixed Quake model mirroring + +[2/20/98] + + * fixed Quake model Skin import + * fixed ping-pong in punch select + * added normal ping-pong + * fixed scaling system + * fixed SHIFT and CTRL key captures (unless focus to treectrl) + * add smooth scale + * hacked workable tree updates + * fixed Z rotation (really!) + * added tweaks to throw code to prevent slow moving + * hack fixed Microsoft's weird texture transparency problem + +[2/21/98] + + * made h2 palette the default + * fixed up Quake model preset positions + +[2/22/98] + + * added multi-skin support + * added icon art + * optimized skin loading + * added group filling to multi-select frames + * FIXME! Don't group select backwards! + * FIXME! Don't think about doing it with Quake2! + * FIXME! Don't switch internal skins after loading a new one! + * fixed keydown capture on skin tree + +[3/17/98] + + * Hexen2 MP finished up, added qMView to SourceSafe + +[2/23/98] + + * Basic FM support + * Load M8 as a skin + * Added double click disk load to skin tree diff --git a/Toolkit/Programming/Tools/qdata/Adpcm.h b/Toolkit/Programming/Tools/qdata/Adpcm.h new file mode 100644 index 0000000..8b31157 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/Adpcm.h @@ -0,0 +1,28 @@ +/* +** adpcm.h - include file for adpcm coder. +** +** Version 1.0, 7-Jul-92. +** +** Modded 10/3/98 +** John Scott +*/ + +typedef struct adpcm_state_s +{ + short in_valprev; // Previous output value + short in_index; // Index into stepsize table + short out_valprev; // Previous output value + short out_index; // Index into stepsize table + int count; // Number of sample counts +} adpcm_state_t; + +typedef struct adpcm_s +{ + adpcm_state_t state; + char adpcm[0x10000]; +} adpcm_t; + +void adpcm_coder(short [], adpcm_t *); +void adpcm_decoder(adpcm_t *, short []); + +// end \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qdata/Fmodels.c b/Toolkit/Programming/Tools/qdata/Fmodels.c new file mode 100644 index 0000000..b93993e --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/Fmodels.c @@ -0,0 +1,3336 @@ +#include "qd_fmodel.h" +#include "animcomp.h" +#include "qd_Skeletons.h" +#include "Skeletons.h" +#include "qdata.h" +#include "flex.h" +#include "Reference.h" + +#include + +/* +======================================================================== + +.FM triangle flexible model file format + +======================================================================== +*/ + +//================================================================= + +#define NUMVERTEXNORMALS 162 + +extern float avertexnormals[NUMVERTEXNORMALS][3]; + +#define MAX_GROUPS 128 + +typedef struct +{ + triangle_t triangle; + int group; +} trigroup_t; + +#define TRIVERT_DIST .1 + +typedef struct +{ + int start_frame; + int num_frames; + int degrees; + char *mat; + char *ccomp; + char *cbase; + float *cscale; + float *coffset; + float trans[3]; + float scale[3]; + float bmin[3]; + float bmax[3]; +} fmgroup_t; + +//================================================================ + +// Initial +fmheader_t fmheader; + +// Skin +extern char g_skins[MAX_FM_SKINS][64]; + +// ST Coord +extern fmstvert_t base_st[MAX_FM_VERTS]; + +// Triangles +extern fmtriangle_t triangles[MAX_FM_TRIANGLES]; + +// Frames +fmframe_t g_frames[MAX_FM_FRAMES]; +//fmframe_t *g_FMframes; + +// GL Commands +extern int commands[16384]; +extern int numcommands; + + +// +// varibles set by commands +// +extern float scale_up; // set by $scale +extern vec3_t adjust; // set by $origin +extern int g_fixedwidth, g_fixedheight; // set by $skinsize +extern char modelname[64]; // set by $modelname + + +extern char *g_outputDir; + + +// Mesh Nodes +mesh_node_t *pmnodes = NULL; +fmmeshnode_t mesh_nodes[MAX_FM_MESH_NODES]; + +fmgroup_t groups[MAX_GROUPS]; +int num_groups; +int frame_to_group[MAX_FM_FRAMES]; + +// +// variables set by command line arguments +// +qboolean g_no_opimizations = false; + + +// +// base frame info +// +static int triangle_st[MAX_FM_TRIANGLES][3][2]; + + +// number of gl vertices +extern int numglverts; +// indicates if a triangle has already been used in a glcmd +extern int used[MAX_FM_TRIANGLES]; +// indicates if a triangle has translucency in it or not +static qboolean translucent[MAX_FM_TRIANGLES]; + +// main output file handle +extern FILE *headerouthandle; +// output sizes of buildst() +static int skin_width, skin_height; + + +// statistics +static int total_skin_pixels; +static int skin_pixels_used; + +int ShareVertex( trigroup_t trione, trigroup_t tritwo); +float DistBetween(vec3_t point1, vec3_t point2); +int GetNumTris( trigroup_t *tris, int group); +void GetOneGroup(trigroup_t *tris, int grp, triangle_t* triangles); +void ScaleTris( vec3_t min, vec3_t max, int Width, int Height, float* u, float* v, int verts); +void NewDrawLine(int x1, int y1, int x2, int y2, unsigned char* picture, int width, int height); + + +//============================================================== + +/* +=============== +ClearModel +=============== +*/ +static void ClearModel (void) +{ + memset (&fmheader, 0, sizeof(fmheader)); + + modelname[0] = 0; + scale_up = 1.0; + VectorCopy (vec3_origin, adjust); + g_fixedwidth = g_fixedheight = 0; + g_skipmodel = false; + num_groups = 0; + + if (pmnodes) + { + free(pmnodes); + pmnodes = NULL; + } + + ClearSkeletalModel(); +} + + +extern void H_printf(char *fmt, ...); + + +void WriteHeader(FILE *FH, char *Ident, int Version, int Size, void *Data) +{ + header_t header; + static long pos = -1; + long CurrentPos; + + if (Size == 0) + { // Don't write out empty packets + return; + } + + if (pos != -1) + { + CurrentPos = ftell(FH); + Size = CurrentPos - pos + sizeof(header_t); + fseek(FH, pos, SEEK_SET); + pos = -2; + } + else if (Size == -1) + { + pos = ftell(FH); + } + + memset(&header,0,sizeof(header)); + strcpy(header.ident,Ident); + header.version = Version; + header.size = Size; + + SafeWrite (FH, &header, sizeof(header)); + + if (Data) + { + SafeWrite (FH, Data, Size); + } + + if (pos == -2) + { + pos = -1; + fseek(FH, 0, SEEK_END); + } +} + +/* +============ +WriteModelFile +============ +*/ +static void WriteModelFile (FILE *modelouthandle) +{ + int i; + int j, k; + fmframe_t *in; + fmaliasframe_t *out; + byte buffer[MAX_FM_VERTS*4+128]; + float v; + int c_on, c_off; + IntListNode_t *current, *toFree; + qboolean framesWritten = false; + size_t temp ,size = 0; + + // probably should do this dynamically one of these days + struct + { + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + } outFrames[MAX_FM_FRAMES]; + +#define DATA_SIZE 0x60000 // 384K had better be enough, particularly for the reference points + byte data[DATA_SIZE]; + byte data2[DATA_SIZE]; + + fmheader.num_glcmds = numcommands; + fmheader.framesize = (int)&((fmaliasframe_t *)0)->verts[fmheader.num_xyz]; + + WriteHeader(modelouthandle, FM_HEADER_NAME, FM_HEADER_VER, sizeof(fmheader), &fmheader); + + // + // write out the skin names + // + + WriteHeader(modelouthandle, FM_SKIN_NAME, FM_SKIN_VER, fmheader.num_skins * MAX_FM_SKINNAME, g_skins); + + // + // write out the texture coordinates + // + c_on = c_off = 0; + for (i=0 ; iname, in->name); + for (j=0 ; j<3 ; j++) + { + out->scale[j] = (in->maxs[j] - in->mins[j])/255; + out->translate[j] = in->mins[j]; + + outFrames[i].scale[j] = out->scale[j]; + outFrames[i].translate[j] = out->translate[j]; + } + + for (j=0 ; jverts[j].lightnormalindex = in->v[j].lightnormalindex; + + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + v = 255.0; + if (v < 0) + v = 0; + out->verts[j].v[k] = v; + } + } + + for (j=0 ; j<3 ; j++) + { + out->scale[j] = LittleFloat (out->scale[j]); + out->translate[j] = LittleFloat (out->translate[j]); + } + + SafeWrite (modelouthandle, out, fmheader.framesize); + } + + // Go back and finish the header + // WriteHeader(modelouthandle, FM_FRAME_NAME, FM_FRAME_VER, -1, NULL); + } + else + { + WriteHeader(modelouthandle, FM_SHORT_FRAME_NAME, FM_SHORT_FRAME_VER,FRAME_NAME_LEN*fmheader.num_frames, NULL); + for (i=0 ; iname,FRAME_NAME_LEN); + } + WriteHeader(modelouthandle, FM_NORMAL_NAME, FM_NORMAL_VER,fmheader.num_xyz, NULL); + in = &g_frames[0]; + for (j=0 ; jv[j].lightnormalindex,1); + } + + // + // write out glcmds + // + WriteHeader(modelouthandle, FM_GLCMDS_NAME, FM_GLCMDS_VER, numcommands*4, commands); + + // + // write out mesh nodes + // + for(i=0;idegrees*sizeof(char) + char *ccomp; g->num_frames*g->degrees*sizeof(char) + char *cbase; fmheader.num_xyz*3*sizeof(unsigned char) + float *cscale; g->degrees*sizeof(float) + float *coffset; g->degrees*sizeof(float) + float trans[3]; 3*sizeof(float) + float scale[3]; 3*sizeof(float) +} fmgroup_t; +*/ + int tmp,k; + fmgroup_t *g; + size=sizeof(int)+fmheader.num_frames*sizeof(int); + for (k=0;kdegrees*sizeof(char); + size+=g->num_frames*g->degrees*sizeof(char); + size+=fmheader.num_xyz*3*sizeof(unsigned char); + size+=g->degrees*sizeof(float); + size+=g->degrees*sizeof(float); + size+=12*sizeof(float); + } + WriteHeader(modelouthandle, FM_COMP_NAME, FM_COMP_VER,size, NULL); + SafeWrite (modelouthandle,&num_groups,sizeof(int)); + SafeWrite (modelouthandle,frame_to_group,sizeof(int)*fmheader.num_frames); + + for (k=0;kstart_frame); + SafeWrite (modelouthandle,&tmp,sizeof(int)); + tmp=LittleLong(g->num_frames); + SafeWrite (modelouthandle,&tmp,sizeof(int)); + tmp=LittleLong(g->degrees); + SafeWrite (modelouthandle,&tmp,sizeof(int)); + + SafeWrite (modelouthandle,g->mat,fmheader.num_xyz*3*g->degrees*sizeof(char)); + SafeWrite (modelouthandle,g->ccomp,g->num_frames*g->degrees*sizeof(char)); + SafeWrite (modelouthandle,g->cbase,fmheader.num_xyz*3*sizeof(unsigned char)); + SafeWrite (modelouthandle,g->cscale,g->degrees*sizeof(float)); + SafeWrite (modelouthandle,g->coffset,g->degrees*sizeof(float)); + SafeWrite (modelouthandle,g->trans,3*sizeof(float)); + SafeWrite (modelouthandle,g->scale,3*sizeof(float)); + SafeWrite (modelouthandle,g->bmin,3*sizeof(float)); + SafeWrite (modelouthandle,g->bmax,3*sizeof(float)); + free(g->mat); + free(g->ccomp); + free(g->cbase); + free(g->cscale); + free(g->coffset); + } + } + + // write the skeletal info + if(g_skelModel.type != SKEL_NULL) + { + size = 0; + + temp = sizeof(int); // change this to a byte + memcpy(data + size, &g_skelModel.type, temp); + size += temp; + + // number of joints + temp = sizeof(int); // change this to a byte + memcpy(data + size, &numJointsInSkeleton[g_skelModel.type], temp); + size += temp; + + // number of verts in each joint cluster + temp = sizeof(int)*numJointsInSkeleton[g_skelModel.type]; // change this to shorts + memcpy(data + size, &g_skelModel.new_num_verts[1], temp); + size += temp; + + // cluster verts + for(i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i) + { + current = g_skelModel.vertLists[i]; + while(current) + { + temp = sizeof(int); // change this to a short + memcpy(data + size, ¤t->data, temp); + size += temp; + toFree = current; + current = current->next; + free(toFree); // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base + } + } + + if(!num_groups) // joints are stored with regular verts for compressed models + { + framesWritten = true; + + temp = sizeof(int); // change this to a byte + memcpy(data + size, &framesWritten, temp); + size += temp; + + for (i = 0; i < fmheader.num_frames; ++i) + { + in = &g_frames[i]; + + for (j = 0 ; j < numJointsInSkeleton[g_skelModel.type]; ++j) + { + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->joints[j].placement.origin[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data + size, &v, temp); + size += temp; + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->joints[j].placement.direction[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data + size, &v, temp); + size += temp; + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->joints[j].placement.up[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data + size, &v, temp); + size += temp; + } + } + } + + } + else + { + temp = sizeof(int); // change this to a byte + memcpy(data + size, &framesWritten, temp); + size += temp; + } + + WriteHeader(modelouthandle, FM_SKELETON_NAME, FM_SKELETON_VER, size, data); + } + + if(g_skelModel.references != REF_NULL) + { + int refnum; + + size = 0; + if (RefPointNum <= 0) + { // Hard-coded labels + refnum = numReferences[g_skelModel.references]; + } + else + { // Labels indicated in QDT + refnum = RefPointNum; + } + + temp = sizeof(int); // change this to a byte + memcpy(data2 + size, &g_skelModel.references, temp); + size += temp; + + if(!num_groups) + { + framesWritten = true; + + temp = sizeof(int); // change this to a byte + memcpy(data2 + size, &framesWritten, temp); + size += temp; + + for (i = 0; i < fmheader.num_frames; ++i) + { + in = &g_frames[i]; + + for (j = 0 ; j < refnum; ++j) + { + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->references[j].placement.origin[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data2 + size, &v, temp); + size += temp; + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->references[j].placement.direction[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data2 + size, &v, temp); + size += temp; + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->references[j].placement.up[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // write out origin as a float since they arn't clamped + temp = sizeof(float); // change this to a short + assert(size+temp < DATA_SIZE); + memcpy(data2 + size, &v, temp); + size += temp; + } + } + } + } + else // FINISH ME: references need to be stored with regular verts for compressed models + { + framesWritten = false; + + temp = sizeof(int); // change this to a byte + memcpy(data2 + size, &framesWritten, temp); + size += temp; + } + + WriteHeader(modelouthandle, FM_REFERENCES_NAME, FM_REFERENCES_VER, size, data2); + } +} + +static void CompressFrames() +{ + fmgroup_t *g; + int i,j,k; + fmframe_t *in; + + j=0; + for (i=0;i=groups[j].start_frame+groups[j].num_frames&&jnum_frames,fmheader.num_xyz,g->degrees); + for (i=0;inum_frames;i++) + { + in = &g_frames[i+g->start_frame]; + for (j=0;jv[j].v[0],in->v[j].v[1],in->v[j].v[2]); + } + AnimCompressDoit(); + g->mat=SafeMalloc(fmheader.num_xyz*3*g->degrees*sizeof(char), "CompressFrames"); + g->ccomp=SafeMalloc(g->num_frames*g->degrees*sizeof(char), "CompressFrames"); + g->cbase=SafeMalloc(fmheader.num_xyz*3*sizeof(unsigned char), "CompressFrames"); + g->cscale=SafeMalloc(g->degrees*sizeof(float), "CompressFrames"); + g->coffset=SafeMalloc(g->degrees*sizeof(float), "CompressFrames"); + AnimCompressToBytes(g->trans,g->scale,g->mat,g->ccomp,g->cbase,g->cscale,g->coffset,g->bmin,g->bmax); + AnimCompressEnd(); + } +} + +static void OptimizeVertices(void) +{ + qboolean vert_used[MAX_FM_VERTS]; + short vert_replacement[MAX_FM_VERTS]; + int i,j,k,l,pos,bit,set_pos,set_bit; + fmframe_t *in; + qboolean Found; + int num_unique; + static IntListNode_t *newVertLists[NUM_CLUSTERS]; + static int newNum_verts[NUM_CLUSTERS]; + IntListNode_t *current, *next; + + printf("Optimizing vertices..."); + + memset(vert_used, 0, sizeof(vert_used)); + + if(g_skelModel.clustered == true) + { + memset(newNum_verts, 0, sizeof(newNum_verts)); + memset(newVertLists, 0, sizeof(newVertLists)); + } + + num_unique = 0; + + // search for common points among all the frames + for (i=0 ; iv[j].v[0] == in->v[k].v[0] && + in->v[j].v[1] == in->v[k].v[1] && + in->v[j].v[2] == in->v[k].v[2]) + { + Found = true; + vert_replacement[j] = k; + break; + } + + } + + if (!Found) + { + if (!vert_used[j]) + { + num_unique++; + } + vert_used[j] = true; + } + } + } + + // recompute the light normals + for (i=0 ; iv[j].vnorm.normalsum, in->v[k].vnorm.normalsum, in->v[k].vnorm.normalsum); + in->v[k].vnorm.numnormals += in->v[j].vnorm.numnormals++; + } + } + + for (j=0 ; jv[j].vnorm.numnormals; + if (!c) + Error ("Vertex with no triangles attached"); + + VectorScale (in->v[j].vnorm.normalsum, 1.0/c, v); + VectorNormalize (v, v); + + maxdot = -999999.0; + maxdotindex = -1; + + for (k=0 ; k maxdot) + { + maxdot = dot; + maxdotindex = k; + } + } + + in->v[j].lightnormalindex = maxdotindex; + } + } + + // create substitution list + num_unique = 0; + for(i=0;inext) + { + if(current->data == i) + { + IntListNode_t *current2; + int m; + qboolean added = false; + + for(m = 0, current2 = newVertLists[k]; m < newNum_verts[k+1]; + ++m, current2 = current2->next) + { + if(current2->data == vert_replacement[i]) + { + added = true; + break; + } + } + + if(!added) + { + ++newNum_verts[k+1]; + + next = newVertLists[k]; + + newVertLists[k] = SafeMalloc(sizeof(IntListNode_t), "OptimizeVertices"); + // freed after model write out + + newVertLists[k]->data = vert_replacement[i]; + newVertLists[k]->next = next; + } + break; + } + } + } + } + } + + // substitute + for (i=0 ; iv[vert_replacement[j]] = in->v[j]; + } + + } + + for(i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i) + { + IntListNode_t *toFree; + current = g_skelModel.vertLists[i]; + + while(current) + { + toFree = current; + current = current->next; + free(toFree); // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base + } + + g_skelModel.vertLists[i] = newVertLists[i]; + g_skelModel.new_num_verts[i+1] = newNum_verts[i+1]; + } + +#ifndef NDEBUG + for(k = 0; k < numJointsInSkeleton[g_skelModel.type]; ++k) + { + for(l = 0, current = g_skelModel.vertLists[k]; + l < g_skelModel.new_num_verts[k+1]; ++l, current = current->next) + { + IntListNode_t *current2; + int m; + + for(m = l+1, current2 = current->next; m < newNum_verts[k+1]; + ++m, current2 = current2->next) + { + if(current->data == current2->data) + { + printf("Warning duplicate vertex: %d\n", current->data); + break; + } + } + } + } +#endif + + for(i=0;i> 3; + bit = 1 << (i & 7 ); + + for (j=0 ; j<3 ; j++) + { + set_bit = set_pos = triangles[i].index_xyz[j] = vert_replacement[triangles[i].index_xyz[j]]; + + set_pos >>= 3; + set_bit = 1 << (set_bit & 7); + + for(k=0;kreferences[j].placement.origin, in->v[index].v); + index++; + + VectorCopy(in->references[j].placement.direction, in->v[index].v); + index++; + + VectorCopy(in->references[j].placement.up, in->v[index].v); + index++; + } + } + + fmheader.num_xyz += refnum*3; + } + + // tack on the skeletal joint verts to the regular verts + if(g_skelModel.type != SKEL_NULL) + { + fmframe_t *in; + int index; + + for (i = 0; i < fmheader.num_frames; ++i) + { + in = &g_frames[i]; + index = fmheader.num_xyz; + + for (j = 0 ; j < numJointsInSkeleton[g_skelModel.type]; ++j) + { + VectorCopy(in->joints[j].placement.origin, in->v[index].v); + index++; + + VectorCopy(in->joints[j].placement.direction, in->v[index].v); + index++; + + VectorCopy(in->joints[j].placement.up, in->v[index].v); + index++; + } + } + + fmheader.num_xyz += numJointsInSkeleton[g_skelModel.type]*3; + } + + CompressFrames(); + } +} + + +/* +=============== +FinishModel +=============== +*/ +void FMFinishModel (void) +{ + FILE *modelouthandle; + int i,j,length,tris,verts,bit,pos,total_tris,total_verts; + char name[1024]; + int trans_count; + + if (!fmheader.num_frames) + return; + +// +// copy to release directory tree if doing a release build +// + if (g_release) + { + if (modelname[0]) + sprintf (name, "%s", modelname); + else + sprintf (name, "%s/tris.fm", cdpartial); + ReleaseFile (name); + + for (i=0 ; i> 3; + bit = 1 << ((j) & 7 ); + if (pmnodes[i].tris[pos] & bit) + { + tris++; + } + } + for(j=0;j> 3; + bit = 1 << ((j) & 7 ); + if (pmnodes[i].verts[pos] & bit) + { + verts++; + } + } + + printf("%-33s %4d %5d\n",pmnodes[i].name,tris,verts); + + total_tris += tris; + total_verts += verts; + } + printf("--------------------------------- ---- -----\n"); + printf("%-33s %4d %5d\n","TOTALS",total_tris,total_verts); + } + } + fclose (modelouthandle); + + // finish writing header file + H_printf("\n"); + + // scale_up is usefull to allow step distances to be adjusted + H_printf("#define MODEL_SCALE\t\t%f\n", scale_up); + + // mesh nodes + if (fmheader.num_mesh_nodes) + { + H_printf("\n"); + H_printf("#define NUM_MESH_NODES\t\t%d\n\n",fmheader.num_mesh_nodes); + for(i=0;iindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+2)%3]; + st1 = last->index_st[(startv+2)%3]; + m2 = last->index_xyz[(startv+1)%3]; + st2 = last->index_st[(startv+1)%3]; + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; j> 3; + bit = 1 << (j & 7 ); + if (!(pmnodes[node].tris[pos] & bit)) + { + continue; + } + for (k=0 ; k<3 ; k++) + { + if (check->index_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j] || translucent[j] != translucent[starttri]) + goto done; + + // the new edge + if (stripcount & 1) + { + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + } + else + { + m1 = check->index_xyz[ (k+2)%3 ]; + st1 = check->index_st[ (k+2)%3 ]; + } + + strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ]; + strip_st[stripcount+2] = check->index_st[ (k+2)%3 ]; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; jindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+0)%3]; + st1 = last->index_st[(startv+0)%3]; + m2 = last->index_xyz[(startv+2)%3]; + st2 = last->index_st[(startv+2)%3]; + + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; j> 3; + bit = 1 << (j & 7 ); + if (!(pmnodes[node].tris[pos] & bit)) + { + continue; + } + for (k=0 ; k<3 ; k++) + { + if (check->index_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j] || translucent[j] != translucent[starttri]) + goto done; + + // the new edge + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + + strip_xyz[stripcount+2] = m2; + strip_st[stripcount+2] = st2; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; j> 3; + bit = 1 << (i & 7 ); + if (!(pmnodes[l].tris[pos] & bit)) + { + continue; + } + + // pick an unused triangle and start the trifan + if (used[i] || trans_check != translucent[i]) + { + continue; + } + + bestlen = 0; + for (type = 0 ; type < 2 ; type++) + // type = 1; + { + for (startv =0 ; startv < 3 ; startv++) + { + if (type == 1) + len = StripLength (i, startv, fmheader.num_tris, l); + else + len = FanLength (i, startv, fmheader.num_tris, l); + if (len > bestlen) + { + besttype = type; + bestlen = len; + for (j=0 ; j + "-------------------------", // ? + "-------------------------", // @ + "-***-*---*******---**---*", // A + "****-*---*****-*---*****-", + "-*****----*----*-----****", + "****-*---**---**---*****-", + "******----****-*----*****", + "******----****-*----*----", + "-*****----*--***---*-****", + "*---**---*******---**---*", + "-***---*----*----*---***-", + "----*----*----**---*-***-", + "-*--*-*-*--**---*-*--*--*", + "-*----*----*----*----****", + "*---***-***-*-**---**---*", + "*---***--**-*-**--***---*", + "-***-*---**---**---*-***-", + "****-*---*****-*----*----", + "-***-*---**---*-***----**", + "****-*---*****-*-*--*--**", + "-*****-----***-----*****-", + "*****--*----*----*----*--", + "*---**---**---**---******", + "*---**---**---*-*-*---*--", + "*---**---**-*-***-***---*", + "*---*-*-*---*---*-*-*---*", + "*---**---*-*-*---*----*--", + "*****---*---*---*---*****" // Z +}; + +void DrawLine(int x1, int y1, int x2, int y2) +{ + int dx, dy; + int adx, ady; + int count; + float xfrac, yfrac, xstep, ystep; + unsigned sx, sy; + float u, v; + + dx = x2 - x1; + dy = y2 - y1; + adx = abs(dx); + ady = abs(dy); + + count = adx > ady ? adx : ady; + count++; + + if(count > 300) + { + printf("Bad count\n"); + return; // don't ever hang up on bad data + } + + xfrac = x1; + yfrac = y1; + + xstep = (float)dx/count; + ystep = (float)dy/count; + + switch(LineType) + { + case LINE_NORMAL: + do + { + if(xfrac < SKINPAGE_WIDTH && yfrac < SKINPAGE_HEIGHT) + { + pic[(int)yfrac*SKINPAGE_WIDTH+(int)xfrac] = LineColor; + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + case LINE_FAT: + do + { + for (u=-0.1 ; u<=0.9 ; u+=0.999) + { + for (v=-0.1 ; v<=0.9 ; v+=0.999) + { + sx = xfrac+u; + sy = yfrac+v; + if(sx < SKINPAGE_WIDTH && sy < SKINPAGE_HEIGHT) + { + pic[sy*SKINPAGE_WIDTH+sx] = LineColor; + } + } + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + case LINE_DOTTED: + do + { + if(count&1 && xfrac < SKINPAGE_WIDTH && + yfrac < SKINPAGE_HEIGHT) + { + pic[(int)yfrac*SKINPAGE_WIDTH+(int)xfrac] = LineColor; + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + default: + Error("Unknown %d.\n", LineType); + } +} + +//========================================================================== +// +// DrawCharacter +// +//========================================================================== + +static void DrawCharacter(int x, int y, int character) +{ + int r, c; + char *def; + + character = toupper(character); + if(character < ASCII_SPACE || character > 'Z') + { + character = ASCII_SPACE; + } + character -= ASCII_SPACE; + for(def = CharDefs[character], r = 0; r < 5; r++) + { + for(c = 0; c < 5; c++) + { + pic[(y+r)*SKINPAGE_WIDTH+x+c] = *def++ == '*' ? 255 : 0; + } + } +} + +//========================================================================== +// +// DrawTextChar +// +//========================================================================== + +void DrawTextChar(int x, int y, char *text) +{ + int c; + + while((c = *text++) != '\0') + { + DrawCharacter(x, y, c); + x += 6; + } +} + + +extern void DrawScreen(float s_scale, float t_scale, float iwidth, float iheight); + +//========================================================================== +// ExtractDigit + +static int ExtractDigit(byte *pic, int x, int y) +{ + int i; + int r, c; + char digString[32]; + char *buffer; + byte backColor; + char **DigitDefs; + + backColor = pic[(SKINPAGE_HEIGHT - 1) * SKINPAGE_WIDTH]; + DigitDefs = &CharDefs['0' - ASCII_SPACE]; + + buffer = digString; + for(r = 0; r < 5; r++) + { + for(c = 0; c < 5; c++) + { + *buffer++ = (pic[(y + r) * SKINPAGE_WIDTH + x + c] == backColor) ? ' ' : '*'; + } + } + *buffer = '\0'; + for(i = 0; i < 10; i++) + { + if(strcmp(DigitDefs[i], digString) == 0) + { + return i; + } + } + + Error("Unable to extract scaling info from skin PCX."); + return 0; +} + +//========================================================================== +// ExtractNumber + +int ExtractNumber(byte *pic, int x, int y) +{ + return ExtractDigit(pic, x, y) * 100 + ExtractDigit(pic, x + 6, y) * 10 + ExtractDigit(pic, x + 12, y); +} + + + + + +/* +============ +BuildST + +Builds the triangle_st array for the base frame and +fmheader.skinwidth / fmheader.skinheight + + FIXME: allow this to be loaded from a file for + arbitrary mappings +============ +*/ +static void BuildST (triangle_t *ptri, int numtri, qboolean DrawSkin) +{ + int backface_flag; + int i, j; + int width, height, iwidth, iheight, swidth; + float basex, basey; + float scale; + vec3_t mins, maxs; + float *pbasevert; + vec3_t vtemp1, vtemp2, normal; + float s_scale, t_scale; + float scWidth; + float scHeight; + int skinwidth; + int skinheight; + + // + // find bounds of all the verts on the base frame + // + ClearBounds (mins, maxs); + backface_flag = false; + + if (ptri[0].HasUV) // if we have the uv already, we don't want to double up or scale + { + iwidth = ScaleWidth; + iheight = ScaleHeight; + + t_scale = s_scale = 1.0; + } + else + { + for (i=0 ; i 0) + { + backface_flag = true; + break; + } + } + scWidth = ScaleWidth*SCALE_ADJUST_FACTOR; + if (backface_flag) //we are doubling + scWidth /= 2; + + scHeight = ScaleHeight*SCALE_ADJUST_FACTOR; + + scale = scWidth/width; + + if(height*scale >= scHeight) + { + scale = scHeight/height; + } + + iwidth = ceil(width*scale)+4; + iheight = ceil(height*scale)+4; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + t_scale = s_scale; + } + if (DrawSkin) + { + if(backface_flag) + DrawScreen(s_scale, t_scale, iwidth*2, iheight); + else + DrawScreen(s_scale, t_scale, iwidth, iheight); + } + if (backface_flag) + skinwidth=iwidth*2; + else + skinwidth=iwidth; + skinheight=iheight; + + +/* if (!g_fixedwidth) + { // old style + scale = 8; + if (width*scale >= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + + s_scale = t_scale = scale; + + iwidth = ceil(width*s_scale); + iheight = ceil(height*t_scale); + + iwidth += 4; + iheight += 4; + } + else + { // new style + iwidth = g_fixedwidth / 2; + iheight = g_fixedheight; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + }*/ + +// +// determine which side of each triangle to map the texture to +// + basey = 2; + for (i=0 ; i 0) + { + basex = iwidth + 2; + } + else + { + basex = 2; + } + + for (j=0 ; j<3 ; j++) + { + pbasevert = ptri[i].verts[j]; + + triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex); + triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey); + } + } + + if (DrawSkin) + { + DrawLine(triangle_st[i][0][0], triangle_st[i][0][1], + triangle_st[i][1][0], triangle_st[i][1][1]); + DrawLine(triangle_st[i][1][0], triangle_st[i][1][1], + triangle_st[i][2][0], triangle_st[i][2][1]); + DrawLine(triangle_st[i][2][0], triangle_st[i][2][1], + triangle_st[i][0][0], triangle_st[i][0][1]); + } + } + +// make the width a multiple of 4; some hardware requires this, and it ensures +// dword alignment for each scan + + swidth = iwidth; + if(backface_flag) + swidth *= 2; + fmheader.skinwidth = (swidth + 3) & ~3; + fmheader.skinheight = iheight; + + skin_width = iwidth; + skin_height = iheight; +} + + +static void BuildNewST (triangle_t *ptri, int numtri, qboolean DrawSkin) +{ + int i, j; + + for (i=0 ; i 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + + d = lp3[0] - lp2[0]; + if (d < -1 || d > 1) + goto split2; + d = lp3[1] - lp2[1]; + if (d < -1 || d > 1) + goto split2; + + d = lp1[0] - lp3[0]; + if (d < -1 || d > 1) + goto split3; + d = lp1[1] - lp3[1]; + if (d < -1 || d > 1) + { +split3: + temp = lp1; + lp1 = lp3; + lp3 = lp2; + lp2 = temp; + + goto split; + } + + return 0; // entire tri is filled + +split2: + temp = lp1; + lp1 = lp2; + lp2 = lp3; + lp3 = temp; + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + +// draw the point if splitting a leading edge + if (lp2[1] > lp1[1]) + goto nodraw; + if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0])) + goto nodraw; + + if (SetPixel) + { + assert ((new[1]*BaseWidth) + new[0] < BaseWidth*BaseHeight); + + if (BaseTrueColor) + { + BasePixels[((new[1]*BaseWidth) + new[0]) * 4] = 1; + } + else + { + BasePixels[(new[1]*BaseWidth) + new[0]] = 1; + } + } + else + { + if (TransPixels) + { + if (TransPixels[(new[1]*TransWidth) + new[0]] != 255) + return 1; + } + else if (BaseTrueColor) + { + if (BasePixels[(((new[1]*BaseWidth) + new[0]) * 4) + 3] != 255) + return 1; + } + else + { +// pixel = BasePixels[(new[1]*BaseWidth) + new[0]]; + } + } + +nodraw: +// recursively continue + if (CheckTransRecursiveTri(lp3, lp1, new)) + return 1; + + return CheckTransRecursiveTri(lp3, new, lp2); +} + +static void ReplaceClusterIndex(int newIndex, int oldindex, int **clusters, + IntListNode_t **vertLists, int *num_verts, int *new_num_verts) +{ + int i, j; + IntListNode_t *next; + + for(j = 0; j < numJointsInSkeleton[g_skelModel.type]; ++j) + { + if(!clusters[j]) + { + continue; + } + + for(i = 0; i < num_verts[j+1]; ++i) + { + if(clusters[j][i] == oldindex) + { + ++new_num_verts[j+1]; + + next = vertLists[j]; + + vertLists[j] = SafeMalloc(sizeof(IntListNode_t), "ReplaceClusterIndex"); + // Currently freed in WriteJointedModelFile only + + vertLists[j]->data = newIndex; + vertLists[j]->next = next; + } + } + } +} + +#define FUDGE_EPSILON 0.002 + +qboolean VectorFudgeCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (fabs(v1[i]-v2[i]) > FUDGE_EPSILON) + return false; + + return true; +} + +/* +================= +Cmd_Base +================= +*/ +void Cmd_FMBase (qboolean GetST) +{ + triangle_t *ptri, *st_tri; + int num_st_tris; + int i, j, k, l; + int x,y,z; +// int time1; + char file1[1024],file2[1024],trans_file[1024], stfile[1024], extension[256]; + vec3_t base_xyz[MAX_FM_VERTS]; + FILE *FH; + int pos,bit; + qboolean NewSkin; + + GetScriptToken (false); + + if (g_skipmodel || g_release || g_archive) + return; + + printf ("---------------------\n"); + sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext); + printf ("%s ", file1); + + ExpandPathAndArchive (file1); + + // Use the input filepath for this one. + sprintf (file1, "%s/%s", cddir, token); + +// time1 = FileTime (file1); +// if (time1 == -1) +// Error ("%s doesn't exist", file1); + +// +// load the base triangles +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes); + else + LoadTriangleList (file1, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes); + + if (g_ignoreTriUV) + { + for (i=0;i> 3; + bit = 1 << (i & 7 ); + if (!(pmnodes[l].tris[pos] & bit)) + { + continue; + } + + for (j=0 ; j<3 ; j++) + { + // get the xyz index + for (k=0 ; k> 3; + bit = 1 << (k & 7); + pmnodes[l].verts[pos] |= bit; + + triangles[i].index_xyz[j] = k; + + // get the st index + for (k=0 ; k= MAX_FM_FRAMES) + Error ("fmheader.num_frames >= MAX_FM_FRAMES"); + fr = &g_frames[fmheader.num_frames]; + fmheader.num_frames++; + + strcpy (fr->name, frame); + +// +// load the frame +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &num_tris, NULL, NULL); + else + LoadTriangleList (file1, &ptri, &num_tris, NULL, NULL); + + if (num_tris != fmheader.num_tris) + Error ("%s: number of triangles (%d) doesn't match base frame (%d)\n", file1, num_tris, fmheader.num_tris); + +// +// allocate storage for the frame's vertices +// + ptrivert = fr->v; + + for (i=0 ; imins, fr->maxs); + +// +// store the frame's vertices in the same order as the base. This assumes the +// triangles and vertices in this frame are in exactly the same order as in the +// base +// + for (i=0 ; imins, fr->maxs); + + VectorAdd (ptrivert[index_xyz].vnorm.normalsum, normal, ptrivert[index_xyz].vnorm.normalsum); + ptrivert[index_xyz].vnorm.numnormals++; + } + } + +// +// calculate the vertex normals, match them to the template list, and store the +// index of the best match +// + for (i=0 ; i maxdot) + { + maxdot = dot; + maxdotindex = j; + } + } + + ptrivert[i].lightnormalindex = maxdotindex; + } + + free (ptri); +} + +/* +=============== +Cmd_Frame +=============== +*/ +void Cmd_FMFrame (void) +{ + while (ScriptTokenAvailable()) + { + GetScriptToken (false); + if (g_skipmodel) + continue; + if (g_release || g_archive) + { + fmheader.num_frames = 1; // don't skip the writeout + continue; + } + + H_printf("#define FRAME_%-16s\t%i\n", token, fmheader.num_frames); + + if((g_skelModel.type != SKEL_NULL) || (g_skelModel.references != REF_NULL)) + { + GrabModelTransform(token); + } + + GrabFrame (token); + + if(g_skelModel.type != SKEL_NULL) + { + GrabSkeletalFrame(token); + } + + if(g_skelModel.references != REF_NULL) + { + GrabReferencedFrame(token); + } + + // need to add the up and dir points to the frame bounds here + // using AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs); + // then remove fudge in determining scale on frame write out + } +} + +/* +=============== +Cmd_Skin + +Skins aren't actually stored in the file, only a reference +is saved out to the header file. +=============== +*/ +void Cmd_FMSkin (void) +{ + byte *palette; + byte *pixels; + int width, height; + byte *cropped; + int y; + char name[1024], savename[1024], transname[1024], extension[256]; + miptex32_t *qtex32; + int size; + FILE *FH; + qboolean TrueColor; + + GetScriptToken (false); + + if (fmheader.num_skins == MAX_FM_SKINS) + Error ("fmheader.num_skins == MAX_FM_SKINS"); + + if (g_skipmodel) + return; + + sprintf (name, "%s/%s", cdarchive, token); + strcpy (name, ExpandPathAndArchive( name ) ); +// sprintf (name, "%s/%s.lbm", cddir, token); + + if (ScriptTokenAvailable()) + { + GetScriptToken (false); + sprintf (g_skins[fmheader.num_skins], "!%s", token); + sprintf (savename, "%s!%s", g_outputDir, token); + sprintf (transname, "%s!%s_a.pcx", gamedir, token); + } + else + { + sprintf (g_skins[fmheader.num_skins], "%s/!%s", cdpartial, token); + sprintf (savename, "%s/!%s", g_outputDir, token); + sprintf (transname, "%s/!%s_a.pcx", cddir, token); + } + + fmheader.num_skins++; + + if (g_skipmodel || g_release || g_archive) + return; + + // load the image + printf ("loading %s\n", name); + ExtractFileExtension (name, extension); + if (extension[0] == 0) + { + strcat(name, ".pcx"); + } + + + TrueColor = LoadAnyImage (name, &pixels, &palette, &width, &height); +// RemapZero (pixels, palette, width, height); + + // crop it to the proper size + + if (!TrueColor) + { + cropped = SafeMalloc (fmheader.skinwidth*fmheader.skinheight, "Cmd_FMSkin"); + for (y=0 ; y= 3); +// figure out the best plane projections + DOsvdPlane ((float*)vertices, num, (float *)&n, (float *)&base); + + if (DotProduct(aveNorm,n) < 0.0f) + { + VectorScale(n, -1.0f, n); + } + VectorNormalize(n,n); + if (fabs(n[2]) < .57) + { + CrossProduct( zaxis, n, crossvect); + VectorCopy(crossvect, u); + } + else + { + CrossProduct( yaxis, n, crossvect); + VectorCopy(crossvect, u); + } + VectorNormalize(u,u); + CrossProduct( n, u, crossvect); + VectorCopy(crossvect, v); + VectorNormalize(v,v); + + num = 0; + + for ( j = 0; j < 3; j++) + { + groupMin[j] = 1e30f; + groupMax[j] = -1e30f; + } + + for ( j = 0; j < numtris; j++) + { + for ( k = 0; k < 3; k++) + { + VectorCopy(grouptris[j].verts[k],v0); + VectorSubtract(v0, base, v0); + uvw[0] = DotProduct(v0, u); + uvw[1] = DotProduct(v0, v); + uvw[2] = DotProduct(v0, n); + VectorCopy(uvw,uvs[num]); + num++; + for ( l = 0; l < 3; l++) + { + if (uvw[l] < groupMin[l]) + { + groupMin[l] = uvw[l]; + } + if (uvw[l] > groupMax[l]) + { + groupMax[l] = uvw[l]; + } + } + } + } + + xwidth = ceil(0 - groupMin[0]) + 2; // move right of origin and avoid overlap + ywidth = ceil(0 - groupMin[1]) + 2; // move "above" origin + + for ( j=0; j < numverts; j++) + { + uFinal[finalcount] = uvs[j][0] + xwidth + xbase; + vFinal[finalcount] = uvs[j][1] + ywidth; + if (uFinal[finalcount] < uvwMin[0]) + { + uvwMin[0] = uFinal[finalcount]; + } + if (uFinal[finalcount] > uvwMax[0]) + { + uvwMax[0] = uFinal[finalcount]; + } + if (vFinal[finalcount] < uvwMin[1]) + { + uvwMin[1] = vFinal[finalcount]; + } + if (vFinal[finalcount] > uvwMax[1]) + { + uvwMax[1] = vFinal[finalcount]; + } + finalcount++; + } + + fprintf(grpfile,"svdPlaned Group min: ( %f , %f )\n",groupMin[0] + xwidth + xbase, groupMin[1] + ywidth); + fprintf(grpfile,"svdPlaned Group max: ( %f , %f )\n",groupMax[0] + xwidth + xbase, groupMax[1] + ywidth); + + finalcount = finalstart; + + for ( count = 0; count < numverts; count++) + { + fprintf(grpfile,"Vertex %d: ( %f , %f , %f )\n",count,vertices[count][0],vertices[count][1],vertices[count][2]); + fprintf(grpfile,"svdPlaned: ( %f , %f )\n",uFinal[finalcount],vFinal[finalcount++]); + } + + finalstart = finalcount; + + fprintf(grpfile,"\n"); + + free(vertices); + free(uvs); + free(grouptris); + + xbase += ceil(groupMax[0] - groupMin[0]) + 2; + + } + + fprintf(grpfile,"Global Min ( %f , %f )\n",uvwMin[0],uvwMin[1]); + fprintf(grpfile,"Global Max ( %f , %f )\n",uvwMax[0],uvwMax[1]); + + + ScaleTris(uvwMin, uvwMax, width, height, uFinal, vFinal, finalcount); + + for (k = 0; k < finalcount; k++) + { + fprintf(grpfile, "scaled vertex %d: ( %f , %f )\n",k,uFinal[k],vFinal[k]); + } + + // i've got the array of vertices in uFinal and vFinal. Now I need to write them and draw lines + + datasize = width * height*sizeof(unsigned char); + newpic = (unsigned char*)SafeMalloc(datasize, "NewGen"); + memset(newpic,0,datasize); + memset(pic_palette,0,sizeof(pic_palette)); + pic_palette[767] = pic_palette[766] = pic_palette[765] = 255; + + k = 0; + while (k < finalcount) + { + NewDrawLine(uFinal[k], vFinal[k], uFinal[k+1], vFinal[k+1], newpic, width, height); + k++; + NewDrawLine(uFinal[k], vFinal[k], uFinal[k+1], vFinal[k+1], newpic, width, height); + k++; + NewDrawLine(uFinal[k], vFinal[k], uFinal[k-2], vFinal[k-2], newpic, width, height); + k++; + fprintf(grpfile, "output tri with verts %d, %d, %d", k-2, k-1, k); + } + + WritePCXfile (OutputName, newpic, width, height, pic_palette); + + fclose(grpfile); + + free(todo); + free(done); + free(triangles); + free(newpic); + return; +} +void NewDrawLine(int x1, int y1, int x2, int y2, unsigned char* picture, int width, int height) +{ + long dx, dy; + long adx, ady; + long count; + float xfrac, yfrac, xstep, ystep; + unsigned long sx, sy; + float u, v; + + dx = x2 - x1; + dy = y2 - y1; + adx = abs(dx); + ady = abs(dy); + + count = adx > ady ? adx : ady; + count++; + + if(count > 300) + { + printf("Bad count\n"); + return; // don't ever hang up on bad data + } + + xfrac = x1; + yfrac = y1; + + xstep = (float)dx/count; + ystep = (float)dy/count; + + switch(LineType) + { + case LINE_NORMAL: + do + { + if(xfrac < width && yfrac < height) + { + picture[(long)yfrac*width+(long)xfrac] = LineColor; + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + case LINE_FAT: + do + { + for (u=-0.1 ; u<=0.9 ; u+=0.999) + { + for (v=-0.1 ; v<=0.9 ; v+=0.999) + { + sx = xfrac+u; + sy = yfrac+v; + if(sx < width && sy < height) + { + picture[sy*width+sx] = LineColor; + } + } + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + case LINE_DOTTED: + do + { + if(count&1 && xfrac < width && + yfrac < height) + { + picture[(long)yfrac*width+(long)xfrac] = LineColor; + } + xfrac += xstep; + yfrac += ystep; + count--; + } while (count > 0); + break; + default: + Error("Unknown %d.\n", LineType); + } +} +*/ +void ScaleTris( vec3_t min, vec3_t max, int Width, int Height, float* u, float* v, int verts) +{ + + int i; + float hscale, vscale; + float scale; + + hscale = max[0]; + vscale = max[1]; + + hscale = (Width-2) / max[0]; + vscale = (Height-2) / max[1]; + + scale = hscale; + if (scale > vscale) + { + scale = vscale; + } + for ( i = 0; i 32) + { + Error ("Degrees of freedom out of range: %d",groups[num_groups].degrees); + } +} + +void Cmd_FMEndGroup (void) +{ + groups[num_groups].num_frames = fmheader.num_frames - groups[num_groups].start_frame; + + if(num_groups < MAX_GROUPS - 1) + { + num_groups++; + } + else + { + Error("Number of compression groups exceded: %i\n", MAX_GROUPS); + } +} + diff --git a/Toolkit/Programming/Tools/qdata/Jointed.c b/Toolkit/Programming/Tools/qdata/Jointed.c new file mode 100644 index 0000000..207dbb3 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/Jointed.c @@ -0,0 +1,550 @@ +#include +#include +#include "token.h" +#include "Joints.h" +#include "Angles.h" + +char *SKEL_ROOT_NAMES[] = +{ + "RAVEN_SPINE" +}; + +char *SKEL_NAMES[] = +{ + "RAVEN_WAIST1", + "RAVEN_WAIST2", + "RAVEN_NECK" +}; + +int NAME_OFFSETS[] = +{ + 0 +}; + +int numJointsForSkeleton[] = +{ + NUM_JOINTS_RAVEN, + NUM_JOINTS_BOX +}; + +float g_scaling[3]; +float g_rotation[3]; +float g_translation[3]; + +//========================================================================== +// +// LoadHRCClustered +// +//========================================================================== + +static void LoadHRCClustered(char *fileName, int **clusterList, int *num_verts, int skelType) +{ + int i, j; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + TK_Beyond(TK_CLUSTERS); + + while(TK_Search(TK_CLUSTER_NAME) != TK_EOF) + { + TK_Require(TK_STRING); + + for( i = 0; i < numJointsForSkeleton[skelType]; ++i) + { + if(_stricmp(tk_String, SKEL_NAMES[NAME_OFFSETS[skelType]+i]) == 0) + { + i = -i + numJointsForSkeleton[skelType] - 1; + + TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER); + + num_verts[i+1] = tk_IntNumber; + + clusterList[i] = SafeMalloc(num_verts[i+1]*sizeof(int), "LoadHRCClustered"); + assert(clusterList[i]); + // currently this function is only called by LoadTriangleListClustered, which in turn is only + // called by Cmd_Base in qdata. This is where the only call to free for this memory is being made. + + TK_Beyond(TK_LBRACE); + + for(j = 0; j < num_verts[i+1]; ++j) + { + TK_Require(TK_INTNUMBER); + clusterList[i][j] = tk_IntNumber; + TK_Fetch(); + } + + break; + } + } + } + + num_verts[0] = numJointsForSkeleton[skelType]; +} + +static void LoadHRCGlobals(char *fileName) +{ + int i; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + TK_Beyond(TK_MODEL); + + TK_Beyond(TK_SCALING); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_scaling[i] = tk_FloatNumber; + TK_Fetch(); + } + + TK_Beyond(TK_ROTATION); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_rotation[i] = tk_FloatNumber; + TK_Fetch(); + } + + TK_Beyond(TK_TRANSLATION); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_translation[i] = tk_FloatNumber; + TK_Fetch(); + } +} + +static void ParseVec3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseRotation3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = -tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseTranslation3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void LoadHRCJointList(char *fileName, QDataJoint_t *jointList, int skelType) +{ +#define MAX_STACK 64 + int i, j; + vec3_t curTranslation[MAX_STACK], curRotation[MAX_STACK], curScale[MAX_STACK]; + int curCorrespondingJoint[MAX_STACK]; + int currentStack = 0, stackSize; + int baseJoint; + float cx, sx, cy, sy, cz, sz; + float rx, ry, rz; + float x2, y2, z2; + + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + TK_Beyond(TK_MODEL); + TK_Beyond(TK_MODEL); + +/* while(1) + { + TK_Beyond(TK_MODEL); + TK_BeyondRequire(TK_NAME, TK_STRING); + + if(_stricmp(tk_String, SKEL_ROOT_NAMES[skelType]) == 0) + break; + }*/ + + TK_Beyond(TK_SCALING); + + ParseVec3(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3(curTranslation[currentStack]); + + // account for global model translation + curTranslation[currentStack][1] += g_translation[0]; + curTranslation[currentStack][2] += g_translation[1]; + curTranslation[currentStack][0] += g_translation[2]; + + ++currentStack; + + for(i = 0; i < NUM_JOINTS_RAVEN; ++i) + { + while(1) + { + TK_Beyond(TK_MODEL); + +// TK_BeyondRequire(TK_NAME, TK_STRING); + +// if(_stricmp(tk_String, SKEL_NAMES[NAME_OFFSETS[skelType]+i]) == 0) + break; + + TK_Beyond(TK_SCALING); + + ParseVec3(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3(curTranslation[currentStack]); + + curCorrespondingJoint[currentStack] = -1; + + ++currentStack; + } + + TK_Beyond(TK_SCALING); + + ParseVec3(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3(curRotation[currentStack]); + + jointList[i].rotation[1] = curRotation[currentStack][1]; + jointList[i].rotation[2] = curRotation[currentStack][2]; + jointList[i].rotation[0] = curRotation[currentStack][0]; + + TK_Beyond(TK_TRANSLATION); + + ParseVec3(curTranslation[currentStack]); + + jointList[i].placement.origin[1] = curTranslation[currentStack][1]; + jointList[i].placement.origin[2] = curTranslation[currentStack][2]; + jointList[i].placement.origin[0] = curTranslation[currentStack][0]; + + jointList[i].placement.direction[1] = 7.5; + jointList[i].placement.direction[2] = 0.0; + jointList[i].placement.direction[0] = 0.0; + + jointList[i].placement.up[1] = 0.0; + jointList[i].placement.up[2] = 7.5; + jointList[i].placement.up[0] = 0.0; + + curCorrespondingJoint[currentStack] = i; + + ++currentStack; + } + + stackSize = currentStack; + + for(i = 0; i < NUM_JOINTS_RAVEN; ++i) + { + rx = jointList[i].rotation[0]*ANGLE_TO_RAD; + ry = jointList[i].rotation[1]*ANGLE_TO_RAD; + rz = jointList[i].rotation[2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + + // y-axis rotation for direction + x2 = jointList[i].placement.direction[0]*cy+jointList[i].placement.direction[2]*sy; + z2 = -jointList[i].placement.direction[0]*sy+jointList[i].placement.direction[2]*cy; + jointList[i].placement.direction[0] = x2; + jointList[i].placement.direction[2] = z2; + + // y-axis rotation for up + x2 = jointList[i].placement.up[0]*cy+jointList[i].placement.up[2]*sy; + z2 = -jointList[i].placement.up[0]*sy+jointList[i].placement.up[2]*cy; + jointList[i].placement.up[0] = x2; + jointList[i].placement.up[2] = z2; + + // z-axis rotation for direction + x2 = jointList[i].placement.direction[0]*cz-jointList[i].placement.direction[1]*sz; + y2 = jointList[i].placement.direction[0]*sz+jointList[i].placement.direction[1]*cz; + jointList[i].placement.direction[0] = x2; + jointList[i].placement.direction[1] = y2; + + // z-axis rotation for up + x2 = jointList[i].placement.up[0]*cz-jointList[i].placement.up[1]*sz; + y2 = jointList[i].placement.up[0]*sz+jointList[i].placement.up[1]*cz; + jointList[i].placement.up[0] = x2; + jointList[i].placement.up[1] = y2; + + // x-axis rotation for direction vector + y2 = jointList[i].placement.direction[1]*cx-jointList[i].placement.direction[2]*sx; + z2 = jointList[i].placement.direction[1]*sx+jointList[i].placement.direction[2]*cx; + jointList[i].placement.direction[1] = y2; + jointList[i].placement.direction[2] = z2; + + // x-axis rotation for up vector + y2 = jointList[i].placement.up[1]*cx-jointList[i].placement.up[2]*sx; + z2 = jointList[i].placement.up[1]*sx+jointList[i].placement.up[2]*cx; + jointList[i].placement.up[1] = y2; + jointList[i].placement.up[2] = z2; + + // translate to position in model + jointList[i].placement.direction[0] += jointList[i].placement.origin[0]; + jointList[i].placement.direction[1] += jointList[i].placement.origin[1]; + jointList[i].placement.direction[2] += jointList[i].placement.origin[2]; + + // translate to position in model + jointList[i].placement.up[0] += jointList[i].placement.origin[0]; + jointList[i].placement.up[1] += jointList[i].placement.origin[1]; + jointList[i].placement.up[2] += jointList[i].placement.origin[2]; + } + + baseJoint = NUM_JOINTS_RAVEN; + + for(i = stackSize/*NUM_JOINTS_RAVEN*/ - 1; i > 0; --i) + { + + rx = curRotation[i-1][0]*ANGLE_TO_RAD; + ry = curRotation[i-1][1]*ANGLE_TO_RAD; + rz = curRotation[i-1][2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + + for(j = i-1; j < stackSize-1; ++j) + { + // y-axis rotation for origin + x2 = jointList[j].placement.origin[0]*cy+jointList[j].placement.origin[2]*sy; + z2 = -jointList[j].placement.origin[0]*sy+jointList[j].placement.origin[2]*cy; + jointList[j].placement.origin[0] = x2; + jointList[j].placement.origin[2] = z2; + + // y-axis rotation for direction + x2 = jointList[j].placement.direction[0]*cy+jointList[j].placement.direction[2]*sy; + z2 = -jointList[j].placement.direction[0]*sy+jointList[j].placement.direction[2]*cy; + jointList[j].placement.direction[0] = x2; + jointList[j].placement.direction[2] = z2; + + // y-axis rotation for up + x2 = jointList[j].placement.up[0]*cy+jointList[j].placement.up[2]*sy; + z2 = -jointList[j].placement.up[0]*sy+jointList[j].placement.up[2]*cy; + jointList[j].placement.up[0] = x2; + jointList[j].placement.up[2] = z2; + + // z-axis rotation for origin + x2 = jointList[j].placement.origin[0]*cz-jointList[j].placement.origin[1]*sz; + y2 = jointList[j].placement.origin[0]*sz+jointList[j].placement.origin[1]*cz; + jointList[j].placement.origin[0] = x2; + jointList[j].placement.origin[1] = y2; + + // z-axis rotation for direction + x2 = jointList[j].placement.direction[0]*cz-jointList[j].placement.direction[1]*sz; + y2 = jointList[j].placement.direction[0]*sz+jointList[j].placement.direction[1]*cz; + jointList[j].placement.direction[0] = x2; + jointList[j].placement.direction[1] = y2; + + // z-axis rotation for up + x2 = jointList[j].placement.up[0]*cz-jointList[j].placement.up[1]*sz; + y2 = jointList[j].placement.up[0]*sz+jointList[j].placement.up[1]*cz; + jointList[j].placement.up[0] = x2; + jointList[j].placement.up[1] = y2; + + // x-axis rotation for origin + y2 = jointList[j].placement.origin[1]*cx-jointList[j].placement.origin[2]*sx; + z2 = jointList[j].placement.origin[1]*sx+jointList[j].placement.origin[2]*cx; + jointList[j].placement.origin[1] = y2; + jointList[j].placement.origin[2] = z2; + + // x-axis rotation for direction vector + y2 = jointList[j].placement.direction[1]*cx-jointList[j].placement.direction[2]*sx; + z2 = jointList[j].placement.direction[1]*sx+jointList[j].placement.direction[2]*cx; + jointList[j].placement.direction[1] = y2; + jointList[j].placement.direction[2] = z2; + + // x-axis rotation for up vector + y2 = jointList[j].placement.up[1]*cx-jointList[j].placement.up[2]*sx; + z2 = jointList[j].placement.up[1]*sx+jointList[j].placement.up[2]*cx; + jointList[j].placement.up[1] = y2; + jointList[j].placement.up[2] = z2; + + if(curCorrespondingJoint[j+1] != -1) + { + // translate origin + jointList[j].placement.origin[0] += curTranslation[i-1][0]; + jointList[j].placement.origin[1] += curTranslation[i-1][1]; + jointList[j].placement.origin[2] += curTranslation[i-1][2]; + + // translate back to local coord + jointList[j].placement.direction[0] += curTranslation[i-1][0]; + jointList[j].placement.direction[1] += curTranslation[i-1][1]; + jointList[j].placement.direction[2] += curTranslation[i-1][2]; + + // translate back to local coord + jointList[j].placement.up[0] += curTranslation[i-1][0]; + jointList[j].placement.up[1] += curTranslation[i-1][1]; + jointList[j].placement.up[2] += curTranslation[i-1][2]; + } + } + } +} + +void LoadGlobals(char *fileName) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCGlobals(InputFileName); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC match.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { + printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCGlobals(fileName); + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void LoadClusters(char *fileName, int **clusterList, int *num_verts, int skelType) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCClustered(InputFileName, clusterList, num_verts, skelType); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC match.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { + printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCClustered(fileName, clusterList, num_verts, skelType); + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void LoadJointList(char *fileName, QDataJoint_t *jointList, int skelType) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCJointList(InputFileName, jointList, skelType); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { + printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCJointList(fileName, jointList, skelType); + + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + diff --git a/Toolkit/Programming/Tools/qdata/Jointed.h b/Toolkit/Programming/Tools/qdata/Jointed.h new file mode 100644 index 0000000..c183ebe --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/Jointed.h @@ -0,0 +1,10 @@ +void LoadGlobals(char *fileName); +void LoadClusters(char *fileName, int **clusterList, int *num_verts, int skel_type); +void LoadJointList(char *fileName, struct QDataJoint_s *jointList, int num_verts); + +#define NUM_CLUSTERS 8 + +#define NOT_JOINTED -1 + +#include "Joints.h" + diff --git a/Toolkit/Programming/Tools/qdata/Joints.h b/Toolkit/Programming/Tools/qdata/Joints.h new file mode 100644 index 0000000..99f106b --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/Joints.h @@ -0,0 +1,118 @@ +#ifndef JOINTS_H +#define JOINTS_H + +#ifdef _HERETIC2_ +#include "Angles.h" +#endif + +typedef float vec3_t[3]; +typedef unsigned char byte; + +typedef struct Placement_s +{ + vec3_t origin; + vec3_t direction; + vec3_t up; +} Placement_t; + +#ifdef _QDATA +typedef struct QDataJoint_s +{ + Placement_t placement; + vec3_t rotation; +} QDataJoint_t; +#endif + +typedef struct ArrayedListNode_s +{ + int data; + int next; + int inUse; +} ArrayedListNode_t; + +#define ARRAYEDLISTNODE_NULL -1 + +typedef struct JointAngles_s +{ + float angles[3]; + int children; + int created; +} JointAngles_t; + +typedef struct JointAngles2_s +{ + float angles[3]; + int children; + int changed[3]; + int inUse; +} JointAngles2_t; + +#define MAX_MODELJOINTS 256 +#define MAX_MODELJOINTNODES 255 + +extern JointAngles_t jointAngles[MAX_MODELJOINTS]; +extern JointAngles2_t jointAngles2[MAX_MODELJOINTS]; + +extern ArrayedListNode_t jointAngleNodes[MAX_MODELJOINTNODES]; + +// Skeletal structures enums +enum { + SKEL_RAVEN = 0, + SKEL_BOX, + NUM_SKELETONS +}; + +// Raven Skeletal structures enums +enum { + RAVEN_WAIST1 = 0, + RAVEN_WAIST2 = 1, + RAVEN_HEAD = 2, + NUM_JOINTS_RAVEN +}; + +// Box Skeletal structures enums +enum { + BOX_CENTER = 0, + NUM_JOINTS_BOX +}; + +extern int numJointsForSkeleton[]; +extern char *RAVEN_SKEL_NAMES[]; + +#define J_NEW_SKELETON 0x00001000 +#define J_YAW_CHANGED 0x00002000 +#define J_PITCH_CHANGED 0x00004000 +#define J_ROLL_CHANGED 0x00008000 +#define MAX_JOINTS 0x00000fff + +_inline int GetFreeNode(ArrayedListNode_t *nodeArray, int max) +{ // yeah, I know this is a sucky, inefficient way to do this, but I didn't feel like taking the time to write a real resource manager in C + int i; + + for(i = 0; i < max; ++i) + { + if(!nodeArray[i].inUse) + { + nodeArray[i].inUse = 1; + return i; + } + } + + assert(0); + return -1; +} + +_inline void FreeNode(ArrayedListNode_t *nodeArray, int index) +{ + nodeArray[index].inUse = 0; +} + +int CreateSkeleton(int structure); +void CreateSkeletonAtIndex(int structure, int index); +void FreeSkeleton(int structure, int index); +void SetJointAngle(int jointIndex, int angleIndex, float angle); +float ModifyJointAngle(int jointIndex, int angleIndex, float deltaAngle); +int ZeroJointAngle(int jointIndex, int angleIndex, float angVel); +int ApplyAngVelToJoint(int jointIndex, int angleIndex, float angVel, float destAng); + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qdata/animcomp.cpp b/Toolkit/Programming/Tools/qdata/animcomp.cpp new file mode 100644 index 0000000..9dee1a0 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/animcomp.cpp @@ -0,0 +1,328 @@ + +#include +#include +#include +#include +#include "animcomp.h" + + +extern "C" void *SafeMalloc(size_t n, char *desc); + + + +float *matrix; +float *delta; +float *best; +float *comp; +float *tcomp; +float *bestcomp; +float *frames; +float *base; + +int MatWidth; +int MatHeight; +int CFrameSize; +int nFrames; + + +extern "C" void AnimCompressInit(int nframes,int nVerts,int CompressedFrameSize) +{ + nFrames=nframes; + MatWidth=nVerts*3; + MatHeight=CompressedFrameSize; + CFrameSize=CompressedFrameSize; + matrix=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit"); + best=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit"); + delta=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit"); + comp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit"); + tcomp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit"); + bestcomp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit"); + base=(float *)SafeMalloc(MatWidth*sizeof(float), "AnimCompressInit"); + frames=(float *)SafeMalloc(MatWidth*nFrames*sizeof(float), "AnimCompressInit"); +} + +extern "C" void AnimSetFrame(int frame,int index,float x,float y,float z) +{ + frames[frame*MatWidth+index*3]=x; + frames[frame*MatWidth+index*3+1]=y; + frames[frame*MatWidth+index*3+2]=z; +} + +typedef struct +{ + int index; + float val; +} SORTP; + + +#define F_RANDOM (((float)rand())/(float)RAND_MAX) + +void DOsvd(float *a,float *res,float *comp,float *values,int nframes,int framesize,int compressedsize); + +extern "C" void AnimCompressDoit() +{ + float compression; + float *rescale; + float *ans; + float maxdev; + float avedev; + float tmp; + int j,k,l,numave; + + for (k=0;kmaxdev) + maxdev=tmp; + avedev+=tmp; + numave++; + } + } + avedev/=(float)numave; +printf("%f Max Deviation (inches) %f Ave Dev. (inches)\n",maxdev,avedev); +printf("%d bytes original size\n",MatWidth*nFrames); +printf("%d bytes of overhead\n",MatWidth*MatHeight); +printf("%d bytes/frame * %d frames = %d bytes\n",CFrameSize,nFrames,CFrameSize*nFrames); + compression=(float)(MatWidth*MatHeight+CFrameSize*nFrames+MatWidth); + compression/=(float)(MatWidth*nFrames); +printf("Overall compression = %f %%\n",100.0f-100.0f*compression); + compression=(float)(CFrameSize); + compression/=(float)(MatWidth); +printf("frame size compression = %f %%\n",100.0f-100.0f*compression); + free(rescale); + free(ans); +} + +extern "C" void AnimCompressToBytes(float *trans,float *scale,char *mat,char *ccomp,unsigned char *cbase,float *cscale,float *coffset,float *bmin,float *bmax) +{ + int k,l,nv,j; + float maxdev; + float avedev; + float tmp; + int numave; + nv=MatWidth/3; + float t,mx; + + trans[0]=1E30f; + scale[0]=-1E30f; + trans[1]=1E30f; + scale[1]=-1E30f; + trans[2]=1E30f; + scale[2]=-1E30f; + for (k=0;kscale[0]) + scale[0]=base[k]; + if (base[k]scale[1]) + scale[1]=base[k+1]; + if (base[k+1]scale[2]) + scale[2]=base[k+2]; + if (base[k+2]255.0f) + t=255.0f; + cbase[k]=(unsigned char)t; + + t=(base[k+1]-trans[1])/scale[1]; + if (t<0.0f) + t=0.0f; + if (t>255.0f) + t=255.0f; + cbase[k+1]=(unsigned char)t; + + t=(base[k+2]-trans[2])/scale[2]; + if (t<0.0f) + t=0.0f; + if (t>255.0f) + t=255.0f; + cbase[k+2]=(unsigned char)t; + } + for (l=0;lmx) + mx=(float)fabs(best[l*MatWidth+k]); + } + if (mx>1E-8) + { + mx/=127.0f; + coffset[l]=1E30f; + cscale[l]=-1E30f; + for (j=0;jcscale[l]) + cscale[l]=bestcomp[j*MatHeight+l]; + if (bestcomp[j*MatHeight+l]1E-10) + { + for (j=0;j127.0f) + tmp=127.0f; + if (tmp<-127.0f) + tmp=-127.0f; + ccomp[j*MatHeight+l]=(char)floor(tmp+0.5); + } + coffset[l]+=cscale[l]*127.0f/254.0f; + cscale[l]/=254.0f; + } + else + { + cscale[l]=1.0f; + coffset[l]=0.0f; + for (j=0;j127.0f) + tmp=127.0f; + if (tmp<-127.0f) + tmp=-127.0f; + mat[k*MatHeight+l]=(char)floor(tmp+0.5); + } + } + else + { + cscale[l]=1.0f; + coffset[l]=0.0f; + for (j=0;jmaxdev) + maxdev=tmp; + avedev+=tmp; + numave++; + + if (bmin[k%3]>ans[k]) + bmin[k%3]=ans[k]; + if (bmax[k%3]version = MIP_VERSION; + + for(i=j=0;i<256;i++,j+=3) + { + mp->palette[i].r = palette[j]; + mp->palette[i].g = palette[j+1]; + mp->palette[i].b = palette[j+2]; + } + pos = (byte *)(mp + 1); + + mp->width[0] = w; + mp->height[0] = h; + mp->offsets[0] = sizeof(*mp); + memcpy(pos, buffer, w * h); + + *FinalSize = size; + return(mp); +} + +miptex32_t *CreateBook32(long *buffer, int w, int h, int *FinalSize) +{ + miptex32_t *mp; + byte *pos; + int size; + + size = sizeof(*mp) + (w * h * 4); + mp = (miptex32_t *)SafeMalloc(size, "CreateBook32"); + memset(mp, 0, size); + + mp->version = MIP32_VERSION; + + pos = (byte *)(mp + 1); + + mp->width[0] = w; + mp->height[0] = h; + mp->offsets[0] = sizeof(*mp); + memcpy(pos, buffer, w * h * 4); + + *FinalSize = size; + return(mp); +} + + +// Routines to chop a random sized image into gl texture friendly chunks + +typedef struct rect_s +{ + int x, y; + int w, h; + char name[4]; +} rect_t; + +int GetCoords(int x, int store[MAX_MD2SKINS]) +{ + int index, start, delta; + + index = 0; + start = 0; + delta = 256; + + store[index++] = start; + while(x) + { + if(x >= delta) + { + start += delta; + store[index++] = start; + x -= delta; + } + else + { + delta >>= 1; + } + } + return(index); +} + +int ChopImage(int w, int h, rect_t coords[MAX_MD2SKINS]) +{ + int xs[MAX_MD2SKINS], ys[MAX_MD2SKINS]; + int xcount, ycount, x, y, index; + + index = 0; + xcount = GetCoords(w, xs) - 1; + ycount = GetCoords(h, ys) - 1; + + for(y = 0; y < ycount; y++) + { + for(x = 0; x < xcount; x++, index++) + { + coords[index].x = xs[x]; + coords[index].y = ys[y]; + coords[index].w = xs[x + 1] - xs[x]; + coords[index].h = ys[y + 1] - ys[y]; + coords[index].name[0] = x + '0'; + coords[index].name[1] = y + '0'; + coords[index].name[2] = 0; + } + } + return(index); +} + +/* +=============== +Cmd_Pic +=============== +*/ + +void Cmd_Book() +{ + int xl,yl,xh,yh,w,h; + byte *dest, *source; + int flags, value, contents; + char lumpname[64]; + char filename[1024]; + unsigned long *destl, *sourcel; + int linedelta, x, y; + int size; + miptex_t *qtex; + miptex32_t *qtex32; + float scale_x, scale_y; + int numrects, i; + rect_t coords[MAX_MD2SKINS]; + bookframe_t bframes[MAX_MD2SKINS]; + bookframe_t *bf; + book_t book; + + GetScriptToken (false); + strcpy (lumpname, token); + + GetScriptToken (false); + xl = atoi (token); + GetScriptToken (false); + yl = atoi (token); + GetScriptToken (false); + w = atoi (token); + GetScriptToken (false); + h = atoi (token); + + total_x += w; + total_y += h; + total_textures++; + + if ( (w & 7) || (h & 7) ) + Error ("line %i: miptex sizes must be multiples of 8", scriptline); + + flags = 0; + contents = 0; + value = 0; + + scale_x = scale_y = 0.5; + + if (g_release) + return; + + if(TrueColorImage) + { + xh = xl + w; + yh = yl + h; + + if (xl >= longimagewidth || xh > longimagewidth || + yl >= longimageheight || yh > longimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,longimagewidth,longimageheight); + } + + sourcel = longimage + (yl * longimagewidth) + xl; + destl = longimage; + linedelta = (longimagewidth - w); + + for(y = yl; y < yh; y++) + { + for(x = xl; x < xh; x++) + { + *destl++ = *sourcel++; // RGBA + } + sourcel += linedelta; + } + + // Get rectangles to chop into + numrects = ChopImage(w, h, coords); + + bf = bframes; + for(i = 0; i < numrects; i++, bf++) + { + // Copy section of image to buffer + sourcel = longimage + (coords[i].y * w) + coords[i].x; + destl = bufferl; + linedelta = w - coords[i].w; + + for(y = 0; y < coords[i].h; y++) + { + for(x = 0; x < coords[i].w; x++) + { + *destl++ = *sourcel++; + } + sourcel += linedelta; + } + + qtex32 = CreateBook32(bufferl, coords[i].w, coords[i].h, &size); + + qtex32->flags = flags; + qtex32->contents = contents; + qtex32->value = value; + qtex32->scale_x = scale_x; + qtex32->scale_y = scale_y; + + sprintf (filename, "%sbook/%s/%s_%s.m32", gamedir, book_prefix, lumpname, coords[i].name); + sprintf (qtex32->name, "%s/%s_%s.m32", book_prefix, lumpname, coords[i].name); + + strcpy(bf->name, qtex32->name); + bf->x = coords[i].x; + bf->y = coords[i].y; + bf->w = coords[i].w; + bf->h = coords[i].h; + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + + free (qtex32); + } + } + else + { + xh = xl + w; + yh = yl + h; + + if (xl >= byteimagewidth || xh > byteimagewidth || + yl >= byteimageheight || yh > byteimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight); + } + + // Copy image to top left + source = byteimage + yl*byteimagewidth + xl; + dest = byteimage; + linedelta = byteimagewidth - w; + + for(y = yl; y < yh; y++) + { + for(x = xl; x < xh; x++) + { + *dest++ = *source++; + } + source += linedelta; + } + + // Get rectangles to chop into + numrects = ChopImage(w, h, coords); + + bf = bframes; + for(i = 0; i < numrects; i++, bf++) + { + // Copy section of image to buffer + source = byteimage + (coords[i].y * w) + coords[i].x; + dest = buffer; + linedelta = w - coords[i].w; + + for(y = 0; y < coords[i].h; y++) + { + for(x = 0; x < coords[i].w; x++) + { + *dest++ = *source++; + } + source += linedelta; + } + + qtex = CreateBook8(buffer, coords[i].w, coords[i].h, lbmpalette, &size); + + qtex->flags = flags; + qtex->contents = contents; + qtex->value = value; + + sprintf (filename, "%sbook/%s/%s_%s.m8", gamedir, book_prefix, lumpname, coords[i].name); + sprintf (qtex->name, "%s/%s_%s.m8", book_prefix, lumpname, coords[i].name); + + strcpy(bf->name, qtex->name); + bf->x = coords[i].x; + bf->y = coords[i].y; + bf->w = coords[i].w; + bf->h = coords[i].h; + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex, size); + + free (qtex); + } + } + // Set up descriptor + size = sizeof(bookframe_t) * numrects; + + book.bheader.ident = IDBOOKHEADER; + book.bheader.version = BOOK_VERSION; + book.bheader.num_segments = numrects; + book.bheader.total_w = w; + book.bheader.total_h = h; + memcpy(book.bframes, bframes, size); + + // Save out segment descriptor + sprintf (filename, "%sBook/%s/%s.bk", gamedir, book_prefix, lumpname); + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)&book, size + sizeof(bookheader_t)); +} + +/* +=============== +Cmd_picdir +=============== +*/ +void Cmd_Bookdir (void) +{ + char filename[1024]; + + GetScriptToken (false); + strcpy (book_prefix, token); + // create the directory if needed + sprintf (filename, "%sBook", gamedir); + Q_mkdir (filename); + sprintf (filename, "%sBook/%s", gamedir, book_prefix); + Q_mkdir (filename); +} + +// end diff --git a/Toolkit/Programming/Tools/qdata/icon1.ico b/Toolkit/Programming/Tools/qdata/icon1.ico new file mode 100644 index 0000000..8f44194 Binary files /dev/null and b/Toolkit/Programming/Tools/qdata/icon1.ico differ diff --git a/Toolkit/Programming/Tools/qdata/images.c b/Toolkit/Programming/Tools/qdata/images.c new file mode 100644 index 0000000..2165f5f --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/images.c @@ -0,0 +1,1372 @@ +#include "qdata.h" +#include +#include + +#ifdef _QDATA + extern char *g_outputDir; +#endif // _QDATA + +char mip_prefix[1024]; // directory to dump the textures in + +qboolean colormap_issued; +byte colormap_palette[768]; + +unsigned total_x = 0; +unsigned total_y = 0; +unsigned total_textures = 0; + +#if 0 +/* +============== +RemapZero + +Replaces all 0 bytes in an image with the closest palette entry. +This is because NT won't let us change index 0, so any palette +animation leaves those pixels untouched. +============== +*/ +void RemapZero (byte *pixels, byte *palette, int width, int height) +{ + int i, c; + int alt_zero; + int value, best; + + alt_zero = 0; + best = 9999999; + for (i=1 ; i<255 ; i++) + { + value = palette[i*3+0]+palette[i*3+1]+palette[i*3+2]; + if (value < best) + { + best = value; + alt_zero = i; + } + } + + c = width*height; + for (i=0 ; i> 16; + palette_g[i] = (palette[i] & 0x0000ff00) >> 8; + palette_b[i] = (palette[i] & 0x000000ff); + } + + for(i=0;i biggest_delta) + continue; + dg = abs(palette_g[i] - g); + if (dg > biggest_delta) + continue; + db = abs(palette_b[i] - b); + if (db > biggest_delta) + continue; + + dist = dr * dr + dg * dg + db * db; + if (dist < min_dist) + { + min_dist = dist; + min_index = i; + if (min_dist == 0) break; + + dist = dr; + if (dg > dist) dist = dg; + if (db > dist) dist = db; + if (dist < biggest_delta) + biggest_delta = dist; + } + } + + last_place++; + if (last_place >= MAX_LAST) + last_place = 0; + + last_r[last_place] = r; + last_g[last_place] = g; + last_b[last_place] = b; + last_i[last_place] = min_index; + + return min_index; +} + + +void GL_ResampleTexture8P (byte *in, int inwidth, int inheight, byte *out, + int outwidth, int outheight, palette_t *palette) +{ + int i, j; + byte *inrow, *inrow2; + unsigned frac, fracstep; + unsigned p1[1024], p2[1024], *p1p, *p2p; + palette_t *c1,*c2,*c3,*c4; + unsigned r,g,b; + + fracstep = inwidth*0x10000/outwidth; + + frac = fracstep>>2; + for (i=0 ; i>16; + frac += fracstep; + } + frac = 3*(fracstep>>2); + for (i=0 ; i>16; + frac += fracstep; + } + + cached = 0; + + for (i=0 ; ir + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r)>>2; + g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g)>>2; + b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b)>>2; + + *out++ = ConvertTrueColorToPal(r,g,b); + } + } +} + +void GL_MipMap8P(byte *out, byte *in, int width, int height, palette_t *palette) +{ + int i, j; + palette_t *c1,*c2,*c3,*c4; + unsigned r,g,b; + + cached = 0; + memset(out, 0, 256 * 256); + width <<= 1; + height <<= 1; + + for (i = 0; i < height; i += 2, in += width) + { + for (j = 0; j < width; j += 2) + { + c1 = &palette[in[0]]; + c3 = &palette[in[width]]; + in++; + c2 = &palette[in[0]]; + c4 = &palette[in[width]]; + in++; + + r = ((unsigned)c1->r + (unsigned)c2->r + (unsigned)c3->r + (unsigned)c4->r) >> 2; + g = ((unsigned)c1->g + (unsigned)c2->g + (unsigned)c3->g + (unsigned)c4->g) >> 2; + b = ((unsigned)c1->b + (unsigned)c2->b + (unsigned)c3->b + (unsigned)c4->b) >> 2; + + *out++ = ConvertTrueColorToPal(r, g, b); + } + } +} + + +miptex_t *CreateMip(byte *data, unsigned width, unsigned height, byte *palette, int *FinalSize, qboolean mip) +{ + int scaled_width, scaled_height; + int i,j,r,g,b; + byte intensitytable[256]; + byte scaled[256*256]; + byte out[256*256]; + int miplevel; + miptex_t *mp; + byte *pos; + int size; + + for (i=0 ; i<256 ; i++) + { + j = i * intensity_value; + if (j > 255) + j = 255; + intensitytable[i] = j; + } + + for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) + ; + if (1 && scaled_width > width && 1) + scaled_width >>= 1; + for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) + ; + if (1 && scaled_height > height && 1) + scaled_height >>= 1; + + // don't ever bother with >256 textures + if (scaled_width > 256) + scaled_width = 256; + if (scaled_height > 256) + scaled_height = 256; + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + size = sizeof(*mp) + (scaled_width*scaled_height*3); + mp = (miptex_t *)SafeMalloc(size, "CreateMip"); + memset(mp,0,size); + + mp->version = MIP_VERSION; + + for(i=j=0;i<256;i++,j+=3) + { + mp->palette[i].r = r = intensitytable[palette[j]]; + mp->palette[i].g = g = intensitytable[palette[j+1]]; + mp->palette[i].b = b = intensitytable[palette[j+2]]; + image_pal[i] = 0xff000000 | (r<<16) | (g<<8) | (b); + } + + PrepareConvert(image_pal); + + if (scaled_width == width && scaled_height == height) + { + memcpy (scaled, data, width*height); + } + else + GL_ResampleTexture8P (data, width, height, scaled, scaled_width, scaled_height, mp->palette); + + pos = (byte *)(mp + 1); + miplevel = 0; + + while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip)) + { + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + if(miplevel > 0) + GL_MipMap8P(out, (byte *)scaled, scaled_width, scaled_height, mp->palette); + else + memcpy(out, scaled, 256 * 256); + + mp->width[miplevel] = scaled_width; + mp->height[miplevel] = scaled_height; + mp->offsets[miplevel] = pos - ((byte *)(mp)); + memcpy(pos, out, scaled_width * scaled_height); + memcpy(scaled, out, 256 * 256); + pos += scaled_width * scaled_height; + + scaled_width >>= 1; + scaled_height >>= 1; + + miplevel++; + } + + *FinalSize = pos - ((byte *)(mp)); + + return mp; +} + + +void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight) +{ + int i, j; + unsigned *inrow, *inrow2; + unsigned frac, fracstep; + unsigned p1[1024], p2[1024]; + byte *pix1, *pix2, *pix3, *pix4; + + fracstep = inwidth*0x10000/outwidth; + + frac = fracstep>>2; + for (i=0 ; i>16); + frac += fracstep; + } + frac = 3*(fracstep>>2); + for (i=0 ; i>16); + frac += fracstep; + } + + for (i=0 ; i> 1; + for (j=0 ; j>2; + ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; + ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; + ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; + } + } +} + +void GL_MipMap (byte *out, byte *in, int width, int height) +{ + int i, j; + + width <<=3; + height <<= 1; + for (i=0 ; i>2; + out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2; + out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2; + out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2; + } + } +} + +miptex32_t *CreateMip32(unsigned *data, unsigned width, unsigned height, int *FinalSize, qboolean mip) +{ + int scaled_width, scaled_height; + unsigned scaled[256*256]; + unsigned out[256*256]; + int miplevel; + miptex32_t *mp; + byte *pos; + int size; + paletteRGBA_t *test; + + for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) + ; + if (1 && scaled_width > width && 1) + scaled_width >>= 1; + for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) + ; + if (1 && scaled_height > height && 1) + scaled_height >>= 1; + + // don't ever bother with >256 textures + if (scaled_width > 256) + scaled_width = 256; + if (scaled_height > 256) + scaled_height = 256; + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + size = sizeof(*mp) + (scaled_width*scaled_height*3*4); + mp = (miptex32_t *)SafeMalloc(size, "CreateMip"); + memset(mp,0,size); + + mp->version = MIP32_VERSION; + + size = width*height; + test = (paletteRGBA_t *)data; + while(size) + { + if (test->a != 255) + { + mp->flags |= LittleLong(SURF_ALPHA_TEXTURE); + break; + } + + size--; + test++; + } + + if (scaled_width == width && scaled_height == height) + { + memcpy (scaled, data, width*height*4); + } + else + GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height); + + pos = (byte *)(mp + 1); + miplevel = 0; + + while ((scaled_width >= 1 || scaled_height >= 1) && (miplevel <= MIPLEVELS-1) && (!miplevel || mip)) + { + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + if (miplevel > 0) + { + GL_MipMap((byte *)out, (byte *)scaled, scaled_width, scaled_height); + } + else + { + memcpy(out, scaled, 256 * 256 * 4); + } + + mp->width[miplevel] = scaled_width; + mp->height[miplevel] = scaled_height; + mp->offsets[miplevel] = pos - ((byte *)(mp)); + memcpy(pos, out, scaled_width * scaled_height * 4); + memcpy(scaled, out, 256 * 256 * 4); + pos += scaled_width * scaled_height * 4; + + scaled_width >>= 1; + scaled_height >>= 1; + + miplevel++; + } + + *FinalSize = pos - ((byte *)(mp)); + + return mp; +} + + + + + + + + + + + + + + + + + + + + + +/* +============== +Cmd_Grab + +$grab filename x y width height +============== +*/ +void Cmd_Grab (void) +{ + int xl,yl,w,h,y; + byte *cropped; + char savename[1024]; + char dest[1024]; + + GetScriptToken (false); + + if (token[0] == '/' || token[0] == '\\') + sprintf (savename, "%s%s.pcx", gamedir, token+1); + else + sprintf (savename, "%spics/%s.pcx", gamedir, token); + + if (g_release) + { + if (token[0] == '/' || token[0] == '\\') + sprintf (dest, "%s.pcx", token+1); + else + sprintf (dest, "pics/%s.pcx", token); + + ReleaseFile (dest); + return; + } + + GetScriptToken (false); + xl = atoi (token); + GetScriptToken (false); + yl = atoi (token); + GetScriptToken (false); + w = atoi (token); + GetScriptToken (false); + h = atoi (token); + + if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = SafeMalloc (w*h, "Cmd_Grab"); + for (y=0 ; ybyteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = SafeMalloc (w*h, "Cmd_Raw"); + for (y=0 ; y 255) + r = 255; + if (r < 0) + r = 0; + if (g > 255) + g = 255; + if (g < 0) + g = 0; + if (b > 255) + b = 255; + if (b < 0) + b = 0; +#ifndef TABLECOLORS + bestcolor = BestColor (r, g, b, 0, 254); +#else + bestcolor = palmap[r>>3][g>>3][b>>3]; +#endif + + return bestcolor; +} + + +void BuildPalmap (void) +{ +#ifdef TABLECOLORS + int r, g, b; + int bestcolor; + + if (palmap_built) + return; + palmap_built = true; + + for (r=4 ; r<256 ; r+=8) + { + for (g=4 ; g<256 ; g+=8) + { + for (b=4 ; b<256 ; b+=8) + { + bestcolor = BestColor (r, g, b, 1, 254); + palmap[r>>3][g>>3][b>>3] = bestcolor; + } + } + } +#endif + + if (!colormap_issued) + Error ("You must issue a $colormap command first"); + +} + +/* +============= +AveragePixels +============= +*/ +byte AveragePixels (int count) +{ + int r,g,b; + int i; + int vis; + int pix; + int bestcolor; + byte *pal; + int fullbright; + + vis = 0; + r = g = b = 0; + fullbright = 0; + for (i=0 ; i +must be multiples of sixteen +SURF_WINDOW +============== +*/ + +void Cmd_Mip (void) +{ + int xl,yl,xh,yh,w,h; + byte *dest, *source; + int flags, value, contents; + mipparm_t *mp; + char lumpname[128]; + char altname[128]; + char animname[128]; + char damagename[128]; + byte buffer[256*256]; + unsigned bufferl[256*256]; + materialtype_t *mat; + char filename[1024]; + unsigned *destl, *sourcel; + int linedelta, x, y; + int size; + miptex_t *qtex; + miptex32_t *qtex32; + float scale_x, scale_y; + int mip_scale; + // detail texturing + char dt_name[128]; + float dt_scale_x, dt_scale_y; + float dt_u, dt_v; + float dt_alpha; + int dt_src_blend_mode, dt_dst_blend_mode; + + + GetScriptToken (false); + strcpy (lumpname, token); + + GetScriptToken (false); + xl = atoi (token); + GetScriptToken (false); + yl = atoi (token); + GetScriptToken (false); + w = atoi (token); + GetScriptToken (false); + h = atoi (token); + + total_x += w; + total_y += h; + total_textures++; + + if ( (w & 15) || (h & 15) ) + Error ("line %i: miptex sizes must be multiples of 16", scriptline); + + flags = 0; + contents = 0; + value = 0; + mip_scale = 0; + + altname[0] = animname[0] = damagename[0] = 0; + + scale_x = scale_y = 0.5; + + // detail texturing + dt_name[0] = 0; + dt_scale_x = dt_scale_y = 0.0; + dt_u = dt_v = 0.0; + dt_alpha = 0.0; + dt_src_blend_mode = dt_dst_blend_mode = 0; + + // get optional flags and values + while (ScriptTokenAvailable ()) + { + GetScriptToken (false); + + for (mp=mipparms ; mp->name ; mp++) + { + if (!strcmp(mp->name, token)) + { + switch (mp->type) + { + case pt_animvalue: + GetScriptToken (false); // specify the next animation frame + strcpy (animname, token); + break; + case pt_altnamevalue: + GetScriptToken (false); // specify the alternate texture + strcpy (altname, token); + break; + case pt_damagenamevalue: + GetScriptToken (false); // specify the damage texture + strcpy (damagename, token); + break; + case pt_flags: + flags |= mp->flags; + break; + case pt_contents: + contents |= mp->flags; + break; + case pt_flagvalue: + flags |= mp->flags; + GetScriptToken (false); // specify the light value + value = atoi(token); + break; + case pt_materialvalue: + GetScriptToken(false); + for (mat=materialtypes ; mat->name ; mat++) + { + if (!strcmp(mat->name, token)) + { + // assumes SURF_MATERIAL is in top 8 bits + flags = (flags & 0x0FFFFFF) | (mat->value << 24); + break; + } + } + break; + case pt_scale: + GetScriptToken (false); // specify the x scale + scale_x = atof(token); + GetScriptToken (false); // specify the y scale + scale_y = atof(token); + break; + + case pt_mip: + mip_scale = 1; + break; + + case pt_detail: + GetScriptToken(false); + strcpy(dt_name, token); + GetScriptToken(false); + dt_scale_x = atof(token); + GetScriptToken(false); + dt_scale_y = atof(token); + GetScriptToken(false); + dt_u = atof(token); + GetScriptToken(false); + dt_v = atof(token); + GetScriptToken(false); + dt_alpha = atof(token); + GetScriptToken(false); + for (mp=mipparms ; mp->name ; mp++) + { + if (!strcmp(mp->name, token)) + { + if (mp->type == pt_gl) + { + dt_src_blend_mode = mp->flags; + break; + } + } + } + if (!mp->name) + { + Error ("line %i: invalid gl blend mode %s", scriptline, token); + } + GetScriptToken (false); + for (mp=mipparms ; mp->name ; mp++) + { + if (!strcmp(mp->name, token)) + { + if (mp->type == pt_gl) + { + dt_dst_blend_mode = mp->flags; + break; + } + } + } + if (!mp->name) + { + Error ("line %i: invalid gl blend mode %s", scriptline, token); + } + break; + } + break; + } + } + if (!mp->name) + Error ("line %i: unknown parm %s", scriptline, token); + } + + if (g_release) + return; // textures are only released by $maps + if (TrueColorImage) + { + xh = xl+w; + yh = yl+h; + + if (xl >= longimagewidth || xh > longimagewidth || + yl >= longimageheight || yh > longimageheight) + { + Error ("line %i image %s: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, lumpname, xl,yl,w,h,longimagewidth,longimageheight); + } + + sourcel = longimage + (yl*longimagewidth) + xl; + destl = bufferl; + linedelta = (longimagewidth - w); + + for (y=yl ; yflags |= LittleLong(flags); + qtex32->contents = LittleLong(contents); + qtex32->value = LittleLong(value); + qtex32->scale_x = scale_x; + qtex32->scale_y = scale_y; + qtex32->mip_scale = mip_scale; + sprintf (qtex32->name, "%s/%s", mip_prefix, lumpname); + if (animname[0]) + { + sprintf (qtex32->animname, "%s/%s", mip_prefix, animname); + } + if (altname[0]) + { + sprintf (qtex32->altname, "%s/%s", mip_prefix, altname); + } + if (damagename[0]) + { + sprintf (qtex32->damagename, "%s/%s", mip_prefix, damagename); + } + if (dt_name[0]) + { + sprintf (qtex32->dt_name, "%s/%s", mip_prefix, dt_name); + qtex32->dt_scale_x = dt_scale_x; + qtex32->dt_scale_y = dt_scale_y; + qtex32->dt_u = dt_u; + qtex32->dt_v = dt_v; + qtex32->dt_alpha = dt_alpha; + qtex32->dt_src_blend_mode = dt_src_blend_mode; + qtex32->dt_dst_blend_mode = dt_dst_blend_mode; + } + + // + // write it out + // + sprintf (filename, "%stextures/%s/%s.m32", g_outputDir, mip_prefix, lumpname); + if(qtex32->flags & (SURF_ALPHA_TEXTURE)) + printf ("writing %s with ALPHA\n", filename); + else + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + + free (qtex32); + } + else + { + xh = xl+w; + yh = yl+h; + + if (xl >= byteimagewidth || xh > byteimagewidth || + yl >= byteimageheight || yh > byteimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight); + } + + source = byteimage + yl*byteimagewidth + xl; + dest = buffer; + linedelta = byteimagewidth - w; + + for (y=yl ; yflags = LittleLong(flags); + qtex->contents = LittleLong(contents); + qtex->value = LittleLong(value); + sprintf (qtex->name, "%s/%s", mip_prefix, lumpname); + if (animname[0]) + sprintf (qtex->animname, "%s/%s", mip_prefix, animname); + + // + // write it out + // + sprintf (filename, "%stextures/%s/%s.m8", g_outputDir, mip_prefix, lumpname); + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex, size); + + free (qtex); + } +} + +/* +=============== +Cmd_Mippal +=============== +*/ +void Cmd_Mippal (void) +{ + colormap_issued = true; + if (g_release) + return; + + memcpy (colormap_palette, lbmpalette, 768); + + BuildPalmap(); +} + + +/* +=============== +Cmd_Mipdir +=============== +*/ +void Cmd_Mipdir (void) +{ + char filename[1024]; + + GetScriptToken (false); + strcpy (mip_prefix, token); + // create the directory if needed + sprintf (filename, "%stextures", g_outputDir); + Q_mkdir (filename); + sprintf (filename, "%stextures/%s", g_outputDir, mip_prefix); + Q_mkdir (filename); +} + + +/* +============================================================================= + +ENVIRONMENT MAP GRABBING + +Creates six pcx files from tga files without any palette edge seams +also copies the tga files for GL rendering. +============================================================================= +*/ + +// 3dstudio environment map suffixes +char *suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"}; + +/* +================= +Cmd_Environment +================= +*/ +void Cmd_Environment (void) +{ + char name[1024]; + int i, x, y; + byte image[256*256]; + byte *tga; + + GetScriptToken (false); + + if (g_release) + { + for (i=0 ; i<6 ; i++) + { + sprintf (name, "env/%s%s.pcx", token, suf[i]); + ReleaseFile (name); + sprintf (name, "env/%s%s.tga", token, suf[i]); + ReleaseFile (name); + } + return; + } + // get the palette + BuildPalmap (); + + sprintf (name, "%senv/", gamedir); + CreatePath (name); + + // convert the images + for (i=0 ; i<6 ; i++) + { + sprintf (name, "%senv/%s%s.tga", gamedir, token, suf[i]); + printf ("loading %s...\n", name); + LoadTGA (name, &tga, NULL, NULL); + + for (y=0 ; y<256 ; y++) + { + for (x=0 ; x<256 ; x++) + { + image[y*256+x] = FindColor (tga[(y*256+x)*4+0],tga[(y*256+x)*4+1],tga[(y*256+x)*4+2]); + } + } + free (tga); + sprintf (name, "%senv/%s%s.pcx", gamedir, token, suf[i]); + if (FileTime (name) != -1) + printf ("%s already exists, not overwriting.\n", name); + else + WritePCXfile (name, image, 256, 256, colormap_palette); + } +} + diff --git a/Toolkit/Programming/Tools/qdata/models.c b/Toolkit/Programming/Tools/qdata/models.c new file mode 100644 index 0000000..0d47295 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/models.c @@ -0,0 +1,2014 @@ + +#include "qdata.h" +#include +#include "Jointed.h" +#include "fmodel.h" + +//================================================================= + +typedef struct +{ + int numnormals; + vec3_t normalsum; +} vertexnormals_t; + +typedef struct +{ + vec3_t v; + int lightnormalindex; +} trivert_t; + +typedef struct +{ + vec3_t mins, maxs; + char name[16]; + trivert_t v[MAX_VERTS]; + QDataJoint_t joints[NUM_CLUSTERS]; // ,this +} frame_t; + +// ,and all of this should get out of here, need to use new stuff in fmodels instead + +typedef struct IntListNode_s +{ + int data; + struct IntListNode_s *next; +} IntListNode_t; // gaak + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this +} PartialAliasFrame_t; + +int jointed; +int clustered; + +int *clusters[NUM_CLUSTERS]; +IntListNode_t *vertLists[NUM_CLUSTERS]; +int num_verts[NUM_CLUSTERS + 1]; +int new_num_verts[NUM_CLUSTERS + 1]; + +// end that + +//================================================================ + +frame_t g_frames[MAX_FRAMES]; +//frame_t *g_frames; + +static dmdl_t model; + + +float scale_up; // set by $scale +vec3_t adjust; // set by $origin +int g_fixedwidth, g_fixedheight; // set by $skinsize + + +// +// base frame info +// +dstvert_t base_st[MAX_VERTS]; +dtriangle_t triangles[MAX_TRIANGLES]; + +static int triangle_st[MAX_TRIANGLES][3][2]; + +// the command list holds counts, s/t values, and xyz indexes +// that are valid for every frame +int commands[16384]; +int numcommands; +int numglverts; +int used[MAX_TRIANGLES]; + +char g_skins[MAX_MD2SKINS][64]; + +char cdarchive[1024]; +char cdpartial[1024]; +char cddir[1024]; + +char modelname[64]; // empty unless $modelname issued (players) + +extern char *g_outputDir; + +#define NUMVERTEXNORMALS 162 + +float avertexnormals[NUMVERTEXNORMALS][3] = +{ + #include "anorms.h" +}; + +unsigned char pic[SKINPAGE_HEIGHT*SKINPAGE_WIDTH], pic_palette[768]; + +FILE *headerouthandle = NULL; + +//============================================================== + +/* +=============== +ClearModel +=============== +*/ +static void ClearModel (void) +{ + memset (&model, 0, sizeof(model)); + + modelname[0] = 0; + jointed = NOT_JOINTED; + clustered = 0; + scale_up = 1.0; + VectorCopy (vec3_origin, adjust); + g_fixedwidth = g_fixedheight = 0; + g_skipmodel = false; +} + + +void H_printf(char *fmt, ...) +{ + va_list argptr; + char name[1024]; + + if (!headerouthandle) + { + sprintf (name, "%s/tris.h", cddir); + headerouthandle = SafeOpenWrite (name); + fprintf(headerouthandle, "// %s\n\n", cddir); + fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n"); + } + + va_start (argptr, fmt); + vfprintf (headerouthandle, fmt, argptr); + va_end (argptr); +} + +#ifdef _RAVEN +/* +============ +WriteModelFile +============ +*/ +void WriteCommonModelFile (FILE *modelouthandle, PartialAliasFrame_t *outFrames) +{ + int i; + dmdl_t modeltemp; + int j, k; + frame_t *in; + daliasframe_t *out; + byte buffer[MAX_VERTS*4+128]; + float v; + int c_on, c_off; + + model.version = ALIAS_VERSION; + model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz]; + model.num_glcmds = numcommands; + model.ofs_skins = sizeof(dmdl_t); + model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME; + model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t); + model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t); + model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize; + model.ofs_end = model.ofs_glcmds + model.num_glcmds*sizeof(int); + // + // write out the model header + // + for (i=0 ; iname, in->name); + for (j=0 ; j<3 ; j++) + { + out->scale[j] = (in->maxs[j] - in->mins[j])/255; + out->translate[j] = in->mins[j]; + + if(outFrames) + { + outFrames[i].scale[j] = out->scale[j]; + outFrames[i].translate[j] = out->translate[j]; + } + } + + for (j=0 ; jverts[j].lightnormalindex = in->v[j].lightnormalindex; + + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + v = 255.0; + if (v < 0) + v = 0; + out->verts[j].v[k] = v; + } + } + + for (j=0 ; j<3 ; j++) + { + out->scale[j] = LittleFloat (out->scale[j]); + out->translate[j] = LittleFloat (out->translate[j]); + } + + SafeWrite (modelouthandle, out, model.framesize); + } + + // + // write out glcmds + // + SafeWrite (modelouthandle, commands, numcommands*4); +} + +/* +============ +WriteModelFile +============ +*/ +void WriteModelFile (FILE *modelouthandle) +{ + model.ident = IDALIASHEADER; + + WriteCommonModelFile(modelouthandle, NULL); +} + +/* +============ +WriteJointedModelFile +============ +*/ +void WriteJointedModelFile (FILE *modelouthandle) +{ + int i; + int j, k; + frame_t *in; + float v; + IntListNode_t *current, *toFree; + PartialAliasFrame_t outFrames[MAX_FRAMES]; + + model.ident = IDJOINTEDALIASHEADER; + + WriteCommonModelFile(modelouthandle, outFrames); + + // Skeletal Type + SafeWrite(modelouthandle, &jointed, sizeof(int)); + + // number of joints + SafeWrite(modelouthandle, &numJointsForSkeleton[jointed], sizeof(int)); + + // number of verts in each cluster + SafeWrite(modelouthandle, &new_num_verts[1], sizeof(int)*numJointsForSkeleton[jointed]); + + // cluster verts + for(i = 0; i < new_num_verts[0]; ++i) + { + current = vertLists[i]; + while(current) + { + SafeWrite (modelouthandle, ¤t->data, sizeof(int)); + toFree = current; + current = current->next; + free(toFree); // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base + } + } + + for (i=0 ; ijoints[j].placement.origin[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + { + v = 255.0; + } + + if (v < 0) + { + v = 0; + } + + // write out origin as a float (there's only a few per model, so it's not really + // a size issue) + SafeWrite (modelouthandle, &v, sizeof(float)); + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->joints[j].placement.direction[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + { + v = 255.0; + } + + if (v < 0) + { + v = 0; + } + + // write out origin as a float (there's only a few per model, so it's not really + // a size issue) + SafeWrite (modelouthandle, &v, sizeof(float)); + } + + for (k=0 ; k<3 ; k++) + { + v = Q_rint ( (in->joints[j].placement.up[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + { + v = 255.0; + } + + if (v < 0) + { + v = 0; + } + + // write out origin as a float (there's only a few per model, so it's not really + // a size issue) + SafeWrite (modelouthandle, &v, sizeof(float)); + } + } + } +} +#else +/* +============ +WriteModelFile +============ +*/ +static void WriteModelFile (FILE *modelouthandle) +{ + int i; + dmdl_t modeltemp; + int j, k; + frame_t *in; + daliasframe_t *out; + byte buffer[MAX_VERTS*4+128]; + float v; + int c_on, c_off; + + model.ident = IDALIASHEADER; + model.version = ALIAS_VERSION; + model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz]; + model.num_glcmds = numcommands; + model.ofs_skins = sizeof(dmdl_t); + model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME; + model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t); + model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t); + model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize; + model.ofs_end = model.ofs_glcmds + model.num_glcmds*4; + + // + // write out the model header + // + for (i=0 ; iname, in->name); + for (j=0 ; j<3 ; j++) + { + out->scale[j] = (in->maxs[j] - in->mins[j])/255; + out->translate[j] = in->mins[j]; + } + + for (j=0 ; jverts[j].lightnormalindex = in->v[j].lightnormalindex; + + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + v = 255.0; + if (v < 0) + v = 0; + out->verts[j].v[k] = v; + } + } + + for (j=0 ; j<3 ; j++) + { + out->scale[j] = LittleFloat (out->scale[j]); + out->translate[j] = LittleFloat (out->translate[j]); + } + + SafeWrite (modelouthandle, out, model.framesize); + } + + // + // write out glcmds + // + SafeWrite (modelouthandle, commands, numcommands*4); +} +#endif + +/* +=============== +FinishModel +=============== +*/ +void FinishModel (void) +{ + FILE *modelouthandle; + int i; + char name[1024]; + + if (!model.num_frames) + return; + +// +// copy to release directory tree if doing a release build +// + if (g_release) + { + if (modelname[0]) + sprintf (name, "%s", modelname); + else + sprintf (name, "%s/tris.md2", cdpartial); + ReleaseFile (name); + + for (i=0 ; iindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+2)%3]; + st1 = last->index_st[(startv+2)%3]; + m2 = last->index_xyz[(startv+1)%3]; + st2 = last->index_st[(startv+1)%3]; + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; jindex_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + if (stripcount & 1) + { + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + } + else + { + m1 = check->index_xyz[ (k+2)%3 ]; + st1 = check->index_st[ (k+2)%3 ]; + } + + strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ]; + strip_st[stripcount+2] = check->index_st[ (k+2)%3 ]; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; jindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+0)%3]; + st1 = last->index_st[(startv+0)%3]; + m2 = last->index_xyz[(startv+2)%3]; + st2 = last->index_st[(startv+2)%3]; + + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; jindex_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + + strip_xyz[stripcount+2] = m2; + strip_st[stripcount+2] = st2; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; j bestlen) + { + besttype = type; + bestlen = len; + for (j=0 ; j= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + + s_scale = t_scale = scale; + + iwidth = ceil(width*s_scale); + iheight = ceil(height*t_scale); + + iwidth += 4; + iheight += 4; + } + else + { // new style + iwidth = g_fixedwidth / 2; + iheight = g_fixedheight; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + } + +// +// determine which side of each triangle to map the texture to +// + for (i=0 ; i 0) + { + basex = iwidth + 2; + } + else + { + basex = 2; + } + basey = 2; + + for (j=0 ; j<3 ; j++) + { + pbasevert = ptri[i].verts[j]; + + triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex); + triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey); + } + } + +// make the width a multiple of 4; some hardware requires this, and it ensures +// dword alignment for each scan + swidth = iwidth*2; + model.skinwidth = (swidth + 3) & ~3; + model.skinheight = iheight; +} +#endif + +//========================================================================== +// +// DrawScreen +// +//========================================================================== + +void DrawScreen(float s_scale, float t_scale, float iwidth, float iheight) +{ + int i; + byte *scrpos; + char buffer[256]; + + // Divider + scrpos = &pic[(INFO_Y-2)*SKINPAGE_WIDTH]; + for(i = 0; i < SKINPAGE_WIDTH; i++) + { + *scrpos++ = 255; + } + + sprintf(buffer, "GENSKIN: "); + DrawTextChar(16, INFO_Y, buffer); + + sprintf(buffer, "( %03d * %03d ) SCALE %f %f, SKINWIDTH %d," + " SKINHEIGHT %d", (int)ScaleWidth, (int)ScaleHeight, s_scale, t_scale, (int)iwidth*2, (int)iheight); + DrawTextChar(80, INFO_Y, buffer); +} + +/* +============ +BuildST + +Builds the triangle_st array for the base frame and +model.skinwidth / model.skinheight + + FIXME: allow this to be loaded from a file for + arbitrary mappings +============ +*/ +void BuildST (triangle_t *ptri, int numtri, qboolean DrawSkin) +{ + int i, j; + int width, height, iwidth, iheight, swidth; + float basex, basey; + float scale; + vec3_t mins, maxs; + float *pbasevert; + vec3_t vtemp1, vtemp2, normal; + float s_scale, t_scale; + float scWidth; + float scHeight; + + // + // find bounds of all the verts on the base frame + // + ClearBounds (mins, maxs); + + for (i=0 ; i= scHeight) + { + scale = scHeight/height; + } + + iwidth = ceil(width*scale)+4; + iheight = ceil(height*scale)+4; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + t_scale = s_scale; + + if (DrawSkin) + DrawScreen(s_scale, t_scale, iwidth, iheight); + + +/* if (!g_fixedwidth) + { // old style + scale = 8; + if (width*scale >= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + + s_scale = t_scale = scale; + + iwidth = ceil(width*s_scale); + iheight = ceil(height*t_scale); + + iwidth += 4; + iheight += 4; + } + else + { // new style + iwidth = g_fixedwidth / 2; + iheight = g_fixedheight; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + }*/ + +// +// determine which side of each triangle to map the texture to +// + for (i=0 ; i 0) + { + basex = iwidth + 2; + } + else + { + basex = 2; + } + basey = 2; + + for (j=0 ; j<3 ; j++) + { + pbasevert = ptri[i].verts[j]; + + triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex); + triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey); + } + } + + DrawLine(triangle_st[i][0][0], triangle_st[i][0][1], + triangle_st[i][1][0], triangle_st[i][1][1]); + DrawLine(triangle_st[i][1][0], triangle_st[i][1][1], + triangle_st[i][2][0], triangle_st[i][2][1]); + DrawLine(triangle_st[i][2][0], triangle_st[i][2][1], + triangle_st[i][0][0], triangle_st[i][0][1]); + } + +// make the width a multiple of 4; some hardware requires this, and it ensures +// dword alignment for each scan + + swidth = iwidth*2; + model.skinwidth = (swidth + 3) & ~3; + model.skinheight = iheight; +} + + +static void ReplaceClusterIndex(int newIndex, int oldindex, int **clusters, + IntListNode_t **vertLists, int *num_verts, int *new_num_verts) +{ + int i, j; + IntListNode_t *next; + + for(j = 0; j < num_verts[0]; ++j) + { + for(i = 0; i < num_verts[j+1]; ++i) + { + if(clusters[j][i] == oldindex) + { + ++new_num_verts[j+1]; + + next = vertLists[j]; + + vertLists[j] = SafeMalloc(sizeof(IntListNode_t), "ReplaceClusterIndex"); + // Currently freed in WriteJointedModelFile only + + vertLists[j]->data = newIndex; + vertLists[j]->next = next; + } + } + } +} + +/* +================= +Cmd_Base +================= +*/ +void Cmd_Base (void) +{ + vec3_t base_xyz[MAX_VERTS]; + triangle_t *ptri; + int i, j, k; +#ifdef _RAVEN +#else + int time1; +#endif + char file1[1024]; + char file2[1024]; + + GetScriptToken (false); + + if (g_skipmodel || g_release || g_archive) + return; + + printf ("---------------------\n"); +#ifdef _RAVEN + sprintf (file1, "%s/%s", cdpartial, token); + printf ("%s ", file1); + + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s", cddir, token); +#else + sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext); + printf ("%s\n", file1); + + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s.%s", cddir, token, trifileext); + + time1 = FileTime (file1); + if (time1 == -1) + Error ("%s doesn't exist", file1); +#endif +// +// load the base triangles +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &model.num_tris, NULL, NULL); + else + LoadTriangleList (file1, &ptri, &model.num_tris, NULL, NULL); + + + GetScriptToken (false); + sprintf (file2, "%s/%s.pcx", cddir, token); +// sprintf (trans_file, "%s/!%s_a.pcx", cddir, token); + + printf ("skin: %s\n", file2); + Load256Image (file2, &BasePixels, &BasePalette, &BaseWidth, &BaseHeight); + + if (BaseWidth != SKINPAGE_WIDTH || BaseHeight != SKINPAGE_HEIGHT) + { + if (g_allow_newskin) + { + ScaleWidth = BaseWidth; + ScaleHeight = BaseHeight; + } + else + { + Error("Invalid skin page size: (%d,%d) should be (%d,%d)", + BaseWidth,BaseHeight,SKINPAGE_WIDTH,SKINPAGE_HEIGHT); + } + } + else + { + ScaleWidth = (float)ExtractNumber(BasePixels, ENCODED_WIDTH_X, + ENCODED_WIDTH_Y); + ScaleHeight = (float)ExtractNumber(BasePixels, ENCODED_HEIGHT_X, + ENCODED_HEIGHT_Y); + } + +// +// get the ST values +// + BuildST (ptri, model.num_tris,false); + +// +// run through all the base triangles, storing each unique vertex in the +// base vertex list and setting the indirect triangles to point to the base +// vertices +// + for (i=0 ; i= '0' && *s <= '9') + s--; + + strcpy (suffix, s+1); + strcpy (base, frame); + base[s-frame+1] = 0; + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "hrc"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "hrc"); + return retname; + } + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "asc"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "asc"); + return retname; + } + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "tri"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "tri"); + return retname; + } + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "3ds"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "3ds"); + return retname; + } + + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "htr"); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, "htr"); + return retname; + } + + // check for 'run.1' + sprintf (file1, "%s/%s.%s",cddir, base, suffix); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s.%s", base, suffix); + return retname; + } + + Error ("frame %s could not be found",frame); + return NULL; +} + +/* +=============== +GrabFrame +=============== +*/ +static void GrabFrame (char *frame) +{ + triangle_t *ptri; + int i, j; + trivert_t *ptrivert; + int num_tris; + char file1[1024]; + frame_t *fr; + vertexnormals_t vnorms[MAX_VERTS]; + int index_xyz; + char *framefile; + + // the frame 'run1' will be looked for as either + // run.1 or run1.tri, so the new alias sequence save + // feature an be used + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("grabbing %s ", file1); + + if (model.num_frames >= MAX_FRAMES) + Error ("model.num_frames >= MAX_FRAMES"); + fr = &g_frames[model.num_frames]; + model.num_frames++; + + strcpy (fr->name, frame); + +// +// load the frame +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &num_tris, NULL, NULL); + else + LoadTriangleList (file1, &ptri, &num_tris, NULL, NULL); + + if (num_tris != model.num_tris) + Error ("%s: number of triangles doesn't match base frame\n", file1); + +// +// allocate storage for the frame's vertices +// + ptrivert = fr->v; + + for (i=0 ; imins, fr->maxs); + +// +// store the frame's vertices in the same order as the base. This assumes the +// triangles and vertices in this frame are in exactly the same order as in the +// base +// + for (i=0 ; imins, fr->maxs); + + VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum); + vnorms[index_xyz].numnormals++; + } + } + +// +// calculate the vertex normals, match them to the template list, and store the +// index of the best match +// + for (i=0 ; i maxdot) + { + maxdot = dot; + maxdotindex = j; + } + } + + ptrivert[i].lightnormalindex = maxdotindex; + } + + free (ptri); +} + +/* +=============== +GrabJointedFrame +=============== +*/ +void GrabJointedFrame(char *frame) +{ + char file1[1024]; + char *framefile; + frame_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("grabbing %s\n", file1); + + fr = &g_frames[model.num_frames - 1]; // last frame read in + + LoadJointList(file1, fr->joints, jointed); +} + +/* +=============== +GrabGlobals +=============== +*/ +void GrabGlobals(char *frame) +{ + char file1[1024]; + char *framefile; + frame_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("grabbing %s\n", file1); + + fr = &g_frames[model.num_frames - 1]; // last frame read in + + LoadGlobals(file1); +} + +/* +=============== +Cmd_Frame +=============== +*/ +void Cmd_Frame (void) +{ + while (ScriptTokenAvailable()) + { + GetScriptToken (false); + if (g_skipmodel) + continue; + if (g_release || g_archive) + { + model.num_frames = 1; // don't skip the writeout + continue; + } + + H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames); + + GrabFrame (token); + } +} + +/* +=============== +Cmd_Skin + +Skins aren't actually stored in the file, only a reference +is saved out to the header file. +=============== +*/ +void Cmd_Skin (void) +{ + byte *palette; + byte *pixels; + int width, height; + byte *cropped; + int y; + char name[1024], savename[1024]; + + GetScriptToken (false); + + if (model.num_skins == MAX_MD2SKINS) + Error ("model.num_skins == MAX_MD2SKINS"); + + if (g_skipmodel) + return; + +#ifdef _RAVEN + sprintf (name, "%s/%s.pcx", cddir, token); + sprintf (savename, "%s/!%s.pcx", g_outputDir, token); + sprintf (g_skins[model.num_skins], "%s/!%s.pcx", cdpartial, token); +#else + sprintf (name, "%s/%s.lbm", cdarchive, token); + strcpy (name, ExpandPathAndArchive( name ) ); +// sprintf (name, "%s/%s.lbm", cddir, token); + + if (ScriptTokenAvailable()) + { + GetScriptToken (false); + sprintf (g_skins[model.num_skins], "%s.pcx", token); + sprintf (savename, "%s%s.pcx", g_outputDir, g_skins[model.num_skins]); + } + else + { + sprintf (savename, "%s/%s.pcx", g_outputDir, token); + sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token); + } +#endif + + model.num_skins++; + + if (g_skipmodel || g_release || g_archive) + return; + + // load the image + printf ("loading %s\n", name); + Load256Image (name, &pixels, &palette, &width, &height); +// RemapZero (pixels, palette, width, height); + + // crop it to the proper size + cropped = SafeMalloc (model.skinwidth*model.skinheight, "Cmd_Skin"); + for (y=0 ; y 32) + Error ("bitcount > 32"); + charbits[nodenum] = bits; + charbitscount[nodenum] = bitcount; + return; + } + + node = &hnodes[nodenum]; + bits <<= 1; + BuildChars (node->children[0], bits, bitcount + 1); + bits |= 1; + BuildChars (node->children[1], bits, bitcount + 1); +} + +/* +================== +Huffman +================== +*/ +cblock_t Huffman (cblock_t in) +{ + int i; + hnode_t *node; + int outbits, c; + unsigned bits; + byte *out_p; + cblock_t out; + int max, maxchar; + + // count + memset(hnodes, 0, sizeof(hnodes)); + for(i = 0; i < in.count; i++) + hnodes[in.data[i]].count++; + + // normalize counts + max = 0; + maxchar = 0; + for(i = 0; i < 256; i++) + { + if (hnodes[i].count > max) + { + max = hnodes[i].count; + maxchar = i; + } + } + if(max == 0) + Error ("Huffman: max == 0"); + + for(i = 0; i < 256; i++) + hnodes[i].count = (hnodes[i].count * 255 + max - 1) / max; + + // build the nodes + numhnodes = 256; + while(numhnodes != 511) + { + node = &hnodes[numhnodes]; + + // pick two lowest counts + node->children[0] = SmallestNode(); + if(node->children[0] == -1) + break; // no more + + node->children[1] = SmallestNode (); + if(node->children[1] == -1) + { + if (node->children[0] != numhnodes - 1) + Error ("Bad smallestnode"); + break; + } + node->count = hnodes[node->children[0]].count + hnodes[node->children[1]].count; + numhnodes++; + } + + BuildChars(numhnodes-1, 0, 0); + + out_p = out.data = malloc(in.count * 2 + 1024); + memset (out_p, 0, in.count * 2 + 1024); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // save out the 256 normalized counts so the tree can be recreated + for(i = 0; i < 256; i++) + *out_p++ = hnodes[i].count; + + // write bits + outbits = 0; + for (i = 0; i < in.count; i++) + { + c = charbitscount[in.data[i]]; + bits = charbits[in.data[i]]; + while (c) + { + c--; + if(bits & (1 << c)) + out_p[outbits >> 3] |= 1<< (outbits & 7); + outbits++; + } + } + + out_p += (outbits + 7) >> 3; + out.count = out_p - out.data; + return(out); +} + +#endif + +#if 0 + +int bwt_size; +byte *bwt_data; + +int bwtCompare (const void *elem1, const void *elem2) +{ + int i; + int i1, i2; + int b1, b2; + + i1 = *(int *)elem1; + i2 = *(int *)elem2; + + for (i=0 ; i b2) + return 1; + if (++i1 == bwt_size) + i1 = 0; + if (++i2 == bwt_size) + i2 = 0; + } + + return 0; +} + +/* +================== +BWT +================== +*/ +cblock_t BWT (cblock_t in) +{ + int *sorted; + int i; + byte *out_p; + cblock_t out; + + bwt_size = in.count; + bwt_data = in.data; + + sorted = malloc(in.count*sizeof(*sorted)); + for (i=0 ; i>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // write head index + for (i=0 ; i>8)&255; + *out_p++ = (i>>16)&255; + *out_p++ = (i>>24)&255; + + // write the L column + for (i=0 ; i>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + for (i=0 ; i<256 ; i++) + index[i] = i; + + for (i=0 ; i>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + for (i=0 ; i 3 || val == RLE_CODE) + { + *out_p++ = RLE_CODE; + *out_p++ = val; + *out_p++ = repeat; + } + else + { + while (repeat--) + *out_p++ = val; + } + } + + out.count = out_p - out.data; + return out; +} +#endif + +//========================================================================== + +#if 0 +unsigned lzss_head[256]; +unsigned lzss_next[0x20000]; + +/* +================== +LZSS +================== +*/ +#define BACK_WINDOW 0x10000 +#define BACK_BITS 16 +#define FRONT_WINDOW 16 +#define FRONT_BITS 4 +cblock_t LZSS (cblock_t in) +{ + int i; + byte *out_p; + cblock_t out; + int val; + int j, start, max; + int bestlength, beststart; + int outbits; + +if (in.count >= sizeof(lzss_next)/4) +Error ("LZSS: too big"); + + memset (lzss_head, -1, sizeof(lzss_head)); + + out_p = out.data = malloc (in.count*2); + memset (out.data, 0, in.count*2); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + outbits = 0; + for (i=0 ; i in.count) + max = in.count - i; + + start = lzss_head[val]; + while (start != -1 && start >= i-BACK_WINDOW) + { + // count match length + for (j=0 ; j bestlength) + { + bestlength = j; + beststart = start; + } + start = lzss_next[start]; + } + +#else +// slow simple search + // search for a match + max = FRONT_WINDOW; + if (i + max > in.count) + max = in.count - i; + + start = i - BACK_WINDOW; + if (start < 0) + start = 0; + bestlength = 0; + beststart = 0; + for ( ; start < i ; start++) + { + if (in.data[start] != val) + continue; + // count match length + for (j=0 ; j bestlength) + { + bestlength = j; + beststart = start; + } + } +#endif + beststart = BACK_WINDOW - (i-beststart); + + if (bestlength < 3) + { // output a single char + bestlength = 1; + + out_p[outbits>>3] |= 1<<(outbits&7); // set bit to mark char + outbits++; + for (j=0 ; j<8 ; j++, outbits++) + if (val & (1<>3] |= 1<<(outbits&7); + } + else + { // output a phrase + outbits++; // leave a 0 bit to mark phrase + for (j=0 ; j>3] |= 1<<(outbits&7); + for (j=0 ; j>3] |= 1<<(outbits&7); + } + + while (bestlength--) + { + val = in.data[i]; + lzss_next[i] = lzss_head[val]; + lzss_head[val] = i; + i++; + } + } + + out_p += (outbits+7)>>3; + out.count = out_p - out.data; + return out; +} + +#endif + +#if 0 +char *RLE(char *in, char *out) +{ + char *end; + char *srun; + char count; + + end = in + 64; // size of DCT block + while(in < end) + { + srun = in; // Start of run + + while(in < end) + { + if(in[0] == in[1]) + break; + in++; + } + count = in - srun; // count of unique bytes + + if(!count) + { + while(in < end) + { + if(in[0] != in[1]) + break; + in++; + } + count = in - srun + 1; // count of repeated bytes + *out++ = -count; + *out++ = *in; + in++; + } + else + { + *out++ = count; + while(count--) + *out++ = *srun++; + } + } + return(out); +} + +char *IRLE(char *in, char *out) +{ + char count; + char data; + char *end; + + end = out + 64; + + while(out < end) + { + count = *in++; + if(count < 0) + { + data = *in++; + while(count++) + *out++ = data; + } + else + { + while(count--) + *out++ = *in++; + } + } + if(out != end) + printf("Rle decompression error\n"); + return(in); +} + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qdata/pics.c b/Toolkit/Programming/Tools/qdata/pics.c new file mode 100644 index 0000000..4d2098b --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/pics.c @@ -0,0 +1,177 @@ + +#include "qdata.h" + +byte *byteimage, *lbmpalette; +int byteimagewidth, byteimageheight; + +qboolean TrueColorImage; +unsigned *longimage; +int longimagewidth, longimageheight; + +char pic_prefix[1024]; +extern char *g_outputDir; + +/* +=============== +Cmd_Pic +=============== +*/ + +void Cmd_Pic (void) +{ + int xl,yl,xh,yh,w,h; + byte *dest, *source; + int flags, value, contents; + char lumpname[128]; + char animname[128]; + byte buffer[256*256]; + unsigned bufferl[256*256]; + char filename[1024]; + unsigned *destl, *sourcel; + int linedelta, x, y; + int size; + miptex_t *qtex; + miptex32_t *qtex32; + float scale_x, scale_y; + + GetScriptToken (false); + strcpy (lumpname, token); + + GetScriptToken (false); + xl = atoi (token); + GetScriptToken (false); + yl = atoi (token); + GetScriptToken (false); + w = atoi (token); + GetScriptToken (false); + h = atoi (token); + + total_x += w; + total_y += h; + total_textures++; + + if ( (w & 7) || (h & 7) ) + Error ("line %i: miptex sizes must be multiples of 8", scriptline); + + flags = 0; + contents = 0; + value = 0; + + animname[0] = 0; + + scale_x = scale_y = 0.5; + + if (TrueColorImage) + { + sprintf (filename, "%spics/%s/%s.m32", g_outputDir, pic_prefix, lumpname); + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + + if (xl >= longimagewidth || xh > longimagewidth || + yl >= longimageheight || yh > longimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,longimagewidth,longimageheight); + } + + sourcel = longimage + (yl*longimagewidth) + xl; + destl = bufferl; + linedelta = (longimagewidth - w); + + for (y=yl ; yflags |= LittleLong(flags); + qtex32->contents = contents; + qtex32->value = value; + qtex32->scale_x = scale_x; + qtex32->scale_y = scale_y; + sprintf (qtex32->name, "%s/%s", pic_prefix, lumpname); + if (animname[0]) + sprintf (qtex32->animname, "%s/%s", pic_prefix, animname); + + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + + free (qtex32); + } + else + { + sprintf (filename, "%spics/%s/%s.m8", g_outputDir, pic_prefix, lumpname); + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + + if (xl >= byteimagewidth || xh > byteimagewidth || + yl >= byteimageheight || yh > byteimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight); + } + + source = byteimage + yl*byteimagewidth + xl; + dest = buffer; + linedelta = byteimagewidth - w; + + for (y=yl ; yflags = flags; + qtex->contents = contents; + qtex->value = value; + sprintf (qtex->name, "%s/%s", pic_prefix, lumpname); + if (animname[0]) + sprintf (qtex->animname, "%s/%s", pic_prefix, animname); + + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex, size); + + free (qtex); + } +} + + +/* +=============== +Cmd_picdir +=============== +*/ +void Cmd_Picdir (void) +{ + char filename[1024]; + + GetScriptToken (false); + strcpy (pic_prefix, token); + // create the directory if needed + sprintf (filename, "%sPics", g_outputDir); + Q_mkdir (filename); + sprintf (filename, "%sPics/%s", g_outputDir, pic_prefix); + Q_mkdir (filename); +} + + diff --git a/Toolkit/Programming/Tools/qdata/qd_fmodel.h b/Toolkit/Programming/Tools/qdata/qd_fmodel.h new file mode 100644 index 0000000..c660265 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/qd_fmodel.h @@ -0,0 +1,42 @@ +#ifndef FMODEL_H +#define FMODEL_H +#include "fmodel.h" +#endif +#include "qd_Skeletons.h" + +typedef float vec3_t[3]; + +typedef struct +{ + int numnormals; + vec3_t normalsum; +} fmvertexnormals_t; + +typedef struct +{ + vec3_t v; + int lightnormalindex; + fmvertexnormals_t vnorm; +} fmtrivert_t; + +#define FRAME_NAME_LEN (16) + +typedef struct +{ + vec3_t mins, maxs; + char name[FRAME_NAME_LEN]; + fmtrivert_t v[MAX_FM_VERTS]; + struct QD_SkeletalJoint_s joints[NUM_CLUSTERS]; + struct QD_SkeletalJoint_s references[NUM_REFERENCES]; +} fmframe_t; + +extern fmframe_t g_frames[MAX_FM_FRAMES]; + +extern fmheader_t fmheader; +extern char cdarchive[1024]; // set by $fmcd +extern char cdpartial[1024]; // set by $fmcd +extern char cddir[1024]; // set by $fmcd + +void GrabFrame (char *frame); +void H_printf(char *fmt, ...); +char *FindFrameFile (char *frame); \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qdata/qd_skeletons.c b/Toolkit/Programming/Tools/qdata/qd_skeletons.c new file mode 100644 index 0000000..144749a --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/qd_skeletons.c @@ -0,0 +1,1270 @@ +#include "qd_Skeletons.h" +#include "Skeletons.h" +#include "qd_fmodel.h" +#include "Angles.h" +#include "token.h" +#include "qdata.h" +#include "Reference.h" + +#include +#include +#include + + +// We're assuming no more than 16 reference points, with no more than 32 characters in the name +char RefPointNameList[REF_MAX_POINTS][REF_MAX_STRLEN]; +int RefPointNum = 0; + +Skeletalfmheader_t g_skelModel; + +void ClearSkeletalModel() +{ + g_skelModel.type = SKEL_NULL; + g_skelModel.clustered = false; + g_skelModel.references = REF_NULL; +} + +//========================================================================== +// +// LoadHRCClustered +// +//========================================================================== + +// Places the null terminated src string into the dest string less any trailing digits or underscores +void StripTrailingDigits(char *src, char *dest) +{ +#ifndef NDEBUG + int max = SKELETAL_NAME_MAX; // should be sufficient for inteded use on names from hrc files +#endif + int i = 0; + + while(src[i] != '\0') + { + ++i; +#ifndef NDEBUG + assert(i < max); +#endif + } + + while((src[--i] >= '0' && src[i] <= '9') || src[i] == '_') + { + + } + + memcpy(dest, src, ++i); + + dest[i] = '\0'; +} + +static void LoadHRCClustered(char *fileName, int **clusterList, int *num_verts, int skelType) +{ + extern void HandleHRCModel(triangle_t **triList, int *triangleCount, + mesh_node_t **nodesList, int *num_mesh_nodes, int ActiveNode, int Depth); + + extern mesh_node_t *pmnodes; + + triangle_t *triList; +// mesh_node_t *nodesList; + int num_mesh_nodes = 0, triangleCount = 0; + +#if 0 + int i; + int j, numVerts; + char stripped[SKELETAL_NAME_MAX]; + + for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i) + { + num_verts[i] = 0; + } + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + TK_Beyond(TK_CLUSTERS); + + while(TK_Search(TK_CLUSTER_NAME) != TK_EOF) + { + TK_Require(TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + for( i = 0; i < numJointsInSkeleton[skelType]; ++i) + { + if(_stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0) + { + i = -i + numJointsInSkeleton[skelType] - 1; + + TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER); + + numVerts = tk_IntNumber; + + if(!num_verts[i+1]) // first set of verts for cluster + { + clusterList[i] = SafeMalloc(numVerts*sizeof(int), "LoadHRCClustered"); + assert(clusterList[i]); + } + else // any later sets of verts need to copy current + { + int *temp; + + temp = SafeMalloc((num_verts[i+1]+numVerts)*sizeof(int), "LoadHRCClustered"); + assert(temp); + + memcpy(temp + numVerts, clusterList[i], num_verts[i+1]*sizeof(int)); + + free(clusterList[i]); + + clusterList[i] = temp; + } + + // currently this function is only called by LoadModelClusters. + // Apparently the matching free has disappeared, + // should probably be free at the end of FMCmd_Base + + TK_Beyond(TK_LBRACE); + + for(j = 0; j < numVerts; ++j) + { + TK_Require(TK_INTNUMBER); + clusterList[i][j] = tk_IntNumber; + TK_Fetch(); + } + + num_verts[i+1] += numVerts; + + break; + } + } + } + + num_verts[0] = numJointsInSkeleton[skelType]; +#endif + +#if 1 // get the index number localized to the root +// for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i) +// { +// g_skelModel.num_verts[i] = 0; +// } + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + // prime it + TK_Beyond(TK_MODEL); + + triList = SafeMalloc(MAXTRIANGLES*sizeof(triangle_t), "Triangle list"); + memset(triList,0,MAXTRIANGLES*sizeof(triangle_t)); +// nodesList = SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + pmnodes = SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + + memset(pmnodes, 0, MAX_FM_MESH_NODES * sizeof(mesh_node_t)); + + // this should eventually use a stripped down version of this + HandleHRCModel(&triList, &triangleCount, &pmnodes, &num_mesh_nodes, 0, 0); + +// free(nodesList); + free(triList); + + num_verts[0] = numJointsInSkeleton[skelType]; +#endif +} + +void ReadHRCClusterList(mesh_node_t *meshNode, int baseIndex) +{ + int i, j, numVerts; + tokenType_t nextToken; + char stripped[SKELETAL_NAME_MAX]; + + meshNode->clustered = true; + + nextToken = TK_Get(TK_CLUSTER_NAME); + + while (nextToken == TK_CLUSTER_NAME) + { + TK_FetchRequire(TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + for( i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i) + { + if(_stricmp(stripped, skeletonJointNames[skeletonNameOffsets[g_skelModel.type]+i]) == 0) + { + i = -i + numJointsInSkeleton[g_skelModel.type] - 1; + + TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER); + + numVerts = tk_IntNumber; + + if(!baseIndex) + { + meshNode->clusters[i] = SafeMalloc(numVerts*sizeof(int), "ReadHRCClusterList"); + assert(meshNode->clusters[i]); + } + else + { + int *temp; + + temp = meshNode->clusters[i]; + meshNode->clusters[i] = SafeMalloc((meshNode->num_verts[i+1]+numVerts)*sizeof(int), "ReadHRCClusterList"); + assert(meshNode->clusters[i]); + + memcpy(meshNode->clusters[i], temp, meshNode->num_verts[i+1]*sizeof(int)); + free(temp); + } + + // currently this function is only called by LoadModelClusters. + // Apparently the matching free has disappeared, + // should probably be free at the end of FMCmd_Base + + TK_Beyond(TK_LBRACE); + + for(j = 0; j < numVerts; ++j) + { + TK_Require(TK_INTNUMBER); + meshNode->clusters[i][baseIndex+j] = tk_IntNumber+baseIndex; + TK_Fetch(); + } + + if(baseIndex) + { + meshNode->num_verts[i+1] += numVerts; + } + else + { + meshNode->num_verts[i+1] = numVerts; + } + + break; + } + } + + TK_BeyondRequire(TK_CLUSTER_STATE, TK_INTNUMBER); + nextToken = TK_Fetch(); + } +} + +static void LoadHRCGlobals(char *fileName) +{ + int i; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + TK_Beyond(TK_MODEL); + + TK_Beyond(TK_SCALING); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_skelModel.scaling[i] = tk_FloatNumber; + TK_Fetch(); + } + + TK_Beyond(TK_ROTATION); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_skelModel.rotation[i] = tk_FloatNumber; + TK_Fetch(); + } + + TK_Beyond(TK_TRANSLATION); + for(i = 0; i < 3; i++) + { + TK_Require(TK_FLOATNUMBER); + g_skelModel.translation[i] = tk_FloatNumber; + TK_Fetch(); + } +} + +static void ParseVec3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseVec3d(vec3d_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseRotation3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseRotation3d(vec3d_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseTranslation3(vec3_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void ParseTranslation3d(vec3d_t in) +{ + TK_Require(TK_FLOATNUMBER); + in[1] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[2] = tk_FloatNumber; + TK_FetchRequire(TK_FLOATNUMBER); + in[0] = tk_FloatNumber; +} + +static void LoadHRCJointList(char *fileName, QD_SkeletalJoint_t *jointList, int skelType) +{ +#define MAX_STACK 64 + int i, j; + vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK], curScale[MAX_STACK]; + int curCorrespondingJoint[MAX_STACK]; + int currentStack = 0, stackSize; + double cx, sx, cy, sy, cz, sz; + double rx, ry, rz; + double x2, y2, z2; + char stripped[SKELETAL_NAME_MAX]; + Placement_d_t *placement; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + TK_Beyond(TK_MODEL); + + while(TK_Search(TK_NAME) != TK_EOF) + { + TK_Require(TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + if(_stricmp(stripped, skeletonRootNames[skeletonRNameOffsets[skelType]]) == 0) + { + break; + } + } + + if(tk_Token == TK_EOF) + { + Error("Bone Chain Root: %s not found\n", skeletonRootNames[skeletonRNameOffsets[skelType]]); + return; + } + + TK_Beyond(TK_SCALING); + + ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3d(curTranslation[currentStack]); + + // account for global model translation + curTranslation[currentStack][1] += g_skelModel.translation[0]; + curTranslation[currentStack][2] += g_skelModel.translation[1]; + curTranslation[currentStack][0] += g_skelModel.translation[2]; + + curCorrespondingJoint[currentStack] = -1; + + ++currentStack; + + for(i = 0; i < numJointsInSkeleton[skelType]; ++i) + { + while(1) + { + TK_Beyond(TK_MODEL); + + TK_BeyondRequire(TK_NAME, TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + if(_stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0) + break; + + TK_Beyond(TK_SCALING); + + ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3d(curTranslation[currentStack]); + + curCorrespondingJoint[currentStack] = -1; + + ++currentStack; + } + + TK_Beyond(TK_SCALING); + + ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + + jointList[i].rotation[1] = curRotation[currentStack][1]; + jointList[i].rotation[2] = curRotation[currentStack][2]; + jointList[i].rotation[0] = curRotation[currentStack][0]; + + TK_Beyond(TK_TRANSLATION); + + ParseVec3d(curTranslation[currentStack]); + +// jointList[i].placement.origin[1] = curTranslation[currentStack][1]; +// jointList[i].placement.origin[2] = curTranslation[currentStack][2]; +// jointList[i].placement.origin[0] = curTranslation[currentStack][0]; + + jointList[i].placement.origin[1] = 0.0; + jointList[i].placement.origin[2] = 0.0; + jointList[i].placement.origin[0] = 0.0; + + jointList[i].placement.direction[1] = 20.0; + jointList[i].placement.direction[2] = 0.0; + jointList[i].placement.direction[0] = 0.0; + + jointList[i].placement.up[1] = 0.0; + jointList[i].placement.up[2] = 20.0; + jointList[i].placement.up[0] = 0.0; + + curCorrespondingJoint[currentStack] = i; + + ++currentStack; + } + + stackSize = currentStack; + +#if 0 + // rotate the direction and up vectors to correspond to the rotation + for(i = 0; i < numJointsInSkeleton[skelType]; ++i) + { + rx = jointList[i].rotation[0]*ANGLE_TO_RAD; + ry = jointList[i].rotation[1]*ANGLE_TO_RAD; + rz = jointList[i].rotation[2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + + // y-axis rotation for direction + x2 = jointList[i].placement.direction[0]*cy+jointList[i].placement.direction[2]*sy; + z2 = -jointList[i].placement.direction[0]*sy+jointList[i].placement.direction[2]*cy; + jointList[i].placement.direction[0] = x2; + jointList[i].placement.direction[2] = z2; + + // y-axis rotation for up + x2 = jointList[i].placement.up[0]*cy+jointList[i].placement.up[2]*sy; + z2 = -jointList[i].placement.up[0]*sy+jointList[i].placement.up[2]*cy; + jointList[i].placement.up[0] = x2; + jointList[i].placement.up[2] = z2; + + // z-axis rotation for direction + x2 = jointList[i].placement.direction[0]*cz-jointList[i].placement.direction[1]*sz; + y2 = jointList[i].placement.direction[0]*sz+jointList[i].placement.direction[1]*cz; + jointList[i].placement.direction[0] = x2; + jointList[i].placement.direction[1] = y2; + + // z-axis rotation for up + x2 = jointList[i].placement.up[0]*cz-jointList[i].placement.up[1]*sz; + y2 = jointList[i].placement.up[0]*sz+jointList[i].placement.up[1]*cz; + jointList[i].placement.up[0] = x2; + jointList[i].placement.up[1] = y2; + + // x-axis rotation for direction vector + y2 = jointList[i].placement.direction[1]*cx-jointList[i].placement.direction[2]*sx; + z2 = jointList[i].placement.direction[1]*sx+jointList[i].placement.direction[2]*cx; + jointList[i].placement.direction[1] = y2; + jointList[i].placement.direction[2] = z2; + + // x-axis rotation for up vector + y2 = jointList[i].placement.up[1]*cx-jointList[i].placement.up[2]*sx; + z2 = jointList[i].placement.up[1]*sx+jointList[i].placement.up[2]*cx; + jointList[i].placement.up[1] = y2; + jointList[i].placement.up[2] = z2; + + // translate direction to a point in the model + jointList[i].placement.direction[0] += jointList[i].placement.origin[0]; + jointList[i].placement.direction[1] += jointList[i].placement.origin[1]; + jointList[i].placement.direction[2] += jointList[i].placement.origin[2]; + + // translate up to a point in the model + jointList[i].placement.up[0] += jointList[i].placement.origin[0]; + jointList[i].placement.up[1] += jointList[i].placement.origin[1]; + jointList[i].placement.up[2] += jointList[i].placement.origin[2]; + } +#endif + + for(i = stackSize - 1; i >= 0; --i) + { + rx = curRotation[i][0]*ANGLE_TO_RAD; + ry = curRotation[i][1]*ANGLE_TO_RAD; + rz = curRotation[i][2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + +#if 1 + for(j = i; j < stackSize; ++j) + { + if(curCorrespondingJoint[j] != -1) + { + placement = &jointList[curCorrespondingJoint[j]].placement; + + // y-axis rotation for origin + x2 = placement->origin[0]*cy+placement->origin[2]*sy; + z2 = -placement->origin[0]*sy+placement->origin[2]*cy; + placement->origin[0] = x2; + placement->origin[2] = z2; + + // y-axis rotation for direction + x2 = placement->direction[0]*cy+placement->direction[2]*sy; + z2 = -placement->direction[0]*sy+placement->direction[2]*cy; + placement->direction[0] = x2; + placement->direction[2] = z2; + + // y-axis rotation for up + x2 = placement->up[0]*cy+placement->up[2]*sy; + z2 = -placement->up[0]*sy+placement->up[2]*cy; + placement->up[0] = x2; + placement->up[2] = z2; + + // z-axis rotation for origin + x2 = placement->origin[0]*cz-placement->origin[1]*sz; + y2 = placement->origin[0]*sz+placement->origin[1]*cz; + placement->origin[0] = x2; + placement->origin[1] = y2; + + // z-axis rotation for direction + x2 = placement->direction[0]*cz-placement->direction[1]*sz; + y2 = placement->direction[0]*sz+placement->direction[1]*cz; + placement->direction[0] = x2; + placement->direction[1] = y2; + + // z-axis rotation for up + x2 = placement->up[0]*cz-placement->up[1]*sz; + y2 = placement->up[0]*sz+placement->up[1]*cz; + placement->up[0] = x2; + placement->up[1] = y2; + + // x-axis rotation for origin + y2 = placement->origin[1]*cx-placement->origin[2]*sx; + z2 = placement->origin[1]*sx+placement->origin[2]*cx; + placement->origin[1] = y2; + placement->origin[2] = z2; + + // x-axis rotation for direction vector + y2 = placement->direction[1]*cx-placement->direction[2]*sx; + z2 = placement->direction[1]*sx+placement->direction[2]*cx; + placement->direction[1] = y2; + placement->direction[2] = z2; + + // x-axis rotation for up vector + y2 = placement->up[1]*cx-placement->up[2]*sx; + z2 = placement->up[1]*sx+placement->up[2]*cx; + placement->up[1] = y2; + placement->up[2] = z2; + + // translate origin + placement->origin[0] += curTranslation[i][0]; + placement->origin[1] += curTranslation[i][1]; + placement->origin[2] += curTranslation[i][2]; + + // translate back to local coord + placement->direction[0] += curTranslation[i][0]; + placement->direction[1] += curTranslation[i][1]; + placement->direction[2] += curTranslation[i][2]; + + // translate back to local coord + placement->up[0] += curTranslation[i][0]; + placement->up[1] += curTranslation[i][1]; + placement->up[2] += curTranslation[i][2]; + } + } +#else + // This screwed up and needs to be sorted out!!! + // The stack info needs to be written too instead of the jointList for j > numJoints for Skeleton + for(j = i-1; j < stackSize-1; ++j) + { + // y-axis rotation for origin + x2 = jointList[j].placement.origin[0]*cy+jointList[j].placement.origin[2]*sy; + z2 = -jointList[j].placement.origin[0]*sy+jointList[j].placement.origin[2]*cy; + jointList[j].placement.origin[0] = x2; + jointList[j].placement.origin[2] = z2; + + // y-axis rotation for direction + x2 = jointList[j].placement.direction[0]*cy+jointList[j].placement.direction[2]*sy; + z2 = -jointList[j].placement.direction[0]*sy+jointList[j].placement.direction[2]*cy; + jointList[j].placement.direction[0] = x2; + jointList[j].placement.direction[2] = z2; + + // y-axis rotation for up + x2 = jointList[j].placement.up[0]*cy+jointList[j].placement.up[2]*sy; + z2 = -jointList[j].placement.up[0]*sy+jointList[j].placement.up[2]*cy; + jointList[j].placement.up[0] = x2; + jointList[j].placement.up[2] = z2; + + // z-axis rotation for origin + x2 = jointList[j].placement.origin[0]*cz-jointList[j].placement.origin[1]*sz; + y2 = jointList[j].placement.origin[0]*sz+jointList[j].placement.origin[1]*cz; + jointList[j].placement.origin[0] = x2; + jointList[j].placement.origin[1] = y2; + + // z-axis rotation for direction + x2 = jointList[j].placement.direction[0]*cz-jointList[j].placement.direction[1]*sz; + y2 = jointList[j].placement.direction[0]*sz+jointList[j].placement.direction[1]*cz; + jointList[j].placement.direction[0] = x2; + jointList[j].placement.direction[1] = y2; + + // z-axis rotation for up + x2 = jointList[j].placement.up[0]*cz-jointList[j].placement.up[1]*sz; + y2 = jointList[j].placement.up[0]*sz+jointList[j].placement.up[1]*cz; + jointList[j].placement.up[0] = x2; + jointList[j].placement.up[1] = y2; + + // x-axis rotation for origin + y2 = jointList[j].placement.origin[1]*cx-jointList[j].placement.origin[2]*sx; + z2 = jointList[j].placement.origin[1]*sx+jointList[j].placement.origin[2]*cx; + jointList[j].placement.origin[1] = y2; + jointList[j].placement.origin[2] = z2; + + // x-axis rotation for direction vector + y2 = jointList[j].placement.direction[1]*cx-jointList[j].placement.direction[2]*sx; + z2 = jointList[j].placement.direction[1]*sx+jointList[j].placement.direction[2]*cx; + jointList[j].placement.direction[1] = y2; + jointList[j].placement.direction[2] = z2; + + // x-axis rotation for up vector + y2 = jointList[j].placement.up[1]*cx-jointList[j].placement.up[2]*sx; + z2 = jointList[j].placement.up[1]*sx+jointList[j].placement.up[2]*cx; + jointList[j].placement.up[1] = y2; + jointList[j].placement.up[2] = z2; + + if(curCorrespondingJoint[j+1] != -1) + { + // translate origin + jointList[j].placement.origin[0] += curTranslation[i-1][0]; + jointList[j].placement.origin[1] += curTranslation[i-1][1]; + jointList[j].placement.origin[2] += curTranslation[i-1][2]; + + // translate back to local coord + jointList[j].placement.direction[0] += curTranslation[i-1][0]; + jointList[j].placement.direction[1] += curTranslation[i-1][1]; + jointList[j].placement.direction[2] += curTranslation[i-1][2]; + + // translate back to local coord + jointList[j].placement.up[0] += curTranslation[i-1][0]; + jointList[j].placement.up[1] += curTranslation[i-1][1]; + jointList[j].placement.up[2] += curTranslation[i-1][2]; + } + } +#endif + } +} + +void LoadModelTransform(char *fileName) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCGlobals(InputFileName); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC match.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { +// printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCGlobals(fileName); + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void LoadModelClusters(char *fileName, int **clusterList, int *num_verts, int skelType) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCClustered(InputFileName, clusterList, num_verts, skelType); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC match.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { +// printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCClustered(fileName, clusterList, num_verts, skelType); + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void LoadSkeleton(char *fileName, QD_SkeletalJoint_t *jointList, int skelType) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCJointList(InputFileName, jointList, skelType); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { +// printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCJointList(fileName, jointList, skelType); + + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +/* +=============== +GrabSkeletalFrame +=============== +*/ +void GrabSkeletalFrame(char *frame) +{ + char file1[1024]; + char *framefile; + fmframe_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("Grabbing Skeletal Frame %s\n", file1); + + fr = &g_frames[fmheader.num_frames - 1]; // last frame read in + + LoadSkeleton(file1, fr->joints, g_skelModel.type); +} + +/* +=============== +GrabModelTransform +=============== +*/ +void GrabModelTransform(char *frame) +{ + char file1[1024]; + char *framefile; + fmframe_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + +// printf ("grabbing %s\n", file1); + + fr = &g_frames[fmheader.num_frames - 1]; // last frame read in + + LoadModelTransform(file1); +} + +void Cmd_FMCluster() +{ + char file1[1024]; + + GetScriptToken (false); + + printf ("---------------------\n"); + sprintf (file1, "%s/%s", cdpartial, token); + printf ("%s\n", file1); + + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s", cddir, token); + + g_skelModel.clustered = -1; + + LoadModelClusters(file1, (int **)&g_skelModel.clusters, (int *)&g_skelModel.num_verts, g_skelModel.type); + + g_skelModel.new_num_verts[0] = g_skelModel.num_verts[0]; + + g_skelModel.clustered = true; +} + +void Cmd_FMSkeleton() +{ + GetScriptToken (false); + g_skelModel.type = atoi(token); +} + +void Cmd_FMSkeletalFrame() +{ + while (ScriptTokenAvailable()) + { + GetScriptToken (false); + if (g_skipmodel) + { + GetScriptToken (false); + continue; + } + if (g_release || g_archive) + { + fmheader.num_frames = 1; // don't skip the writeout + GetScriptToken (false); + continue; + } + + H_printf("#define FRAME_%-16s\t%i\n", token, fmheader.num_frames); + + GrabModelTransform (token); + GrabFrame (token); + GrabSkeletalFrame (token); + + // need to add the up and dir points to the frame bounds here + // using AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs); + // then remove fudge in determining scale on frame write out + } +} + +static void LoadHRCReferences(char *fileName, fmframe_t *fr) +{ +#define MAX_STACK 64 + int i, j, k; + vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK]; + int curCorrespondingJoint[MAX_STACK]; + int currentStack, stackSize; + double cx, sx, cy, sy, cz, sz; + double rx, ry, rz; + double x2, y2, z2; + char stripped[SKELETAL_NAME_MAX]; + Placement_d_t *placement; + int refnum; + + TK_OpenSource(fileName); + TK_FetchRequire(TK_HRCH); + TK_FetchRequire(TK_COLON); + TK_FetchRequire(TK_SOFTIMAGE); + + if (RefPointNum <= 0) + { // There were no labels indicated in the QDT, so use the hard-coded stuff. + refnum = numReferences[g_skelModel.references]; + } + else + { + refnum = RefPointNum; + } + + for(k = 0; k < refnum; ++k) + { + currentStack = 0; + + // Load the root to get translation and initial rotation +// TK_Beyond(TK_MODEL); + + while(TK_Search(TK_NAME) != TK_EOF) + { + TK_Require(TK_STRING); + + StripTrailingDigits(tk_String, stripped); + + if (RefPointNum == 0) + { // Hard coded refpoint labels + if(_stricmp(stripped, + referenceRootNames[referenceRootNameOffsets[g_skelModel.references]+k]) == 0) + { + break; + } + } + else + { // labels indicated by the QDT + if(_stricmp(stripped, RefPointNameList[k]) == 0) + { + break; + } + } + } + + if(tk_Token == TK_EOF) + { + if (RefPointNum == 0) + { // Hard coded refpoint labels + Error("Bone Chain Root: %s not found\n", referenceRootNames[referenceRootNameOffsets[g_skelModel.references]]); + } + else + { // labels indicated by the QDT + Error("Bone Chain Root: %s not found\n", RefPointNameList[k]); + } + return; + } + +// TK_Beyond(TK_SCALING); + +// ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + + TK_Beyond(TK_TRANSLATION); + + ParseVec3d(curTranslation[currentStack]); + + // account for global model translation + curTranslation[currentStack][1] += g_skelModel.translation[0]; + curTranslation[currentStack][2] += g_skelModel.translation[1]; + curTranslation[currentStack][0] += g_skelModel.translation[2]; + + curCorrespondingJoint[currentStack] = -1; + +// rjr - this one not needed, as there is also a stack increment 20 lines below??? +// ++currentStack; + + // Load the joint to get orientation + TK_Beyond(TK_MODEL); + +// TK_Beyond(TK_SCALING); + +// ParseVec3d(curScale[currentStack]); + + TK_Beyond(TK_ROTATION); + + ParseRotation3d(curRotation[currentStack]); + +// TK_Beyond(TK_TRANSLATION); + +// ParseVec3d(curTranslation[currentStack]); + + fr->references[k].placement.origin[1] = 0.0; + fr->references[k].placement.origin[2] = 0.0; + fr->references[k].placement.origin[0] = 0.0; + + fr->references[k].placement.direction[1] = 20.0; + fr->references[k].placement.direction[2] = 0.0; + fr->references[k].placement.direction[0] = 0.0; + + fr->references[k].placement.up[1] = 0.0; + fr->references[k].placement.up[2] = 20.0; + fr->references[k].placement.up[0] = 0.0; + + curCorrespondingJoint[currentStack] = k; + + ++currentStack; + + stackSize = currentStack; + + for(i = stackSize - 1; i >= 0; --i) + { + rx = curRotation[i][0]*ANGLE_TO_RAD; + ry = curRotation[i][1]*ANGLE_TO_RAD; + rz = curRotation[i][2]*ANGLE_TO_RAD; + + cx = cos(rx); + sx = sin(rx); + + cy = cos(ry); + sy = sin(ry); + + cz = cos(rz); + sz = sin(rz); + + for(j = i; j < stackSize; ++j) + { + if(curCorrespondingJoint[j] != -1) + { + placement = &fr->references[curCorrespondingJoint[j]].placement; + + // y-axis rotation for origin + x2 = placement->origin[0]*cy+placement->origin[2]*sy; + z2 = -placement->origin[0]*sy+placement->origin[2]*cy; + placement->origin[0] = x2; + placement->origin[2] = z2; + + // y-axis rotation for direction + x2 = placement->direction[0]*cy+placement->direction[2]*sy; + z2 = -placement->direction[0]*sy+placement->direction[2]*cy; + placement->direction[0] = x2; + placement->direction[2] = z2; + + // y-axis rotation for up + x2 = placement->up[0]*cy+placement->up[2]*sy; + z2 = -placement->up[0]*sy+placement->up[2]*cy; + placement->up[0] = x2; + placement->up[2] = z2; + + // z-axis rotation for origin + x2 = placement->origin[0]*cz-placement->origin[1]*sz; + y2 = placement->origin[0]*sz+placement->origin[1]*cz; + placement->origin[0] = x2; + placement->origin[1] = y2; + + // z-axis rotation for direction + x2 = placement->direction[0]*cz-placement->direction[1]*sz; + y2 = placement->direction[0]*sz+placement->direction[1]*cz; + placement->direction[0] = x2; + placement->direction[1] = y2; + + // z-axis rotation for up + x2 = placement->up[0]*cz-placement->up[1]*sz; + y2 = placement->up[0]*sz+placement->up[1]*cz; + placement->up[0] = x2; + placement->up[1] = y2; + + // x-axis rotation for origin + y2 = placement->origin[1]*cx-placement->origin[2]*sx; + z2 = placement->origin[1]*sx+placement->origin[2]*cx; + placement->origin[1] = y2; + placement->origin[2] = z2; + + // x-axis rotation for direction vector + y2 = placement->direction[1]*cx-placement->direction[2]*sx; + z2 = placement->direction[1]*sx+placement->direction[2]*cx; + placement->direction[1] = y2; + placement->direction[2] = z2; + + // x-axis rotation for up vector + y2 = placement->up[1]*cx-placement->up[2]*sx; + z2 = placement->up[1]*sx+placement->up[2]*cx; + placement->up[1] = y2; + placement->up[2] = z2; + + // translate origin + placement->origin[0] += curTranslation[i][0]; + placement->origin[1] += curTranslation[i][1]; + placement->origin[2] += curTranslation[i][2]; + + // translate back to local coord + placement->direction[0] += curTranslation[i][0]; + placement->direction[1] += curTranslation[i][1]; + placement->direction[2] += curTranslation[i][2]; + + // translate back to local coord + placement->up[0] += curTranslation[i][0]; + placement->up[1] += curTranslation[i][1]; + placement->up[2] += curTranslation[i][2]; + + } + } + } + printf("%f, %f, %f\n", placement->origin[0], placement->origin[1], placement->origin[2]); + } + printf("\n"); +} + +void Cmd_FMReferenced() +{ + int i; + + GetScriptToken (false); + g_skelModel.references = atoi(token); + + // Guess what? Now, we now want a list of strings to look for here instead of a hard-coded list + for (i=0; i 0) + { + printf("Searching for %d different reference points.\n", RefPointNum); + } + else + { + printf("Using built-in reference points.\n"); + } + +} + +void LoadReferences(char *fileName, fmframe_t *fr) +{ + FILE *file1; + int dot = '.'; + char *dotstart; + char InputFileName[256]; + + dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name? + + if (!dotstart) + { + strcpy(InputFileName, fileName); + strcat(InputFileName, ".hrc"); + if((file1 = fopen(InputFileName, "rb")) != NULL) + { + fclose(file1); + + LoadHRCReferences(InputFileName, fr); + + printf(" - assuming .HRC\n"); + return; + } + + Error("\n Could not open file '%s':\n" + "No HRC.\n", fileName); + } + else + { + if((file1 = fopen(fileName, "rb")) != NULL) + { + printf("\n"); + fclose(file1); + if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0) + { + LoadHRCReferences(fileName, fr); + + return; + } + } + + Error("Could not open file '%s':\n",fileName); + } +} + +void GrabReferencedFrame(char *frame) +{ + char file1[1024]; + char *framefile; + fmframe_t *fr; + + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("Grabbing Referenced %s\n", file1); + + fr = &g_frames[fmheader.num_frames - 1]; // last frame read in + + LoadReferences(file1, fr); +} + diff --git a/Toolkit/Programming/Tools/qdata/qd_skeletons.h b/Toolkit/Programming/Tools/qdata/qd_skeletons.h new file mode 100644 index 0000000..b7c3166 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/qd_skeletons.h @@ -0,0 +1,67 @@ +#ifndef QD_SKELETONS_H +#define QD_SKELETONS_H + +#include "Placement.h" + +typedef float vec3_t[3]; +typedef double vec3d_t[3]; +typedef int qboolean; + + +typedef struct Placement_d_s +{ + vec3d_t origin; + vec3d_t direction; + vec3d_t up; +} Placement_d_t; + +typedef struct QD_SkeletalJoint_s +{ + Placement_d_t placement; + vec3d_t rotation; +} QD_SkeletalJoint_t; + +#define NUM_CLUSTERS 8 + +typedef struct IntListNode_s +{ + int data; + struct IntListNode_s *next; +} IntListNode_t; // gaak + +typedef struct Skeletalfmheader_s +{ + int type; + int clustered; + int references; + + int *clusters[NUM_CLUSTERS]; + IntListNode_t *vertLists[NUM_CLUSTERS]; + int num_verts[NUM_CLUSTERS + 1]; + int new_num_verts[NUM_CLUSTERS + 1]; + + float scaling[3]; + float rotation[3]; + float translation[3]; +} Skeletalfmheader_t; + +#define SKELETAL_NAME_MAX 32 + +extern Skeletalfmheader_t g_skelModel; + +void ClearSkeletalModel(); +void GrabModelTransform(char *frame); +void GrabSkeletalFrame(char *frame); +void GrabReferencedFrame(char *frame); + +// Reference Stuff +#define NUM_REFERENCES 8 + +#define REF_MAX_POINTS 16 +#define REF_MAX_STRLEN 32 + +// We're assuming no more than 16 reference points, with no more than 32 characters in the name +extern char RefPointNameList[REF_MAX_POINTS][REF_MAX_STRLEN]; +extern int RefPointNum; + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qdata/qdata.c b/Toolkit/Programming/Tools/qdata/qdata.c new file mode 100644 index 0000000..490dc51 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/qdata.c @@ -0,0 +1,709 @@ +#include "qdata.h" +#include + +void TK_Init(); + +qboolean g_compress_pak; +qboolean g_release; // don't grab, copy output data to new tree +qboolean g_pak; // if true, copy to pak instead of release +char g_releasedir[1024]; // c:\quake2\baseq2, etc +qboolean g_archive; // don't grab, copy source data to new tree +qboolean do3ds; +char g_only[256]; // if set, only grab this cd +qboolean g_skipmodel; // set true when a cd is not g_only +int g_forcemodel = MODEL_AUTO; +qboolean g_verbose = false; +qboolean g_allow_newskin = true; +qboolean g_ignoreTriUV = false; +qboolean g_publishOutput = false; + +char *ext_3ds = "3ds"; +char *ext_tri= "tri"; +char *trifileext; + +char g_materialFile[256] = "none"; // default for Heretic2 +char *g_outputDir; +extern char *g_publishDir; + +extern qboolean g_nomkdir; + +/* +======================================================= + + PAK FILES + +======================================================= +*/ + +unsigned Com_BlockChecksum (void *buffer, int length); + +typedef struct +{ + char name[56]; + int filepos, filelen; +} packfile_t; + +typedef struct +{ + char id[4]; + int dirofs; + int dirlen; +} packheader_t; + +packfile_t pfiles[16384]; +FILE *pakfile; +packfile_t *pf; +packheader_t pakheader; + + + +/* +============== +BeginPak +============== +*/ +void BeginPak (char *outname) +{ + if (!g_pak) + return; + + pakfile = SafeOpenWrite (outname); + + // leave space for header + SafeWrite (pakfile, &pakheader, sizeof(pakheader)); + + pf = pfiles; +} + + +/* +============== +ReleaseFile + +Filename should be gamedir reletive. +Either copies the file to the release dir, or adds it to +the pak file. +============== +*/ +void ReleaseFile (char *filename) +{ + int len; + byte *buf; + char source[1024]; + char dest[1024]; + + if (!g_release) + return; + + sprintf (source, "%s%s", gamedir, filename); + + if (!g_pak) + { // copy it + sprintf (dest, "%s/%s", g_releasedir, filename); + printf ("copying to %s\n", dest); + QCopyFile (source, dest); + return; + } + + // pak it + printf ("paking %s\n", filename); + if (strlen(filename) >= sizeof(pf->name)) + Error ("Filename too long for pak: %s", filename); + + len = LoadFile (source, (void **)&buf); + + // segment moved to old.c + + strcpy (pf->name, filename); + pf->filepos = LittleLong(ftell(pakfile)); + pf->filelen = LittleLong(len); + pf++; + + SafeWrite (pakfile, buf, len); + + free (buf); +} + + +/* +============== +FinishPak +============== +*/ +void FinishPak (void) +{ + int dirlen; + int d; + int i; + unsigned checksum; + + if (!g_pak) + return; + + pakheader.id[0] = 'P'; + pakheader.id[1] = 'A'; + pakheader.id[2] = 'C'; + pakheader.id[3] = 'K'; + dirlen = (byte *)pf - (byte *)pfiles; + pakheader.dirofs = LittleLong(ftell(pakfile)); + pakheader.dirlen = LittleLong(dirlen); + + checksum = Com_BlockChecksum ( (void *)pfiles, dirlen ); + + SafeWrite (pakfile, pfiles, dirlen); + + i = ftell (pakfile); + + fseek (pakfile, 0, SEEK_SET); + SafeWrite (pakfile, &pakheader, sizeof(pakheader)); + fclose (pakfile); + + d = pf - pfiles; + printf ("%i files packed in %i bytes\n",d, i); + printf ("checksum: 0x%x\n", checksum); +} + + +/* +=============== +Cmd_File + +This is only used to cause a file to be copied during a release +build (default.cfg, maps, etc) +=============== +*/ +void Cmd_File (void) +{ + GetScriptToken (false); + ReleaseFile (token); +} + +/* +=============== +PackDirectory_r + +=============== +*/ +#ifdef _WIN32 +#include "io.h" +void PackDirectory_r (char *dir) +{ + struct _finddata_t fileinfo; + int handle; + char dirstring[1024]; + char filename[1024]; + + sprintf (dirstring, "%s%s/*.*", gamedir, dir); + + handle = _findfirst (dirstring, &fileinfo); + if (handle == -1) + return; + + do + { + sprintf (filename, "%s/%s", dir, fileinfo.name); + if (fileinfo.attrib & _A_SUBDIR) + { // directory + if (fileinfo.name[0] != '.') // don't pak . and .. + PackDirectory_r (filename); + continue; + } + // copy or pack the file + ReleaseFile (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); +} +#else + +#include +#ifdef NeXT +#include +#else +#include +#endif + +void PackDirectory_r (char *dir) +{ +#ifdef NeXT + struct direct **namelist, *ent; +#else + struct dirent **namelist, *ent; +#endif + int count; + struct stat st; + int i; + int len; + char fullname[1024]; + char dirstring[1024]; + char *name; + + sprintf (dirstring, "%s%s", gamedir, dir); + count = scandir(dirstring, &namelist, NULL, NULL); + + for (i=0 ; id_name; + + if (name[0] == '.') + continue; + + sprintf (fullname, "%s/%s", dir, name); + sprintf (dirstring, "%s%s/%s", gamedir, dir, name); + + if (stat (dirstring, &st) == -1) + Error ("fstating %s", pf->name); + if (st.st_mode & S_IFDIR) + { // directory + PackDirectory_r (fullname); + continue; + } + + // copy or pack the file + ReleaseFile (fullname); + } +} +#endif + + +/* +=============== +Cmd_Dir + +This is only used to cause a directory to be copied during a +release build (sounds, etc) +=============== +*/ +void Cmd_Dir (void) +{ + GetScriptToken (false); + PackDirectory_r (token); +} + +//======================================================================== + +#define MAX_RTEX 16384 +int numrtex; +char rtex[MAX_RTEX][64]; + +void ReleaseTexture (char *name) +{ + int i; + char path[1024]; + + for (i=0 ; i width height\n"); + } + return 0; + } +*/ else if (!strcmpi(argv[i], "-genskin")) + { + i++; + if (i < argc-3) + { + GenSkin(argv[i],argv[i+1],atol(argv[i+2]),atol(argv[i+3])); + } + else + { + printf("qdata -genskin \n"); + } + return 0; + + } + else if (!strcmpi(argv[i], "-noopts")) + { + g_no_opimizations = true; + printf("not performing optimizations\n"); + } + else if (!strcmpi(argv[i], "-md2")) + { + g_forcemodel = MODEL_MD2; + } + else if (!strcmpi(argv[i], "-fm")) + { + g_forcemodel = MODEL_FM; + } + else if (!strcmpi(argv[i], "-verbose")) + { + g_verbose = true; + } + else if (!strcmpi(argv[i], "-oldskin")) + { + g_allow_newskin = false; + } + else if (!strcmpi(argv[i], "-ignoreUV")) + { + g_ignoreTriUV = true; + } + else if (!strcmpi(argv[i], "-publish")) + { + g_publishOutput = true; + } + else if (!strcmpi(argv[i], "-nomkdir")) + { + g_nomkdir = true; + } + else if (argv[i][0] == '-') + Error ("Unknown option \"%s\"", argv[i]); + else + break; + } + + if (i >= argc) + { + Error ("usage: qdata [-archive ]\n" + " [-release ]\n" + " [-only ]\n" + " [-3ds]\n" + " [-pak ]\n" + " [-compress]\n" + " [-noopts]\n" + " [-md2]\n" + " [-fm]\n" + " [-ignoreUV]\n" + " [-oldskin]\n" + " [-noopts]\n" + " [-verbose]\n" + " [-keypress]\n" + " [-materialfile]\n" + " file.qdt\n" + "or\n" + " qdata -genskin "); + } + + if (do3ds) + trifileext = ext_3ds; + else + trifileext = ext_tri; + + for ( ; i +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=qdata - Win32 Release +!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 "qdata.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 "qdata.mak" CFG="qdata - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qdata - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qdata - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "qdata - Win32 Hybrid" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Wolf/Final/Utilities/qdata", UODAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qdata - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /G6 /W3 /GX /O2 /Ob2 /I "..\common" /I "..\qcommon" /I "..\ref_gl" /I "..\qdata" /I "..\ref_common" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_QDATA" /D "_TOOL" /D "_RAVEN" /D "H2COMMON_STATIC" /Fr /YX /FD /c +# 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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib uuid.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "qdata - 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 "_CONSOLE" /YX /c +# ADD CPP /nologo /G6 /W3 /Gm /Gi /GX /ZI /Od /I "..\qcommon" /I "..\ref_gl" /I "..\qdata" /I "..\ref_common" /I "..\common" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_QDATA" /D "_TOOL" /D "_RAVEN" /D "H2COMMON_STATIC" /FR /YX /FD /c +# 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:console /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib /nologo /subsystem:console /debug /machine:I386 +# SUBTRACT LINK32 /verbose + +!ELSEIF "$(CFG)" == "qdata - Win32 Hybrid" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "qdata___" +# PROP BASE Intermediate_Dir "qdata___" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "hybrid" +# PROP Intermediate_Dir "hybrid" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /O2 /Ob2 /I "..\common" /I "..\qcommon" /I "..\ref_gl" /I "..\qdata" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_QDATA" /D "_TOOL" /D "_RAVEN" /D "H2COMMON_STATIC" /Fr /YX /FD /c +# ADD CPP /nologo /G6 /W3 /Zi /O2 /Ob2 /I "..\common" /I "..\qcommon" /I "..\ref_gl" /I "..\qdata" /I "..\ref_common" /D "WIN32" /D "_CONSOLE" /D "_QDATA" /D "_TOOL" /D "_RAVEN" /D "H2COMMON_STATIC" /Fr /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib uuid.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib uuid.lib /nologo /subsystem:console /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "qdata - Win32 Release" +# Name "qdata - Win32 Debug" +# Name "qdata - Win32 Hybrid" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\animcomp.cpp +# End Source File +# Begin Source File + +SOURCE=.\book.c +# End Source File +# Begin Source File + +SOURCE=..\common\bspfile.c +# End Source File +# Begin Source File + +SOURCE=..\common\cmdlib.c +# End Source File +# Begin Source File + +SOURCE=.\fmodels.c +# End Source File +# Begin Source File + +SOURCE=.\images.c +# End Source File +# Begin Source File + +SOURCE=.\Jointed.c +# End Source File +# Begin Source File + +SOURCE=..\common\l3dslib.c +# End Source File +# Begin Source File + +SOURCE=..\common\lbmlib.c +# End Source File +# Begin Source File + +SOURCE=..\common\mathlib.c +# End Source File +# Begin Source File + +SOURCE=..\common\md4.c +# End Source File +# Begin Source File + +SOURCE=.\models.c +# End Source File +# Begin Source File + +SOURCE=.\pics.c +# End Source File +# Begin Source File + +SOURCE=.\qd_Skeletons.c +# End Source File +# Begin Source File + +SOURCE=.\qdata.c +# End Source File +# Begin Source File + +SOURCE=..\common\qfiles.c +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Reference.c +# End Source File +# Begin Source File + +SOURCE=..\qcommon\ResourceManager.c +# End Source File +# Begin Source File + +SOURCE=..\common\scriplib.c +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Skeletons.c +# End Source File +# Begin Source File + +SOURCE=.\sprites.c +# End Source File +# Begin Source File + +SOURCE=.\svdcmp.cpp +# End Source File +# Begin Source File + +SOURCE=.\tables.c +# End Source File +# Begin Source File + +SOURCE=..\common\threads.c +# End Source File +# Begin Source File + +SOURCE=.\tmix.c +# End Source File +# Begin Source File + +SOURCE=..\common\token.c +# End Source File +# Begin Source File + +SOURCE=..\common\trilib.c +# End Source File +# Begin Source File + +SOURCE=.\video.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\Adpcm.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Angles.h +# End Source File +# Begin Source File + +SOURCE=.\animcomp.h +# End Source File +# Begin Source File + +SOURCE=.\anorms.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\ArrayedList.h +# End Source File +# Begin Source File + +SOURCE=..\common\bspfile.h +# End Source File +# Begin Source File + +SOURCE=..\common\cmdlib.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\fc.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\flex.h +# End Source File +# Begin Source File + +SOURCE=..\ref_common\fmodel.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\h2common.h +# End Source File +# Begin Source File + +SOURCE=.\Jointed.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Joints.h +# End Source File +# Begin Source File + +SOURCE=.\Joints.h +# End Source File +# Begin Source File + +SOURCE=..\common\l3dslib.h +# End Source File +# Begin Source File + +SOURCE=..\common\lbmlib.h +# End Source File +# Begin Source File + +SOURCE=..\common\mathlib.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Placement.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_typedef.h +# End Source File +# Begin Source File + +SOURCE=.\qd_fmodel.h +# End Source File +# Begin Source File + +SOURCE=.\qd_Skeletons.h +# End Source File +# Begin Source File + +SOURCE=.\qdata.h +# End Source File +# Begin Source File + +SOURCE=..\common\qfiles.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Reference.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\resourcemanager.h +# End Source File +# Begin Source File + +SOURCE=..\common\scriplib.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Skeletons.h +# End Source File +# Begin Source File + +SOURCE=..\common\threads.h +# End Source File +# Begin Source File + +SOURCE=..\common\token.h +# End Source File +# Begin Source File + +SOURCE=..\common\trilib.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\Vector.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\icon1.ico +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\Script1.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/Toolkit/Programming/Tools/qdata/qdata.dsw b/Toolkit/Programming/Tools/qdata/qdata.dsw new file mode 100644 index 0000000..ec9bc49 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/qdata.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "qdata"=.\qdata.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/qdata", UODAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/qdata", UODAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Toolkit/Programming/Tools/qdata/qdata.h b/Toolkit/Programming/Tools/qdata/qdata.h new file mode 100644 index 0000000..20e97cf --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/qdata.h @@ -0,0 +1,136 @@ +// qdata.h + + +#include +#include +#include +#include +#include + +#include "cmdlib.h" +#include "scriplib.h" +#include "mathlib.h" +#include "trilib.h" +#include "lbmlib.h" +#include "threads.h" +#include "l3dslib.h" +#include "bspfile.h" + + +#define MODEL_AUTO 0 +#define MODEL_MD2 1 +#define MODEL_FM 2 + +// Model cover functions (to allow the forcing of a model type) +void MODELCMD_Modelname (int modeltype); +void MODELCMD_Cd (int modeltype); +void MODELCMD_Origin (int modeltype); +void MODELCMD_Jointed (int modeltype); +void MODELCMD_Cluster (int modeltype); +void MODELCMD_Base (int modeltype); +void MODELCMD_BaseST (int modeltype); +void MODELCMD_ScaleUp (int modeltype); +void MODELCMD_Frame (int modeltype); +void MODELCMD_Skin (int modeltype); +void MODELCMD_Skinsize (int modeltype); +void MODELCMD_Skeleton (int modeltype); +void MODELCMD_SkeletalFrame (int modeltype); +void MODELCMD_BeginGroup(int modeltype); +void MODELCMD_EndGroup(int modeltype); +void MODELCMD_Referenced(int modeltype); + +void Cmd_Modelname (void); +void Cmd_Base (void); +void Cmd_Cd (void); +void Cmd_Origin (void); +void Cmd_ScaleUp (void); +void Cmd_Frame (void); +void Cmd_Skin (void); +void Cmd_Skinsize (void); +void FinishModel (void); +void Cmd_Cluster (void); + +// Flexible Models +//void Cmd_FMModelname (void); +void Cmd_FMBase (qboolean GetST); +void Cmd_FMCd (void); +//void Cmd_FMOrigin (void); +void Cmd_FMCluster(); +void Cmd_FMSkeleton(); +//void Cmd_FMScaleUp (void); +void Cmd_FMFrame (void); +void Cmd_FMSkeletalFrame(); +void Cmd_FMSkin (void); +//void Cmd_FMSkinsize (void); +void Cmd_FMBeginGroup(void); +void Cmd_FMEndGroup(void); +void Cmd_FMReferenced(); +void FMFinishModel (void); +void GenSkin(char *ModelFile, char *OutputName, int Width, int Height); +void NewGen (char *ModelFile, char *OutputName, int width, int height); + + +void Cmd_Inverse16Table( void ); + +void Cmd_SpriteName (void); +void Cmd_Load (void); +void Cmd_SpriteFrame (void); +void Cmd_Sprdir (void); +void FinishSprite (void); + +void Cmd_Grab (void); +void Cmd_Raw (void); +void Cmd_Mip (void); +void Cmd_Environment (void); +void Cmd_Colormap (void); + +void Cmd_File (void); +void Cmd_Dir (void); +void Cmd_StartWad (void); +void Cmd_EndWad (void); +void Cmd_Mippal (void); +void Cmd_Mipdir (void); +void Cmd_Alphalight (void); + +void Cmd_Picdir (void); +void Cmd_Pic (void); + +void Cmd_Bookdir (void); +void Cmd_Book (void); + +void Cmd_TextureMix (void); + +void Cmd_Video (void); + +//void RemapZero (byte *pixels, byte *palette, int width, int height); + +void ReleaseFile (char *filename); + +extern byte *byteimage, *lbmpalette; +extern int byteimagewidth, byteimageheight; +extern qboolean TrueColorImage; +extern unsigned *longimage; +extern int longimagewidth, longimageheight; + +extern qboolean g_release; // don't grab, copy output data to new tree +extern char g_releasedir[1024]; // c:\quake2\baseq2, etc +extern qboolean g_archive; // don't grab, copy source data to new tree +extern qboolean do3ds; +extern char g_only[256]; // if set, only grab this cd +extern qboolean g_skipmodel; // set true when a cd is not g_only +extern qboolean g_no_opimizations; +extern int g_forcemodel; +extern qboolean g_verbose; +extern qboolean g_allow_newskin; +extern qboolean g_ignoreTriUV; //from qdata.c + +extern char *trifileext; + +extern char g_materialFile[256]; + +extern unsigned total_x; +extern unsigned total_y; +extern unsigned total_textures; + +miptex_t *CreateMip(byte *data, unsigned width, unsigned height, byte *palette, int *FinalSize, qboolean mip); +miptex32_t *CreateMip32(unsigned *data, unsigned width, unsigned height, int *FinalSize, qboolean mip); diff --git a/Toolkit/Programming/Tools/qdata/resource.h b/Toolkit/Programming/Tools/qdata/resource.h new file mode 100644 index 0000000..b71bb50 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Script1.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_3D_CONTROLS 1 +#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/Toolkit/Programming/Tools/qdata/script1.rc b/Toolkit/Programming/Tools/qdata/script1.rc new file mode 100644 index 0000000..70e3691 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/script1.rc @@ -0,0 +1,115 @@ +//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 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "icon1.ico" + +#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 + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Heavily modified from original ID tool\0" + VALUE "CompanyName", "Raven Software\0" + VALUE "FileDescription", "qdata\0" + VALUE "FileVersion", "2.0\0" + VALUE "InternalName", "qdata\0" + VALUE "LegalCopyright", "Copyright © 1998\0" + VALUE "OriginalFilename", "qdata.exe\0" + VALUE "ProductName", "Raven Software qdata\0" + VALUE "ProductVersion", "2.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Toolkit/Programming/Tools/qdata/sprites.c b/Toolkit/Programming/Tools/qdata/sprites.c new file mode 100644 index 0000000..a8c0f77 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/sprites.c @@ -0,0 +1,328 @@ + +#include "qdata.h" + +#define MAX_SPRFRAMES MAX_MD2SKINS + +dsprite_t sprite; +dsprframe_t frames[MAX_SPRFRAMES]; + +byte *byteimage, *lbmpalette; +int byteimagewidth, byteimageheight; + +qboolean TrueColorImage; +unsigned *longimage; +int longimagewidth, longimageheight; + +char spritename[1024]; + + +void FinishSprite (void); +void Cmd_Spritename (void); + +char spr_prefix[1024]; +char pic_prefix[1024]; + +extern char *g_outputDir; + + +/* +============== +FinishSprite +============== +*/ +void FinishSprite (void) +{ + FILE *spriteouthandle; + int i, curframe; + dsprite_t spritetemp; + char savename[1024]; + + if (sprite.numframes == 0) + return; + + if (!strlen(spritename)) + Error ("Didn't name sprite file"); + + sprintf (savename, "%sSprites/%s/%s.sp2", g_outputDir, spr_prefix, spritename); + + if (g_release) + { + char name[1024]; + + sprintf (name, "%s.sp2", spritename); + ReleaseFile (name); + spritename[0] = 0; // clear for a new sprite + sprite.numframes = 0; + return; + } + + + printf ("saving in %s\n", savename); + CreatePath (savename); + spriteouthandle = SafeOpenWrite (savename); + + +// +// write out the sprite header +// + spritetemp.ident = LittleLong (IDSPRITEHEADER); + spritetemp.version = LittleLong (SPRITE_VERSION); + spritetemp.numframes = LittleLong (sprite.numframes); + + SafeWrite (spriteouthandle, &spritetemp, 12); + +// +// write out the frames +// + curframe = 0; + + for (i=0 ; i 256) || (h > 256)) + Error ("Sprite has a dimension longer than 256"); + + xh = xl+w; + yh = yl+h; + + if (sprite.numframes >= MAX_SPRFRAMES) + Error ("Too many frames; increase MAX_SPRFRAMES\n"); + + pframe = &frames[sprite.numframes]; + pframe->width = w; + pframe->height = h; + pframe->origin_x = ox; + pframe->origin_y = oy; + + if (g_release) + { + ReleaseFile (pframe->name); + return; + } + + if (TrueColorImage) + { + sprintf (filename, "%ssprites/%s/%s_%i.m32", g_outputDir, spr_prefix, spritename, sprite.numframes); + sprintf (pframe->name, "%s/%s_%i.m32", spr_prefix, spritename, sprite.numframes); + + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + + if (xl >= longimagewidth || xh > longimagewidth || + yl >= longimageheight || yh > longimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,longimagewidth,longimageheight); + } + + sourcel = longimage + (yl*longimagewidth) + xl; + destl = bufferl; + linedelta = (longimagewidth - w); + + for (y=yl ; ycontents = 0; + qtex32->value = 0; + strcpy(qtex32->name, pframe->name); + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + + free (qtex32); + } + else + { + sprintf (filename, "%ssprites/%s/%s_%i.m8", g_outputDir, spr_prefix, spritename, sprite.numframes); + sprintf (pframe->name, "%s/%s_%i.m8", spr_prefix, spritename, sprite.numframes); + + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + + if (xl >= byteimagewidth || xh > byteimagewidth || + yl >= byteimageheight || yh > byteimageheight) + { + Error ("line %i: bad clip dimmensions (%d,%d) (%d,%d) > image (%d,%d)", scriptline, xl,yl,w,h,byteimagewidth,byteimageheight); + } + + source = byteimage + yl*byteimagewidth + xl; + dest = buffer; + linedelta = byteimagewidth - w; + + for (y=yl ; yflags = 0; + qtex->contents = 0; + qtex->value = 0; + strcpy(qtex->name, pframe->name); + // + // write it out + // + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex, size); + + free (qtex); + } + + sprite.numframes++; +} + + +/* +============== +Cmd_SpriteName +============== +*/ +void Cmd_SpriteName (void) +{ + if (sprite.numframes) + FinishSprite (); + + GetScriptToken (false); + strcpy (spritename, token); + memset (&sprite, 0, sizeof(sprite)); + memset (&frames, 0, sizeof(frames)); +} + + +/* +=============== +Cmd_Sprdir +=============== +*/ +void Cmd_Sprdir (void) +{ + char filename[1024]; + + GetScriptToken (false); + strcpy (spr_prefix, token); + // create the directory if needed + sprintf (filename, "%sSprites", g_outputDir); + Q_mkdir (filename); + sprintf (filename, "%sSprites/%s", g_outputDir, spr_prefix); + Q_mkdir (filename); +} + + diff --git a/Toolkit/Programming/Tools/qdata/svdcmp.cpp b/Toolkit/Programming/Tools/qdata/svdcmp.cpp new file mode 100644 index 0000000..a629aa4 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/svdcmp.cpp @@ -0,0 +1,467 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +static double at,bt,ct; +#define PYTHAG(a,b) ((at=fabs(a)) > (bt=fabs(b)) ? \ + (ct=bt/at,at*sqrt(1.0+ct*ct)) : (bt ? (ct=at/bt,bt*sqrt(1.0+ct*ct)): 0.0)) + + static double maxarg1,maxarg2; +#define MAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\ + (maxarg1) : (maxarg2)) +#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) + +void ntrerror(char *s) +{ + printf("%s\n",s); + DebugBreak(); + exit(1); +} + +double *allocVect(int sz) +{ + double *ret=new double[sz]; + ret--; + return ret; +} + +void freeVect(double *ret) +{ + ret++; + delete[] ret; +} + +double **allocMatrix(int r,int c) +{ + double **ret=new double *[r]; + int i; + for (i=0;i=1;i--) { + if (i < n) { + if (g) { + for (j=l;j<=n;j++) + v[j][i]=(a[i][j]/a[i][l])/g; + for (j=l;j<=n;j++) { + for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j]; + for (k=l;k<=n;k++) v[k][j] += s*v[k][i]; + } + } + for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0; + } + v[i][i]=1.0; + g=rv1[i]; + l=i; + } + for (i=n;i>=1;i--) { + l=i+1; + g=w[i]; + if (i < n) + for (j=l;j<=n;j++) a[i][j]=0.0; + if (g) { + g=1.0/g; + if (i != n) { + for (j=l;j<=n;j++) { + for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j]; + f=(s/a[i][i])*g; + for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; + } + } + for (j=i;j<=m;j++) a[j][i] *= g; + } else { + for (j=i;j<=m;j++) a[j][i]=0.0; + } + ++a[i][i]; + } + for (k=n;k>=1;k--) { + for (its=1;its<=30;its++) { + flag=1; + for (l=k;l>=1;l--) { + nm=l-1; + if (fabs(rv1[l])+anorm == anorm) { + flag=0; + break; + } + if (fabs(w[nm])+anorm == anorm) break; + } + if (flag) { + c=0.0; + s=1.0; + for (i=l;i<=k;i++) { + f=s*rv1[i]; + if (fabs(f)+anorm != anorm) { + g=w[i]; + h=PYTHAG(f,g); + w[i]=h; + h=1.0/h; + c=g*h; + s=(-f*h); + for (j=1;j<=m;j++) { + y=a[j][nm]; + z=a[j][i]; + a[j][nm]=y*c+z*s; + a[j][i]=z*c-y*s; + } + } + } + } + z=w[k]; + if (l == k) { + if (z < 0.0) { + w[k] = -z; + for (j=1;j<=n;j++) v[j][k]=(-v[j][k]); + } + break; + } + if (its == 30) ntrerror("No convergence in 30 SVDCMP iterations"); + x=w[l]; + nm=k-1; + y=w[nm]; + g=rv1[nm]; + h=rv1[k]; + f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); + g=PYTHAG(f,1.0); + f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x; + c=s=1.0; + for (j=l;j<=nm;j++) { + i=j+1; + g=rv1[i]; + y=w[i]; + h=s*g; + g=c*g; + z=PYTHAG(f,h); + rv1[j]=z; + c=f/z; + s=h/z; + f=x*c+g*s; + g=g*c-x*s; + h=y*s; + y=y*c; + for (jj=1;jj<=n;jj++) { + x=v[jj][j]; + z=v[jj][i]; + v[jj][j]=x*c+z*s; + v[jj][i]=z*c-x*s; + } + z=PYTHAG(f,h); + w[j]=z; + if (z) { + z=1.0/z; + c=f*z; + s=h*z; + } + f=(c*g)+(s*y); + x=(c*y)-(s*g); + for (jj=1;jj<=m;jj++) { + y=a[jj][j]; + z=a[jj][i]; + a[jj][j]=y*c+z*s; + a[jj][i]=z*c-y*s; + } + } + rv1[l]=0.0; + rv1[k]=f; + w[k]=x; + } + } + freeVect(rv1); +} + + + +void svbksb(double** u, double* w, double** v,int m, int n, double* b, double* x) +{ + int jj,j,i; + double s,*tmp; + tmp=allocVect(n); + for (j=1;j<=n;j++) + { + s=0.0; + if (w[j]) + { + for (i=1;i<=m;i++) + s += u[i][j]*b[i]; + s /= w[j]; + } + tmp[j]=s; + } + for (j=1;j<=n;j++) + { + s=0.0; + for (jj=1;jj<=n;jj++) + s += v[j][jj]*tmp[jj]; + x[j]=s; + } + freeVect(tmp); +} + +#undef SIGN +#undef MAX +#undef PYTHAG + + +#if 1 +void DOsvd(float *a,float *res,float *comp,float *values,int nframes,int framesize,int compressedsize) +{ + int *remap; + int i,j; + double **da=allocMatrix(framesize,nframes); + double **v=allocMatrix(nframes,nframes); + double *w=allocVect(nframes); + bool DOFerr = false; + for (i=0;imx) + { + mx=fabs(w[i+1]); + bestat=i; + } + } + + if(mx>0) + { + remap[bestat]=j; + } + else + { + DOFerr = true; + } + } + + if(DOFerr) + { + printf("Warning: To many degrees of freedom! File size may increase\n"); + + for (i=0;imx) + { + mx=fabs(w[i+1]); + bestat=i; + } + } + assert(mx>-.5f); + remap[bestat]=j; + } + // josh **DO NOT** put your dof>nframes mod here + for (i=0;i=3); + base[0]=pnts[0]; + base[1]=pnts[1]; + base[2]=pnts[2]; + for (i=1;i> 5 ) & 63 ) << 2; + b[0] = ( ( color >> 11 ) & 31 ) << 3; + + for ( i = 0; i < 256; i++ ) + { + r[1] = ( d_8to24table[i] >> 0 ) & 0xFF; + g[1] = ( d_8to24table[i] >> 8 ) & 0xFF; + b[1] = ( d_8to24table[i] >> 16 ) & 0xFF; + + d = ( r[1] - r[0] ) * ( r[1] - r[0] ) + + ( g[1] - g[0] ) * ( g[1] - g[0] ) + + ( b[1] - b[0] ) * ( b[1] - b[0] ); + + if ( d < closest_distance_so_far ) + { + closest_distance_so_far = d; + closest_so_far = i; + } + } + + return closest_so_far; +} +*/ + +extern byte BestColor( int, int, int, int, int ); + +void Inverse16_BuildTable( void ) +{ + int i; + + /* + ** create the 16-to-8 table + */ + for ( i = 0; i < 65536; i++ ) + { + int r = i & 31; + int g = ( i >> 5 ) & 63; + int b = ( i >> 11 ) & 31; + + r <<= 3; + g <<= 2; + b <<= 3; + + inverse16to8table[i] = BestColor( r, g, b, 0, 255 ); + } +} + +void Alphalight_Thread (int i) +{ + int j; + float r, g, b; + float mr, mg, mb, ma; + float distortion, bestdistortion; + float v; + + r = (i>>10) * (1.0/16); + g = ((i>>5)&31) * (1.0/16); + b = (i&31) * (1.0/16); + + bestdistortion = 999999; + for (j=0 ; j<16*16*16*16 ; j++) + { + mr = (j>>12) * (1.0/16); + mg = ((j>>8)&15) * (1.0/16); + mb = ((j>>4)&15) * (1.0/16); + ma = (j&15) * (1.0/16); + + v = r * 0.5 - (mr*ma + 0.5*(1.0-ma)); + distortion = v*v; + v = g * 0.5 - (mg*ma + 0.5*(1.0-ma)); + distortion += v*v; + v = b * 0.5 - (mb*ma + 0.5*(1.0-ma)); + distortion += v*v; + + distortion *= 1.0 + ma*4; + + if (distortion < bestdistortion) + { + bestdistortion = distortion; + alphamap[i] = j; + } + } +} + +void Cmd_Alphalight (void) +{ + char savename[1024]; + + GetScriptToken (false); + + if (g_release) + { + ReleaseFile (token); + return; + } + + sprintf (savename, "%s%s", gamedir, token); + printf ("Building alphalight table...\n"); + + RunThreadsOnIndividual (32*32*32, true, Alphalight_Thread); + + SaveFile (savename, (byte *)alphamap, sizeof(alphamap)); +} + + +void Cmd_Inverse16Table( void ) +{ + char savename[1024]; + + if ( g_release ) + { + sprintf (savename, "pics/16to8.dat"); + ReleaseFile( savename ); + return; + } + + sprintf (savename, "%spics/16to8.dat", gamedir); + printf ("Building inverse 16-to-8 table...\n"); + + Inverse16_BuildTable(); + + SaveFile( savename, (byte *) inverse16to8table, sizeof( inverse16to8table ) ); +} diff --git a/Toolkit/Programming/Tools/qdata/tmix.c b/Toolkit/Programming/Tools/qdata/tmix.c new file mode 100644 index 0000000..03c8abd --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/tmix.c @@ -0,0 +1,677 @@ +#include "qdata.h" +#include "flex.h" + +#define MAXFILES 2048 + +typedef struct +{ + int x; + int y; + int w; + int h; + int cw; + int ch; + int rw; + int index; + int depth; + int col; + int baseline; + char name[128]; +} Coords; + +int filenum; +int valid; +Coords in[MAXFILES]; +Coords out; +char outscript[256]; +char sourcedir[256]; +char outusage[256]; +char root[32]; + +int destsize = 0; +byte *pixels = NULL; // Buffer to load image +long *outpixels = NULL; // Buffer to store combined textures +long *usagemap = NULL; // Buffer of usage map +void *bmptemp = NULL; // Buffer of usage map +byte *map = NULL; + +int xcharsize; +int ycharsize; +int dosort = 0; +int missed = 0; +int overlap = 0; +int nobaseline = 0; +int percent; + +////////////////////////////////////////////////// +// Setting the char based usage map // +////////////////////////////////////////////////// + +byte TryPlace(Coords *coord) +{ + int x, y; + byte entry = 0; + byte *mapitem; + + mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw); + + for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw) + { + for (x = 0; x < coord->cw; x++) + { + if (entry |= *mapitem++ & 8) + { + return(entry); + } + } + } + return(entry); +} + +void SetMap(Coords *coord) +{ + int x, y; + byte *mapitem; + + mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw); + + for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw) + for (x = 0; x < coord->cw; x++) + *mapitem++ |= 8; +} + +////////////////////////////////////////////////// +// Setting the pixel based usage map // +////////////////////////////////////////////////// + +void CheckOverlap(Coords *coord) +{ + int x; + int y; + long *dest; + + x = coord->x; + y = coord->y; + + dest = (long *)(usagemap + x + (y * out.w)); + + for (y = 0; y < coord->h; y++, dest += out.w - coord->w) + { + for (x = 0; x < coord->w; x++) + { + if (*dest++) + { + overlap++; + return; + } + } + } +} + +void SetUsageMap(Coords *coord) +{ + int x; + int y; + long *dest; + + x = coord->x; + y = coord->y; + + dest = (long *)(usagemap + x + (y * out.w)); + + for (y = 0; y < coord->h; y++, dest += out.w - coord->w) + { + for (x = 0; x < coord->w; x++) + { + *dest++ = coord->col; + } + } +} + +////////////////////////////////////////////////// +// Flips the BMP image to the correct way up // +////////////////////////////////////////////////// + +void CopyLine(byte *dest, byte *src, int size) +{ + int x; + + for (x = 0; x < size; x++) + *dest++ = *src++; +} + +/****************************************************/ +/* Printing headers etc */ +/****************************************************/ + +void RemoveLeading(char *name) +{ + int i; + char temp[128]; + + for(i = strlen(name) - 1; i > 0; i--) + { + if((name[i] == '\\') || (name[i] == '/')) + { + strcpy(temp, name + i + 1); + strcpy(name, temp); + return; + } + } +} + +void RemoveExt(char *name) +{ + while ((*name != '.') && *name) + name++; + *name = 0; +} + +/****************************************************/ +/* Misc calcualtions */ +/****************************************************/ + +int TotalArea() +{ + int i; + int total = 0; + + for (i = 0; i < (filenum + 2); i++) + total += in[i].w * in[i].h; + + return(total); +} + +/****************************************************/ +/* Setup and checking of all info */ +/****************************************************/ + +void InitVars() +{ + filenum = 0; + valid = 0; + dosort = 0; + missed = 0; + overlap = 0; + nobaseline = 0; + + memset(outscript, 0, sizeof(outscript)); + memset(outscript, 0, sizeof(sourcedir)); + memset(outscript, 0, sizeof(outusage)); + memset(outscript, 0, sizeof(root)); + + memset(in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); +} +void Cleanup() +{ + if (pixels) + free(pixels); + if (usagemap) + free(usagemap); + if (outpixels) + free(outpixels); + if (bmptemp) + free(bmptemp); + if (map) + free(map); +} + +typedef struct glxy_s +{ + float xl, yt, xr, yb; + int w, h, baseline; +} glxy_t; + +int SaveScript(char *name) +{ + FILE *fp; + int i, j; + glxy_t buff; + + if(fp = fopen(name, "wb")) + { + for (j = 0; j < filenum; j++) + { + for (i = 0; i < filenum; i++) + { + if (in[i].index == j) + { + if (in[i].depth) + { + buff.xl = (float)in[i].x / (float)out.w; + buff.yt = (float)in[i].y / (float)out.h; + buff.xr = ((float)in[i].w + (float)in[i].x) / (float)out.w; + buff.yb = ((float)in[i].h + (float)in[i].y) / (float)out.h; + buff.w = in[i].w; + buff.h = in[i].h; + buff.baseline = in[i].baseline; + } + else + { + memset(&buff, 0, sizeof(glxy_t)); + } + fwrite(&buff, 1, sizeof(glxy_t), fp); + i = filenum; + } + } + } + fclose(fp); + return(true); + } + else + return(false); +} + +int GetScriptInfo(char *name) +{ + FILE *fp; + char buffer[256]; + char tempbuff[256]; + char delims[] = {" \t,\n"}; + + printf("Opening script file %s.\n", name); + + if (fp = fopen(name, "r")) + { + while(fgets(buffer, 256, fp)) + { + if (strncmp(buffer, "//", 2) && strncmp(buffer, "\n", 1)) + { + strupr(buffer); + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "OUTPUT") == 0) + { + strcpy(out.name, strtok(NULL, delims)); + strlwr(out.name); + } + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "SOURCEDIR") == 0) + { + strcpy(tempbuff, strtok(NULL, delims)); + strcpy(sourcedir, ExpandPathAndArchive(tempbuff)); + } + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "DOSORT") == 0) + dosort = 1; + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "XCHARSIZE") == 0) + xcharsize = strtol(strtok(NULL, delims), NULL, 0); + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "YCHARSIZE") == 0) + ycharsize = strtol(strtok(NULL, delims), NULL, 0); + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "OUTSCRIPT") == 0) + { + strcpy(outscript, strtok(NULL, delims)); + strlwr(outscript); + } + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "OUTUSAGE") == 0) + strcpy(outusage, strtok(NULL, delims)); + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "POS") == 0) + { + out.w = strtol(strtok(NULL, delims), NULL, 0); + out.h = strtol(strtok(NULL, delims), NULL, 0); + } + + strcpy(tempbuff, buffer); + if (strcmp(strtok(tempbuff, delims), "FILE") == 0) + { + strcpy(in[filenum].name, strtok(NULL, delims)); + in[filenum].x = strtol(strtok(NULL, delims), NULL, 0); + in[filenum].y = strtol(strtok(NULL, delims), NULL, 0); + in[filenum].col = strtol(strtok(NULL, delims), NULL, 0); + filenum++; + } + } + } + fclose(fp); + return(true); + } + else + { + printf("ERROR : Could not open script file.\n"); + return(false); + } +} + +int CheckVars() +{ + int i; + + if (out.name[0] == 0) + { + printf("ERROR : No output name specified.\n"); + return(false); + } + if ((out.w <= 0) || (out.h <= 0)) + { + printf("ERROR : Invalid VRAM coordinates.\n"); + return(false); + } + if (filenum == 0) + { + printf("ERROR : No input files specified.\n"); + return(false); + } + for (i = 0; i < filenum; i++) + if (in[i].name[0] == 0) + { + printf("ERROR : Input filename invalid.\n"); + return(false); + } + return(true); +} + +// Makes sure texture is totally within the output area + +int CheckCoords(Coords *coord) +{ + if ((coord->x + coord->w) > out.w) + return(false); + if ((coord->y + coord->h) > out.h) + return(false); + + return(true); +} +// Gets the width, height, palette width and palette height of each BMP file + +int GetFileDimensions() +{ + int i; + int width, height; + char name[128]; + + for (i = 0; i < filenum; i++) + { + in[i].index = i; + + strcpy(name, sourcedir); + strcat(name, in[i].name); + printf("Getting file dimensions, file : %s \r", in[i].name); + if(FileExists(name)) + { + LoadAnyImage(name, NULL, NULL, &width, &height); + in[i].depth = 32; + in[i].rw = width; + in[i].w = width; // makes it width in + in[i].h = height; + in[i].cw = (in[i].w + (xcharsize - 1)) / xcharsize; + in[i].ch = (in[i].h + (ycharsize - 1)) / ycharsize; + + if (!CheckCoords(&in[i]) && (in[i].x >= 0)) + { + printf("Error : texture %s out of bounds.\n", in[i].name); + return(false); + } + valid++; + } + else + { + in[i].depth = 0; + in[i].x = -1; + in[i].y = -1; + in[i].w = 0; + in[i].h = 0; + } + } + printf("\n\n"); + return(true); +} + +// Sorts files into order for optimal space finding +// Fixed position ones first, followed by the others in descending size +// The theory being that it is easier to find space for smaller textures. +// size = (width + height) +// For space finding it is easier to place a 32x32 than a 128x2 + +#define WEIGHT 0x8000 + +void Swap(Coords *a, Coords *b) +{ + Coords c; + + c = *a; + *a = *b; + *b = c; +} + +void SortInNames() +{ + int i, j; + int largest, largcount; + int size; + + printf("Sorting filenames by size.\n\n"); + + for (j = 0; j < filenum; j++) + { + largest = -1; + largcount = -1; + + for (i = j; i < filenum; i++) + { + if (in[i].depth) + { + size = in[i].w + in[i].h; + + if ((in[i].x < 0) && (size > largest)) + { + largcount = i; + largest = size; + } + } + } + if ((largcount >= 0) && (largcount != j)) + Swap(&in[j], &in[largcount]); + } +} + +int SetVars(char *name) +{ + if (!GetScriptInfo(name)) + return(false); + + if (!CheckVars()) + return(false); + + destsize = out.w * out.h; + + out.cw = out.w / xcharsize; + out.ch = out.h / ycharsize; + + if ((usagemap = (long *)SafeMalloc(destsize * 4, "")) == NULL) + return(false); + if ((outpixels = (long *)SafeMalloc(destsize * 4, "")) == NULL) + return(false); + if ((bmptemp = (void *)SafeMalloc(destsize * 4, "")) == NULL) + return(false); + if ((map = (byte *)SafeMalloc(destsize / (xcharsize * ycharsize), "")) == NULL) + return(false); + + if (GetFileDimensions() == false) + return(false); + + if (dosort) + SortInNames(); + + return(true); +} +/****************************************************/ +/* Actual copying routines */ +/****************************************************/ + +int FindCoords(Coords *coord) +{ + int tx, ty; + + if (coord->x >= 0) + { + SetMap(coord); + return(true); + } + else + { + for (ty = 0; ty < out.ch; ty++) + { + for (tx = 0; tx < out.cw; tx++) + { + coord->x = (tx * xcharsize); + coord->y = (ty * ycharsize); + + if (CheckCoords(coord) && !TryPlace(coord)) + { + SetMap(coord); + return(true); + } + } + } + } + coord->x = -1; + coord->y = -1; + + return(false); +} + +void CheckBaseline(int i) +{ + int y; + long *pix; + + in[i].baseline = -1; + pix = (long *)pixels; + + for(y = 0; y < in[i].h; y++, pix += in[i].w) + { + if((*pix & 0x00ffffff) == 0x00ff00ff) + { + in[i].baseline = y; + break; + } + } + pix = (long *)pixels; + for(y = 0; y < in[i].w * in[i].h; y++, pix++) + { + if((*pix & 0x00ffffff) == 0x00ff00ff) + { + *pix = 0; + } + } + + if(in[i].baseline == -1) + { + printf("\nERROR : %s has no baseline\n", in[i].name); + nobaseline++; + } +} + +void CopyToMain32(Coords *coord) +{ + int x; + int y; + long *source; + long *dest; + + x = coord->x; + y = coord->y; + + source = (long *)pixels; + dest = (long *)(outpixels + x + (y * out.w)); + + for (y = 0; y < coord->h; y++, dest += out.w - coord->w) + { + for (x = 0; x < coord->w; x++) + { + *dest++ = *source++; + } + } +} + +void CreateMain() +{ + int i, count; + int width, height; + char name[128]; + + for (i = 0, count = 0; i < filenum; i++) + { + if (in[i].depth) + { + printf("\rProcessing %d of %d (%d missed, %d overlapping, %d nobase)\r", count + 1, valid, missed, overlap, nobaseline); + count++; + if (!FindCoords(&in[i])) + missed++; + else + { + strcpy(name, sourcedir); + strcat(name, in[i].name); + LoadAnyImage(name, &pixels, NULL, &width, &height); + CheckBaseline(i); + CheckOverlap(&in[i]); + CopyToMain32(&in[i]); + SetUsageMap(&in[i]); + } + } + } +} + +void Cmd_TextureMix() +{ + miptex32_t *qtex32; + char filename[1024]; + int size; + + InitVars(); + + GetScriptToken (false); + + strcpy(root, token); + RemoveExt(root); + RemoveLeading(root); + + strcpy(filename, ExpandPathAndArchive(token)); + if (SetVars(filename)) + { + // Create combined texture + percent = ((TotalArea() * 100) / (out.w * out.h)); + printf("Total area consumed : %d%%\n", percent); + printf("Texture resolution : %dx%d pixels.\n", xcharsize, ycharsize); + CreateMain(); + + // Save image as m32 + sprintf (filename, "%spics/misc/%s.m32", gamedir, out.name); + qtex32 = CreateMip32((unsigned long *)outpixels, out.w, out.h, &size, false); + + qtex32->contents = 0; + qtex32->value = 0; + qtex32->scale_x = 1.0; + qtex32->scale_y = 1.0; + sprintf (qtex32->name, "misc/%s", out.name); + + printf ("\n\nwriting %s\n", filename); + SaveFile (filename, (byte *)qtex32, size); + free (qtex32); + + // Save out script file + sprintf (filename, "%spics/misc/%s.fnt", gamedir, outscript); + printf("Writing %s as script file\n", filename); + if (!SaveScript(filename)) + { + printf("Unable to save output script.\n"); + } + } + printf("Everythings groovy.\n"); + Cleanup(); +} + +// end + diff --git a/Toolkit/Programming/Tools/qdata/tonet.bat b/Toolkit/Programming/Tools/qdata/tonet.bat new file mode 100644 index 0000000..eb672c2 --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/tonet.bat @@ -0,0 +1 @@ +xcopy/d release\qdata.exe r:\bin_nt diff --git a/Toolkit/Programming/Tools/qdata/video.c b/Toolkit/Programming/Tools/qdata/video.c new file mode 100644 index 0000000..653fbdc --- /dev/null +++ b/Toolkit/Programming/Tools/qdata/video.c @@ -0,0 +1,1127 @@ +// To do + +// Sound error handling (when sound too short) +// rle b4 huffing +// adpcm encoding of sound + +#if 0 +#include "qdata.h" +#include "flex.h" +#include "fc.h" +#include "adpcm.h" + +#define MIN_REPT 15 +#define MAX_REPT 0 +#define HUF_TOKENS (256 + MAX_REPT) + +#define BLOCKSIZE 8 + +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#define SQRT2 1.414213562 + +typedef struct hnode_s +{ + int count; + qboolean used; + int children[2]; +} hnode_t; + +typedef struct +{ + int rate; + int width; + int channels; + int loopstart; + int samples; + int dataofs; // chunk starts this many bytes from file start +} wavinfo_t; + +// These weren`t picked out my ass.... +// They were defined at http://www.rahul.net/jfm/dct.html +// However, I think he plucked them out of his ass..... + +float Quantise[BLOCKSIZE * BLOCKSIZE]; + +float LUT_Quantise[BLOCKSIZE * BLOCKSIZE] = +{ + 16.0F/16.0F, 11.0F/16.0F, 10.0F/16.0F, 16.0F/16.0F, 24.0F/16.0F, 40.0F/16.0F, 51.0F/16.0F, 61.0F/16.0F, + 12.0F/16.0F, 13.0F/16.0F, 14.0F/16.0F, 19.0F/16.0F, 26.0F/16.0F, 58.0F/16.0F, 60.0F/16.0F, 55.0F/16.0F, + 14.0F/16.0F, 13.0F/16.0F, 16.0F/16.0F, 24.0F/16.0F, 40.0F/16.0F, 57.0F/16.0F, 69.0F/16.0F, 56.0F/16.0F, + 14.0F/16.0F, 17.0F/16.0F, 22.0F/16.0F, 29.0F/16.0F, 51.0F/16.0F, 87.0F/16.0F, 80.0F/16.0F, 62.0F/16.0F, + 18.0F/16.0F, 22.0F/16.0F, 37.0F/16.0F, 56.0F/16.0F, 68.0F/16.0F,109.0F/16.0F,103.0F/16.0F, 77.0F/16.0F, + 24.0F/16.0F, 35.0F/16.0F, 55.0F/16.0F, 64.0F/16.0F, 81.0F/16.0F,104.0F/16.0F,113.0F/16.0F, 92.0F/16.0F, + 49.0F/16.0F, 64.0F/16.0F, 78.0F/16.0F, 87.0F/16.0F,103.0F/16.0F,121.0F/16.0F,120.0F/16.0F,101.0F/16.0F, + 72.0F/16.0F, 92.0F/16.0F, 95.0F/16.0F, 98.0F/16.0F,112.0F/16.0F,100.0F/16.0F,103.0F/16.0F, 99.0F/16.0F +}; + +int LUT_ZZ[BLOCKSIZE * BLOCKSIZE] = +{ + 0, + 1, 8, + 16, 9, 2, + 3, 10, 17, 24, + 32, 25, 18, 11, 4, + 5, 12, 19, 26, 33, 40, + 48, 41, 34, 27, 20, 13, 6, + 7, 14, 21, 28, 35, 42, 49, 56, + 57, 50, 43, 36, 29, 22, 15, + 23, 30, 37, 44, 51, 58, + 59, 52, 45, 38, 31, + 39, 46, 53, 60, + 61, 54, 47, + 55, 62, + 63 +}; + +char base[32]; + +byte *soundtrack; + +byte scaled[256][HUF_TOKENS]; +unsigned int charbits1[256][HUF_TOKENS]; +int charbitscount1[256][HUF_TOKENS]; +hnode_t hnodes1[256][HUF_TOKENS * 2]; +int numhnodes1[256]; +int order0counts[256]; +int numhnodes; +hnode_t hnodes[512]; +unsigned charbits[256]; +int charbitscount[256]; + +CineHead_t cinehead; + +byte *data_p; +byte *iff_end; +byte *last_chunk; +byte *iff_data; +int iff_chunk_len; + +float dctbase[BLOCKSIZE][BLOCKSIZE]; +float red[BLOCKSIZE * BLOCKSIZE]; +float green[BLOCKSIZE * BLOCKSIZE]; +float blue[BLOCKSIZE * BLOCKSIZE]; +float temp[BLOCKSIZE * BLOCKSIZE]; + +wavinfo_t wavinfo; +adpcm_t adpcm; + +/* +=============================================================================== + +WAV loading + +=============================================================================== +*/ + +/* Intel ADPCM step variation table */ +static int indexTable[16] = +{ + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8, +}; + +static int stepsizeTable[89] = +{ + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + +#if 0 +static void adpcm_decoder(char *indata, short *outdata, int len, adpcm_state_t *state) +{ + signed char *inp; /* Input buffer pointer */ + short *outp; /* output buffer pointer */ + int sign; /* Current adpcm sign bit */ + int delta; /* Current adpcm output value */ + int step; /* Stepsize */ + int valpred; /* Predicted value */ + int vpdiff; /* Current change to valpred */ + int index; /* Current step change index */ + int inputbuffer; /* place to keep next 4-bit value */ + int bufferstep; /* toggle between inputbuffer/input */ + + outp = outdata; + inp = (signed char *)indata; + + valpred = state->valprev; + index = state->index; + step = stepsizeTable[index]; + + bufferstep = 0; + + for(; len > 0; len--) + { + /* Step 1 - get the delta value */ + if (bufferstep) + delta = inputbuffer & 0xf; + else + { + inputbuffer = *inp++; + delta = (inputbuffer >> 4) & 0xf; + } + bufferstep = !bufferstep; + + /* Step 2 - Find new index value (for later) */ + index += indexTable[delta]; + if(index < 0) + index = 0; + if(index > 88) + index = 88; + + /* Step 3 - Separate sign and magnitude */ + sign = delta & 8; + delta = delta & 7; + + /* Step 4 - Compute difference and new predicted value */ + /* + ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment + ** in adpcm_coder. + */ + vpdiff = step >> 3; + if(delta & 4) + vpdiff += step; + if(delta & 2) + vpdiff += step>>1; + if(delta & 1) + vpdiff += step>>2; + + if (sign) + valpred -= vpdiff; + else + valpred += vpdiff; + + /* Step 5 - clamp output value */ + if (valpred > 32767) + valpred = 32767; + else if (valpred < -32768) + valpred = -32768; + + /* Step 6 - Update step value */ + step = stepsizeTable[index]; + + /* Step 7 - Output value */ + *outp++ = valpred; + } + + state->valprev = valpred; + state->index = index; +} +#endif + +void adpcm_coder(short *inp, adpcm_t *adpcm) +{ + int val; /* Current input sample value */ + int sign; /* Current adpcm sign bit */ + int delta; /* Current adpcm output value */ + int diff; /* Difference between val and valprev */ + int step; /* Stepsize */ + int valpred; /* Predicted output value */ + int vpdiff; /* Current change to valpred */ + int index; /* Current step change index */ + int outputbuffer; /* place to keep previous 4-bit value */ + int bufferstep; /* toggle between outputbuffer/output */ + adpcm_state_t *state; + char *outp; + int len; + + state = &adpcm->state; + len = state->count; + outp = adpcm->adpcm; + + valpred = state->in_valprev; + index = state->in_index; + step = stepsizeTable[index]; + + bufferstep = 1; + while(len--) + { + val = *inp++; + + /* Step 1 - compute difference with previous value */ + diff = val - valpred; + sign = (diff < 0) ? 8 : 0; + if (sign) + diff = -diff; + + /* Step 2 - Divide and clamp */ + /* Note: + ** This code *approximately* computes: + ** delta = diff*4/step; + ** vpdiff = (delta+0.5)*step/4; + ** but in shift step bits are dropped. The net result of this is + ** that even if you have fast mul/div hardware you cannot put it to + ** good use since the fixup would be too expensive. + */ + delta = 0; + vpdiff = (step >> 3); + + if (diff >= step) + { + delta = 4; + diff -= step; + vpdiff += step; + } + step >>= 1; + if (diff >= step) + { + delta |= 2; + diff -= step; + vpdiff += step; + } + step >>= 1; + if (diff >= step) + { + delta |= 1; + vpdiff += step; + } + + /* Step 3 - Update previous value */ + if (sign) + valpred -= vpdiff; + else + valpred += vpdiff; + + /* Step 4 - Clamp previous value to 16 bits */ + if (valpred > 32767) + valpred = 32767; + else if (valpred < -32768) + valpred = -32768; + + /* Step 5 - Assemble value, update index and step values */ + delta |= sign; + + index += indexTable[delta]; + if (index < 0) + index = 0; + if (index > 88) + index = 88; + step = stepsizeTable[index]; + + /* Step 6 - Output value */ + if (bufferstep) + outputbuffer = (delta << 4) & 0xf0; + else + *outp++ = (delta & 0x0f) | outputbuffer; + + bufferstep = !bufferstep; + } + + /* Output last step, if needed */ + if(!bufferstep) + *outp++ = outputbuffer; + + state->out_valprev = valpred; + state->out_index = index; +} + +void FindNextChunk(char *name) +{ + while(1) + { + data_p = last_chunk; + + if(data_p >= iff_end) + { // didn't find the chunk + data_p = NULL; + return; + } + + data_p += 4; + iff_chunk_len = *(long *)data_p; + data_p += 4; + if(iff_chunk_len < 0) + { + data_p = NULL; + return; + } + + data_p -= 8; + last_chunk = data_p + 8 + ((iff_chunk_len + 1) & ~1); + if (!strncmp(data_p, name, 4)) + return; + } +} + +void FindChunk(char *name) +{ + last_chunk = iff_data; + FindNextChunk (name); +} + +void DumpChunks(void) +{ + char str[5]; + + str[4] = 0; + data_p = iff_data; + do + { + memcpy (str, data_p, 4); + data_p += 4; + iff_chunk_len = *(long *)data_p; + data_p += 4; + printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); + data_p += (iff_chunk_len + 1) & ~1; + } + while(data_p < iff_end); +} + +/* +============ +GetWavinfo +============ +*/ +wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) +{ + wavinfo_t info; + int i; + int format; + int samples; + + memset(&info, 0, sizeof(info)); + + if (!wav) + return(info); + + iff_data = wav; + iff_end = wav + wavlength; + +// find "RIFF" chunk + FindChunk("RIFF"); + if (!(data_p && !strncmp(data_p + 8, "WAVE", 4))) + { + printf("Missing RIFF/WAVE chunks\n"); + return(info); + } + +// get "fmt " chunk + iff_data = data_p + 12; + + FindChunk("fmt "); + if(!data_p) + { + printf("Missing fmt chunk\n"); + return(info); + } + data_p += 8; + format = *(short *)data_p; + data_p += 2; + if (format != 1) + { + printf("Microsoft PCM format only\n"); + return(info); + } + + info.channels = *(short *)data_p; + data_p += 2; + info.rate = *(long *)data_p; + data_p += 4; + data_p += 6; + info.width = *(short *)data_p / 8; + data_p += 2; + +// get cue chunk + FindChunk("cue "); + if(data_p) + { + data_p += 32; + info.loopstart = *(long *)data_p; + data_p += 4; + +// if the next chunk is a LIST chunk, look for a cue length marker + FindNextChunk ("LIST"); + if(data_p) + { +// this is not a proper parse, but it works with cooledit... + if (!strncmp (data_p + 28, "mark", 4)) + { + data_p += 24; + i = *(long *)data_p; // samples in loop + data_p += 4; + info.samples = info.loopstart + i; + } + } + } + else + info.loopstart = -1; + +// find data chunk + FindChunk("data"); + if (!data_p) + { + printf("Missing data chunk\n"); + return(info); + } + + data_p += 4; + samples = *(long *)data_p; + data_p += 4; + + if (info.samples) + { + if(samples < info.samples) + Error ("Sound %s has a bad loop length", name); + } + else + info.samples = samples; + + info.dataofs = data_p - wav; + return(info); +} + +// ============== +// LoadSoundtrack +// ============== + +void LoadSoundtrack() +{ + char name[1024]; + FILE *f; + int len; + + soundtrack = NULL; + sprintf (name, "%svideo/%s/%s.wav", gamedir, base, base); + printf ("\nLoading sound : %s\n", name); + f = fopen (name, "rb"); + if (!f) + { + printf ("\nNo soundtrack for %s\n", base); + return; + } + len = Q_filelength(f); + soundtrack = SafeMalloc(len, "LoadSoundtrack"); + fread(soundtrack, 1, len, f); + fclose(f); + + wavinfo = GetWavinfo(name, soundtrack, len); + adpcm.state.out_valprev = 0; + adpcm.state.out_index = 0; +} + +// ================== +// WriteSound +// ================== + +int WriteSound(FILE *output, int frame, int numframes) +{ + int start, end; + int count; + int empty = 0; + int width; + char *work; + + width = wavinfo.width * wavinfo.channels; + start = ((frame * wavinfo.rate / 14) + 31) & 0xffffffe0; // start sample + end = (((frame + numframes) * wavinfo.rate / 14) + 31) & 0xffffffe0; // end sample + count = end - start; + + work = soundtrack + wavinfo.dataofs + (start * width); + adpcm.state.count = count * wavinfo.channels; // Number of samples + adpcm.state.in_valprev = adpcm.state.out_valprev; + adpcm.state.in_index = adpcm.state.out_index; + adpcm_coder((short *)work, &adpcm); + WriteHeader(output, FC_SOUND_22KMADPCM, FC_ADPCM_VERSION, (adpcm.state.count / 2) + sizeof(adpcm_state_t), (char *)&adpcm); + return(count / 2); +} +// ============================== +// Basic run length encoder +// ============================== + +char *RLEZZ(char *in, char *out) +{ + int srun; + char count; + int idx = 0; + + while(idx < 64) + { + srun = idx; // Start of run + + while(idx < 63) + { + if(in[LUT_ZZ[idx]] != in[LUT_ZZ[idx + 1]]) + break; + idx++; + } + count = (char)(idx - srun); // count of repeated bytes + + if(!count) + { + while(idx < 63) + { + if(in[LUT_ZZ[idx]] == in[LUT_ZZ[idx + 1]]) + break; + idx++; + } + if(idx == 63) + idx++; + + count = (char)(idx - srun); // count of unique bytes + *out++ = count; + while(count--) + *out++ = in[LUT_ZZ[srun++]]; + } + else + { + *out++ = -(count + 1); + *out++ = in[LUT_ZZ[idx]]; + idx++; + } + } + return(out); +} + +// ============================== +// Discrete Cosine Transformation +// ============================== + +void init_base(float quant) +{ + int y, x; + + for(y = 0; y < BLOCKSIZE; y++) + for(x = 0; x < BLOCKSIZE; x++) + { + if(y == 0) + dctbase[y][x] = 1; + else + dctbase[y][x] = SQRT2 * cos(((x * 2 + 1) * y * M_PI) / (BLOCKSIZE * 2)); + } + + for(y = 0; y < BLOCKSIZE * BLOCKSIZE; y++) + Quantise[y] = LUT_Quantise[y] / quant; +} + +void SplitComponents(byte *src, int width, int height) +{ + int i, j; + float *tr = red; + float *tg = green; + float *tb = blue; + + for(i = 0; i < BLOCKSIZE; i++, src += (width - BLOCKSIZE) * 4) + for(j = 0; j < BLOCKSIZE; j++) + { + *tr++ = ((float)*src++) - 128.0F; + *tg++ = ((float)*src++) - 128.0F; + *tb++ = ((float)*src++) - 128.0F; + src++; + } +} + +void transferH(float *src, float *dst) +{ + int y, dx, dy; + float sum; + float *work; + + for(y = 0; y < BLOCKSIZE; y++, src += BLOCKSIZE) + { + for(dy = 0; dy < BLOCKSIZE; dy++) + { + sum = 0; + work = src; + for(dx = 0; dx < BLOCKSIZE; dx++, work++) + sum += dctbase[dy][dx] * *work; + + *dst++ = sum / BLOCKSIZE; + } + } +} + +void transferV(float *src, float *dst) +{ + int x, dy, fy; + float sum; + float *work; + + for(x = 0; x < BLOCKSIZE; x++, src++, dst++) + { + for(fy = 0; fy < BLOCKSIZE; fy++) + { + sum = 0; + work = src; + for(dy = 0; dy < BLOCKSIZE; dy++, work += BLOCKSIZE) + sum += dctbase[fy][dy] * *work; + + dst[fy * BLOCKSIZE] = sum / BLOCKSIZE; + } + } +} + +char *Combine(byte *dst, float *p, float *q) +{ + int i, j; + byte rlesrc[BLOCKSIZE * BLOCKSIZE]; + int c; + byte *work; + + work = rlesrc; + for(j = 0; j < BLOCKSIZE; j++) + for(i = 0; i < BLOCKSIZE; i++) + { + c = (int)((*p++ / *q++) + 128.5F); + c -= 128; + + if(c < -128) + c = -128; + if(c > 127) + c = 127; + + *work++ = (char)c; + } + + dst = RLEZZ(rlesrc, dst); + return(dst); +} + +char *CombineComponents(char *dst, int width, int height) +{ + dst = Combine(dst, red, Quantise); + dst = Combine(dst, green, Quantise); + dst = Combine(dst, blue, Quantise); + return(dst); +} + +void DCT(cblock_t *out, cblock_t in, int width, int height) +{ + int x, y; + char *cursrc; + char *curdst; + + curdst = out->data; + for(y = 0; y < height; y += BLOCKSIZE) + for(x = 0; x < width; x += BLOCKSIZE) + { + cursrc = in.data + ((y * width) + x) * 4; + SplitComponents(cursrc, width, height); + transferH(red, temp); + transferV(temp, red); + transferH(green, temp); + transferV(temp, green); + transferH(blue, temp); + transferV(temp, blue); + curdst = CombineComponents(curdst, width, height); + } + out->count = curdst - out->data; +} + +// ================== +// BuildChars1 +// ================== + +void BuildChars1(int prev, int nodenum, unsigned bits, int bitcount) +{ + hnode_t *node; + + if(nodenum < HUF_TOKENS) + { + if (bitcount > 32) + Error("bitcount > 32"); + charbits1[prev][nodenum] = bits; + charbitscount1[prev][nodenum] = bitcount; + return; + } + + node = &hnodes1[prev][nodenum]; + bits <<= 1; + BuildChars1(prev, node->children[0], bits, bitcount+1); + bits |= 1; + BuildChars1(prev, node->children[1], bits, bitcount+1); +} + +// ================== +// SmallestNode1 +// ================== + +int SmallestNode1(hnode_t *hnodes, int numhnodes) +{ + int i; + int best, bestnode; + + best = 99999999; + bestnode = -1; + for(i = 0; i < numhnodes; i++) + { + if(hnodes[i].used) + continue; + if(!hnodes[i].count) + continue; + if(hnodes[i].count < best) + { + best = hnodes[i].count; + bestnode = i; + } + } + + if (bestnode == -1) + return(-1); + + hnodes[bestnode].used = true; + return(bestnode); +} + +// ================== +// BuildTree1 +// ================== + +void BuildTree1(int prev) +{ + hnode_t *node, *nodebase; + int numhnodes; + + // build the nodes + numhnodes = HUF_TOKENS; + nodebase = hnodes1[prev]; + while(1) + { + node = &nodebase[numhnodes]; + + // pick two lowest counts + node->children[0] = SmallestNode1 (nodebase, numhnodes); + if (node->children[0] == -1) + break; // no more + + node->children[1] = SmallestNode1 (nodebase, numhnodes); + if (node->children[1] == -1) + break; + + node->count = nodebase[node->children[0]].count + + nodebase[node->children[1]].count; + numhnodes++; + } + numhnodes1[prev] = numhnodes-1; + BuildChars1 (prev, numhnodes-1, 0, 0); +} + +// ================== +// Huffman1_Count +// ================== + +void Huffman1_Count(cblock_t in) +{ + int i; + int prev; + int v; + int rept; + + prev = 0; + for(i = 0; i < in.count; i++) + { + v = in.data[i]; + order0counts[v]++; + hnodes1[prev][v].count++; + prev = v; + + for(rept = 1; (i + rept < in.count) && (rept < MAX_REPT); rept++) + if(in.data[i+rept] != v) + break; + if(rept > MIN_REPT) + { + hnodes1[prev][255 + rept].count++; + i += rept - 1; + } + } +} + +// ================== +// Huffman1_Build +// ================== + +void Huffman1_Build() +{ + int i, j, v; + int max; + int total; + + for(i = 0; i < 256; i++) + { +// normalize and save the counts + max = 0; + for (j = 0; j < HUF_TOKENS; j++) + { + if (hnodes1[i][j].count > max) + max = hnodes1[i][j].count; + } + if (max == 0) + max = 1; + total = 0; +// easy to overflow 32 bits here! + for(j = 0; j < HUF_TOKENS; j++) + { + v = (hnodes1[i][j].count * (double) 255 + max - 1) / max; + if (v > 255) + Error ("v > 255"); + scaled[i][j] = hnodes1[i][j].count = v; + if (v) + total++; + } + if (total == 1) + { // must have two tokens + if (!scaled[i][0]) + scaled[i][0] = hnodes1[i][0].count = 1; + else + scaled[i][1] = hnodes1[i][1].count = 1; + } + BuildTree1 (i); + } +} + +// ================== +// Huffman1 +// Order 1 compression with pre-built table +// ================== + +cblock_t Huffman1(cblock_t in) +{ + int i; + int outbits, c; + unsigned bits; + byte *out_p; + cblock_t out; + int prev; + int v; + int rept; + + out_p = out.data = SafeMalloc((in.count * 2) + 1024 + 4, "Huffman"); + memset(out_p, 0, (in.count * 2) + 1024 + 4); + + // leave space for compressed count + out_p += 4; + // write count + *(long *)out_p = in.count; + out_p += 4; + + // write bits + outbits = 0; + prev = 0; + for(i = 0; i < in.count; i++) + { + v = in.data[i]; + + c = charbitscount1[prev][v]; + bits = charbits1[prev][v]; + if (!c) + Error ("!bits"); + while (c) + { + c--; + if (bits & (1 << c)) + out_p[outbits>>3] |= 1 << (outbits & 7); + outbits++; + } + + prev = v; + // check for repeat encodes + for(rept = 1; (i + rept < in.count) && (rept < MAX_REPT); rept++) + if(in.data[i + rept] != v) + break; + if (rept > MIN_REPT) + { + c = charbitscount1[prev][255 + rept]; + bits = charbits1[prev][255 + rept]; + if (!c) + Error ("!bits"); + while (c) + { + c--; + if(bits & (1 << c)) + out_p[outbits >> 3] |= 1 << (outbits & 7); + outbits++; + } + i += rept - 1; + } + } + out_p += (outbits + 7) >> 3; + out.count = out_p - out.data; + + out_p = out.data; + *(long *)out_p = out.count; + return(out); +} +// =================== +// LoadFrame +// =================== + +void LoadFrame(cblock_t *out, char *base, int frame) +{ + cblock_t in; + int width, height; + char name[1024]; + FILE *f; + + in.data = NULL; + in.count = -1; + sprintf (name, "%svideo/%s/%s%04i.tga", gamedir, base, base, frame); + + f = fopen(name, "rb"); + if (!f) + { + out->data = NULL; + return; + } + fclose (f); + + LoadTGA(name, &in.data, &width, &height); + if((width != cinehead.Width) || (height != cinehead.Height)) + { + free(in.data); + printf("Invalid picture size\n"); + out->data = NULL; + return; + } + out->data = SafeMalloc(width * height * 3, "LoadFrame"); // rle could possibly expand file so this not 100% safe (however DCT should force a lot of compression) + DCT(out, in, width, height); + free(in.data); +} + +// ================================== +// Cmd_Video +// +// video +// ================================== + +void Cmd_Video() +{ + char savename[256]; + char name[256]; + FILE *output; + int frame; + int width, height; + cblock_t in, huffman; + int size; + float dctconst; + int maxsize, ssize; + int min_rle_size, warnings; + int ave_image, ave_sound; + + GetScriptToken(false); + strcpy(base, token); + if (g_release) + return; + + GetScriptToken(false); + dctconst = atof(token); + GetScriptToken(false); + maxsize = atoi(token); + + sprintf (savename, "%svideo/%s.cin", gamedir, base); + + // clear stuff + memset(charbits1, 0, sizeof(charbits1)); + memset(charbitscount1, 0, sizeof(charbitscount1)); + memset(hnodes1, 0, sizeof(hnodes1)); + memset(numhnodes1, 0, sizeof(numhnodes1)); + memset(order0counts, 0, sizeof(order0counts)); + + // load the entire sound wav file if present + LoadSoundtrack(); + + cinehead.SndRate = wavinfo.rate; + cinehead.SndWidth = wavinfo.width; + cinehead.SndChannels = wavinfo.channels; + + sprintf(name, "%svideo/%s/%s0000.tga", gamedir, base, base); + printf("Loading sequence : %s\n", name); + printf("DCT constant : %f\n", dctconst); + + LoadTGA (name, NULL, &width, &height); + + output = fopen (savename, "wb"); + if (!output) + Error ("Can't open %s", savename); + + if((width % BLOCKSIZE) || (height % BLOCKSIZE)) + Error("Width and height must be a multiple of %d", BLOCKSIZE); + + cinehead.Width = width; + cinehead.Height = height; + init_base(dctconst); + + // build the dictionary + printf("Counting : "); + min_rle_size = 0; + for (frame = 0; ; frame++) + { + printf("."); + LoadFrame(&in, base, frame); + if(!in.data) + break; + Huffman1_Count(in); + if(in.count > min_rle_size) + min_rle_size = in.count; + free(in.data); + } + printf ("\n"); + cinehead.NumFrames = frame; + printf("Num Frames : %d\n", frame); + cinehead.MaxRleSize = (min_rle_size + 0x1f) & 0xfffffe0; + cinehead.MaxSndSize = ((4 * wavinfo.rate * wavinfo.channels / 14) + 0x1f) & 0xffffffe0; + + WriteHeader(output, FC_HEADER_NAME, FC_HEADER_VERSION, sizeof(CineHead_t), &cinehead); + + // build nodes and write counts + Huffman1_Build(); + WriteHeader(output, FC_HUFFBITS_NAME, FC_HUFFBITS_VERSION, sizeof(scaled), scaled); + WriteHeader(output, FC_QUANT_NAME, FC_QUANT_VERSION, sizeof(Quantise), Quantise); + + ave_image = 0; + ave_sound = 0; + warnings = 0; + // compress it with the dictionary + if(soundtrack) + { + ssize = WriteSound(output, frame, 4); + ave_sound += ssize; + } + + for (frame = 0; frame < cinehead.NumFrames; frame++) + { + // save some sound samples + printf ("Packing : ", frame); + LoadFrame(&in, base, frame); + + // save the image + huffman = Huffman1(in); + printf ("%d bytes rle, %d bytes huffman", in.count, huffman.count); + size = (huffman.count + 3) & 0xfffffffc; // round up to longwords + if(size > maxsize) + { + printf(" ** WARNING **"); + warnings++; + } + printf("\n"); + ave_image += huffman.count; + + WriteHeader(output, FC_IMAGE_NAME, FC_IMAGE_VERSION, size, huffman.data); + if(soundtrack) + { + ssize = WriteSound(output, frame + 4, 1); + ave_sound += ssize; + } + + free (in.data); + free (huffman.data); + } + printf("\nTotal size: %d (headers + %d image + %d sound)\n", ftell(output), ave_image, ave_sound); + printf("Data rate : %d bytes per sec (image and sound)\n", (ave_image + ave_sound) / cinehead.NumFrames); + printf("Cin created ok with %d warnings.\n", warnings); + fclose (output); + + if (soundtrack) + free (soundtrack); +} +#endif + +void Cmd_Video() +{ +} + +// end \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qe4/brush.c b/Toolkit/Programming/Tools/qe4/brush.c new file mode 100644 index 0000000..3f475f8 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/brush.c @@ -0,0 +1,1811 @@ +#include +#include "qe3.h" + +#define MAX_POINTS_ON_WINDING 64 + + +void FreeWinding (winding_t *w); +winding_t *Winding_Clone( winding_t *w ); +winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon); + +void PrintWinding (winding_t *w) +{ + int i; + + printf ("-------------\n"); + for (i=0 ; inumpoints ; i++) + printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0] + , w->points[i][1], w->points[i][2]); +} + +void PrintPlane (plane_t *p) +{ + printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1], + p->normal[2], p->dist); +} + +void PrintVector (vec3_t v) +{ + printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]); +} + + +face_t *Face_Clone (face_t *f) +{ + face_t *n; + + n = Face_Alloc(); + n->texdef = f->texdef; + memcpy (n->planepts, f->planepts, sizeof(n->planepts)); + + // all other fields are derived, and will be set by Brush_Build + return n; +} + +//============================================================================ + +#define BOGUS_RANGE 18000 + + +/* +================== +NewWinding +================== +*/ +winding_t *NewWinding (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("NewWinding: %i points", points); + + size = (int)((winding_t *)0)->points[points]; + w = malloc (size); + memset (w, 0, size); + w->maxpoints = points; + + return w; +} + + +void FreeWinding (winding_t *w) +{ + free (w); +} + + +/* +================== +Winding_Clone +================== +*/ +winding_t *Winding_Clone(winding_t *w) +{ + int size; + winding_t *c; + + size = (int)((winding_t *)0)->points[w->numpoints]; + c = qmalloc (size); + memcpy (c, w, size); + return c; +} + + +/* +================== +ClipWinding + +Clips the winding to the plane, returning the new winding on the positive side +Frees the input winding. +If keepon is true, an exactly on-plane winding will be saved, otherwise +it will be clipped away. +================== +*/ +winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon) +{ + vec_t dists[MAX_POINTS_ON_WINDING]; + int sides[MAX_POINTS_ON_WINDING]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *neww; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (keepon && !counts[0] && !counts[1]) + return in; + + if (!counts[0]) + { + FreeWinding (in); + return NULL; + } + if (!counts[1]) + return in; + + maxpts = in->numpoints+4; // can't use counts[0]+2 because + // of fp grouping errors + neww = NewWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (neww->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + +// free the original winding + FreeWinding (in); + + return neww; +} + + + +/* +============================================================================= + + TEXTURE COORDINATES + +============================================================================= +*/ + + +/* +================== +textureAxisFromPlane +================== +*/ +vec3_t baseaxis[18] = +{ +{0,0,1}, {1,0,0}, {0,-1,0}, // floor +{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling +{1,0,0}, {0,1,0}, {0,0,-1}, // west wall +{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall +{0,1,0}, {1,0,0}, {0,0,-1}, // south wall +{0,-1,0}, {1,0,0}, {0,0,-1} // north wall +}; + +void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) +{ + int bestaxis; + float dot,best; + int i; + + best = 0; + bestaxis = 0; + + for (i=0 ; i<6 ; i++) + { + dot = DotProduct (pln->normal, baseaxis[i*3]); + if (dot > best) + { + best = dot; + bestaxis = i; + } + } + + VectorCopy (baseaxis[bestaxis*3+1], xv); + VectorCopy (baseaxis[bestaxis*3+2], yv); +} + + +float lightaxis[3] = {0.6, 0.8, 1.0}; +/* +================ +SetShadeForPlane + +Light different planes differently to +improve recognition +================ +*/ +float SetShadeForPlane (plane_t *p) +{ + int i; + float f; + + // axial plane + for (i=0 ; i<3 ; i++) + if (fabs(p->normal[i]) > 0.9) + { + f = lightaxis[i]; + return f; + } + + // between two axial planes + for (i=0 ; i<3 ; i++) + if (fabs(p->normal[i]) < 0.1) + { + f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2; + return f; + } + + // other + f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3; + return f; +} + +vec3_t vecs[2]; +float shift[2]; + +/* +================ +BeginTexturingFace +================ +*/ +void BeginTexturingFace (brush_t *b, face_t *f, qtexture_t *q) +{ + vec3_t pvecs[2]; + int sv, tv; + float ang, sinv, cosv; + float ns, nt; + int i,j; + float shade; + + // get natural texture axis + TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]); + + // set shading for face + shade = SetShadeForPlane (&f->plane); + if (camera.draw_mode == cd_texture && !b->owner->eclass->fixedsize) + { + f->d_color[0] = + f->d_color[1] = + f->d_color[2] = shade; + } + else + { + f->d_color[0] = shade*q->color[0]; + f->d_color[1] = shade*q->color[1]; + f->d_color[2] = shade*q->color[2]; + } + + if (camera.draw_mode != cd_texture) + return; + + if (!f->texdef.scale[0]) + f->texdef.scale[0] = q->scale_x; + if (!f->texdef.scale[1]) + f->texdef.scale[1] = q->scale_y; + + +// rotate axis + if (f->texdef.rotate == 0) + { sinv = 0 ; cosv = 1; } + else if (f->texdef.rotate == 90) + { sinv = 1 ; cosv = 0; } + else if (f->texdef.rotate == 180) + { sinv = 0 ; cosv = -1; } + else if (f->texdef.rotate == 270) + { sinv = -1 ; cosv = 0; } + else + { + ang = f->texdef.rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + } + + if (pvecs[0][0]) + sv = 0; + else if (pvecs[0][1]) + sv = 1; + else + sv = 2; + + if (pvecs[1][0]) + tv = 0; + else if (pvecs[1][1]) + tv = 1; + else + tv = 2; + + for (i=0 ; i<2 ; i++) + { + ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv]; + nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv]; + vecs[i][sv] = ns; + vecs[i][tv] = nt; + } + + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + vecs[i][j] = vecs[i][j] / f->texdef.scale[i]; +} + + +void _EmitTextureCoordinates (vec3_t v, qtexture_t *q) +{ + float s, t; + + s = DotProduct (v, vecs[0]); + t = DotProduct (v, vecs[1]); + + s += shift[0]; + t += shift[1]; + + s /= q->width; + t /= q->height; + + glTexCoord2f (s, t); +} + +void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f) +{ + float s, t, ns, nt; + float ang, sinv, cosv; + vec3_t vecs[2]; + texdef_t *td; + + // get natural texture axis + TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]); + + td = &f->texdef; + + ang = td->rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + + if (!td->scale[0]) + td->scale[0] = 1; + if (!td->scale[1]) + td->scale[1] = 1; + + s = DotProduct(xyzst, vecs[0]); + t = DotProduct(xyzst, vecs[1]); + + ns = cosv * s - sinv * t; + nt = sinv * s + cosv * t; + + s = ns/td->scale[0] + td->shift[0]; + t = nt/td->scale[1] + td->shift[1]; + + // gl scales everything from 0 to 1 + s /= q->width; + t /= q->height; + + xyzst[3] = s; + xyzst[4] = t; +} + +//========================================================================== + + +/* +================= +BasePolyForPlane +================= +*/ +winding_t *BasePolyForPlane (plane_t *p) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(p->normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("BasePolyForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + + v = DotProduct (vup, p->normal); + VectorMA (vup, -v, p->normal, vup); + VectorNormalize (vup, vup); + + VectorScale (p->normal, p->dist, org); + + CrossProduct (vup, p->normal, vright); + + VectorScale (vup, 8192, vup); + VectorScale (vright, 8192, vright); + +// project a really big axis aligned box onto the plane + w = NewWinding (4); + + VectorSubtract (org, vright, w->points[0]); + VectorAdd (w->points[0], vup, w->points[0]); + + VectorAdd (org, vright, w->points[1]); + VectorAdd (w->points[1], vup, w->points[1]); + + VectorAdd (org, vright, w->points[2]); + VectorSubtract (w->points[2], vup, w->points[2]); + + VectorSubtract (org, vright, w->points[3]); + VectorSubtract (w->points[3], vup, w->points[3]); + + w->numpoints = 4; + + return w; +} + +void Brush_MakeFacePlanes (brush_t *b) +{ + face_t *f; + int j; + vec3_t t1, t2, t3; + + for (f=b->brush_faces ; f ; f=f->next) + { + // convert to a vector / dist plane + for (j=0 ; j<3 ; j++) + { + t1[j] = f->planepts[0][j] - f->planepts[1][j]; + t2[j] = f->planepts[2][j] - f->planepts[1][j]; + t3[j] = f->planepts[1][j]; + } + + CrossProduct(t1,t2, f->plane.normal); + if (VectorCompare (f->plane.normal, vec3_origin)) + printf ("WARNING: brush plane with no normal\n"); + VectorNormalize (f->plane.normal, f->plane.normal); + f->plane.dist = DotProduct (t3, f->plane.normal); + } +} + +void DrawBrushEntityName (brush_t *b) +{ + char *name; + float a, s, c; + vec3_t mid; + int i; + + if (!b->owner) + return; // during contruction + + if (b->owner == world_entity) + return; + + if (b != b->owner->brushes.onext) + return; // not key brush + + // draw the angle pointer + a = FloatForKey (b->owner, "angle"); + if (a) + { + s = sin (a/180*Q_PI); + c = cos (a/180*Q_PI); + for (i=0 ; i<3 ; i++) + mid[i] = (b->mins[i] + b->maxs[i])*0.5; + + glBegin (GL_LINE_STRIP); + glVertex3fv (mid); + mid[0] += c*8; + mid[1] += s*8; + glVertex3fv (mid); + mid[0] -= c*4; + mid[1] -= s*4; + mid[0] -= s*4; + mid[1] += c*4; + glVertex3fv (mid); + mid[0] += c*4; + mid[1] += s*4; + mid[0] += s*4; + mid[1] -= c*4; + glVertex3fv (mid); + mid[0] -= c*4; + mid[1] -= s*4; + mid[0] += s*4; + mid[1] -= c*4; + glVertex3fv (mid); + glEnd (); + } + + if (!g_qeglobals.d_savedinfo.show_names) + return; + + name = ValueForKey (b->owner, "classname"); + glRasterPos2f (b->mins[0]+4, b->mins[1]+4); + glCallLists (strlen(name), GL_UNSIGNED_BYTE, name); +} + +/* +================= +MakeFaceWinding + +returns the visible polygon on a face +================= +*/ +winding_t *MakeFaceWinding (brush_t *b, face_t *face) +{ + winding_t *w; + face_t *clip; + plane_t plane; + qboolean past; + + // get a poly that covers an effectively infinite area + w = BasePolyForPlane (&face->plane); + + // chop the poly by all of the other faces + past = false; + for (clip = b->brush_faces ; clip && w ; clip=clip->next) + { + if (clip == face) + { + past = true; + continue; + } + if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999 + && fabs(face->plane.dist - clip->plane.dist) < 0.01 ) + { // identical plane, use the later one + if (past) + { + free (w); + return NULL; + } + continue; + } + + // flip the plane, because we want to keep the back side + VectorSubtract (vec3_origin,clip->plane.normal, plane.normal); + plane.dist = -clip->plane.dist; + + w = ClipWinding (w, &plane, false); + if (!w) + return w; + } + + if (w->numpoints < 3) + { + free(w); + w = NULL; + } + + if (!w) + printf ("unused plane\n"); + + return w; +} + + +void Brush_SnapPlanepts (brush_t *b) +{ + int i, j; + face_t *f; + + for (f=b->brush_faces ; f; f=f->next) + for (i=0 ; i<3 ; i++) + for (j=0 ; j<3 ; j++) + f->planepts[i][j] = floor (f->planepts[i][j] + 0.5); +} + +/* +** Brush_Build +** +** Builds a brush rendering data and also sets the min/max bounds +*/ +#define ZERO_EPSILON 0.001 +static int inabuild = 0; +void Brush_Build( brush_t *b ) +{ +// int order; +// face_t *face; +// winding_t *w; + char title[1024]; + + QE_ResetIdle(); + + if (modified != 1) + { + modified = true; // mark the map as changed + sprintf (title, "%s *", currentmap); + + QE_ConvertDOSToUnixName( title, title ); + Sys_SetTitle (title); + } + + /* + ** build the windings and generate the bounding box + */ + Brush_BuildWindings( b ); + + + + /* + ** move the points and edges if in select mode + */ + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) + SetupVertexSelection (); +} + +/* +================= +Brush_Parse + +The brush is NOT linked to any list +================= +*/ +brush_t *Brush_Parse (void) +{ + brush_t *b; + face_t *f; + int i,j; + + g_qeglobals.d_parsed_brushes++; + b = qmalloc(sizeof(brush_t)); + + do + { + if (!GetToken (true)) + break; + if (!strcmp (token, "}") ) + break; + + f = Face_Alloc(); + + // add the brush to the end of the chain, so + // loading and saving a map doesn't reverse the order + + f->next = NULL; + if (!b->brush_faces) + { + b->brush_faces = f; + } + else + { + face_t *scan; + + for (scan=b->brush_faces ; scan->next ; scan=scan->next) + ; + scan->next = f; + } + + // read the three point plane definition + for (i=0 ; i<3 ; i++) + { + if (i != 0) + GetToken (true); + if (strcmp (token, "(") ) + Error ("parsing brush"); + + for (j=0 ; j<3 ; j++) + { + GetToken (false); + f->planepts[i][j] = atoi(token); + } + + GetToken (false); + if (strcmp (token, ")") ) + Error ("parsing brush"); + + } + + // read the texturedef + GetToken (false); + strcpy(f->texdef.name, token); + GetToken (false); + f->texdef.shift[0] = atoi(token); + GetToken (false); + f->texdef.shift[1] = atoi(token); + GetToken (false); + f->texdef.rotate = atoi(token); + GetToken (false); + f->texdef.scale[0] = atof(token); + GetToken (false); + f->texdef.scale[1] = atof(token); + + // the flags and value field aren't necessarily present + f->d_texture = Texture_ForName( f->texdef.name ); + f->texdef.flags = f->d_texture->flags; + f->texdef.value = f->d_texture->value; + f->texdef.contents = f->d_texture->contents; + + if (TokenAvailable ()) + { + GetToken (false); + f->texdef.contents = atoi(token); + GetToken (false); + f->texdef.flags = atoi(token); + GetToken (false); + f->texdef.value = atoi(token); + } + + if (TokenAvailable()) + { + GetToken (false); + f->texdef.lighting[0] = atof(token); // red + GetToken (false); + f->texdef.lighting[1] = atof(token); // green + GetToken (false); + f->texdef.lighting[2] = atof(token); // blue + GetToken (false); + f->texdef.lighting[3] = atof(token); // alpha + } + + } while (1); + + return b; +} + +/* +================= +Brush_Write +================= +*/ +void Brush_Write (brush_t *b, FILE *f) +{ + face_t *fa; + char *pname; + int i; + + fprintf (f, "{\n"); + for (fa=b->brush_faces ; fa ; fa=fa->next) + { + for (i=0 ; i<3 ; i++) + fprintf (f, "( %i %i %i ) ", (int)fa->planepts[i][0] + , (int)fa->planepts[i][1], (int)fa->planepts[i][2]); + + pname = fa->texdef.name; + if (pname[0] == 0) + pname = "unnamed"; + + fprintf (f, "%s %i %i %i ", pname, + (int)fa->texdef.shift[0], (int)fa->texdef.shift[1], + (int)fa->texdef.rotate); + + if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) + fprintf (f, "%i ", (int)fa->texdef.scale[0]); + else + fprintf (f, "%f ", (float)fa->texdef.scale[0]); + if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) + fprintf (f, "%i", (int)fa->texdef.scale[1]); + else + fprintf (f, "%f", (float)fa->texdef.scale[1]); + + // only output flags and value if not default + if (fa->texdef.value != fa->d_texture->value + || fa->texdef.flags != fa->d_texture->flags + || fa->texdef.contents != fa->d_texture->contents || (fa->texdef.flags & 0x400)) + { + fprintf (f, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value); + } + + + if(fa->texdef.flags & 0x400) // tall wall, write lighting values + { + fprintf (f, " %f %f %f %f", fa->texdef.lighting[0], fa->texdef.lighting[1], fa->texdef.lighting[2], fa->texdef.lighting[3]); + } + + fprintf (f, "\n"); + } + fprintf (f, "}\n"); +} + + +/* +============= +Brush_Create + +Create non-textured blocks for entities +The brush is NOT linked to any list +============= +*/ +brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef) +{ + int i, j; + vec3_t pts[4][2]; + face_t *f; + brush_t *b; + + for (i=0 ; i<3 ; i++) + if (maxs[i] < mins[i]) + Error ("Brush_InitSolid: backwards"); + + b = qmalloc (sizeof(brush_t)); + b->texLocked = false; + + pts[0][0][0] = mins[0]; + pts[0][0][1] = mins[1]; + + pts[1][0][0] = mins[0]; + pts[1][0][1] = maxs[1]; + + pts[2][0][0] = maxs[0]; + pts[2][0][1] = maxs[1]; + + pts[3][0][0] = maxs[0]; + pts[3][0][1] = mins[1]; + + for (i=0 ; i<4 ; i++) + { + pts[i][0][2] = mins[2]; + pts[i][1][0] = pts[i][0][0]; + pts[i][1][1] = pts[i][0][1]; + pts[i][1][2] = maxs[2]; + } + + for (i=0 ; i<4 ; i++) + { + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + j = (i+1)%4; + + VectorCopy (pts[j][1], f->planepts[0]); + VectorCopy (pts[i][1], f->planepts[1]); + VectorCopy (pts[i][0], f->planepts[2]); + } + + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[0][1], f->planepts[0]); + VectorCopy (pts[1][1], f->planepts[1]); + VectorCopy (pts[2][1], f->planepts[2]); + + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[2][0], f->planepts[0]); + VectorCopy (pts[1][0], f->planepts[1]); + VectorCopy (pts[0][0], f->planepts[2]); + + return b; +} + + +/* +============= +Brush_MakeSided + +Makes the current brushhave the given number of 2d sides +============= +*/ +void Brush_MakeSided (int sides) +{ + int i; + vec3_t mins, maxs; + brush_t *b; + texdef_t *texdef; + face_t *f; + vec3_t mid; + float width; + float sv, cv; + qboolean wasLocked; + + if (sides < 3) + { + Sys_Status ("Bad sides number", 0); + return; + } + + if (!QE_SingleBrush ()) + { + Sys_Status ("Must have a single brush selected", 0 ); + return; + } + + b = selected_brushes.next; + VectorCopy (b->mins, mins); + VectorCopy (b->maxs, maxs); + texdef = &g_qeglobals.d_texturewin.texdef; + wasLocked = b->texLocked; + + Brush_Free (b); + + // find center of brush + width = 8; + for (i=0 ; i<2 ; i++) + { + mid[i] = (maxs[i] + mins[i])*0.5; + if (maxs[i] - mins[i] > width) + width = maxs[i] - mins[i]; + } + width /= 2; + + b = qmalloc (sizeof(brush_t)); + b->texLocked = wasLocked; + + // create top face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + +f->planepts[2][0] = mins[0];f->planepts[2][1] = mins[1];f->planepts[2][2] = maxs[2]; +f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = maxs[2]; +f->planepts[0][0] = maxs[0];f->planepts[0][1] = maxs[1];f->planepts[0][2] = maxs[2]; + + // create bottom face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + +f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2]; +f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2]; +f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2]; + + for (i=0 ; itexdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + sv = sin (i*3.14159265*2/sides); + cv = cos (i*3.14159265*2/sides); + + f->planepts[0][0] = floor(mid[0]+width*cv+0.5); + f->planepts[0][1] = floor(mid[1]+width*sv+0.5); + f->planepts[0][2] = mins[2]; + + f->planepts[1][0] = f->planepts[0][0]; + f->planepts[1][1] = f->planepts[0][1]; + f->planepts[1][2] = maxs[2]; + + f->planepts[2][0] = floor(f->planepts[0][0] - width*sv + 0.5); + f->planepts[2][1] = floor(f->planepts[0][1] + width*cv + 0.5); + f->planepts[2][2] = maxs[2]; + + } + + Brush_AddToList (b, &selected_brushes); + + Entity_LinkBrush (world_entity, b); + + Brush_Build( b ); + + Sys_UpdateWindows (W_ALL); +} + +/* +============= +Brush_MakeSided_Snap + +Makes the current brushhave the given number of 2d sides, and snap vertices to grid +============= +*/ +void Brush_MakeSided_Snap (int sides) +{ + int i; + vec3_t mins, maxs; + brush_t *b; + texdef_t *texdef; + face_t *f; + vec3_t mid; + float width; + float s1, s2, c1, c2; + float alpha; + float ca; + qboolean wasLocked; + + if (sides < 3) + { + Sys_Status ("Bad sides number", 0); + return; + } + + if (!QE_SingleBrush ()) + { + Sys_Status ("Must have a single brush selected", 0 ); + return; + } + + b = selected_brushes.next; + VectorCopy (b->mins, mins); + VectorCopy (b->maxs, maxs); + texdef = &g_qeglobals.d_texturewin.texdef; + wasLocked = b->texLocked; + + Brush_Free (b); + + // find center of brush + width = 8; + for (i=0 ; i<2 ; i++) + { + mid[i] = (maxs[i] + mins[i])*0.5; + if (maxs[i] - mins[i] > width) + width = maxs[i] - mins[i]; + } + width /= 2; + + b = qmalloc (sizeof(brush_t)); + b->texLocked = wasLocked; + + // create top face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + +f->planepts[2][0] = mins[0];f->planepts[2][1] = mins[1];f->planepts[2][2] = maxs[2]; +f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = maxs[2]; +f->planepts[0][0] = maxs[0];f->planepts[0][1] = maxs[1];f->planepts[0][2] = maxs[2]; + + // create bottom face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + +f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2]; +f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2]; +f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2]; + + alpha = (3.14159265/sides); + ca = cos (alpha); + for (i=0 ; itexdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + s1 = sin ((i*3.14159265*2/sides) - alpha); + s2 = sin ((i*3.14159265*2/sides) + alpha); + c1 = cos ((i*3.14159265*2/sides) - alpha); + c2 = cos ((i*3.14159265*2/sides) + alpha); + f->planepts[0][0] = floor(mid[0]+(width/ca*c1+0.5)); + f->planepts[0][1] = floor(mid[1]+(width/ca*s1+0.5)); + + f->planepts[1][0] = f->planepts[0][0]; + f->planepts[1][1] = f->planepts[0][1]; + + f->planepts[2][0] = floor(mid[0]+(width/ca*c2+0.5)); + f->planepts[2][1] = floor(mid[1]+(width/ca*s2+0.5)); + + + f->planepts[0][0] = floor(f->planepts[0][0]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + f->planepts[0][1] = floor(f->planepts[0][1]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + f->planepts[0][2] = mins[2]; + f->planepts[1][0] = floor(f->planepts[1][0]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + f->planepts[1][1] = floor(f->planepts[1][1]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + f->planepts[1][2] = maxs[2]; + f->planepts[2][0] = floor(f->planepts[2][0]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + f->planepts[2][1] = floor(f->planepts[2][1]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + f->planepts[2][2] = maxs[2]; + + } + + Brush_AddToList (b, &selected_brushes); + + Entity_LinkBrush (world_entity, b); + + Brush_Build( b ); + + Sys_UpdateWindows (W_ALL); +} + +/* +============= +Brush_Free + +Frees the brush with all of its faces and display list. +Unlinks the brush from whichever chain it is in. +Decrements the owner entity's brushcount. +Removes owner entity if this was the last brush +unless owner is the world. +============= +*/ +void Brush_Free (brush_t *b) +{ + face_t *f, *next; + + // free faces + for (f=b->brush_faces ; f ; f=next) + { + next = f->next; + Face_Free( f ); + } + + /* + for ( i = 0; i < b->d_numwindings; i++ ) + { + if ( b->d_windings[i] ) + { + FreeWinding( b->d_windings[i] ); + b->d_windings[i] = 0; + } + } + */ + + // unlink from active/selected list + if (b->next) + Brush_RemoveFromList (b); + + // unlink from entity list + if (b->onext) + Entity_UnlinkBrush (b); + + free (b); +} + +/* +============ +Brush_Move +============ +*/ +void Brush_Move (brush_t *b, vec3_t move, qboolean moveorigin) +{ + int i, j; + face_t *f; + float points[5], s[MAXPOINTS], t[MAXPOINTS]; + vec3_t origin; + char text[128]; + + j=0; + for (f=b->brush_faces ; f ; f=f->next) + { + if(b->texLocked) + { + VectorCopy(f->planepts[0], points); + EmitTextureCoordinates(points, f->d_texture, f); + s[j] = points[3]; + t[j++] = points[4]; + } + for (i=0 ; i<3 ; i++) + VectorAdd (f->planepts[i], move, f->planepts[i]); + + } + + if (strcmp(b->owner->eclass->name,"worldspawn") && (b->owner->eclass->fixedsize || + b->owner->eclass->PhysicsModel) && moveorigin) + { //need to set this only once for physics models! + GetVectorForKey (b->owner, "origin", origin); + VectorAdd (origin, move, origin); + sprintf (text, "%i %i %i", (int)origin[0],(int)origin[1], (int)origin[2]); + SetKeyValue (b->owner, "origin", text); + } + if(b->texLocked) + { + j=0; + for (f=b->brush_faces ; f ; f=f->next) + { + VectorCopy(f->planepts[0], points); + EmitTextureCoordinates(points, f->d_texture, f); + f->texdef.shift[0] += (s[j] - points[3]) * f->d_texture->width; + f->texdef.shift[1] += (t[j++] - points[4]) * f->d_texture->height; + } + } + Brush_Build( b ); +} + + +/* +============ +Brush_Clone + +Does NOT add the new brush to any lists +============ +*/ +brush_t *Brush_Clone (brush_t *b) +{ + brush_t *n; + face_t *f, *nf; + + n = qmalloc(sizeof(brush_t)); + n->owner = b->owner; + n->texLocked = b->texLocked; + for (f=b->brush_faces ; f ; f=f->next) + { + nf = Face_Clone( f ); + nf->next = n->brush_faces; + n->brush_faces = nf; + } + return n; +} + +/* +============== +Brush_Ray + +Intersects a ray with a brush +Returns the face hit and the distance along the ray the intersection occured at +Returns NULL and 0 if not hit at all +============== +*/ +face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist) +{ + face_t *f, *firstface; + vec3_t p1, p2; + float frac, d1, d2; + int i; + + VectorCopy (origin, p1); + for (i=0 ; i<3 ; i++) + p2[i] = p1[i] + dir[i]*16384; + + for (f=b->brush_faces ; f ; f=f->next) + { + d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; + d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; + if (d1 >= 0 && d2 >= 0) + { + + *dist = 0; +// continue; + return NULL; // ray is on front side of face + } + if (d1 <=0 && d2 <= 0) + continue; + // clip the ray to the plane + frac = d1 / (d1 - d2); + if (d1 > 0) + { + firstface = f; + for (i=0 ; i<3 ; i++) + p1[i] = p1[i] + frac *(p2[i] - p1[i]); + } + else + { + for (i=0 ; i<3 ; i++) + p2[i] = p1[i] + frac *(p2[i] - p1[i]); + } + } + + // find distance p1 is along dir + VectorSubtract (p1, origin, p1); + d1 = DotProduct (p1, dir); + + *dist = d1; + + return firstface; +} + +void Brush_AddToList (brush_t *b, brush_t *list) +{ + if (b->next || b->prev) + Error ("Brush_AddToList: allready linked"); + b->next = list->next; + list->next->prev = b; + list->next = b; + b->prev = list; +} + +void Brush_RemoveFromList (brush_t *b) +{ + if (!b->next || !b->prev) + Error ("Brush_RemoveFromList: not linked"); + b->next->prev = b->prev; + b->prev->next = b->next; + b->next = b->prev = NULL; +} + +void Brush_SetTexture (brush_t *b, texdef_t *texdef) +{ + face_t *f; + + for (f=b->brush_faces ; f ; f=f->next) + f->texdef = *texdef; + Brush_Build( b ); +} + + +qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f) +{ + float d1, d2, fr; + int i; + float *v; + + d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; + d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; + + if (d1 >= 0 && d2 >= 0) + return false; // totally outside + if (d1 <= 0 && d2 <= 0) + return true; // totally inside + + fr = d1 / (d1 - d2); + + if (d1 > 0) + v = p1; + else + v = p2; + + for (i=0 ; i<3 ; i++) + v[i] = p1[i] + fr*(p2[i] - p1[i]); + + return true; +} + + +int AddPlanept (float *f) +{ + int i; + + for (i=0 ; iowner->eclass->fixedsize) + return; + + c = 0; + for (i=0 ; i<3 ; i++) + c += AddPlanept (f->planepts[i]); + if (c == 0) + return; // allready completely added + + // select all points on this plane in all brushes the selection + for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next) + { + if (b2 == b) + continue; + for (f2=b2->brush_faces ; f2 ; f2=f2->next) + { + for (i=0 ; i<3 ; i++) + if (fabs(DotProduct(f2->planepts[i], f->plane.normal) + -f->plane.dist) > ON_EPSILON) + break; + if (i==3) + { // move this face as well + Brush_SelectFaceForDragging (b2, f2, shear); + break; + } + } + } + + + // if shearing, take all the planes adjacent to + // selected faces and rotate their points so the + // edge clipped by a selcted face has two of the points + if (!shear) + return; + + for (f2=b->brush_faces ; f2 ; f2=f2->next) + { + if (f2 == f) + continue; + w = MakeFaceWinding (b, f2); + if (!w) + continue; + + // any points on f will become new control points + for (i=0 ; inumpoints ; i++) + { + d = DotProduct (w->points[i], f->plane.normal) + - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + break; + } + + // + // if none of the points were on the plane, + // leave it alone + // + if (i != w->numpoints) + { + if (i == 0) + { // see if the first clockwise point was the + // last point on the winding + d = DotProduct (w->points[w->numpoints-1] + , f->plane.normal) - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + i = w->numpoints - 1; + } + + AddPlanept (f2->planepts[0]); + + VectorCopy (w->points[i], f2->planepts[0]); + if (++i == w->numpoints) + i = 0; + + // see if the next point is also on the plane + d = DotProduct (w->points[i] + , f->plane.normal) - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + AddPlanept (f2->planepts[1]); + + VectorCopy (w->points[i], f2->planepts[1]); + if (++i == w->numpoints) + i = 0; + + // the third point is never on the plane + + VectorCopy (w->points[i], f2->planepts[2]); + } + + free(w); + } +} + +/* +============== +Brush_SideSelect + +The mouse click did not hit the brush, so grab one or more side +planes for dragging +============== +*/ +void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir + , qboolean shear) +{ + face_t *f, *f2; + vec3_t p1, p2; + + for (f=b->brush_faces ; f ; f=f->next) + { + VectorCopy (origin, p1); + VectorMA (origin, 16384, dir, p2); + + for (f2=b->brush_faces ; f2 ; f2=f2->next) + { + if (f2 == f) + continue; + ClipLineToFace (p1, p2, f2); + } + + if (f2) + continue; + + if (VectorCompare (p1, origin)) + continue; + if (ClipLineToFace (p1, p2, f)) + continue; + + Brush_SelectFaceForDragging (b, f, shear); + } + + +} + +void Brush_BuildWindings( brush_t *b ) +{ + winding_t *w; + face_t *face; + vec_t v; + + Brush_SnapPlanepts( b ); + + // clear the mins/maxs bounds + b->mins[0] = b->mins[1] = b->mins[2] = 99999; + b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999; + + Brush_MakeFacePlanes (b); + + face = b->brush_faces; + + for ( ; face ; face=face->next) + { + int i, j; + + w = face->face_winding = MakeFaceWinding (b, face); + face->d_texture = Texture_ForName( face->texdef.name ); + + if (!w) + { + continue; + } + + for (i=0 ; inumpoints ; i++) + { + // add to bounding box + for (j=0 ; j<3 ; j++) + { + v = w->points[i][j]; + if (v > b->maxs[j]) + b->maxs[j] = v; + if (v < b->mins[j]) + b->mins[j] = v; + } + } + // setup s and t vectors, and set color + BeginTexturingFace( b, face, face->d_texture); + + + for (i=0 ; inumpoints ; i++) + { + EmitTextureCoordinates( w->points[i], face->d_texture, face); + } + } +} + +/* +================== +Brush_RemoveEmptyFaces + +Frees any overconstraining faces +================== +*/ +void Brush_RemoveEmptyFaces ( brush_t *b ) +{ + face_t *f, *next; + + f = b->brush_faces; + b->brush_faces = NULL; + + for ( ; f ; f=next) + { + next = f->next; + if (!f->face_winding) + Face_Free (f); + else + { + f->next = b->brush_faces; + b->brush_faces = f; + } + + } +} + +void Brush_Draw( brush_t *b ) +{ + face_t *face; + int i, order; + qtexture_t *prev = 0; + winding_t *w; + vec3_t testVect, tempVect; + + VectorAdd(b->mins, b->maxs, tempVect); + VectorScale(tempVect, .5, tempVect); + VectorSubtract(tempVect, camera.origin, testVect); + if(VectorLength(testVect) > g_qeglobals.d_maxViewDist)return; + + if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture) + glDisable (GL_TEXTURE_2D); + + // guarantee the texture will be set first + prev = NULL; + for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + { + w = face->face_winding; + if (!w) + continue; // freed face + + if ( face->d_texture != prev && camera.draw_mode == cd_texture) + { + // set the texture for this face + prev = face->d_texture; + glBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number ); + } + + glColor3fv( face->d_color ); + + // draw the polygon + glBegin(GL_POLYGON); + for (i=0 ; inumpoints ; i++) + { + if (camera.draw_mode == cd_texture) + glTexCoord2fv( &w->points[i][3] ); + glVertex3fv(w->points[i]); + } + glEnd(); + } + + if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture) + glEnable (GL_TEXTURE_2D); + + glBindTexture( GL_TEXTURE_2D, 0 ); +} + +void Face_Draw( face_t *f ) +{ + int i; + + if ( f->face_winding == 0 ) + return; + glBegin( GL_POLYGON ); + for ( i = 0 ; i < f->face_winding->numpoints; i++) + glVertex3fv( f->face_winding->points[i] ); + glEnd(); +} + +void Brush_DrawXY( brush_t *b ) +{ + face_t *face; + int order; + winding_t *w; + int i; + + for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + { + // only draw up facing polygons + if (face->plane.normal[2] <= 0) + continue; + + w = face->face_winding; + if (!w) + continue; + + // draw the polygon + glBegin(GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + glVertex3fv(w->points[i]); + glEnd(); + } + + // optionally add a text label + if ( g_qeglobals.d_savedinfo.show_names ) + DrawBrushEntityName (b); +} + +face_t *Face_Alloc( void ) +{ + face_t *f = qmalloc( sizeof( *f ) ); + + return f; +} + +void Face_Free( face_t *f ) +{ + assert( f != 0 ); + + if ( f->face_winding ) + free( f->face_winding ), f->face_winding = 0; + free( f ); +} + +/* +================== +Brush_Scale + +Scales all selected brushes +================== +*/ + +void Brush_Scale(float scale, int groupCenter, int nox, int noy, int noz) +{ + brush_t *b, *startBrush; + face_t *face; + int i; + int numBrushes = 0; + vec3_t center, dist; + + + if(groupCenter) + { + b = selected_brushes.next; + + startBrush = b; + + VectorClear(center); + + while(b != &selected_brushes) + { + numBrushes++; + + VectorAdd(center, b->maxs, center); + VectorAdd(center, b->mins, center); + + b = b->next; + } + VectorScale(center, (1.0 / (numBrushes*2.0)), center); + } + + b = selected_brushes.next; + + startBrush = b; + + while(b != &selected_brushes) + { + if(!groupCenter) + { + VectorAdd(b->mins, b->maxs, center); + VectorScale(center, .5, center); + } + + // Stretch the thingy out + for (face = b->brush_faces; face ; face=face->next) + { + // scale the planepts + for (i=0 ; i<3 ; i++) + { + VectorSubtract(face->planepts[i], center, dist); + if(!nox) + { + face->planepts[i][0] = center[0] + dist[0] * scale; + } + if(!noy) + { + face->planepts[i][1] = center[1] + dist[1] * scale; + } + if(!noz) + { + face->planepts[i][2] = center[2] + dist[2] * scale; + } + } + } + + Brush_Build(b); + + b = b->next; + } + + Sys_UpdateWindows (W_ALL); +} \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qe4/brush.h b/Toolkit/Programming/Tools/qe4/brush.h new file mode 100644 index 0000000..8eb8548 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/brush.h @@ -0,0 +1,72 @@ + +// brush.h + + +typedef struct +{ + int numpoints; + int maxpoints; + float points[8][5]; // variable sized +} winding_t; + + +// the normals on planes point OUT of the brush +#define MAXPOINTS 16 +typedef struct face_s +{ + struct face_s *next; + vec3_t planepts[3]; + texdef_t texdef; + + plane_t plane; + + winding_t *face_winding; + + vec3_t d_color; + qtexture_t *d_texture; + +// int d_numpoints; +// vec3_t *d_points; +} face_t; + +#define MAX_FACES 16 +typedef struct brush_s +{ + struct brush_s *prev, *next; // links in active/selected + struct brush_s *oprev, *onext; // links in entity + struct entity_s *owner; + vec3_t mins, maxs; + qboolean texLocked; // don't move textures when translating + qboolean rotatedonload; + face_t *brush_faces; +} brush_t; + + +void Brush_AddToList (brush_t *b, brush_t *list); +void Brush_Build(brush_t *b); +void Brush_BuildWindings( brush_t *b ); +brush_t *Brush_Clone (brush_t *b); +brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef); +void Brush_Draw( brush_t *b ); +void Brush_DrawXY( brush_t *b ); +void Brush_Free (brush_t *b); +void Brush_MakeSided (int sides); +void Brush_MakeSided_Snap (int sides); +void Brush_Move (brush_t *b, vec3_t move, qboolean moveorigin); +brush_t *Brush_Parse (void); +face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist); +void Brush_RemoveFromList (brush_t *b); +void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear); +void Brush_SetTexture (brush_t *b, texdef_t *texdef); +void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir, qboolean shear); +void Brush_Write (brush_t *b, FILE *f); +void Brush_RemoveEmptyFaces ( brush_t *b ); +void Brush_Scale(float scale, int groupCenter, int nox, int noy, int noz); + +int AddPlanept (float *f); +face_t *Face_Clone (face_t *f); +void Face_Draw( face_t *face ); +winding_t *MakeFaceWinding (brush_t *b, face_t *face); +face_t *Face_Alloc( void ); +void Face_Free( face_t *f ); +winding_t *NewWinding (int points); diff --git a/Toolkit/Programming/Tools/qe4/camera.c b/Toolkit/Programming/Tools/qe4/camera.c new file mode 100644 index 0000000..9e40956 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/camera.c @@ -0,0 +1,575 @@ + +#include "qe3.h" + +#define PAGEFLIPS 2 + +void DrawPathLines (void); + +camera_t camera; + +/* +============ +Cam_Init +============ +*/ +void Cam_Init (void) +{ +// camera.draw_mode = cd_texture; +// camera.draw_mode = cd_solid; +// camera.draw_mode = cd_wire; + + camera.timing = false; + + camera.origin[0] = 0; + camera.origin[1] = 20; + camera.origin[2] = 46; + + camera.color[0] = 0.3; + camera.color[1] = 0.3; + camera.color[2] = 0.3; +} + + +//============================================================================ + +void Cam_BuildMatrix (void) +{ + float xa, ya; + float matrix[4][4]; + int i; + + xa = camera.angles[0]/180*Q_PI; + ya = camera.angles[1]/180*Q_PI; + + // the movement matrix is kept 2d + + camera.forward[0] = cos(ya); + camera.forward[1] = sin(ya); + camera.right[0] = camera.forward[1]; + camera.right[1] = -camera.forward[0]; + + glGetFloatv (GL_PROJECTION_MATRIX, &matrix[0][0]); + + for (i=0 ; i<3 ; i++) + { + camera.vright[i] = matrix[i][0]; + camera.vup[i] = matrix[i][1]; + camera.vpn[i] = matrix[i][2]; + } + + VectorNormalize (camera.vright,camera.vright); + VectorNormalize (camera.vup,camera.vup); + VectorNormalize (camera.vpn,camera.vpn); +} + +//=============================================== + +/* +=============== +Cam_ChangeFloor +=============== +*/ +void Cam_ChangeFloor (qboolean up) +{ + brush_t *b; + float d, bestd, current; + vec3_t start, dir; + + start[0] = camera.origin[0]; + start[1] = camera.origin[1]; + start[2] = 8192; + dir[0] = dir[1] = 0; + dir[2] = -1; + + current = 8192 - (camera.origin[2] - 48); + if (up) + bestd = 0; + else + bestd = 16384; + + for (b=active_brushes.next ; b != &active_brushes ; b=b->next) + { + if (!Brush_Ray (start, dir, b, &d)) + continue; + if (up && d < current && d > bestd) + bestd = d; + if (!up && d > current && d < bestd) + bestd = d; + } + + if (bestd == 0 || bestd == 16384) + return; + + camera.origin[2] += current - bestd; + Sys_UpdateWindows (W_CAMERA|W_Z_OVERLAY); +} + + +//=============================================== + +int cambuttonstate; +static int buttonx, buttony; +static int cursorx, cursory; + +face_t *side_select; + +#define ANGLE_SPEED 300 +#define MOVE_SPEED 400 + +/* +================ +Cam_PositionDrag +================ +*/ +void Cam_PositionDrag (void) +{ + int x, y; + + Sys_GetCursorPos (&x, &y); + if (x != cursorx || y != cursory) + { + x -= cursorx; + VectorMA (camera.origin, x, camera.vright, camera.origin); + y -= cursory; + camera.origin[2] -= y; + + Sys_SetCursorPos (cursorx, cursory); + Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY); + } +} + +/* +=============== +Cam_MouseControl +=============== +*/ +void Cam_MouseControl (float dtime) +{ + int xl, xh; + int yl, yh; + float xf, yf; + + if (cambuttonstate != MK_RBUTTON) + return; + + xf = (float)(buttonx - camera.width/2) / (camera.width/2); + yf = (float)(buttony - camera.height/2) / (camera.height/2); + + xl = camera.width/3; + xh = xl*2; + yl = camera.height/3; + yh = yl*2; + +#if 0 + // strafe + if (buttony < yl && (buttonx < xl || buttonx > xh)) + VectorMA (camera.origin, xf*dtime*MOVE_SPEED, camera.right, camera.origin); + else +#endif + { + xf *= 1.0 - fabs(yf); + if (xf < 0) + { + xf += 0.1; + if (xf > 0) + xf = 0; + } + else + { + xf -= 0.1; + if (xf < 0) + xf = 0; + } + + VectorMA (camera.origin, yf*dtime*MOVE_SPEED, camera.forward, camera.origin); + camera.angles[YAW] += xf*-dtime*ANGLE_SPEED; + } + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); +} + + + + +/* +============== +Cam_MouseDown +============== +*/ +void Drag_Reset (void); +void Cam_MouseDown (int x, int y, int buttons) +{ + vec3_t dir; + float f, r, u; + int i; + + // + // calc ray direction + // + Drag_Reset(); + u = (float)(y - camera.height/2) / (camera.width/2); + r = (float)(x - camera.width/2) / (camera.width/2); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = camera.vpn[i] * f + camera.vright[i] * r + camera.vup[i] * u; + VectorNormalize (dir,dir); + + Sys_GetCursorPos (&cursorx, &cursory); + + cambuttonstate = buttons; + buttonx = x; + buttony = y; + + // LBUTTON = manipulate selection + // shift-LBUTTON = select + // middle button = grab texture + // ctrl-middle button = set entire brush to texture + // ctrl-shift-middle button = set single face to texture + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == (MK_LBUTTON | MK_CONTROL)) + || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) + || (buttons == MK_MBUTTON) + || (buttons == (MK_MBUTTON|MK_CONTROL)) + || (buttons == (MK_MBUTTON|MK_SHIFT|MK_CONTROL)) ) + { + Drag_Begin (x, y, buttons, + camera.vright, camera.vup, + camera.origin, dir); + return; + } + + if (buttons == MK_RBUTTON) + { + Cam_MouseControl (0.1); + return; + } +} + +/* +============== +Cam_MouseUp +============== +*/ +void Cam_MouseUp (int x, int y, int buttons) +{ + cambuttonstate = 0; + Drag_MouseUp (); +} + + +/* +============== +Cam_MouseMoved +============== +*/ +void Cam_MouseMoved (int x, int y, int buttons) +{ + cambuttonstate = buttons; + if (!buttons) + return; + buttonx = x; + buttony = y; + + if (buttons == (MK_RBUTTON|MK_CONTROL) ) + { + Cam_PositionDrag (); + Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); + return; + } + + Sys_GetCursorPos (&cursorx, &cursory); + + if (buttons & (MK_LBUTTON | MK_MBUTTON) ) + { + Drag_MouseMoved (x, y, buttons); + Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); + } +} + + +vec3_t cull1, cull2; +int cullv1[3], cullv2[3]; + +void InitCull (void) +{ + int i; + + VectorSubtract (camera.vpn, camera.vright, cull1); + VectorAdd (camera.vpn, camera.vright, cull2); + + for (i=0 ; i<3 ; i++) + { + if (cull1[i] > 0) + cullv1[i] = 3+i; + else + cullv1[i] = i; + if (cull2[i] > 0) + cullv2[i] = 3+i; + else + cullv2[i] = i; + } +} + +qboolean CullBrush (brush_t *b) +{ + int i; + vec3_t point; + float d; + + for (i=0 ; i<3 ; i++) + point[i] = b->mins[cullv1[i]] - camera.origin[i]; + + d = DotProduct (point, cull1); + if (d < -1) + return true; + + for (i=0 ; i<3 ; i++) + point[i] = b->mins[cullv2[i]] - camera.origin[i]; + + d = DotProduct (point, cull2); + if (d < -1) + return true; + + return false; +} + + +/* +============== +Cam_Draw +============== +*/ +void Cam_Draw (void) +{ + brush_t *brush; + face_t *face; + float screenaspect; + float yfov; + double start, end; + int i; + + if (!active_brushes.next) + return; // not valid yet + + if (camera.timing) + start = Sys_DoubleTime (); + + // + // clear + // + QE_CheckOpenGLForErrors(); + + glViewport(0, 0, camera.width, camera.height); + glScissor(0, 0, camera.width, camera.height); + glClearColor ( + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], + 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // + // set up viewpoint + // + glMatrixMode(GL_PROJECTION); + glLoadIdentity (); + + screenaspect = (float)camera.width/camera.height; + yfov = 2*atan((float)camera.height/camera.width)*180/Q_PI; + gluPerspective (yfov, screenaspect, 2, 8192); + + glRotatef (-90, 1, 0, 0); // put Z going up + glRotatef (90, 0, 0, 1); // put Z going up + glRotatef (camera.angles[0], 0, 1, 0); + glRotatef (-camera.angles[1], 0, 0, 1); + glTranslatef (-camera.origin[0], -camera.origin[1], -camera.origin[2]); + + Cam_BuildMatrix (); + + InitCull (); + + // + // draw stuff + // + + switch (camera.draw_mode) + { + case cd_wire: + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_1D); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glColor3f(1.0, 1.0, 1.0); +// glEnable (GL_LINE_SMOOTH); + break; + + case cd_solid: + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + glShadeModel (GL_FLAT); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glDisable(GL_TEXTURE_2D); + + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDepthFunc (GL_LEQUAL); + break; + + case cd_texture: + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + + glShadeModel (GL_FLAT); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_TEXTURE_2D); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDepthFunc (GL_LEQUAL); + +#if 0 + + { + GLfloat fogColor[4] = {0.0, 1.0, 0.0, 0.25}; + + glFogi (GL_FOG_MODE, GL_LINEAR); + glHint (GL_FOG_HINT, GL_NICEST); /* per pixel */ + glFogf (GL_FOG_START, -8192); + glFogf (GL_FOG_END, 65536); + glFogfv (GL_FOG_COLOR, fogColor); + + } + +#endif + break; + + case cd_blend: + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + + glShadeModel (GL_FLAT); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_TEXTURE_2D); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glDisable(GL_DEPTH_TEST); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + } + + glMatrixMode(GL_TEXTURE); + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if (CullBrush (brush)) + continue; + if (FilterBrush (brush)) + continue; + + Brush_Draw( brush ); + } + glMatrixMode(GL_PROJECTION); + + // + // now draw selected brushes + // + + glTranslatef (g_qeglobals.d_select_translate[0], g_qeglobals.d_select_translate[1], g_qeglobals.d_select_translate[2]); + glMatrixMode(GL_TEXTURE); + + // draw normally + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + Brush_Draw( brush ); + } + + // blend on top + glMatrixMode(GL_PROJECTION); + + glColor4f(1.0, 0.0, 0.0, 0.3); + glEnable (GL_BLEND); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_TEXTURE_2D); + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + for (face=brush->brush_faces ; face ; face=face->next) + Face_Draw( face ); + if (selected_face) + Face_Draw(selected_face); + + // non-zbuffered outline + + glDisable (GL_BLEND); + glDisable (GL_DEPTH_TEST); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glColor3f (1, 1, 1); + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + for (face=brush->brush_faces ; face ; face=face->next) + Face_Draw( face ); + + // edge / vertex flags + + if (g_qeglobals.d_select_mode == sel_vertex) + { + glPointSize (4); + glColor3f (0,1,0); + glBegin (GL_POINTS); + for (i=0 ; ibrush_faces; + while (curFace->next != NULL) + { + curFace = curFace->next; + } + theFace = Face_Alloc(); + VectorCopy(clipDown,theFace->planepts[0]); + VectorCopy(clipUp,theFace->planepts[1]); + theFace->planepts[2][0] = clipUp[0]; + theFace->planepts[2][1] = clipUp[1]; + theFace->planepts[2][2] = (clipUp[2] + 10); + theFace->texdef = g_qeglobals.d_texturewin.texdef; + + + curFace->next = theFace; + Brush_Build(theBrush); + UNDO_FinishBrushEdit(NULL); + Sys_UpdateWindows (W_ALL); + return; +} +/* else + { + Sys_Status ("No intersection between clipping segment and selected brush!", 0); + Sys_Beep (); + } + return; +*/ + +void Draw_Clip(vec3_t start, vec3_t finish) +{ + glColor3f(1.0,0.0,1.0); + glBegin(GL_LINES); + glVertex2f(start[0], start[1]); + glVertex2f(finish[0], finish[1]); + glEnd(); + return; +} diff --git a/Toolkit/Programming/Tools/qe4/clip.h b/Toolkit/Programming/Tools/qe4/clip.h new file mode 100644 index 0000000..3986c1e --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/clip.h @@ -0,0 +1,10 @@ +// clip.h +// routines for clipping brush + + +#include "qe3.h" +#include "undo.h" + + void Begin_Clip(int firstx, int firsty); + void Finish_Clip(int lastx, int lasty); + void Draw_Clip(vec3_t start, vec3_t finish); diff --git a/Toolkit/Programming/Tools/qe4/csg.c b/Toolkit/Programming/Tools/qe4/csg.c new file mode 100644 index 0000000..bacd8af --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/csg.c @@ -0,0 +1,156 @@ + +#include "qe3.h" +#include "undo.h" + +/* +============== +CSG_SplitBrushByFace + +The incoming brush is NOT freed. +The incoming face is NOT left referenced. +============== +*/ +void CSG_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back) +{ + brush_t *b; + face_t *nf; + vec3_t temp; + + b = Brush_Clone (in); + nf = Face_Clone (f); + + nf->texdef = b->brush_faces->texdef; + nf->next = b->brush_faces; + b->brush_faces = nf; + + Brush_Build( b ); + Brush_RemoveEmptyFaces ( b ); + if ( !b->brush_faces ) + { // completely clipped away + Brush_Free (b); + *back = NULL; + } + else + { + Entity_LinkBrush (in->owner, b); + *back = b; + } + + b = Brush_Clone (in); + nf = Face_Clone (f); + // swap the plane winding + VectorCopy (nf->planepts[0], temp); + VectorCopy (nf->planepts[1], nf->planepts[0]); + VectorCopy (temp, nf->planepts[1]); + + nf->texdef = b->brush_faces->texdef; + nf->next = b->brush_faces; + b->brush_faces = nf; + + Brush_Build( b ); + Brush_RemoveEmptyFaces ( b ); + if ( !b->brush_faces ) + { // completely clipped away + Brush_Free (b); + *front = NULL; + } + else + { + Entity_LinkBrush (in->owner, b); + *front = b; + } +} + +/* +============= +CSG_MakeHollow +============= +*/ +void CSG_MakeHollow (void) +{ + brush_t *b, *front, *back, *next; + face_t *f; + face_t split; + vec3_t move; + int i; + + UNDO_StartBrushEdit("&Undo Hollow"); + for (b = selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + for (f = b->brush_faces ; f ; f=f->next) + { + split = *f; + VectorScale (f->plane.normal, g_qeglobals.d_gridsize, move); + for (i=0 ; i<3 ; i++) + VectorSubtract (split.planepts[i], move, split.planepts[i]); + + CSG_SplitBrushByFace (b, &split, &front, &back); + if (back) + Brush_Free (back); + if (front) + Brush_AddToList (front, &selected_brushes); + } + Brush_Free (b); + } + UNDO_FinishBrushEdit (NULL); + Sys_UpdateWindows (W_ALL); +} + + +/* +============= +CSG_Subtract +============= +*/ +void CSG_Subtract (void) +{ + brush_t *b, *s, *frag, *front, *back, *next, *snext; + face_t *f; + int i; + + UNDO_StartSubtraction(); + Sys_Printf ("Subtracting...\n"); + + for (b = selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + + if (b->owner->eclass->fixedsize) + continue; // can't use texture from a fixed entity, so don't subtract + + for (s=active_brushes.next ; s != &active_brushes ; s=snext) + { + snext = s->next; + if (s->owner->eclass->fixedsize) + continue; + + for (i=0 ; i<3 ; i++) + if (b->mins[i] >= s->maxs[i] - ON_EPSILON + || b->maxs[i] <= s->mins[i] + ON_EPSILON) + break; + if (i != 3) + continue; // definately don't touch + + frag = s; + UNDO_AddToSubtractData(s); + for (f = b->brush_faces ; f && frag ; f=f->next) + { + CSG_SplitBrushByFace (frag, f, &front, &back); + Brush_Free (frag); + frag = back; + if (front) + { + UNDO_AddToSubtractList(front); + Brush_AddToList (front, &active_brushes); + } + } + if (frag) + Brush_Free (frag); + } + } + UNDO_FinishSubtraction("&Undo Subtract"); + + Sys_Printf ("done.\n"); + Sys_UpdateWindows (W_ALL); +} diff --git a/Toolkit/Programming/Tools/qe4/drag.c b/Toolkit/Programming/Tools/qe4/drag.c new file mode 100644 index 0000000..5dbc517 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/drag.c @@ -0,0 +1,501 @@ +#include "qe3.h" +#include "undo.h" + +typedef enum +{ //these are used so undo knows what happened at the end + drag_op_none, // used to signal undo hasn't started yet + drag_op_noundo, // such as selection, deselection + drag_op_create, + drag_op_modify //includes any edge & vertex manipulation and move +} drag_ops; + +static drag_ops drag_type; + +/* + + drag either multiple brushes, or select plane points from + a single brush. + +*/ + +qboolean drag_ok; +vec3_t drag_xvec; +vec3_t drag_yvec; + +static int buttonstate; +static int pressx, pressy; +static vec3_t pressdelta; +static int buttonx, buttony; + + +//int num_move_points; +//float *move_points[1024]; + +int lastx, lasty; + +qboolean drag_first; + + +void AxializeVector (vec3_t v) +{ + vec3_t a; + float o; + int i; + + if (!v[0] && !v[1]) + return; + if (!v[1] && !v[2]) + return; + if (!v[0] && !v[2]) + return; + + for (i=0 ; i<3 ; i++) + a[i] = fabs(v[i]); + if (a[0] > a[1] && a[0] > a[2]) + i = 0; + else if (a[1] > a[0] && a[1] > a[2]) + i = 1; + else + i = 2; + + o = v[i]; + VectorCopy (vec3_origin, v); + if (o<0) + v[i] = -1; + else + v[i] = 1; + +} + + +/* +=========== +Drag_Setup +=========== +*/ +void Drag_Setup (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir) +{ + trace_t t; + face_t *f; + brush_t *b; + + drag_type = drag_op_none; + + if (selected_brushes.next == &selected_brushes) + { + drag_type = drag_op_create; + Sys_Status("No selection to drag\n", 0); + return; + } + + drag_first = true; + g_qeglobals.d_num_move_points = 0; + VectorCopy (vec3_origin, pressdelta); + pressx = x; + pressy = y; + + VectorCopy (xaxis, drag_xvec); + AxializeVector (drag_xvec); + VectorCopy (yaxis, drag_yvec); + AxializeVector (drag_yvec); + + if (g_qeglobals.d_select_mode == sel_vertex) + { + SelectVertexByRay (origin, dir); + if (g_qeglobals.d_num_move_points) + { + drag_ok = true; + return; + } + } + if (g_qeglobals.d_select_mode == sel_edge) + { + SelectEdgeByRay (origin, dir); + if (g_qeglobals.d_num_move_points) + { + drag_ok = true; + return; + } + } + + + // + // check for direct hit first + // + t = Test_Ray (origin, dir, true); + if (t.selected) + { + drag_ok = true; + + if (buttons == (MK_LBUTTON|MK_CONTROL) ) + { + Sys_Printf ("Shear dragging face\n"); + Brush_SelectFaceForDragging (t.brush, t.face, true); + } + else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) + { + Sys_Printf ("Sticky dragging brush\n"); + for (f=t.brush->brush_faces ; f ; f=f->next) + Brush_SelectFaceForDragging (t.brush, f, false); + } + else + Sys_Printf ("Dragging entire selection\n"); + + return; + } + + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) + return; + + // + // check for side hit + // + if (selected_brushes.next->next != &selected_brushes) + { +// if (buttons == (MK_LBUTTON|MK_RBUTTON)) +// { + // here is the multiple resize + b = selected_brushes.next; + while (b->brush_faces != NULL) + { + Brush_SideSelect (b, origin, dir, false); + b = b->next; + } + Sys_Printf ("Multiple Brush Side Stretch\n"); + Sys_Printf ("happy now?\n"); + drag_ok = true; + return; +// } +// else +// { +// return; +// } + } + + if (selected_brushes.next->owner->eclass->fixedsize) + { + Sys_Printf ("Can't stretch fixed size entities\n"); + return; + } + + + if (buttons & MK_CONTROL) + Brush_SideSelect (selected_brushes.next, origin, dir, true); + else + Brush_SideSelect (selected_brushes.next, origin, dir, false); + + + Sys_Printf ("Side stretch\n"); + drag_ok = true; +} + +entity_t *peLink; + +void UpdateTarget(vec3_t origin, vec3_t dir) +{ + trace_t t; + entity_t *pe; + int i; + char sz[128]; + + t = Test_Ray (origin, dir, 0); + + if (!t.brush) + return; + + pe = t.brush->owner; + + if (pe == NULL) + return; + + // is this the first? + if (peLink != NULL) + { + + // Get the target id from out current target + // if there is no id, make one + + i = IntForKey(pe, "target"); + if (i <= 0) + { + i = GetUniqueTargetId(1); + sprintf(sz, "%d", i); + + SetKeyValue(pe, "target", sz); + } + + // set the target # into our src + + sprintf(sz, "%d", i); + SetKeyValue(peLink, "targetname", sz); + + Sys_UpdateWindows(W_ENTITY); + + } + + // promote the target to the src + + peLink = pe; + +} + + +/* +=========== +Drag_Reset - resets type so undo works properly +=========== +*/ +void Drag_Reset () +{ + drag_type = drag_op_none; +} + + +/* +=========== +Drag_Begin +=========== +*/ +void Drag_Begin (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir) +{ + trace_t t; + + drag_ok = false; + VectorCopy (vec3_origin, pressdelta); + + drag_first = true; + peLink = NULL; + + // shift LBUTTON = select entire brush + if (buttons == (MK_LBUTTON | MK_SHIFT)) + { +// selection, don't want undo for this + drag_type = drag_op_noundo; + if (!dir[0] && !dir[1]) + Select_Ray (origin, dir, SF_ENTITIES_FIRST); // hack for XY + else + Select_Ray (origin, dir, 0); + return; + } + + // ctrl-shift LBUTTON = select single face + if (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) + { + drag_type = drag_op_noundo; + Select_Deselect (); + Select_Ray (origin, dir, SF_SINGLEFACE); + return; + } + + // LBUTTON + all other modifiers = manipulate selection + if (buttons & MK_LBUTTON) + { + Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir); + if(drag_type == drag_op_none) + { + UNDO_StartBrushDrag (); +// drag_type = drag_op_modify; + } + return; + } + + // middle button = grab texture + if (buttons == MK_MBUTTON) + { + drag_type = drag_op_noundo; + t = Test_Ray (origin, dir, false); + if (t.face) + { + g_qeglobals.d_new_brush_bottom_z = t.brush->mins[2]; + g_qeglobals.d_new_brush_top_z = t.brush->maxs[2]; + Texture_SetTexture (&t.face->texdef); + } + else + Sys_Printf ("Did not select a texture\n"); + return; + } + + // ctrl-middle button = set entire brush to texture + if (buttons == (MK_MBUTTON|MK_CONTROL) ) + { + drag_type = drag_op_noundo; + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.name[0] == '(') + Sys_Printf ("Can't change an entity texture\n"); + else + { + Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef); + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a brush\n"); + return; + } + + // ctrl-shift-middle button = set single face to texture + if (buttons == (MK_MBUTTON|MK_SHIFT|MK_CONTROL) ) + { + drag_type = drag_op_noundo; + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.name[0] == '(') + Sys_Printf ("Can't change an entity texture\n"); + else + { + t.face->texdef = g_qeglobals.d_texturewin.texdef; + Brush_Build( t.brush ); + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a brush\n"); + return; + } + drag_type = drag_op_noundo; + +} + + +/* +=========== +MoveSelection +=========== +*/ +void MoveSelection (vec3_t move) +{ + int i; + brush_t *b; + + if (!move[0] && !move[1] && !move[2]) + return; + + drag_type = drag_op_modify; + Sys_UpdateWindows (W_XY|W_CAMERA); + + // + // dragging only a part of the selection + // + if (g_qeglobals.d_num_move_points) + { + for (i=0 ; inext) + { + Brush_Build( b ); + for (i=0 ; i<3 ; i++) + if (b->mins[i] > b->maxs[i] + || b->maxs[i] - b->mins[i] > 4096) + break; // dragged backwards or fucked up + if (i != 3) + break; + } + + // if any of the brushes were crushed out of existance + // calcel the entire move + if (b != &selected_brushes) + { + Sys_Printf ("Brush dragged backwards, move canceled\n"); + for (i=0 ; inext) + Brush_Build( b ); + } + + } + else + { + // + // if there are lots of brushes selected, just translate instead + // of rebuilding the brushes + // + if (drag_yvec[2] == 0 && selected_brushes.next->next != &selected_brushes) + { + VectorAdd (g_qeglobals.d_select_translate, move, g_qeglobals.d_select_translate); + } + else + { + Select_Move (move); + } + } +} + +/* +=========== +Drag_MouseMoved +=========== +*/ +void Drag_MouseMoved (int x, int y, int buttons) +{ + vec3_t move, delta; + int i; + char movestring[128]; + + if (!buttons) + { + drag_ok = false; + return; + } + if (!drag_ok) + return; + + // clear along one axis + if (buttons & MK_SHIFT) + { + drag_first = false; + if (abs(x-pressx) > abs(y-pressy)) + y = pressy; + else + x = pressx; + } + + + for (i=0 ; i<3 ; i++) + { + move[i] = drag_xvec[i]*(x - pressx) + + drag_yvec[i]*(y - pressy); + move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + + sprintf (movestring, "drag (%i %i %i)", (int)move[0], (int)move[1], (int)move[2]); + Sys_Status (movestring, 0); + + VectorSubtract (move, pressdelta, delta); + MoveSelection (delta); + VectorCopy (move, pressdelta); +} + +/* +=========== +Drag_MouseUp +=========== +*/ +void Drag_MouseUp (void) +{ +// UNDO_FinishBrushEdit (); + + Sys_Status ("drag completed.", 0); + if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2]) + { + Select_Move (g_qeglobals.d_select_translate); + VectorCopy (vec3_origin, g_qeglobals.d_select_translate); + Sys_UpdateWindows (W_CAMERA); + } + switch(drag_type) + { + case drag_op_modify: + UNDO_FinishBrushDrag ("&Undo Drag"); + break; +// case drag_op_create: +// UNDO_FinishBrushAdd ("Undo New Brush"); + } +} diff --git a/Toolkit/Programming/Tools/qe4/eclass.c b/Toolkit/Programming/Tools/qe4/eclass.c new file mode 100644 index 0000000..69792f7 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/eclass.c @@ -0,0 +1,276 @@ + +#include "qe3.h" +#include "io.h" +#include "entityw.h" + +eclass_t *eclass; +eclass_t *eclass_bad; +char eclass_directory[1024]; + +/* + +the classname, color triple, and bounding box are parsed out of comments +A ? size means take the exact brush size. + +/*QUAKED (0 0 0) ? +/*QUAKED (0 0 0) (-8 -8 -8) (8 8 8) + +Flag names can follow the size description: + +/*QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY + +*/ +char *debugname; + +eclass_t *Eclass_InitFromText (char *text) +{ + char *t; + int len; + int r, i; + char parms[256], *p; + eclass_t *e; + char color[128]; + + + e = qmalloc(sizeof(*e)); + memset (e, 0, sizeof(*e)); + + text += strlen("/*QUAKED "); + +// grab the name + text = COM_Parse (text); + e->name = qmalloc (strlen(com_token)+1); + strcpy (e->name, com_token); + debugname = e->name; + +// grab the color, reformat as texture name + r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]); + if (r != 3) + return e; + sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); + strcpy (e->texdef.name, color); + + while (*text != ')') + { + if (!*text) + return e; + text++; + } + text++; + +// get the size + text = COM_Parse (text); + if (com_token[0] == '(') + { // parse the size as two vectors, mins and maxs + e->PhysicsModel = false; + e->fixedsize = true; + r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], + &e->maxs[0], &e->maxs[1], &e->maxs[2]); + if (r != 6) + return e; + + for (i=0 ; i<2 ; i++) + { + while (*text != ')') + { + if (!*text) + return e; + text++; + } + text++; + } + } + else if (!strcmp(com_token,"PHYSICS_MODEL")) + { // use the brushes + e->PhysicsModel = true; + } + else + { + e->PhysicsModel = false; + } + +// get the flags + + +// copy to the first /n + p = parms; + while (*text && *text != '\n') + *p++ = *text++; + *p = 0; + text++; + +// any remaining words are parm flags + p = parms; + for (i=0 ; iflagnames[i], com_token); + } + + for (i=FIRST_HIGH_SPAWNFLAG ; iflagnames[i - (FIRST_HIGH_SPAWNFLAG - LAST_LOW_SPAWNFLAG)], com_token); + } + + // find the length until close comment + for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++) + ; + +// copy the comment block out + len = t-text; + e->comments = qmalloc (len+1); + memcpy (e->comments, text, len); +#if 0 + for (i=0 ; icomments[i] = '\r'; + else + e->comments[i] = text[i]; +#endif + e->comments[len] = 0; + + return e; +} + + +/* +================= +Eclass_InsertAlphabetized +================= +*/ +void Eclass_InsertAlphabetized (eclass_t *e) +{ + eclass_t *s; + + if (!eclass) + { + eclass = e; + return; + } + + + s = eclass; + if (stricmp (e->name, s->name) < 0) + { + e->next = s; + eclass = e; + return; + } + + do + { + if (!s->next || stricmp (e->name, s->next->name) < 0) + { + e->next = s->next; + s->next = e; + return; + } + s=s->next; + } while (1); +} + + +/* +================= +Eclass_ScanFile +================= +*/ +void Eclass_ScanFile (char *filename) +{ + int size; + char *data; + eclass_t *e; + int i; + char temp[1024]; + + QE_ConvertDOSToUnixName( temp, filename ); + + Sys_Printf ("ScanFile: %s\n", temp); + + size = LoadFile (filename, (void *)&data); + + for (i=0 ; inext) + if (!strcmp (name, e->name)) + return e; + + // create a new class for it + if (has_brushes) + { + sprintf (init, "/*QUAKED %s (0 0.5 0) ?\nNot found in source.\n", name); + e = Eclass_InitFromText (init); + } + else + { + sprintf (init, "/*QUAKED %s (0 0.5 0) (-8 -8 -8) (8 8 8)\nNot found in source.\n", name); + e = Eclass_InitFromText (init); + } + + Eclass_InsertAlphabetized (e); + + return e; +} + diff --git a/Toolkit/Programming/Tools/qe4/entity.c b/Toolkit/Programming/Tools/qe4/entity.c new file mode 100644 index 0000000..619caea --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/entity.c @@ -0,0 +1,906 @@ +#include "qe3.h" + +BOOL KeyExists (entity_t *ent, char *key) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + return TRUE; + return FALSE; +} + +char *ValueForKey (entity_t *ent, char *key) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + return ep->value; + return ""; +} + +void SetKeyValue (entity_t *ent, char *key, char *value) +{ + epair_t *ep; + + if (ent == NULL) + return; + + if (!key || !key[0]) + return; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + { + free (ep->value); + ep->value = qmalloc(strlen(value)+1); + strcpy (ep->value, value); + return; + } + ep = qmalloc (sizeof(*ep)); + ep->next = ent->epairs; + ent->epairs = ep; + ep->key = qmalloc(strlen(key)+1); + strcpy (ep->key, key); + ep->value = qmalloc(strlen(value)+1); + strcpy (ep->value, value); +} + +void DeleteKey (entity_t *ent, char *key) +{ + epair_t **ep, *next; + + ep = &ent->epairs; + while (*ep) + { + next = *ep; + if ( !strcmp (next->key, key) ) + { + *ep = next->next; + free(next->key); + free(next->value); + free(next); + return; + } + ep = &next->next; + } +} + +float FloatForKey (entity_t *ent, char *key) +{ + char *k; + + k = ValueForKey (ent, key); + return atof(k); +} + +int IntForKey (entity_t *ent, char *key) +{ + char *k; + + k = ValueForKey (ent, key); + return atoi(k); +} + +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec) +{ + char *k; + + k = ValueForKey (ent, key); + sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]); +} + + +/* +=============== +Entity_Free + +Frees the entity and any brushes is has. +The entity is removed from the global entities list. +=============== +*/ +void Entity_Free (entity_t *e) +{ + epair_t *ep, *next; + + while (e->brushes.onext != &e->brushes) + Brush_Free (e->brushes.onext); + + if (e->next) + { + e->next->prev = e->prev; + e->prev->next = e->next; + } + + for (ep = e->epairs ; ep ; ep=next) + { + next = ep->next; + free (ep); + } + free (e); +} + +/* +================= +ParseEpair +================= +*/ +epair_t *ParseEpair (void) +{ + epair_t *e; + + e = qmalloc (sizeof(*e)); + + e->key = qmalloc(strlen(token)+1); + strcpy (e->key, token); + + GetToken (false); + e->value = qmalloc(strlen(token)+1); + strcpy (e->value, token); + + return e; +} + +/* +================ +Entity_Parse + +If onlypairs is set, the classname info will not +be looked up, and the entity will not be added +to the global list. Used for parsing the project. +================ +*/ +entity_t *Entity_Parse (qboolean onlypairs) +{ + entity_t *ent; + eclass_t *e; + brush_t *b; + vec3_t mins, maxs; + epair_t *ep; + qboolean has_brushes; + + if (!GetToken (true)) + return NULL; + + if (strcmp (token, "{") ) + Error ("ParseEntity: { not found"); + + ent = qmalloc (sizeof(*ent)); + ent->brushes.onext = ent->brushes.oprev = &ent->brushes; + + do + { + if (!GetToken (true)) + Error ("ParseEntity: EOF without closing brace"); + if (!strcmp (token, "}") ) + break; + if (!strcmp (token, "{") ) + { + b = Brush_Parse (); + b->owner = ent; + + // add to the end of the entity chain + b->onext = &ent->brushes; + b->oprev = ent->brushes.oprev; + ent->brushes.oprev->onext = b; + ent->brushes.oprev = b; + } + else + { + ep = ParseEpair (); + ep->next = ent->epairs; + ent->epairs = ep; + } + } while (1); + + if (onlypairs) + return ent; + + if (ent->brushes.onext == &ent->brushes) + has_brushes = false; + else + has_brushes = true; + + GetVectorForKey (ent, "origin", ent->origin); + + e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes); + ent->eclass = e; + if (e->fixedsize) + { // fixed size entity + if (ent->brushes.onext != &ent->brushes) + { + printf ("Warning: Fixed size entity with brushes\n"); +#if 0 + while (ent->brushes.onext != &ent->brushes) + { // FIXME: this will free the entity and crash! + Brush_Free (b); + } +#endif +ent->brushes.next = ent->brushes.prev = &ent->brushes; + } + // create a custom brush + VectorAdd (e->mins, ent->origin, mins); + VectorAdd (e->maxs, ent->origin, maxs); + b = Brush_Create (mins, maxs, &e->texdef); + b->owner = ent; + + b->onext = ent->brushes.onext; + b->oprev = &ent->brushes; + ent->brushes.onext->oprev = b; + ent->brushes.onext = b; + } + else + { // brush entity + if (ent->brushes.next == &ent->brushes) + printf ("Warning: Brush entity with no brushes\n"); + } + + // add all the brushes to the main list + for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext) + { + b->next = active_brushes.next; + active_brushes.next->prev = b; + b->prev = &active_brushes; + active_brushes.next = b; + } + + return ent; +} + +/* +============ +Entity_Write +============ +*/ +void Entity_Write (entity_t *e, FILE *f, qboolean use_region) +{ + epair_t *ep; + brush_t *b; +// vec3_t origin; +// char text[128]; + int count; + + + // if none of the entities brushes are in the region, + // don't write the entity at all + if (use_region) + { + // in region mode, save the camera position as playerstart + if ( !strcmp(ValueForKey (e, "classname"), "info_player_start") ) + { + fprintf (f, "{\n"); + fprintf (f, "\"classname\" \"info_player_start\"\n"); + fprintf (f, "\"origin\" \"%i %i %i\"\n", (int)camera.origin[0], + (int)camera.origin[1], (int)camera.origin[2]); + fprintf (f, "\"angle\" \"%i\"\n", (int)camera.angles[YAW]); + fprintf (f, "}\n"); + return; + } + + for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) + if (!Map_IsBrushFiltered(b)) + break; // got one + + if (b == &e->brushes) + return; // nothing visible + } + + // if fixedsize, calculate a new origin based on the current + // brush position +/* if (e->eclass->fixedsize) + { + VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin); // only called on save! + sprintf (text, "%i %i %i", (int)origin[0], + (int)origin[1], (int)origin[2]); + SetKeyValue (e, "origin", text); + } +*/ + fprintf (f, "{\n"); + for (ep = e->epairs ; ep ; ep=ep->next) + fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value); + + if (!e->eclass->fixedsize) // not a fixed sized entity, so write its brushes + // bmodels/physicsmodels fall into this category + { + count = 0; + for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) + { + if (!use_region || !Map_IsBrushFiltered (b)) + { + fprintf (f, "// brush %i\n", count); + count++; + Brush_Write (b, f); + } + } + } + fprintf (f, "}\n"); +} + + + +/* +============ +Entity_Create + +Creates a new entity out of the selected_brushes list. +If the entity class is fixed size, the brushes are only +used to find a midpoint. Otherwise, the brushes have +their ownershi[ transfered to the new entity. +============ +*/ +entity_t *Entity_Create (eclass_t *c) +{ + entity_t *e; + brush_t *b; + vec3_t mins, maxs; + int i; + vec3_t origin; + char text[128]; + + + // check to make sure the brushes are ok + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (b->owner != world_entity) + { + Sys_Printf ("Entity NOT created, brushes not all from world\n"); + Sys_Beep (); + return NULL; + } + + // create it + + e = qmalloc(sizeof(*e)); + e->brushes.onext = e->brushes.oprev = &e->brushes; + e->eclass = c; + SetKeyValue (e, "classname", c->name); + + // add the entity to the entity list + e->next = entities.next; + entities.next = e; + e->next->prev = e; + e->prev = &entities; + + if (c->PhysicsModel) + { + // get mins of the drawn area + b = selected_brushes.next; + GetPhysicsModelBrushes( b->mins, e ); + + // send the mins and the entity to the function which will get + // the brush data from the standard file + } + else if (c->fixedsize) + { + // + // just use the selection for positioning + // + b = selected_brushes.next; + for (i=0 ; i<3 ; i++) + e->origin[i] = b->mins[i] - c->mins[i]; + + // create a custom brush + VectorAdd (c->mins, e->origin, mins); + VectorAdd (c->maxs, e->origin, maxs); + b = Brush_Create (mins, maxs, &c->texdef); + + Entity_LinkBrush (e, b); + + // delete the current selection + Select_Delete (FALSE); + + // select the new brush + b->next = b->prev = &selected_brushes; + selected_brushes.next = selected_brushes.prev = b; + + + Brush_Build( b ); + + + VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin); + sprintf (text, "%i %i %i", (int)origin[0], + (int)origin[1], (int)origin[2]); + SetKeyValue (e, "origin", text); + + } + else + { + // + // change the selected brushes over to the new entity + // + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + Entity_UnlinkBrush (b); + Entity_LinkBrush (e, b); + Brush_Build( b ); // so the key brush gets a name + } + } + + Sys_UpdateWindows (W_ALL); + return e; +} + + +/* +=========== +Entity_LinkBrush +=========== +*/ +void Entity_LinkBrush (entity_t *e, brush_t *b) +{ + if (b->oprev || b->onext) + Error ("Entity_LinkBrush: Allready linked"); + b->owner = e; + + b->onext = e->brushes.onext; + b->oprev = &e->brushes; + e->brushes.onext->oprev = b; + e->brushes.onext = b; +} + +/* +=========== +Entity_UnlinkBrush +=========== +*/ +void Entity_UnlinkBrush (brush_t *b) +{ + if (!b->owner || !b->onext || !b->oprev) + Error ("Entity_UnlinkBrush: Not currently linked"); + b->onext->oprev = b->oprev; + b->oprev->onext = b->onext; + b->onext = b->oprev = NULL; + b->owner = NULL; +} + + + +/* +=========== +Entity_Clone +=========== +*/ +entity_t *Entity_Clone (entity_t *e) +{ + entity_t *n; + epair_t *ep, *np; + + n = qmalloc(sizeof(*n)); + n->brushes.onext = n->brushes.oprev = &n->brushes; + n->eclass = e->eclass; + + // add the entity to the entity list + n->next = entities.next; + entities.next = n; + n->next->prev = n; + n->prev = &entities; + + for (ep = e->epairs ; ep ; ep=ep->next) + { + np = qmalloc(sizeof(*np)); + np->key = copystring(ep->key); + np->value = copystring(ep->value); + np->next = n->epairs; + n->epairs = np; + } + return n; +} + +int GetUniqueTargetId(int iHint) +{ + int iMin, iMax, i; + BOOL fFound; + entity_t *pe; + + fFound = FALSE; + pe = entities.next; + iMin = 0; + iMax = 0; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + i = IntForKey(pe, "target"); + if (i) + { + iMin = min(i, iMin); + iMax = max(i, iMax); + if (i == iHint) + fFound = TRUE; + } + } + + if (fFound) + return iMax + 1; + else + return iHint; +} + +entity_t *FindEntity(char *pszKey, char *pszValue) +{ + entity_t *pe; + + pe = entities.next; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + if (!strcmp(ValueForKey(pe, pszKey), pszValue)) + return pe; + } + + return NULL; +} + +entity_t *FindEntityInt(char *pszKey, int iValue) +{ + entity_t *pe; + + pe = entities.next; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + if (IntForKey(pe, pszKey) == iValue) + return pe; + } + + return NULL; +} +/* +================ +Entity_ListInUse +================ + +*/ + +void Entity_ListInUse (void) +{ + + entlist_t* entitylist; // the first entity name in the list + entlist_t* thisentity; // entity currently read in + entlist_t* curEntity; // entity in the list that we're working with + entlist_t* prevEntity; // entity prior to curEntity + entity_t* e; + + entitylist = NULL; + + SetInspectorMode(W_CONSOLE); + Sys_ClearPrintf(); + Sys_Printf ("Entities in use:\n"); + + if ( entities.next != &entities ) + { + for ( e = entities.next ; e != &entities ; e = e->next) + { + thisentity = malloc( sizeof(entlist_t)); + if (thisentity == NULL) + { + Error("Not enough memory"); + return; + } + thisentity->uses = 0; + thisentity->name[0] = '\0'; + thisentity->prev = NULL; + thisentity->next = NULL; + strcpy(thisentity->name, e->eclass->name); + + if (entitylist == NULL) + { + thisentity->uses++; + entitylist = thisentity; //put first member on list + } + else + { + curEntity = entitylist; // grab the list + prevEntity = curEntity->prev; + while (1) + { + if (curEntity->name == NULL) // end of list + { + thisentity->uses++; + thisentity->prev = prevEntity; // add Entity on + prevEntity->next = thisentity; + break; + } + if (strcmp(thisentity->name,curEntity->name) == 0) // Entity already on list + { + curEntity->uses++; + free (thisentity); + break; + } + if (strcmp(thisentity->name,curEntity->name) < 0) // Entity belongs ahead of this one + { + if (prevEntity == NULL) // texture goes at front of list + { + thisentity->uses++; + thisentity->next = curEntity; + curEntity->prev = thisentity; + entitylist = thisentity; // list now starts here + } + else + { + thisentity->uses++; + thisentity->prev = curEntity->prev; + thisentity->next = curEntity; + curEntity->prev = thisentity; + prevEntity->next = thisentity; + } + break; + } + prevEntity = curEntity; + curEntity = curEntity->next; // advance to next Entity in list + } // while + } // else + } //entity loop + + for (curEntity = entitylist; curEntity; curEntity=curEntity->next) + { + Sys_Printf("%s, Used %d times\n",curEntity->name, curEntity->uses); + } + + + } // any entities? + else + { + Sys_Printf ("No entities in use.\n"); + } + +} + +/*============== + PrintConsole + ============*/ + +void PrintConsole(void) +{ + DOCINFO di; + PRINTDLG pd; + + LRESULT theResult; + UINT buffsize; + char* buff; + + int i; + char thechar; + + char* lineStart; + int lineSize; + + TEXTMETRIC textMetrics; + RECT textRect; + int lineNum; // lame hard code, i know, but time is short right now + + + lineNum = 0; + theResult = SendMessage(g_qeglobals.d_hwndEdit, WM_GETTEXTLENGTH, 0, 0); + buffsize = (UINT)theResult; + if (buffsize <= 0) + { + return; + } + + buff = (char*)malloc(buffsize); + theResult = SendMessage(g_qeglobals.d_hwndEdit, WM_GETTEXT, (WPARAM)buffsize, (LPARAM)buff); + if (buffsize != (UINT)theResult) + { + buffsize = (UINT)theResult; + } + + memset ( &pd, 0, sizeof(pd)); + pd.lStructSize = sizeof(pd); + pd.hwndOwner = g_qeglobals.d_hwndEdit; + pd.Flags = PD_RETURNDC; + pd.hInstance = 0; + + if ( !PrintDlg( &pd ) || !pd.hDC ) + { + free(buff); + MessageBox( g_qeglobals.d_hwndMain, "Could not PrintDlg()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + + memset ( &di, 0, sizeof(di)); + di.cbSize = sizeof( di ); + di.lpszDocName = "Console"; + + if ( StartDoc( pd.hDC, &di ) <= 0 ) + { + free(buff); + MessageBox( g_qeglobals.d_hwndMain, "Could not StartDoc()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + + if ( StartPage( pd.hDC ) <= 0 ) + { + free(buff); + MessageBox( g_qeglobals.d_hwndMain, "Could not StartPage()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + // establish print page and get textRect from that + GetTextMetrics(pd.hDC, &textMetrics); + SetRect(&textRect, 0, 0, 11550, textMetrics.tmHeight); + lineStart = buff; + lineSize = 0; + for (i = 0; i < buffsize; i++) + { + thechar = buff[i]; + lineSize++; + if((thechar == '\n') || (lineSize == 80)) // need a line feed + { + lineNum++; + DrawText(pd.hDC, lineStart, lineSize, &textRect, DT_LEFT); + lineStart += lineSize; + lineSize = 0; + textRect.top = textRect.bottom; + textRect.bottom += textMetrics.tmHeight + textMetrics.tmExternalLeading; + if (lineNum == 60) + { + if ( EndPage( pd.hDC ) <= 0 ) + { + free(buff); + MessageBox( g_qeglobals.d_hwndMain, "QE4 Print Error", "Could not EndPage()", MB_OK | MB_ICONERROR ); + return; + } + if ( StartPage( pd.hDC ) <= 0 ) + { + free(buff); + MessageBox( g_qeglobals.d_hwndMain, "Could not StartPage()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + lineNum = 0; + textRect.top = 0; + textRect.bottom = textMetrics.tmHeight; + // set up new pagerect and textrect + } + } + } + + free(buff); + if ( EndPage( pd.hDC ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "QE4 Print Error", "Could not EndPage()", MB_OK | MB_ICONERROR ); + return; + } + + if ( EndDoc( pd.hDC ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "QE4 Print Error", "Could not EndDoc()", MB_OK | MB_ICONERROR ); + return; + } + +} + +//=============================== +// GetPhysicsModelBrushes +//=============================== +/* + This function looks in the standard physics model file specified in the project file for + the brush data corresponding to the entity that is passed to it. It then adds those brushes + to the entity and puts them on the map. +*/ + + + +void GetPhysicsModelBrushes (vec3_t mins, entity_t *e) +{ + char* physmodfile; + char* data; + + physmodfile = ValueForKey(g_qeglobals.d_project_entity, "physicsmodels"); + + if ( LoadFileNoCrash (physmodfile, (void *)&data) == -1) + { + Error ("Failed to load physics model file specified in project file."); + return; + } + + StartTokenParsing (data); + Physmod_Parse( e , mins); + + + return; +} + +void Physmod_Parse ( entity_t *e, vec3_t mins) +{ + qboolean rightent, moveorigin, getout; + brush_t* b; + epair_t* ep; + + rightent = false; + moveorigin = true; + getout = false; + + if (!GetToken (true)) + { + return; + } + + if (strcmp (token, "{") ) // file must start with { + { + Error ("Physmod_Parse: { not found"); + return; + } + + do // parsing for physmodels + { + if (!GetToken (true)) + { + Error ("Physmod_Parse: EOF without closing brace"); + return; + } + if (!strcmp (token, "}end") ) + { + break; // EOF + } + if (!strcmp (token, "entity{")) // got one, start parsing an entity + { + do + { + GetToken(true); + if (!strcmp (token, "{")) // brush data for entity + { + if (rightent) + { + b = Brush_Parse (); + Entity_LinkBrush (e,b); + Brush_Move(b, mins, moveorigin); + moveorigin = false; + } + else // hey, we shouldn't be getting brush data until we know we + // have the right entity! + { + Error("Brush data before confirmation of correct entity!"); + return; + } + } + else if (!strcmp (token, "}")) + { + if (rightent) + { + // delete the current selection + Select_Delete (FALSE); + for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) + { + Brush_AddToList(b, &selected_brushes); + } + return;//we're done + } + else + { + break;//end of entity, check next + } + } + else // we should be getting epair kay/values + { + ep = ParseEpair (); + if (!strcmp(ep->key, "classname")) + { + if (!strcmp(ep->value, ValueForKey(e, "classname"))) + { + rightent = true; + } + else + { + break; // not the right physicsmodel + } + } + else + { + if (rightent) + { + SetKeyValue(e, ep->key, ep->value); + } + else + { + Error("Physics model data without classname specification."); + return; + } + } + } // getting epair key/values + } while (1); + } + } while (1); + + return; + +} diff --git a/Toolkit/Programming/Tools/qe4/entity.h b/Toolkit/Programming/Tools/qe4/entity.h new file mode 100644 index 0000000..524a136 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/entity.h @@ -0,0 +1,78 @@ + +// entity.h +#define ENTKEY_COLOR "_color" + + +#define MAX_FLAGS 17 + +typedef struct eclass_s +{ + struct eclass_s *next; + char *name; + qboolean fixedsize; + qboolean PhysicsModel; //new pseudo bmodel type + qboolean unknown; // wasn't found in source + vec3_t mins, maxs; + vec3_t color; + texdef_t texdef; + char *comments; + char flagnames[MAX_FLAGS][32]; +} eclass_t; + +extern eclass_t *eclass; + +void Eclass_InitForSourceDirectory (char *path); +eclass_t *Eclass_ForName (char *name, qboolean has_brushes); + +//=================================================== + + +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct entity_s +{ + struct entity_s *prev, *next; + brush_t brushes; // head/tail of list + vec3_t origin; + eclass_t *eclass; + epair_t *epairs; +} entity_t; + +typedef struct entlist_s +{ + char name[64]; + int uses; + struct entlist_s* prev; + struct entlist_s* next; +} entlist_t; + +BOOL KeyExists (entity_t *ent, char *key); +char *ValueForKey (entity_t *ent, char *key); +void SetKeyValue (entity_t *ent, char *key, char *value); +void DeleteKey (entity_t *ent, char *key); +float FloatForKey (entity_t *ent, char *key); +int IntForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +void Entity_Free (entity_t *e); +entity_t *Entity_Parse (qboolean onlypairs); +void Entity_Write (entity_t *e, FILE *f, qboolean use_region); +entity_t *Entity_Create (eclass_t *c); +entity_t *Entity_Clone (entity_t *e); + +void Entity_LinkBrush (entity_t *e, brush_t *b); +void Entity_UnlinkBrush (brush_t *b); +entity_t *FindEntity(char *pszKey, char *pszValue); +entity_t *FindEntityInt(char *pszKey, int iValue); +void Entity_ListInUse (void); +void PrintConsole(void); +void GetPhysicsModelBrushes(vec3_t mins, entity_t *e); +void Physmod_Parse ( entity_t *e, vec3_t mins); + +int GetUniqueTargetId(int iHint); + diff --git a/Toolkit/Programming/Tools/qe4/entityw.h b/Toolkit/Programming/Tools/qe4/entityw.h new file mode 100644 index 0000000..c36481a --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/entityw.h @@ -0,0 +1,61 @@ +// entity.h + +#define DlgXBorder 5 +#define DlgYBorder 5 + + +#define EntList 0 +#define EntComment 1 +#define EntCheck1 2 +#define EntCheck2 3 +#define EntCheck3 4 +#define EntCheck4 5 +#define EntCheck5 6 +#define EntCheck6 7 +#define EntCheck7 8 +#define EntCheck8 9 +#define EntCheck9 10 +#define EntCheck10 11 +#define EntCheck11 12 +#define EntCheck12 13 + +#define EntCheck13 14 +#define EntCheck14 15 +#define EntCheck15 16 +#define EntCheck16 17 +#define EntCheck17 18 +#define EntCheck18 19 +#define EntCheck19 20 +#define EntCheck20 21 +#define EntCheck21 22 + +#define EntProps 23 +#define EntDir0 24 +#define EntDir45 25 +#define EntDir90 26 +#define EntDir135 27 +#define EntDir180 28 +#define EntDir225 29 +#define EntDir270 30 +#define EntDir315 31 +#define EntDirUp 32 +#define EntDirDown 33 +#define EntDelProp 34 +#define EntKeyLabel 35 +#define EntKeyField 36 +#define EntValueLabel 37 +#define EntValueField 38 +#define EntColor 39 + +#define EntLast 40 + +#define NUM_SPAWNFLAGS 21 +#define LAST_LOW_SPAWNFLAG 8 +#define FIRST_HIGH_SPAWNFLAG 13 +#define LAST_HIGH_SPAWNFLAG 21 + +extern HWND hwndEnt[EntLast]; + +extern int rgIds[EntLast]; + +int GetEntityColor(int iIndex); \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qe4/glingr.h b/Toolkit/Programming/Tools/qe4/glingr.h new file mode 100644 index 0000000..41d1faa --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/glingr.h @@ -0,0 +1,76 @@ +// This .h file contains constants, typedefs, etc. for Intergraph +// extensions to OpenGL. These extensions are: +// +// Multiple Palette Extension +// Texture Object Extension + +#define GL_INGR_multiple_palette 1 +#define GL_EXT_texture_object 1 + + +// New constants and typedefs for the Multiple Palette Extension +#define GL_PALETTE_INGR 0x80c0 +#define GL_MAX_PALETTES_INGR 0x80c1 +#define GL_MAX_PALETTE_ENTRIES_INGR 0x80c2 +#define GL_CURRENT_PALETTE_INGR 0x80c3 +#define GL_PALETTE_WRITEMASK_INGR 0x80c4 +#define GL_CURRENT_RASTER_PALETTE_INGR 0x80c5 +#define GL_PALETTE_CLEAR_VALUE_INGR 0x80c6 + +// Function prototypes for the Multiple Palette Extension routines +typedef void (APIENTRY *PALETTEFUNCPTR)(GLuint); +typedef void (APIENTRY *PALETTEMASKFUNCPTR)(GLboolean); +typedef void (APIENTRY *WGLLOADPALETTEFUNCPTR)(GLuint, GLsizei, GLuint *); +typedef void (APIENTRY *CLEARPALETTEFUNCPTR)(GLuint); + + +// New Constants and typedefs for the Texture Object Extension +#define GL_TEXTURE_PRIORITY_EXT 0x8066 +#define GL_TEXTURE_RESIDENT_EXT 0x8067 +#define GL_TEXTURE_1D_BINDING_EXT 0x8068 +#define GL_TEXTURE_2D_BINDING_EXT 0x8069 + +// Function prototypes for the Texture Object Extension routines +typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *, + const GLboolean *); +typedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint); +typedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *); +typedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *); +typedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint); +typedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *, + const GLclampf *); + + +/* OpenGL ExtEscape escape function constants */ +#ifndef OPENGL_GETINFO +#define OPENGL_GETINFO 4353 /* for OpenGL ExtEscape */ +#endif + +// OPENGL_GETINFO ExtEscape sub-escape numbers. They are defined by +// Microsoft. + +#ifndef OPENGL_GETINFO_DRVNAME + +#define OPENGL_GETINFO_DRVNAME 0 + + +// Input structure for OPENGL_GETINFO ExtEscape. + +typedef struct _OPENGLGETINFO +{ + ULONG ulSubEsc; +} OPENGLGETINFO, *POPENGLGETINFO; + + +// Output structure for OPENGL_GETINFO_DRVNAME ExtEscape. + +typedef struct _GLDRVNAMERET +{ + ULONG ulVersion; // must be 1 for this version + ULONG ulDriverVersion; // driver specific version number + WCHAR awch[MAX_PATH+1]; +} GLDRVNAMERET, *PGLDRVNAMERET; + +#endif + + diff --git a/Toolkit/Programming/Tools/qe4/icon1.ico b/Toolkit/Programming/Tools/qe4/icon1.ico new file mode 100644 index 0000000..d5f65ce Binary files /dev/null and b/Toolkit/Programming/Tools/qe4/icon1.ico differ diff --git a/Toolkit/Programming/Tools/qe4/map.c b/Toolkit/Programming/Tools/qe4/map.c new file mode 100644 index 0000000..49b251c --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/map.c @@ -0,0 +1,731 @@ +// map.c + + +#include "qe3.h" + +qboolean modified; // for quit confirmation (0 = clean, 1 = unsaved, + // 2 = autosaved, but not regular saved) + +char currentmap[1024]; + +brush_t active_brushes; // brushes currently being displayed +brush_t selected_brushes; // highlighted +face_t *selected_face; +brush_t *selected_face_brush; +brush_t filtered_brushes; // brushes that have been filtered or regioned + +entity_t entities; // head/tail of doubly linked list + +entity_t *world_entity; + +void AddRegionBrushes (void); +void RemoveRegionBrushes (void); + +/* +============================================================= + + Cross map selection saving + + this could fuck up if you have only part of a complex entity selected... +============================================================= +*/ + +brush_t between_brushes; +entity_t between_entities; + + +void Map_SaveBetween (void) +{ + brush_t *b; + entity_t *e, *e2; + + between_brushes.next = selected_brushes.next; + between_brushes.prev = selected_brushes.prev; + between_brushes.next->prev = &between_brushes; + between_brushes.prev->next = &between_brushes; + + between_entities.next = between_entities.prev = &between_entities; + selected_brushes.next = selected_brushes.prev = &selected_brushes; + + for (b=between_brushes.next ; b != &between_brushes ; b=b->next) + { + e = b->owner; + if (e == world_entity) + b->owner = NULL; + else + { + for (e2=between_entities.next ; e2 != &between_entities ; e2=e2->next) + if (e2 == e) + goto next; // allready got the entity + // move the entity over + e->prev->next = e->next; + e->next->prev = e->prev; + e->next = between_entities.next; + e->prev = &between_entities; + e->next->prev = e; + e->prev->next = e; + } +next: ; + } +} + +void Map_RestoreBetween (void) +{ + entity_t *head, *tail; + brush_t *b; + + if (!between_brushes.next) + return; + + for (b=between_brushes.next ; b != &between_brushes ; b=b->next) + { + if (!b->owner) + { + b->owner = world_entity; + b->onext = world_entity->brushes.onext; + b->oprev = &world_entity->brushes; + b->onext->oprev = b; + b->oprev->onext = b; + } + } + + selected_brushes.next = between_brushes.next; + selected_brushes.prev = between_brushes.prev; + selected_brushes.next->prev = &selected_brushes; + selected_brushes.prev->next = &selected_brushes; + + head = between_entities.next; + tail = between_entities.prev; + + if (head != tail) + { + entities.prev->next = head; + head->prev = entities.prev; + tail->next = &entities; + entities.prev = tail; + } + + between_brushes.next = NULL; + between_entities.next = NULL; +} + +//============================================================================ + +void Map_BuildBrushData(qboolean firsttime) +{ + brush_t *b, *next; + int angle; + + if (active_brushes.next == NULL) + return; + + Sys_BeginWait (); // this could take a while + + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=b->next) + b->rotatedonload = false; + + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next) + { + next = b->next; + Brush_Build( b ); + if (strcmp(b->owner->eclass->name,"worldspawn") && + (b->rotatedonload != true) && + (b->owner->eclass->fixedsize) && + (firsttime == true)) // entity + { + b->rotatedonload = true; + angle = FloatForKey(b->owner, "angle"); // this will read in entity facings correctly and draw + if (angle > -1) + { + Select_Brush(b); + Select_RotateAxis( 2, 0-angle ); + Select_Deselect(); + } + } + if (!b->brush_faces) + { + Brush_Free (b); + Sys_Printf ("Removed degenerate brush\n"); + } + } + + Sys_EndWait(); +} + +entity_t *Map_FindClass (char *cname) +{ + entity_t *ent; + + for (ent = entities.next ; ent != &entities ; ent=ent->next) + { + if (!strcmp(cname, ValueForKey (ent, "classname"))) + return ent; + } + return NULL; +} + +/* +================ +Map_Free +================ +*/ +void Map_Free (void) +{ + if (selected_brushes.next && + (selected_brushes.next != &selected_brushes) ) + { + if (MessageBox(g_qeglobals.d_hwndMain, "Copy selection?", "", MB_YESNO) == IDYES) + Map_SaveBetween (); + } + + Texture_ClearInuse (); + Pointfile_Clear (); + strcpy (currentmap, "unnamed.map"); + Sys_SetTitle (currentmap); + g_qeglobals.d_num_entities = 0; + + if (!active_brushes.next) + { // first map + active_brushes.prev = active_brushes.next = &active_brushes; + selected_brushes.prev = selected_brushes.next = &selected_brushes; + filtered_brushes.prev = filtered_brushes.next = &filtered_brushes; + + entities.prev = entities.next = &entities; + } + else + { + while (active_brushes.next != &active_brushes) + Brush_Free (active_brushes.next); + while (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next); + while (filtered_brushes.next != &filtered_brushes) + Brush_Free (filtered_brushes.next); + + while (entities.next != &entities) + Entity_Free (entities.next); + } + + world_entity = NULL; +} + +/* +================ +Map_LoadFile +================ +*/ +void Map_LoadFile (char *filename) +{ + char *buf; + entity_t *ent; + char temp[1024]; + + Sys_BeginWait (); + + SetInspectorMode(W_CONSOLE); + + QE_ConvertDOSToUnixName( temp, filename ); + Sys_Printf ("Map_LoadFile: %s\n", temp ); + + Map_Free (); + + g_qeglobals.d_parsed_brushes = 0; + strcpy (currentmap, filename); + LoadFile (filename, (void **)&buf); + + StartTokenParsing (buf); + + g_qeglobals.d_num_entities = 0; + + while (1) + { + ent = Entity_Parse (false); + if (!ent) + break; + if (!strcmp(ValueForKey (ent, "classname"), "worldspawn")) + { + if (world_entity) + Sys_Printf ("WARNING: multiple worldspawn\n"); + world_entity = ent; + } + else + { + // add the entity to the end of the entity list + ent->next = &entities; + ent->prev = entities.prev; + entities.prev->next = ent; + entities.prev = ent; + g_qeglobals.d_num_entities++; + } + } + + free (buf); + + if (!world_entity) + { + Sys_Printf ("No worldspawn in map.\n"); + Map_New (); + return; + } + + Sys_Printf ("--- LoadMapFile ---\n"); + Sys_Printf ("%s\n", temp ); + + Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes ); + Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities); + + + Sys_Printf ("Map_BuildAllDisplayLists\n"); + Map_BuildBrushData(true); + Map_RestoreBetween (); + + // + // move the view to a start position + // + ent = Map_FindClass ("info_player_start"); + if (!ent) + ent = Map_FindClass ("info_player_deathmatch"); + camera.angles[PITCH] = 0; + if (ent) + { + GetVectorForKey (ent, "origin", camera.origin); + GetVectorForKey (ent, "origin", g_qeglobals.d_xy.origin); + camera.angles[YAW] = FloatForKey (ent, "angle"); + } + else + { + camera.angles[YAW] = 0; + VectorCopy (vec3_origin, camera.origin); + VectorCopy (vec3_origin, g_qeglobals.d_xy.origin); + } + + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); + + + Map_RegionOff (); + + QE_ResetIdle(); + modified = false; + Sys_SetTitle (temp); + Texture_SetScrollRange(); + Texture_ShowInuse (); + + Sys_EndWait(); + +} + +/* +=========== +Map_SaveFile +=========== +*/ + + +void Map_SaveFile (char *filename, qboolean use_region ) +{ + entity_t *e, *next, *prev, *after; + FILE *f; + char temp[1024]; + int count; + qboolean swapmade; + + QE_ConvertDOSToUnixName( temp, filename ); + + if (!use_region) + { + char backup[1024]; + + // rename current to .bak + strcpy (backup, filename); + StripExtension (backup); + strcat (backup, ".bak"); + _unlink (backup); + rename (filename, backup); + } + + Sys_Printf ("Map_SaveFile: %s\n", filename); + + f = fopen(filename, "w"); + if (!f) + { + Sys_Printf ("ERROR!!!! Couldn't open %s\n", filename); + return; + } + + if (use_region) + AddRegionBrushes (); + + // write world entity first + Entity_Write (world_entity, f, use_region); + + swapmade = true; + while (swapmade) + { + swapmade = false; + for (e=entities.next ; e != &entities ; e=next) + { + // lame bubble sort by e->origin[2], but hey, it fits this editor's style well + // **** set up to see if stuff exists + if (e->prev != &entities) + { + prev = e->prev; + } + else + { + prev = NULL; + } + if (e->next != &entities) + { + next = e->next; + if (e->next->next != &entities) + { + after = e->next->next; + } + else + { + after = NULL; + } + } + else + { + next = e->next; + continue; + } + // **** end of set up to see if stuff exists + + if (e->origin[2] > next->origin[2]) + { //swap 'em + swapmade = true; + if (prev) + { + prev->next = next; + next->prev = prev; + } + else + { + next->prev = &entities; + entities.next = next; + } + if (after) + { + next->next->prev = e; + e->next = after; + } + else + { + e->next = &entities; + } + e->prev = next; + next->next = e; + next = e; + } + } + } + // then write all other ents + count = 1; + for (e=entities.next ; e != &entities ; e=next) + { + fprintf (f, "// entity %i\n", count); + count++; + next = e->next; + if (e->brushes.onext == &e->brushes) + Entity_Free (e); // no brushes left, so remove it + else + Entity_Write (e, f, use_region); + } + + fclose (f); + + if (use_region) + RemoveRegionBrushes (); + + Sys_Printf ("Saved.\n"); + QE_ResetIdle(); + modified = false; + + if ( !strstr( temp, "autosave" ) ) + Sys_SetTitle (temp); + + if (!use_region) + { + time_t timer; + FILE *f; + + time (&timer); + MessageBeep (MB_ICONEXCLAMATION); + f = fopen ("c:/tstamps.log", "a"); + if (f) + { + fprintf (f, "%4i : %35s : %s", g_qeglobals.d_workcount, filename, ctime(&timer)); + fclose (f); + g_qeglobals.d_workcount = 0; + } + fclose (f); + Sys_Status ("Saved.\n", 0); + } +} + +/* +=========== +Map_New +=========== +*/ +void Map_New (void) +{ + Sys_Printf ("Map_New\n"); + Map_Free (); + world_entity = qmalloc(sizeof(*world_entity)); + world_entity->brushes.onext = + world_entity->brushes.oprev = &world_entity->brushes; + SetKeyValue (world_entity, "classname", "worldspawn"); + world_entity->eclass = Eclass_ForName ("worldspawn", true); + + camera.angles[YAW] = 0; + VectorCopy (vec3_origin, camera.origin); + camera.origin[2] = 48; + VectorCopy (vec3_origin, g_qeglobals.d_xy.origin); + + Map_RestoreBetween (); + + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); + + QE_ResetIdle(); + modified = false; +} + + +/* +=========================================================== + + REGION + +=========================================================== +*/ + +qboolean region_active; +vec3_t region_mins = {-4096, -4096, -4096}; +vec3_t region_maxs = {4096, 4096, 4096}; + +brush_t *region_sides[4]; + +/* +=========== +AddRegionBrushes + +a regioned map will have temp walls put up at the region boundary +=========== +*/ +void AddRegionBrushes (void) +{ + vec3_t mins, maxs; + int i; + texdef_t td; + + if (!region_active) + return; + + memset (&td, 0, sizeof(td)); + strcpy (td.name, "REGION"); + + mins[0] = region_mins[0] - 16; + maxs[0] = region_mins[0] + 1; + mins[1] = region_mins[1] - 16; + maxs[1] = region_maxs[1] + 16; + mins[2] = -2048; + maxs[2] = 2048; + region_sides[0] = Brush_Create (mins, maxs, &td); + + mins[0] = region_maxs[0] - 1; + maxs[0] = region_maxs[0] + 16; + region_sides[1] = Brush_Create (mins, maxs, &td); + + mins[0] = region_mins[0] - 16; + maxs[0] = region_maxs[0] + 16; + mins[1] = region_mins[1] - 16; + maxs[1] = region_mins[1] + 1; + region_sides[2] = Brush_Create (mins, maxs, &td); + + mins[1] = region_maxs[1] - 1; + maxs[1] = region_maxs[1] + 16; + region_sides[3] = Brush_Create (mins, maxs, &td); + + for (i=0 ; i<4 ; i++) + { + Brush_AddToList (region_sides[i], &selected_brushes); + Entity_LinkBrush (world_entity, region_sides[i]); + Brush_Build( region_sides[i] ); + } +} + +void RemoveRegionBrushes (void) +{ + int i; + + if (!region_active) + return; + for (i=0 ; i<4 ; i++) + Brush_Free (region_sides[i]); +} + + +qboolean Map_IsBrushFiltered (brush_t *b) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] > region_maxs[i]) + return true; + if (b->maxs[i] < region_mins[i]) + return true; + } + return false; +} + +/* +=========== +Map_RegionOff + +Other filtering options may still be on +=========== +*/ +void Map_RegionOff (void) +{ + brush_t *b, *next; + int i; + + region_active = false; + for (i=0 ; i<3 ; i++) + { + region_maxs[i] = 4096; + region_mins[i] = -4096; + } + + for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next) + { + next = b->next; + if (Map_IsBrushFiltered (b)) + continue; // still filtered + Brush_RemoveFromList (b); + Brush_AddToList (b, &active_brushes); + } + + Sys_UpdateWindows (W_ALL); +} + +void Map_ApplyRegion (void) +{ + brush_t *b, *next; + + region_active = true; + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + if (!Map_IsBrushFiltered (b)) + continue; // still filtered + Brush_RemoveFromList (b); + Brush_AddToList (b, &filtered_brushes); + } + + Sys_UpdateWindows (W_ALL); +} + + +/* +======================== +Map_RegionSelectedBrushes +======================== +*/ +void Map_RegionSelectedBrushes (void) +{ + Map_RegionOff (); + + region_active = true; + Select_GetBounds (region_mins, region_maxs); + + // move the entire active_brushes list to filtered_brushes + filtered_brushes.next = active_brushes.next; + filtered_brushes.prev = active_brushes.prev; + filtered_brushes.next->prev = &filtered_brushes; + filtered_brushes.prev->next = &filtered_brushes; + + // move the entire selected_brushes list to active_brushes + active_brushes.next = selected_brushes.next; + active_brushes.prev = selected_brushes.prev; + active_brushes.next->prev = &active_brushes; + active_brushes.prev->next = &active_brushes; + + // clear selected_brushes + selected_brushes.next = selected_brushes.prev = &selected_brushes; + + Sys_UpdateWindows (W_ALL); +} + + +/* +=========== +Map_RegionXY +=========== +*/ +void Map_RegionXY (void) +{ + Map_RegionOff (); + + region_mins[0] = g_qeglobals.d_xy.origin[0] - 0.5*g_qeglobals.d_xy.width/g_qeglobals.d_xy.scale; + region_maxs[0] = g_qeglobals.d_xy.origin[0] + 0.5*g_qeglobals.d_xy.width/g_qeglobals.d_xy.scale; + region_mins[1] = g_qeglobals.d_xy.origin[1] - 0.5*g_qeglobals.d_xy.height/g_qeglobals.d_xy.scale; + region_maxs[1] = g_qeglobals.d_xy.origin[1] + 0.5*g_qeglobals.d_xy.height/g_qeglobals.d_xy.scale; + region_mins[2] = -4096; + region_maxs[2] = 4096; + + Map_ApplyRegion (); +} + +/* +=========== +Map_RegionTallBrush +=========== +*/ +void Map_RegionTallBrush (void) +{ + brush_t *b; + + if (!QE_SingleBrush ()) + return; + + b = selected_brushes.next; + + Map_RegionOff (); + + VectorCopy (b->mins, region_mins); + VectorCopy (b->maxs, region_maxs); + region_mins[2] = -4096; + region_maxs[2] = 4096; + + Select_Delete (FALSE); + Map_ApplyRegion (); +} +/* +=========== +Map_RegionBrush +=========== +*/ +void Map_RegionBrush (void) +{ + brush_t *b; + + if (!QE_SingleBrush ()) + return; + + b = selected_brushes.next; + + Map_RegionOff (); + + VectorCopy (b->mins, region_mins); + VectorCopy (b->maxs, region_maxs); + + Select_Delete (FALSE); + Map_ApplyRegion (); +} + diff --git a/Toolkit/Programming/Tools/qe4/map.h b/Toolkit/Programming/Tools/qe4/map.h new file mode 100644 index 0000000..f563b9b --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/map.h @@ -0,0 +1,31 @@ +// map.h -- the state of the current world that all views are displaying + +extern char currentmap[1024]; + +// head/tail of doubly linked lists +extern brush_t active_brushes; // brushes currently being displayed +extern brush_t selected_brushes; // highlighted +extern face_t *selected_face; +extern brush_t *selected_face_brush; +extern brush_t filtered_brushes; // brushes that have been filtered or regioned + +extern entity_t entities; +extern entity_t *world_entity; // the world entity is NOT included in + // the entities chain + +extern qboolean modified; // for quit confirmations + +extern vec3_t region_mins, region_maxs; +extern qboolean region_active; + +void Map_LoadFile (char *filename); +void Map_SaveFile (char *filename, qboolean use_region); +void Map_New (void); +void Map_BuildBrushData(qboolean firsttime); + +void Map_RegionOff (void); +void Map_RegionXY (void); +void Map_RegionTallBrush (void); +void Map_RegionBrush (void); +void Map_RegionSelectedBrushes (void); +qboolean Map_IsBrushFiltered (brush_t *b); diff --git a/Toolkit/Programming/Tools/qe4/mru.c b/Toolkit/Programming/Tools/qe4/mru.c new file mode 100644 index 0000000..41f8596 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/mru.c @@ -0,0 +1,649 @@ +//************************************************************* +// File name: mru.c +// +// Description: +// +// Routines for MRU support +// +// Development Team: +// +// Gilles Vollant (100144.2636@compuserve.com) +// +//************************************************************* + +#include +#include +#include + +#include "mru.h" +// CreateMruMenu : MRUMENU constructor +// wNbLruShowInit : nb of item showed in menu +// wNbLruMenuInit : nb of item stored in memory +// wMaxSizeLruItemInit : size max. of filename + + +//************************************************************* +// +// CreateMruMenu() +// +// Purpose: +// +// Allocate and Initialize an MRU and return a pointer on it +// +// +// Parameters: +// +// WORD wNbLruShowInit - Maximum number of item displayed on menu +// WORD wNbLruMenuInit - Maximum number of item stored in memory +// WORD wMaxSizeLruItemInit - Maximum size of an item (ie size of pathname) +// WORD wIdMruInit - ID of the first item in the menu (default:IDMRU) +// +// +// Return: (LPMRUMENU) +// +// Pointer on a MRUMENU structure, used by other function +// +// +// Comments: +// wNbLruShowInit <= wNbLruMenuInit +// +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* + +LPMRUMENU CreateMruMenu (WORD wNbLruShowInit, + WORD wNbLruMenuInit,WORD wMaxSizeLruItemInit,WORD wIdMruInit) +{ +LPMRUMENU lpMruMenu; + lpMruMenu = (LPMRUMENU)GlobalAllocPtr(GHND,sizeof(MRUMENU)); + + lpMruMenu->wNbItemFill = 0; + lpMruMenu->wNbLruMenu = wNbLruMenuInit; + lpMruMenu->wNbLruShow = wNbLruShowInit; + lpMruMenu->wIdMru = wIdMruInit; + lpMruMenu->wMaxSizeLruItem = wMaxSizeLruItemInit; + lpMruMenu->lpMRU = (LPSTR)GlobalAllocPtr(GHND, + lpMruMenu->wNbLruMenu*(UINT)lpMruMenu->wMaxSizeLruItem); + if (lpMruMenu->lpMRU == NULL) + { + GlobalFreePtr(lpMruMenu); + lpMruMenu = NULL; + } + return lpMruMenu; +} + +//************************************************************* +// +// CreateMruMenuDefault() +// +// Purpose: +// +// Allocate and Initialize an MRU and return a pointer on it +// Use default parameter +// +// +// Parameters: +// +// +// Return: (LPMRUMENU) +// +// Pointer on a MRUMENU structure, used by other function +// +// +// Comments: +// +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* + +LPMRUMENU CreateMruMenuDefault() +{ + return CreateMruMenu (NBMRUMENUSHOW,NBMRUMENU,MAXSIZEMRUITEM,IDMRU); +} + + +//************************************************************* +// +// DeleteMruMenu() +// +// Purpose: +// Destructor : +// Clean and free a MRUMENU structure +// +// Parameters: +// +// LPMRUMENU lpMruMenu - pointer on MRUMENU, allocated +// by CreateMruMenu() or CreateMruMenuDefault() +// +// +// Return: void +// +// +// Comments: +// +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +void DeleteMruMenu(LPMRUMENU lpMruMenu) +{ + GlobalFreePtr(lpMruMenu->lpMRU); + GlobalFreePtr(lpMruMenu); +} + +//************************************************************* +// +// SetNbLruShow() +// +// Purpose: +// Change the maximum number of item displayed on menu +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// WORD wNbLruShowInit - Maximum number of item displayed on menu +// +// +// Return: void +// +// +// Comments: +// +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +void SetNbLruShow (LPMRUMENU lpMruMenu,WORD wNbLruShowInit) +{ + lpMruMenu->wNbLruShow = min(wNbLruShowInit,lpMruMenu->wNbLruMenu); +} + +//************************************************************* +// +// SetMenuItem() +// +// Purpose: +// Set the filename of an item +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// WORD wItem - Number of Item to set, zero based +// LPSTR lpItem - String, contain the filename of the item +// +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// used when load .INI or reg database +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL SetMenuItem (LPMRUMENU lpMruMenu,WORD wItem,LPSTR lpItem) +{ + if (wItem >= NBMRUMENU) + return FALSE; + _fstrncpy((lpMruMenu->lpMRU) + + ((lpMruMenu->wMaxSizeLruItem) * (UINT)wItem), + lpItem,lpMruMenu->wMaxSizeLruItem-1); + lpMruMenu->wNbItemFill = max(lpMruMenu->wNbItemFill,wItem+1); + return TRUE; +} + +//************************************************************* +// +// GetMenuItem() +// +// Purpose: +// Get the filename of an item +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// WORD wItem - Number of Item to set, zero based +// BOOL fIDMBased - TRUE : wItem is based on ID menu item +// FALSE : wItem is zero-based +// LPSTR lpItem - String where the filename of the item will be +// stored by GetMenuItem() +// UINT uiSize - Size of the lpItem buffer +// +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Used for saving in .INI or reg database, or when user select +// an MRU in File menu +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL GetMenuItem (LPMRUMENU lpMruMenu,WORD wItem, + BOOL fIDMBased,LPSTR lpItem,UINT uiSize) +{ + if (fIDMBased) + wItem -= (lpMruMenu->wIdMru + 1); + if (wItem >= lpMruMenu->wNbItemFill) + return FALSE; + _fstrncpy(lpItem,(lpMruMenu->lpMRU) + + ((lpMruMenu->wMaxSizeLruItem) * (UINT)(wItem)),uiSize); + *(lpItem+uiSize-1) = '\0'; + return TRUE; +} + +//************************************************************* +// +// AddNewItem() +// +// Purpose: +// Add an item at the begin of the list +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpItem - String contain the filename to add +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Used when used open a file (using File Open common +// dialog, Drag and drop or MRU) +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +void AddNewItem (LPMRUMENU lpMruMenu,LPSTR lpItem) +{ +WORD i,j; + for (i=0;iwNbItemFill;i++) + if (lstrcmpi(lpItem,(lpMruMenu->lpMRU) + + ((lpMruMenu->wMaxSizeLruItem) * (UINT)i)) == 0) + { + // Shift the other items + for (j=i;j>0;j--) + lstrcpy((lpMruMenu->lpMRU) + (lpMruMenu->wMaxSizeLruItem * (UINT)j), + (lpMruMenu->lpMRU) + (lpMruMenu->wMaxSizeLruItem * (UINT)(j-1))); + _fstrncpy(lpMruMenu->lpMRU,lpItem,lpMruMenu->wMaxSizeLruItem-1); + return ; + } + lpMruMenu->wNbItemFill = min(lpMruMenu->wNbItemFill+1,lpMruMenu->wNbLruMenu); + for (i=lpMruMenu->wNbItemFill-1;i>0;i--) + lstrcpy(lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)i), + lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)(i-1))); + _fstrncpy(lpMruMenu->lpMRU,lpItem,lpMruMenu->wMaxSizeLruItem-1); +} + +//************************************************************* +// +// DelMenuItem() +// +// Purpose: +// Delete an item +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// WORD wItem - Number of Item to set, zero based +// BOOL fIDMBased - TRUE : wItem is based on ID menu item +// FALSE : wItem is zero-based +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Used when used open a file, using MRU, and when an error +// occured (by example, when file was deleted) +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL DelMenuItem(LPMRUMENU lpMruMenu,WORD wItem,BOOL fIDMBased) +{ +WORD i; + if (fIDMBased) + wItem -= (lpMruMenu->wIdMru + 1); + if (lpMruMenu->wNbItemFill <= wItem) + return FALSE; + lpMruMenu->wNbItemFill--; + for (i=wItem;iwNbItemFill;i++) + lstrcpy(lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)i), + lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)(i+1))); + return TRUE; +} + +//************************************************************* +// +// PlaceMenuMRUItem() +// +// Purpose: +// Add MRU at the end of a menu +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// HMENU hMenu - Handle of menu where MRU must be added +// UINT uiItem - Item of menu entry where MRU must be added +// +// Return: void +// +// +// Comments: +// Used MRU is modified, for refresh the File menu +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +void PlaceMenuMRUItem(LPMRUMENU lpMruMenu,HMENU hMenu,UINT uiItem) +{ +int i; +WORD wNbShow; + if (hMenu == NULL) + return; + // remove old MRU in menu + for (i=0;i<=(int)(lpMruMenu->wNbLruMenu);i++) + RemoveMenu(hMenu,i+lpMruMenu->wIdMru,MF_BYCOMMAND); + + if (lpMruMenu->wNbItemFill == 0) + return; + + // If they are item, insert a separator before the files + InsertMenu(hMenu,uiItem,MF_SEPARATOR,lpMruMenu->wIdMru,NULL); + + wNbShow = min(lpMruMenu->wNbItemFill,lpMruMenu->wNbLruShow); + for (i=(int)wNbShow-1;i>=0;i--) + { + LPSTR lpTxt; + if (lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20)) + { + wsprintf(lpTxt,"&%lu %s", + (DWORD)(i+1),lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem*(UINT)i)); + InsertMenu(hMenu,(((WORD)i)!=(wNbShow-1)) ? (lpMruMenu->wIdMru+i+2) : lpMruMenu->wIdMru, + MF_STRING,lpMruMenu->wIdMru+i+1,lpTxt); + GlobalFreePtr(lpTxt); + } + } + +} + +/////////////////////////////////////////// + + + +//************************************************************* +// +// SaveMruInIni() +// +// Purpose: +// Save MRU in a private .INI +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpszSection - Points to a null-terminated string containing +// the name of the section +// LPSTR lpszFile - Points to a null-terminated string that names +// the initialization file. +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// See WritePrivateProfileString API for more info on lpszSection and lpszFile +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL SaveMruInIni(LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile) +{ +LPSTR lpTxt; +WORD i; + + lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20); + if (lpTxt == NULL) + return FALSE; + + for (i=0;iwNbLruMenu;i++) + { + char szEntry[16]; + wsprintf(szEntry,"File%lu",(DWORD)i+1); + if (!GetMenuItem(lpMruMenu,i,FALSE,lpTxt,lpMruMenu->wMaxSizeLruItem + 10)) + *lpTxt = '\0'; + WritePrivateProfileString(lpszSection,szEntry,lpTxt,lpszFile); + } + GlobalFreePtr(lpTxt); + WritePrivateProfileString(NULL,NULL,NULL,lpszFile); // flush cache + return TRUE; +} + + +//************************************************************* +// +// LoadMruInIni() +// +// Purpose: +// Load MRU from a private .INI +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpszSection - Points to a null-terminated string containing +// the name of the section +// LPSTR lpszFile - Points to a null-terminated string that names +// the initialization file. +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// See GetPrivateProfileString API for more info on lpszSection and lpszFile +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL LoadMruInIni(LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile) +{ +LPSTR lpTxt; +WORD i; + lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20); + if (lpTxt == NULL) + return FALSE; + + for (i=0;iwNbLruMenu;i++) + { + char szEntry[16]; + + wsprintf(szEntry,"File%lu",(DWORD)i+1); + GetPrivateProfileString(lpszSection,szEntry,"",lpTxt, + lpMruMenu->wMaxSizeLruItem + 10,lpszFile); + if (*lpTxt == '\0') + break; + SetMenuItem(lpMruMenu,i,lpTxt); + } + GlobalFreePtr(lpTxt); + return TRUE; +} + +#ifdef WIN32 + +BOOL IsWin395OrHigher(void) +{ + WORD wVer; + + wVer = LOWORD(GetVersion()); + wVer = (((WORD)LOBYTE(wVer)) << 8) | (WORD)HIBYTE(wVer); + + return (wVer >= 0x035F); // 5F = 95 dec +} + + +//************************************************************* +// +// SaveMruInReg() +// +// Purpose: +// Save MRU in the registry +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpszKey - Points to a null-terminated string +// specifying the name of a key that +// this function opens or creates. +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Win32 function designed for Windows NT and Windows 95 +// See RegCreateKeyEx API for more info on lpszKey +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL SaveMruInReg(LPMRUMENU lpMruMenu,LPSTR lpszKey) +{ +LPSTR lpTxt; +WORD i; +HKEY hCurKey; +DWORD dwDisp; + + lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20); + if (lpTxt == NULL) + return FALSE; + + RegCreateKeyEx(HKEY_CURRENT_USER,lpszKey,0,NULL, + REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hCurKey,&dwDisp); + + for (i=0;iwNbLruMenu;i++) + { + char szEntry[16]; + wsprintf(szEntry,"File%lu",(DWORD)i+1); + if (!GetMenuItem(lpMruMenu,i,FALSE,lpTxt,lpMruMenu->wMaxSizeLruItem + 10)) + *lpTxt = '\0'; + RegSetValueEx(hCurKey,szEntry,0,REG_SZ,lpTxt,lstrlen(lpTxt)); + } + RegCloseKey(hCurKey); + GlobalFreePtr(lpTxt); + return TRUE; +} + +//************************************************************* +// +// LoadMruInReg() +// +// Purpose: +// Load MRU from the registry +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpszKey - Points to a null-terminated string +// specifying the name of a key that +// this function opens or creates. +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Win32 function designed for Windows NT and Windows 95 +// See RegOpenKeyEx API for more info on lpszKey +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL LoadMruInReg(LPMRUMENU lpMruMenu,LPSTR lpszKey) +{ +LPSTR lpTxt; +WORD i; +HKEY hCurKey; +DWORD dwType; + lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20); + if (lpTxt == NULL) + return FALSE; + + RegOpenKeyEx(HKEY_CURRENT_USER,lpszKey,0,KEY_READ,&hCurKey); + + + for (i=0;iwNbLruMenu;i++) + { + char szEntry[16]; + DWORD dwSizeBuf; + wsprintf(szEntry,"File%lu",(DWORD)i+1); + *lpTxt = '\0'; + dwSizeBuf = lpMruMenu->wMaxSizeLruItem + 10; + RegQueryValueEx(hCurKey,szEntry,NULL,&dwType,(LPBYTE)lpTxt,&dwSizeBuf); + *(lpTxt+dwSizeBuf)='\0'; + if (*lpTxt == '\0') + break; + SetMenuItem(lpMruMenu,i,lpTxt); + } + RegCloseKey(hCurKey); + GlobalFreePtr(lpTxt); + return TRUE; +} + + +//************************************************************* +// +// GetWin32Kind() +// +// Purpose: +// Get the Win32 platform +// +// Parameters: +// +// Return: (WIN32KIND) +// WINNT - Run under Windows NT +// WIN32S - Run under Windows 3.1x + Win32s +// WIN95ORGREATHER - Run under Windows 95 +// +// +// Comments: +// Win32 function designed for Windows NT and Windows 95 +// See RegOpenKeyEx API for more info on lpszKey +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +WIN32KIND GetWin32Kind() +{ +BOOL IsWin395OrHigher(void); + + WORD wVer; + + if ((GetVersion() & 0x80000000) == 0) + return WINNT; + wVer = LOWORD(GetVersion()); + wVer = (((WORD)LOBYTE(wVer)) << 8) | (WORD)HIBYTE(wVer); + + if (wVer >= 0x035F) + return WIN95ORGREATHER; + else + return WIN32S; +} +#endif diff --git a/Toolkit/Programming/Tools/qe4/mru.h b/Toolkit/Programming/Tools/qe4/mru.h new file mode 100644 index 0000000..39d257e --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/mru.h @@ -0,0 +1,79 @@ +//************************************************************* +// File name: mru.h +// +// Description: +// +// Header for MRU support +// +// Development Team: +// +// Gilles Vollant (100144.2636@compuserve.com) +// +//************************************************************* + +#ifndef __MRU_H__ +#define __MRU_H__ + +#define NBMRUMENUSHOW 6 // Default number of MRU showed in the menu File +#define NBMRUMENU 9 // Default number of MRU stored +#define IDMRU 8000 // Default First ID of MRU +#ifdef OFS_MAXPATHNAME +#define MAXSIZEMRUITEM OFS_MAXPATHNAME +#else +#define MAXSIZEMRUITEM 128 // Default max size of an entry +#endif + +typedef struct +{ +WORD wNbItemFill; +WORD wNbLruShow; +WORD wNbLruMenu; +WORD wMaxSizeLruItem; +WORD wIdMru; +LPSTR lpMRU; +} MRUMENU; + +typedef MRUMENU FAR * LPMRUMENU; + +#ifdef __cplusplus +LPMRUMENU CreateMruMenu (WORD wNbLruShowInit=NBMRUMENUSHOW, + WORD wNbLruMenuInit=NBMRUMENU, + WORD wMaxSizeLruItemInit=MAXSIZEMRUITEM, + WORD wIdMruInit=IDMRU); +#else +LPMRUMENU CreateMruMenu (WORD wNbLruShowInit, + WORD wNbLruMenuInit, + WORD wMaxSizeLruItemInit, + WORD wIdMruInit); +#endif + +LPMRUMENU CreateMruMenuDefault(); +void DeleteMruMenu (LPMRUMENU lpMruMenu); + +void SetNbLruShow (LPMRUMENU lpMruMenu,WORD wNbLruShowInit); +BOOL SetMenuItem (LPMRUMENU lpMruMenu,WORD wItem, + LPSTR lpItem); +BOOL GetMenuItem (LPMRUMENU lpMruMenu,WORD wItem, + BOOL fIDMBased,LPSTR lpItem,UINT uiSize); +BOOL DelMenuItem (LPMRUMENU lpMruMenu,WORD wItem,BOOL fIDMBased); +void AddNewItem (LPMRUMENU lpMruMenu,LPSTR lpItem); +void PlaceMenuMRUItem(LPMRUMENU lpMruMenu,HMENU hMenu,UINT uiItem); + +BOOL SaveMruInIni (LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile); +BOOL LoadMruInIni (LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile); +#ifdef WIN32 +BOOL SaveMruInReg (LPMRUMENU lpMruMenu,LPSTR lpszKey); +BOOL LoadMruInReg (LPMRUMENU lpMruMenu,LPSTR lpszKey); + +typedef enum +{ +WIN32S, +WINNT, +WIN95ORGREATHER +} WIN32KIND; +WIN32KIND GetWin32Kind(); +#endif + + +////////////////////////////////////////////////////////////// +#endif diff --git a/Toolkit/Programming/Tools/qe4/parse.c b/Toolkit/Programming/Tools/qe4/parse.c new file mode 100644 index 0000000..8d7d702 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/parse.c @@ -0,0 +1,120 @@ + +#include "qe3.h" + +char token[MAXTOKEN]; +qboolean unget; +char *script_p; +int scriptline; + +void StartTokenParsing (char *data) +{ + scriptline = 1; + script_p = data; + unget = false; +} + +qboolean GetToken (qboolean crossline) +{ + char *token_p; + + if (unget) // is a token allready waiting? + return true; + +// +// skip space +// +skipspace: + while (*script_p <= 32) + { + if (!*script_p) + { + if (!crossline) + Error ("Line %i is incomplete",scriptline); + return false; + } + if (*script_p++ == '\n') + { + if (!crossline) + Error ("Line %i is incomplete",scriptline); + scriptline++; + } + } + + if (script_p[0] == '/' && script_p[1] == '/') // comment field + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + while (*script_p++ != '\n') + if (!*script_p) + { + if (!crossline) + Error ("Line %i is incomplete",scriptline); + return false; + } + goto skipspace; + } + +// +// copy token +// + token_p = token; + + if (*script_p == '"') + { + script_p++; + while ( *script_p != '"' ) + { + if (!*script_p) + Error ("EOF inside quoted token"); + *token_p++ = *script_p++; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i",scriptline); + } + script_p++; + } + else while ( *script_p > 32 ) + { + *token_p++ = *script_p++; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i",scriptline); + } + + *token_p = 0; + + return true; +} + +void UngetToken (void) +{ + unget = true; +} + + +/* +============== +TokenAvailable + +Returns true if there is another token on the line +============== +*/ +qboolean TokenAvailable (void) +{ + char *search_p; + + search_p = script_p; + + while ( *search_p <= 32) + { + if (*search_p == '\n') + return false; + if (*search_p == 0) + return false; + search_p++; + } + + if (*search_p == ';') + return false; + + return true; +} + diff --git a/Toolkit/Programming/Tools/qe4/parse.h b/Toolkit/Programming/Tools/qe4/parse.h new file mode 100644 index 0000000..7218604 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/parse.h @@ -0,0 +1,12 @@ +// parse.h -- text file parsing routines + +#define MAXTOKEN 1024 + +extern char token[MAXTOKEN]; +extern int scriptline; + +void StartTokenParsing (char *data); +qboolean GetToken (qboolean crossline); +void UngetToken (void); +qboolean TokenAvailable (void); + diff --git a/Toolkit/Programming/Tools/qe4/points.c b/Toolkit/Programming/Tools/qe4/points.c new file mode 100644 index 0000000..e0098c3 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/points.c @@ -0,0 +1,134 @@ + +#include "qe3.h" + + +#define MAX_POINTFILE 8192 +static vec3_t s_pointvecs[MAX_POINTFILE]; +static int s_num_points, s_check_point; + +void Pointfile_Delete (void) +{ + char name[1024]; + + strcpy (name, currentmap); + StripExtension (name); + strcat (name, ".lin"); + + remove(name); +} + +// advance camera to next point +void Pointfile_Next (void) +{ + vec3_t dir; + + if (s_check_point >= s_num_points-2) + { + Sys_Status ("End of pointfile", 0); + return; + } + s_check_point++; + VectorCopy (s_pointvecs[s_check_point], camera.origin); + VectorCopy (s_pointvecs[s_check_point], g_qeglobals.d_xy.origin); + VectorSubtract (s_pointvecs[s_check_point+1], camera.origin, dir); + VectorNormalize (dir,dir); + camera.angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + camera.angles[0] = asin (dir[2])*180/3.14159; + + Sys_UpdateWindows (W_ALL); +} + +// advance camera to previous point +void Pointfile_Prev (void) +{ + vec3_t dir; + + if ( s_check_point == 0) + { + Sys_Status ("Start of pointfile", 0); + return; + } + s_check_point--; + VectorCopy (s_pointvecs[s_check_point], camera.origin); + VectorCopy (s_pointvecs[s_check_point], g_qeglobals.d_xy.origin); + VectorSubtract (s_pointvecs[s_check_point+1], camera.origin, dir); + VectorNormalize (dir,dir); + camera.angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + camera.angles[0] = asin (dir[2])*180/3.14159; + + Sys_UpdateWindows (W_ALL); +} + +void Pointfile_Check (void) +{ + char name[1024]; + FILE *f; + vec3_t v; + + strcpy (name, currentmap); + StripExtension (name); + strcat (name, ".lin"); + + f = fopen (name, "r"); + if (!f) + return; + + Sys_Printf ("Reading pointfile %s\n", name); + + if (!g_qeglobals.d_pointfile_display_list) + g_qeglobals.d_pointfile_display_list = glGenLists(1); + + s_num_points = 0; + glNewList (g_qeglobals.d_pointfile_display_list, GL_COMPILE); + glColor3f (1, 0, 0); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_1D); + glLineWidth (4); + glBegin(GL_LINE_STRIP); + do + { + if (fscanf (f, "%f %f %f\n", &v[0], &v[1], &v[2]) != 3) + break; + if (s_num_points < MAX_POINTFILE) + { + VectorCopy (v, s_pointvecs[s_num_points]); + s_num_points++; + } + glVertex3fv (v); + } while (1); + glEnd(); + glLineWidth (1); + glEndList (); + + s_check_point = 0; + fclose (f); + Pointfile_Next (); +} + +void Pointfile_Draw( void ) +{ + int i; + + glColor3f( 1.0F, 0.0F, 0.0F ); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_1D); + glLineWidth (4); + glBegin(GL_LINE_STRIP); + for ( i = 0; i < s_num_points; i++ ) + { + glVertex3fv( s_pointvecs[i] ); + } + glEnd(); + glLineWidth( 1 ); +} + +void Pointfile_Clear (void) +{ + if (!g_qeglobals.d_pointfile_display_list) + return; + + glDeleteLists (g_qeglobals.d_pointfile_display_list, 1); + g_qeglobals.d_pointfile_display_list = 0; + Sys_UpdateWindows (W_ALL); +} + diff --git a/Toolkit/Programming/Tools/qe4/q.bmp b/Toolkit/Programming/Tools/qe4/q.bmp new file mode 100644 index 0000000..598971a Binary files /dev/null and b/Toolkit/Programming/Tools/qe4/q.bmp differ diff --git a/Toolkit/Programming/Tools/qe4/qe3.c b/Toolkit/Programming/Tools/qe4/qe3.c new file mode 100644 index 0000000..7df929c --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/qe3.c @@ -0,0 +1,536 @@ + +#include "qe3.h" +#include "undo.h" + +QEGlobals_t g_qeglobals; + +void QE_CheckOpenGLForErrors(void) +{ + int i; + + while ( ( i = glGetError() ) != GL_NO_ERROR ) + { + char buffer[100]; + + sprintf( buffer, "OpenGL Error: %s", gluErrorString( i ) ); + + MessageBox( g_qeglobals.d_hwndMain, buffer , "QuakeEd Error", MB_OK | MB_ICONEXCLAMATION ); + exit( 1 ); + } +} + + +char *ExpandReletivePath (char *p) +{ + static char temp[1024]; + char *base; + + if (!p || !p[0]) + return NULL; + if (p[0] == '/' || p[0] == '\\') + return p; + + base = ValueForKey(g_qeglobals.d_project_entity, "basepath"); + sprintf (temp, "%s/%s", base, p); + return temp; +} + + +void QE_ResetIdle(void) +{ + int h,m,s; + double diff; + clock_t now; + static clock_t i_start = 0; + + now = clock(); + + if ( now - i_start > ( CLOCKS_PER_SEC * 60 * QE_IDLE_LOG_INTERVAL ) ) + { + diff = (now - i_start) / CLOCKS_PER_SEC; + h = diff / (60*60); + diff -= h * (60*60); + m = diff / 60; + diff -= m * 60; + s = diff; + WriteUserLog("Idle Time: %d:%02d:%02d",h,m,s); + } + + i_start = now; +} + +/* +=============== +QE_CheckAutoSave + +If five minutes have passed since making a change +and the map hasn't been saved, save it out. +=============== +*/ +void QE_CheckAutoSave( void ) +{ + static clock_t s_start; + clock_t now; + + now = clock(); + + if ( modified != 1 || !s_start) + { + s_start = now; + return; + } + + if ( now - s_start > ( CLOCKS_PER_SEC * 60 * QE_AUTOSAVE_INTERVAL ) ) + { + Sys_Printf ("Autosaving...\n"); + Sys_Status ("Autosaving...", 0 ); + + Map_SaveFile (ValueForKey(g_qeglobals.d_project_entity, "autosave"), false); + + Sys_Status ("Autosaving...Saved.", 0 ); + modified = 2; + s_start = now; + } +} + + + +/* +=========== +QE_LoadProject +=========== +*/ +qboolean QE_LoadProject (char *projectfile) +{ + char *data; + char path2[MAX_PATH]; + + Sys_Printf ("QE_LoadProject (%s)\n", projectfile); + + strcpy(path2, projectfile); + StripExtension(path2); + DefaultExtension(path2, ".mat"); + QFile_ReadMaterialTypes(ExpandArg(path2)); + if ( LoadFileNoCrash (projectfile, (void *)&data) == -1) + return false; + StartTokenParsing (data); + g_qeglobals.d_project_entity = Entity_Parse (true); // parses project file and + // stores key value pairs in linked list g_qeglobals.d_project_entity.epairs, accessed + // using ValueforKey(g_qeglobals.d_project_entity, "keyname")); + if (!g_qeglobals.d_project_entity) + Error ("Couldn't parse %s", projectfile); + free (data); + + Eclass_InitForSourceDirectory (ValueForKey (g_qeglobals.d_project_entity, "entitypath")); + + FillClassList (); // list in entity window + + Map_New (); + + FillTextureMenu (); + FillBSPMenu (); + + return true; +} + +/* +=========== +QE_KeyDown +=========== +*/ +#define SPEED_MOVE 32 +#define SPEED_TURN 22.5 + +qboolean QE_KeyDown (int key) +{ + switch (key) + { + case VK_UP: + VectorMA (camera.origin, SPEED_MOVE, camera.forward, camera.origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_DOWN: + VectorMA (camera.origin, -SPEED_MOVE, camera.forward, camera.origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_LEFT: + camera.angles[1] += SPEED_TURN; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_RIGHT: + camera.angles[1] -= SPEED_TURN; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_COMMA: + VectorMA (camera.origin, -SPEED_MOVE, camera.right, camera.origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_PERIOD: + VectorMA (camera.origin, SPEED_MOVE, camera.right, camera.origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_BACK: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_DELETE, 0); + break; + case VK_ESCAPE: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_DESELECT, 0); + break; + case VK_END: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_CENTER, 0); + break; + case VK_DELETE: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_ZOOMIN, 0); + break; + case VK_INSERT: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_ZOOMOUT, 0); + break; + case VK_NEXT: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_DOWNFLOOR, 0); + break; + case VK_PRIOR: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_UPFLOOR, 0); + break; + case 'A': + camera.angles[0] += SPEED_TURN; + if (camera.angles[0] > 85) + camera.angles[0] = 85; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case 'C': + camera.origin[2] -= SPEED_MOVE; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z_OVERLAY); + break; + case 'D': + camera.origin[2] += SPEED_MOVE; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z_OVERLAY); + break; + case 'E': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_DRAGEDGES, 0); + break; + case 'G': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_BRUSH_ROTATEX, 0); + break; + case 'H': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_BRUSH_ROTATEY, 0); + break; + case 'I': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_BRUSH_FLIPZ, 0); + break; + case 'J': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_BRUSH_ROTATEZ, 0); + break; + case 'K': + PostMessage( g_qeglobals.d_hwndMain, WM_COMMAND, ID_MISC_SELECTENTITYCOLOR, 0 ); + break; + case 'N': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_ENTITY, 0); + break; + case 'O': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_CONSOLE, 0); + break; + case 'S': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_TEXTURES_INSPECTOR, 0); + break; + case 'T': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_TEXTURE, 0); + break; + case 'U': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_BRUSH_FLIPY, 0); + break; + case 'V': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_DRAGVERTECIES, 0); + break; + case 'W': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_TOWER, 0); + break; + case 'Y': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_BRUSH_FLIPX, 0); + break; + case 'Z': + camera.angles[0] -= SPEED_TURN; + if (camera.angles[0] < -85) + camera.angles[0] = -85; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case '0': + g_qeglobals.d_showgrid = !g_qeglobals.d_showgrid; + PostMessage( g_qeglobals.d_hwndXY, WM_PAINT, 0, 0 ); + break; + case '1': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_1, 0); + break; + case '2': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_2, 0); + break; + case '3': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_4, 0); + break; + case '4': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_8, 0); + break; + case '5': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_16, 0); + break; + case '6': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_32, 0); + break; + case '7': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_64, 0); + break; + case ' ': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_CLONE, 0); + break; + default: + return false; + } + + return true; +} + +/* +=============== +ConnectEntities + +Sets target / targetname on the two entities selected +from the first selected to the secon +=============== +*/ +void ConnectEntities (void) +{ + entity_t *e1, *e2, *e; + char *target, *tn, *target2, *target1; + int maxtarg, targetnum; + char newtarg[32]; + + if (!QE_DoubleEntity()) + { + Sys_Status ("Must have two different entities selected.", 0); + Sys_Beep (); + return; + } + + e1 = g_qeglobals.d_select_order[0]->owner; + e2 = g_qeglobals.d_select_order[1]->owner; + + if (e1 == world_entity || e2 == world_entity) + { + Sys_Status ("Can't connect to the world.", 0); + Sys_Beep (); + return; + } + + target1 = ValueForKey (e1, "target"); + target = target1; + + target2 = ValueForKey (e1, "target2"); + if ((target && target[0]) && (target2 && target2[0]))// e1 has a target and target2 name + { + strcpy (newtarg, target); + } + else + { + target = ValueForKey (e2, "targetname"); + if (target && target[0]) + strcpy (newtarg, target); + else + { + // make a unique target value + maxtarg = 0; + for (e=entities.next ; e != &entities ; e=e->next) + { + tn = ValueForKey (e, "targetname"); + if (tn && tn[0]) + { + targetnum = atoi(tn+1); + if (targetnum > maxtarg) + maxtarg = targetnum; + } + } + sprintf (newtarg, "t%i", maxtarg+1); + } + } + + if (target1 && target1[0] && (!(strcmp(ValueForKey(e1, "classname"), "info_buoy")))) + { + SetKeyValue ( e1, "target2", newtarg); + } + else + { + SetKeyValue (e1, "target", newtarg); + } + SetKeyValue (e2, "targetname", newtarg); + Sys_UpdateWindows (W_XY | W_CAMERA); + + Select_Deselect(); + Select_Brush (g_qeglobals.d_select_order[1]); +} + +qboolean QE_SingleBrush (void) +{ + if ( (selected_brushes.next == &selected_brushes) + || (selected_brushes.next->next != &selected_brushes) ) + { + Sys_Printf ("Error: you must have a single brush selected\n"); + return false; + } + if (selected_brushes.next->owner->eclass->fixedsize) + { + Sys_Printf ("Error: you cannot manipulate fixed size entities\n"); + return false; + } + + return true; +} + +// similar to above, except allows fixed size +qboolean QE_DoubleBrush (void) +{ + brush_t *brush; + brush = selected_brushes.next; + if(brush == &selected_brushes) + { + return false; + } + // brushes are added at head, so reverse order + g_qeglobals.d_select_order[1] = brush; + brush = brush->next; + if(brush == &selected_brushes) + { + return false; + } + g_qeglobals.d_select_order[0] = brush; + if(brush->next != &selected_brushes) + { + return false; + } + return true; +} + +qboolean QE_DoubleEntity (void) +{ + entity_t *e1,*e2,*e3; + brush_t *b1,*b2; + + b1 = selected_brushes.next; + if((b1 == &selected_brushes) || (b1->next == &selected_brushes)) + { + return false; // one or no brush selected + } + + e1 = b1->owner; + b2 = b1->next; + e2 = b2->owner; + while (e1 == e2) + { + b2 = b2->next; + if(b2 == &selected_brushes) + { + return false; // only one entity + } + e2 = b2->owner; + } + // brushes are added at head, so reverse order + g_qeglobals.d_select_order[1] = b1; + g_qeglobals.d_select_order[0] = b2; + // now we have brushes from two different entities selected + // are there more entities selected?? + while (b2 != &selected_brushes) + { + b2 = b2->next; + e3 = b2->owner; + if ((e3) && (e3 != e1) && (e3 != e2)) + { + return false; // more than two entities selected + } + } + + return true; +} + +void SurfaceDlg_Init (void); +void QE_Init (void) +{ + /* + ** initialize variables + */ + g_qeglobals.d_gridsize = 8; + g_qeglobals.d_showgrid = true; + + g_qeglobals.uMSH_MOUSEWHEEL = 0; + g_qeglobals.d_hwndBsp = 0;// Q: 0 or NULL for handles? --ss + if (g_qeglobals.d_savedinfo.maxViewDist < 16) // in other words, has not yet been defined + { + g_qeglobals.d_savedinfo.maxViewDist = 1024; + } + g_qeglobals.d_maxViewDist = g_qeglobals.d_savedinfo.maxViewDist;//1024.0; + + /* + ** other stuff + */ + Texture_Init (); + Cam_Init (); + XY_Init (); + Z_Init (); + UNDO_Init (); + SurfaceDlg_Init (); +} + +void QE_ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + +int g_numbrushes, g_numentities; + +void QE_CountBrushesAndUpdateStatusBar( void ) +{ + static int s_lastbrushcount, s_lastentitycount; + static qboolean s_didonce; + + entity_t *e; + brush_t *b, *next; + + g_numbrushes = 0; + g_numentities = 0; + + if ( active_brushes.next != NULL ) + { + for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next) + { + next = b->next; + if (b->brush_faces ) + { + if ( !b->owner->eclass->fixedsize) + g_numbrushes++; + else + g_numentities++; + } + } + } + + if ( entities.next != NULL ) + { + for ( e = entities.next ; e != &entities && g_numentities != MAX_MAP_ENTITIES ; e = e->next) + { + g_numentities++; + } + } + + if ( ( ( g_numbrushes != s_lastbrushcount ) || ( g_numentities != s_lastentitycount ) ) || ( !s_didonce ) ) + { + Sys_UpdateStatusBar(); + + s_lastbrushcount = g_numbrushes; + s_lastentitycount = g_numentities; + s_didonce = true; + } +} + diff --git a/Toolkit/Programming/Tools/qe4/qe3.h b/Toolkit/Programming/Tools/qe4/qe3.h new file mode 100644 index 0000000..65e6457 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/qe3.h @@ -0,0 +1,313 @@ +#ifndef __QE3_H__ +#define __QE3_H__ + +#define _WIN32_WINNT 0x0800 //for mousewheel code + +// disable data conversion warnings for gl +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA + +#include +#include + +#include +#include +#include +#include "glingr.h" +#include +#include + +#include "cmdlib.h" +#include "mathlib.h" +#include "parse.h" +#include "lbmlib.h" + +#include +#include "afxres.h" +#include "resource.h" + +#include "qedefs.h" + +typedef struct +{ + vec3_t normal; + double dist; + int type; +} plane_t; + +#include "qfiles.h" + +#include "textures.h" +#include "brush.h" +#include "entity.h" +#include "map.h" +#include "select.h" + +#include "camera.h" +#include "xy.h" +#include "z.h" +#include "mru.h" + +typedef struct +{ + int p1, p2; + face_t *f1, *f2; +} pedge_t; + +typedef struct +{ + int iSize; + int iTexMenu; // nearest, linear, etc + float maxViewDist; // duh + float fGamma; // gamma for textures + char szProject[256]; // last project loaded + vec3_t colors[COLOR_LAST]; + qboolean show_names, + show_coordinates; + int exclude; +} SavedInfo_t; + +// +// system functions +// +void Sys_UpdateStatusBar( void ); +void Sys_UpdateWindows (int bits); +void Sys_Beep (void); +void Sys_ClearPrintf (void); +void Sys_Printf (char *text, ...); +double Sys_DoubleTime (void); +void Sys_GetCursorPos (int *x, int *y); +void Sys_SetCursorPos (int x, int y); +void Sys_SetTitle (char *text); +void Sys_BeginWait (void); +void Sys_EndWait (void); +void Sys_Status(const char *psz, int part); + + + +/* +** most of the QE globals are stored in this structure +*/ +typedef struct +{ + qboolean d_showgrid; + int d_gridsize; + + int d_num_entities; + + entity_t *d_project_entity; + + float d_new_brush_bottom_z, + d_new_brush_top_z; + + HINSTANCE d_hInstance; + + HGLRC d_hglrcBase; + HDC d_hdcBase; + + HWND d_hwndMain; + HWND d_hwndCamera; + HWND d_hwndEdit; + HWND d_hwndEntity; + HWND d_hwndTexture; + HWND d_hwndXY; + HWND d_hwndZ; + HWND d_hwndStatus; + HWND d_hwndBsp; + HWND d_hwndTexModDlg; + + vec3_t d_points[MAX_POINTS]; + int d_numpoints; + pedge_t d_edges[MAX_EDGES]; + int d_numedges; + + int d_num_move_points; + float *d_move_points[1024]; + + qtexture_t *d_qtextures; + + texturewin_t d_texturewin; + + int d_pointfile_display_list; + + xy_t d_xy; + + LPMRUMENU d_lpMruMenu; + + SavedInfo_t d_savedinfo; + + int d_workcount; + + // connect entities uses the last two brushes selected +// int d_select_count; + brush_t *d_select_order[2]; + vec3_t d_select_translate; // for dragging w/o making new display lists + select_t d_select_mode; + + int d_font_list; + + int d_parsed_brushes; + + qboolean show_blocks; + + float d_maxViewDist; // Maximum distance at which brushes will be drawn. + + UINT uMSH_MOUSEWHEEL; // Value returned from + // RegisterWindowMessage() + // for mousewheel message-- + // win95 & older nt + +} QEGlobals_t; + +void *qmalloc (int size); +char *copystring (char *s); +char *ExpandReletivePath (char *p); + +void Pointfile_Delete (void); +void Pointfile_Check (void); +void Pointfile_Next (void); +void Pointfile_Prev (void); +void Pointfile_Clear (void); +void Pointfile_Draw( void ); +void Pointfile_Load( void ); + +// +// drag.c +// +void Drag_Begin (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir); +void Drag_MouseMoved (int x, int y, int buttons); +void Drag_MouseUp (void); + +// +// csg.c +// +void CSG_MakeHollow (void); +void CSG_Subtract (void); + +// +// vertsel.c +// + +void SetupVertexSelection (void); +void SelectEdgeByRay (vec3_t org, vec3_t dir); +void SelectVertexByRay (vec3_t org, vec3_t dir); + +void ConnectEntities (void); + +extern int update_bits; + +extern int screen_width; +extern int screen_height; + +extern HANDLE bsp_process; + +char *TranslateString (char *buf); + +void ProjectDialog (void); + +void FillTextureMenu (void); +void FillBSPMenu (void); + +BOOL CALLBACK Win_Dialog ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter +); + + +// +// win_cam.c +// +void WCam_Create (HINSTANCE hInstance); + + +// +// win_xy.c +// +void WXY_Create (HINSTANCE hInstance); + +// +// win_z.c +// +void WZ_Create (HINSTANCE hInstance); + +// +// win_ent.c +// + + +// +// win_main.c +// +void Main_Create (HINSTANCE hInstance); +extern BOOL SaveWindowState(HWND hWnd, const char *pszName); +extern BOOL LoadWindowState(HWND hWnd, const char *pszName); + +extern BOOL SaveRegistryInfo(const char *pszName, void *pvBuf, long lSize); +extern BOOL loadRegistryInfo(const char *pszName, void *pvBuf, long *plSize); + +// +// entityw.c +// +BOOL CreateEntityWindow(HINSTANCE hInstance); +void FillClassList (void); +BOOL UpdateEntitySel(eclass_t *pec); +void SetInspectorMode(int iType); +int DrawTexControls(HWND hWnd); +void SetSpawnFlags(void); +void GetSpawnFlags(void); +void SetKeyValuePairs(void); +extern void BuildGammaTable(float g); + + +// win_dlg.c + +void DoGamma(void); +void DoFind(void); +void DoRotate(void); +void DoSides(void); +void DoAbout(void); +void DoSurface(void); +void DoTextureReplace(void); +void DoScale(void); +void DoSetMaxViewDist(void); +void DoDefaultTextures(void); + +// Reset check box for texture lock +void TEXMOD_UpdateCheck(); + + +/* +** QE function declarations +*/ +void QE_ResetIdle(void); +void QE_CheckAutoSave( void ); +void QE_ConvertDOSToUnixName( char *dst, const char *src ); +void QE_CountBrushesAndUpdateStatusBar( void ); +void QE_CheckOpenGLForErrors(void); +void QE_ExpandBspString (char *bspaction, char *out, char *mapname); +void QE_Init (void); +qboolean QE_KeyDown (int key); +qboolean QE_LoadProject (char *projectfile); +qboolean QE_SingleBrush (void); +qboolean QE_DoubleBrush (void); +qboolean QE_DoubleEntity (void); + +/* +** QE Win32 function declarations +*/ +int QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer ); +void QEW_StopGL( HWND hWnd, HGLRC hGLRC, HDC hDC ); + +/* +** extern declarations +*/ +extern QEGlobals_t g_qeglobals; + +void WriteUserLog(char *fmt, ...); + +#endif diff --git a/Toolkit/Programming/Tools/qe4/qe4.dsp b/Toolkit/Programming/Tools/qe4/qe4.dsp new file mode 100644 index 0000000..c19f470 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/qe4.dsp @@ -0,0 +1,351 @@ +# Microsoft Developer Studio Project File - Name="qe3" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=qe3 - Win32 Release +!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 "qe4.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 "qe4.mak" CFG="qe3 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qe3 - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "qe3 - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Wolf/Final/Utilities/qe4", VODAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qe3 - 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" /YX /c +# ADD CPP /nologo /W3 /GX /Zi /O2 /I "..\common" /I "..\qcommon" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WIN_ERROR" /Fr /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /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 comctl32.lib opengl32.lib glu32.lib 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 + +!ELSEIF "$(CFG)" == "qe3 - 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" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\common" /I "..\qcommon" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WIN_ERROR" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /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 +# ADD LINK32 comctl32.lib opengl32.lib glu32.lib 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 /profile /map /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "qe3 - Win32 Release" +# Name "qe3 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\brush.c +# End Source File +# Begin Source File + +SOURCE=.\brush.h +# End Source File +# Begin Source File + +SOURCE=.\camera.c +# End Source File +# Begin Source File + +SOURCE=.\clip.c +# End Source File +# Begin Source File + +SOURCE=..\common\cmdlib.c +# End Source File +# Begin Source File + +SOURCE=.\csg.c +# End Source File +# Begin Source File + +SOURCE=.\drag.c +# End Source File +# Begin Source File + +SOURCE=.\eclass.c +# End Source File +# Begin Source File + +SOURCE=.\entity.c +# End Source File +# Begin Source File + +SOURCE=..\common\lbmlib.c +# End Source File +# Begin Source File + +SOURCE=.\map.c +# End Source File +# Begin Source File + +SOURCE=..\common\mathlib.c +# End Source File +# Begin Source File + +SOURCE=.\mru.c +# End Source File +# Begin Source File + +SOURCE=.\parse.c +# End Source File +# Begin Source File + +SOURCE=.\points.c +# End Source File +# Begin Source File + +SOURCE=.\qe3.c +# End Source File +# Begin Source File + +SOURCE=.\qe3.h +# End Source File +# Begin Source File + +SOURCE=..\common\qfiles.c +# End Source File +# Begin Source File + +SOURCE=..\common\scriplib.c +# End Source File +# Begin Source File + +SOURCE=.\select.c +# End Source File +# Begin Source File + +SOURCE=.\textmod.c +# End Source File +# Begin Source File + +SOURCE=.\textures.c +# End Source File +# Begin Source File + +SOURCE=.\tower.c +# End Source File +# Begin Source File + +SOURCE=.\undo.c +# End Source File +# Begin Source File + +SOURCE=.\vertsel.c +# End Source File +# Begin Source File + +SOURCE=.\win_bsp.c +# End Source File +# Begin Source File + +SOURCE=.\win_cam.c +# End Source File +# Begin Source File + +SOURCE=.\win_dlg.c +# End Source File +# Begin Source File + +SOURCE=.\win_ent.c +# End Source File +# Begin Source File + +SOURCE=.\win_main.c +# End Source File +# Begin Source File + +SOURCE=.\win_qe3.c +# End Source File +# Begin Source File + +SOURCE=.\win_xy.c +# End Source File +# Begin Source File + +SOURCE=.\win_z.c +# End Source File +# Begin Source File + +SOURCE=.\xy.c +# End Source File +# Begin Source File + +SOURCE=.\z.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\camera.h +# End Source File +# Begin Source File + +SOURCE=.\clip.h +# End Source File +# Begin Source File + +SOURCE=..\common\cmdlib.h +# End Source File +# Begin Source File + +SOURCE=.\entity.h +# End Source File +# Begin Source File + +SOURCE=.\entityw.h +# End Source File +# Begin Source File + +SOURCE=.\glingr.h +# End Source File +# Begin Source File + +SOURCE=..\common\lbmlib.h +# End Source File +# Begin Source File + +SOURCE=.\map.h +# End Source File +# Begin Source File + +SOURCE=..\common\mathlib.h +# End Source File +# Begin Source File + +SOURCE=.\mru.h +# End Source File +# Begin Source File + +SOURCE=.\parse.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\q_typedef.h +# End Source File +# Begin Source File + +SOURCE=.\qedefs.h +# End Source File +# Begin Source File + +SOURCE=..\common\qfiles.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=..\common\scriplib.h +# End Source File +# Begin Source File + +SOURCE=.\select.h +# End Source File +# Begin Source File + +SOURCE=.\textures.h +# End Source File +# Begin Source File + +SOURCE=.\tower.h +# End Source File +# Begin Source File + +SOURCE=.\undo.h +# End Source File +# Begin Source File + +SOURCE=.\win_bsp.h +# End Source File +# Begin Source File + +SOURCE=.\xy.h +# End Source File +# Begin Source File + +SOURCE=.\z.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\icon1.ico +# End Source File +# Begin Source File + +SOURCE=.\q.bmp +# End Source File +# Begin Source File + +SOURCE=.\toolbar1.bmp +# End Source File +# Begin Source File + +SOURCE=.\win_qe3.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/Toolkit/Programming/Tools/qe4/qe4.dsw b/Toolkit/Programming/Tools/qe4/qe4.dsw new file mode 100644 index 0000000..ddfff38 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/qe4.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "qe3"=.\qe4.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/qe4", VODAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Q2 Utilities/qe4", VODAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Toolkit/Programming/Tools/qe4/qedefs.h b/Toolkit/Programming/Tools/qe4/qedefs.h new file mode 100644 index 0000000..3a68093 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/qedefs.h @@ -0,0 +1,97 @@ +#ifndef __QEDEFS_H__ +#define __QEDEFS_H__ + +#define QE_VERSION 0x0401 + +#define QE3_STYLE (WS_OVERLAPPED| WS_CAPTION | WS_THICKFRAME | \ + /* WS_MINIMIZEBOX | */ WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | \ + WS_CLIPCHILDREN | WS_CHILD) + +#define QE_AUTOSAVE_INTERVAL 5 // number of minutes between autosaves +#define QE_IDLE_LOG_INTERVAL 20 // number of minutes for idle time to be recorded + +#define CAMERA_WINDOW_CLASS "QCamera" +#define XY_WINDOW_CLASS "QXY" +#define Z_WINDOW_CLASS "QZ" +#define ENT_WINDOW_CLASS "QENT" + +#define ZWIN_WIDTH 40 +#define CWIN_SIZE (0.4) + +#define MAX_EDGES 256 +#define MAX_POINTS 512 + +#define CMD_TEXTUREWAD 60000 +#define CMD_BSPCOMMAND 61000 + +#define PITCH 0 +#define YAW 1 +#define ROLL 2 + +#define QE_TIMER0 1 + +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +#define ON_EPSILON 0.01 + +#define KEY_FORWARD 1 +#define KEY_BACK 2 +#define KEY_TURNLEFT 4 +#define KEY_TURNRIGHT 8 +#define KEY_LEFT 16 +#define KEY_RIGHT 32 +#define KEY_LOOKUP 64 +#define KEY_LOOKDOWN 128 +#define KEY_UP 256 +#define KEY_DOWN 512 + +// xy.c +#define EXCLUDE_LIGHTS 1 +#define EXCLUDE_ENT 2 +#define EXCLUDE_PATHS 4 +#define EXCLUDE_WATER 8 +#define EXCLUDE_WORLD 16 +#define EXCLUDE_CLIP 32 +#define EXCLUDE_DETAIL 64 +#define BUOY_ONLY 128 + + +// +// menu indexes for modifying menus +// +#define MENU_VIEW 2 +#define MENU_BSP 4 +#define MENU_TEXTURE 6 + + +// odd things not in windows header... +#define VK_COMMA 188 +#define VK_PERIOD 190 + +/* +** window bits +*/ +#define W_CAMERA 0x0001 +#define W_XY 0x0002 +#define W_XY_OVERLAY 0x0004 +#define W_Z 0x0008 +#define W_TEXTURE 0x0010 +#define W_Z_OVERLAY 0x0020 +#define W_CONSOLE 0x0040 +#define W_ENTITY 0x0080 +#define W_ALL 0xFFFFFFFF + +#define COLOR_TEXTUREBACK 0 +#define COLOR_GRIDBACK 1 +#define COLOR_GRIDMINOR 2 +#define COLOR_GRIDMAJOR 3 +#define COLOR_CAMERABACK 4 +#define COLOR_ENTITY 5 +#define COLOR_LAST 6 + +#endif diff --git a/Toolkit/Programming/Tools/qe4/resource.h b/Toolkit/Programming/Tools/qe4/resource.h new file mode 100644 index 0000000..950ad84 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/resource.h @@ -0,0 +1,330 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by win_qe3.rc +// +#define IDAPPLY 3 +#define IDR_MENU1 101 +#define IDR_ACCELERATOR1 104 +#define IDD_CREATE_ENTITY 107 +#define IDD_EDIT_ENTITY 108 +#define IDR_TOOLBAR1 109 +#define IDD_FINDTEXTURE 111 +#define IDD_ENTITY 115 +#define IDR_E_MENU 116 +#define IDD_EDITPROP 117 +#define IDD_GAMMA 118 +#define IDD_FINDBRUSH 119 +#define IDI_ICON1 120 +#define IDD_ROTATE 121 +#define IDD_SIDES 122 +#define IDD_ABOUT 123 +#define IDB_BITMAP1 127 +#define IDD_SURFACE 129 +#define IDD_REPLACE 130 +#define IDD_SCALE 131 +#define IDD_MAXVIEWDIST 134 +#define IDD_BSP 135 +#define IDD_TEXMODIFY 136 +#define IDC_ENTITY_COMMENT 1018 +#define IDC_VALUE 1021 +#define IDC_KEY 1022 +#define IDC_LIGHT_GREEN 1022 +#define IDC_ENTITY_LIST 1023 +#define IDC_LIGHT_BLUE 1023 +#define IDC_PAIRS 1024 +#define IDC_LIGHT_ALPHA 1024 +#define IDC_LIGHT_RED 1025 +#define IDC_CHECK1 1026 +#define IDC_CHECK2 1027 +#define IDC_CHECK3 1028 +#define IDC_CHECK4 1029 +#define IDC_CHECK5 1030 +#define IDC_CHECK6 1031 +#define IDC_CHECK7 1032 +#define IDC_CHECK8 1033 +#define IDC_CHECK9 1034 +#define IDC_CHECK10 1035 +#define IDC_CHECK11 1036 +#define IDC_CHECK12 1037 +#define IDC_ANGLE90 1038 +#define IDC_CHECK13 1038 +#define IDC_ANGLE45 1039 +#define IDC_CHECK14 1039 +#define IDC_ANGLE135 1040 +#define IDC_CHECK15 1040 +#define IDC_ANGLE225 1041 +#define IDC_CHECK16 1041 +#define IDC_ANGLEUP 1042 +#define IDC_CHECK17 1042 +#define IDC_ANGLE180 1043 +#define IDC_CHECK18 1043 +#define IDC_ANGLE315 1044 +#define IDC_CHECK19 1044 +#define IDC_ANGLE0 1045 +#define IDC_CHECK20 1045 +#define IDC_ANGLE270 1046 +#define IDC_CHECK21 1046 +#define IDC_ANGLEDOWN 1047 +#define IDC_CHECK22 1047 +#define IDC_DELETEKEY 1048 +#define IDC_ADDPAIR 1048 +#define IDC_CHECK23 1048 +#define IDC_DELETEPAIR 1049 +#define IDC_CHECK24 1049 +#define IDC_CHECK25 1050 +#define IDC_SPAWN1 1051 +#define IDC_CHECK26 1051 +#define IDC_SPAWN2 1052 +#define IDC_CHECK27 1052 +#define IDC_SPAWN3 1053 +#define IDC_CHECK28 1053 +#define IDC_SPAWN4 1054 +#define IDC_CHECK29 1054 +#define IDC_SPAWN5 1055 +#define IDC_CHECK30 1055 +#define IDC_SPAWN6 1056 +#define IDC_CHECK31 1056 +#define IDC_SPAWN7 1057 +#define IDC_CHECK32 1057 +#define IDC_SPAWN8 1058 +#define IDC_CHECK33 1058 +#define IDC_EDIT1 1059 +#define IDC_CHECK34 1059 +#define IDC_ROTATE_BOX 1060 +#define IDC_ROTZ 1060 +#define IDC_CHECK35 1060 +#define IDC_SCALE_BOX 1061 +#define IDC_ROTY 1061 +#define IDC_CHECK36 1061 +#define IDC_E_VALUE_FIELD 1062 +#define IDC_CHECK37 1062 +#define IDC_CHECK38 1063 +#define IDC_E_LIST 1064 +#define IDC_CHECK39 1064 +#define IDC_E_COMMENT 1065 +#define IDC_CHECK40 1065 +#define IDC_CHECK41 1066 +#define IDC_E_PROPS 1067 +#define IDC_CHECK42 1067 +#define IDC_E_135 1068 +#define IDC_CHECK43 1068 +#define IDC_E_180 1069 +#define IDC_CHECK44 1069 +#define IDC_E_225 1070 +#define IDC_CHECK45 1070 +#define IDC_E_270 1071 +#define IDC_CHECK46 1071 +#define IDC_E_90 1072 +#define IDC_CHECK47 1072 +#define IDC_E_45 1073 +#define IDC_CHECK48 1073 +#define IDC_E_0 1074 +#define IDC_CHECK49 1074 +#define IDC_E_315 1075 +#define IDC_CHECK50 1075 +#define IDC_E_UP 1076 +#define IDC_CHECK51 1076 +#define IDC_E_DOWN 1077 +#define IDC_CHECK52 1077 +#define IDC_CHECK53 1078 +#define IDC_CHECK54 1079 +#define IDC_E_ADDPROP 1080 +#define IDC_CHECK55 1080 +#define IDC_E_DELPROP 1081 +#define IDC_CHECK56 1081 +#define IDC_E_CREATE 1082 +#define IDC_CHECK57 1082 +#define IDC_E_STATUS 1083 +#define IDC_CHECK58 1083 +#define IDC_CHECK59 1084 +#define IDC_CHECK60 1085 +#define IDC_CHECK61 1086 +#define IDC_CHECK62 1087 +#define IDC_CHECK63 1088 +#define IDC_CHECK64 1089 +#define IDC_SHIFT_BOX 1090 +#define IDC_HSHIFT 1090 +#define IDC_VSHIFT 1091 +#define IDC_ROTATEV 1092 +#define IDC_SCALEV 1093 +#define IDC_SCALEH 1094 +#define IDC_SHIFTV 1095 +#define IDC_HSHIFTA 1095 +#define IDC_SHIFTH 1096 +#define IDC_VSHIFTA 1097 +#define IDC_HSCALE 1098 +#define IDC_HSCALEA 1099 +#define IDC_VSCALE 1100 +#define IDC_VSCALEA 1101 +#define IDC_ROTATE 1102 +#define IDC_G_EDIT 1103 +#define IDC_ROTATEA 1103 +#define IDC_STATIC_KEY 1104 +#define IDC_FIND_BRUSH 1104 +#define IDC_STATIC_VALUE 1105 +#define IDC_E_KEY_FIELD 1106 +#define IDC_FIND_ENTITY 1107 +#define IDC_SIDES 1108 +#define IDC_ROTX 1109 +#define IDC_E_COLOR 1111 +#define IDC_ABOUT_GLVENDOR 1112 +#define IDC_ABOUT_GLVERSION 1113 +#define IDC_ABOUT_GLRENDERER 1114 +#define IDC_TEXTURE 1114 +#define IDC_ABOUT_GLEXTENSIONS 1115 +#define IDD_REPLACESELECTED 1115 +#define IDC_REP_EDIT2 1116 +#define IDD_REPLACEALL 1117 +#define IDC_REP_EDIT1 1118 +#define IDC_SCALE 1119 +#define IDC_SCALE_EACH_ORIGIN 1120 +#define IDC_CHECK_NOX 1121 +#define IDC_CHECK_NOY 1122 +#define IDC_CHECK_NOZ 1123 +#define IDC_MAXVIEWDIST 1124 +#define IDC_BSPTEXT 1125 +#define IDC_TEXLOCK_CHECK 1126 +#define IDC_TEXTURE_MATERIAL 1128 +#define ID_FILE_EXIT 40002 +#define ID_FILE_SAVEAS 40004 +#define ID_VIEW_CENTER 40005 +#define ID_VIEW_UPFLOOR 40006 +#define ID_VIEW_DOWNFLOOR 40007 +#define ID_BRUSH_FLIPX 40008 +#define ID_BRUSH_FLIPY 40009 +#define ID_BRUSH_FLIPZ 40010 +#define ID_BRUSH_ROTATEX 40011 +#define ID_BRUSH_ROTATEY 40012 +#define ID_BRUSH_ROTATEZ 40013 +#define ID_BSP_FULLVIS 40016 +#define ID_BSP_FASTVIS 40017 +#define ID_BSP_NOVIS 40018 +#define ID_BSP_RELIGHT 40019 +#define ID_BSP_ENTITIES 40020 +#define ID_FILE_POINTFILE 40021 +#define ID_VIEW_100 40022 +#define ID_VIEW_75 40023 +#define ID_VIEW_50 40024 +#define ID_VIEW_25 40025 +#define ID_VIEW_12 40026 +#define ID_GRID_1 40028 +#define ID_GRID_2 40029 +#define ID_GRID_4 40030 +#define ID_GRID_8 40031 +#define ID_GRID_16 40032 +#define ID_TEXTURES_SHOWALL 40033 +#define ID_TEXTURES_SHOWINUSE 40034 +#define ID_TEXTURES_TOGGLEVIEW 40037 +#define ID_SELECTION_CREATEENTITY 40039 +#define ID_SELECTION_EDITENTITY 40040 +#define ID_MISC_BENCHMARK 40041 +#define ID_REGION_OFF 40043 +#define ID_REGION_SETXY 40044 +#define ID_REGION_SETBRUSH 40045 +#define ID_SELECTION_MAKEHOLLOW 40046 +#define ID_SELECTION_SELECTPARTIALTALL 40047 +#define ID_SELECTION_SELECTCOMPLETETALL 40048 +#define ID_SELECTION_CSGSUBTRACT 40049 +#define ID_SELECTION_SELECTTOUCHING 40050 +#define ID_SELECTION_TOWER 40051 +#define ID_VIEW_NEAREST 40052 +#define ID_VIEW_LINEAR 40053 +#define ID_VIEW_BILINEAR 40054 +#define ID_VIEW_TRILINEAR 40055 +#define ID_VIEW_NEARESTMIPMAP 40056 +#define ID_VIEW_BILINEARMIPMAP 40057 +#define ID_VIEW_SHOWNAMES 40058 +#define ID_VIEW_ZOOMIN 40059 +#define ID_VIEW_ZOOMOUT 40060 +#define ID_VIEW_SHOWCOORDINATES 40061 +#define ID_VIEW_Z100 40062 +#define ID_VIEW_ZZOOMIN 40063 +#define ID_VIEW_ZZOOMOUT 40064 +#define ID_SELECTION_CLONE 40065 +#define ID_SELECTION_DESELECT 40066 +#define ID_SELECTION_DELETE 40067 +#define ID_BUTTON40068 40068 +#define ID_TEXTURES_WIREFRAME 40072 +#define ID_TEXTURES_FLATSHADE 40073 +#define ID_SELECTION_DRAGVERTECIES 40074 +#define ID_SELECTION_DRAGEDGES 40075 +#define ID_REGION_SETTALLBRUSH 40076 +#define ID_SELECTION_SELECTINSIDE 40092 +#define ID_PROJECT_RELEAD 40094 +#define ID_PROJECT_CHANGE 40095 +#define ID_MISC_GAMMA 40097 +#define ID_VIEW_SHOWENT 40098 +#define ID_VIEW_SHOWPATH 40099 +#define ID_VIEW_SHOWLIGHTS 40100 +#define ID_VIEW_SHOWCLIP 40101 +#define ID_VIEW_SHOWWATER 40102 +#define ID_VIEW_SHOWWORLD 40103 +#define ID_MISC_TEXTUREBACKGROUN 40104 +#define ID_TEXTUREBK 40105 +#define ID_COLORS_XYBK 40106 +#define ID_FILE_ABOUT 40107 +#define ID_VIEW_CONSOLE 40108 +#define ID_VIEW_ENTITY 40109 +#define ID_VIEW_TEXTURE 40110 +#define ID_COLORS_MAJOR 40111 +#define ID_COLORS_MINOR 40113 +#define ID_SELECTION_CONNECT 40114 +#define ID_FILE_LOADPROJECT 40115 +#define ID_MISC_FINDBRUSH 40116 +#define ID_MISC_NEXTLEAKSPOT 40117 +#define ID_MISC_PREVIOUSLEAKSPOT 40118 +#define ID_BRUSH_3SIDED 40119 +#define ID_BRUSH_4SIDED 40120 +#define ID_BRUSH_5SIDED 40121 +#define ID_BRUSH_6SIDED 40122 +#define ID_BRUSH_7SIDED 40123 +#define ID_BRUSH_8SIDED 40124 +#define ID_BRUSH_9SIDED 40125 +#define ID_SELECTION_ARBITRARYROTATION 40126 +#define ID_BRUSH_ARBITRARYSIDED 40127 +#define ID_GRID_32 40128 +#define ID_GRID_64 40129 +#define ID_SELECTION_UNGROUPENTITY 40130 +#define ID_MISC_SELECTENTITYCOLOR 40131 +#define ID_MISC_PRINTXY 40132 +#define ID_HELP_ABOUT 40134 +#define ID_EDIT_COPYBRUSH 40135 +#define ID_EDIT_PASTEBRUSH 40136 +#define ID_TEXTURES_INSPECTOR 40137 +#define ID_VIEW_SHOWDETAIL 40138 +#define ID_SELECTION_MAKE_DETAIL 40139 +#define ID_SELECTION_MAKE_STRUCTURAL 40140 +#define ID_REGION_SETSELECTION 40142 +#define ID_VIEW_SHOWBLOCKS 40143 +#define ID_EDIT 40144 +#define ID_MISC_REPLACETEXTURE 40145 +#define ID_SELECTION_SCALE 40146 +#define ID_BUTTON40147 40147 +#define ID_BUTTON_UNDO 40147 +#define ID_BUTTON40148 40148 +#define ID_MISC_SETMAXVIEWDISTANCE 40149 +#define ID_BRUSH_3SNAP 40150 +#define ID_BRUSH_4SNAP 40151 +#define ID_BRUSH_5SNAP 40152 +#define ID_BRUSH_6SNAP 40153 +#define ID_BRUSH_7SNAP 40154 +#define ID_BRUSH_8SNAP 40155 +#define ID_BRUSH_9SNAP 40156 +#define ID_TEXTURE_LISTINUSE 40157 +#define ID_BRUSH_SNAPOK 40158 +#define ID_ENTITY_LISTINUSE 40158 +#define ID_FILE_PRINT_CONSOLE 40159 +#define ID_TEXTURES_DEFAULT_MATERIALS 40160 +#define ID_MISC_DEFAULTTEXTURES 40161 +#define ID_VIEW_SHOWBUOYONLY 40162 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 137 +#define _APS_NEXT_COMMAND_VALUE 40163 +#define _APS_NEXT_CONTROL_VALUE 1129 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif diff --git a/Toolkit/Programming/Tools/qe4/select.c b/Toolkit/Programming/Tools/qe4/select.c new file mode 100644 index 0000000..4d7cedf --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/select.c @@ -0,0 +1,1144 @@ +// select.c + +#include "qe3.h" +#include "undo.h" + +/* +=========== +Test_Ray +=========== +*/ +#define DIST_START 999999 +trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags) +{ + brush_t *brush; + face_t *face; + float dist; + trace_t t; + + memset (&t, 0, sizeof(t)); + t.dist = DIST_START; + + if (! (flags & SF_SELECTED_ONLY) ) + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) + continue; + if (FilterBrush (brush)) + continue; + face = Brush_Ray (origin, dir, brush, &dist); + if (dist > 0 && dist < t.dist) + { + t.dist = dist; + t.brush = brush; + t.face = face; + t.selected = false; + } + } + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) + continue; + if (FilterBrush (brush)) + continue; + face = Brush_Ray (origin, dir, brush, &dist); + if (dist > 0 && dist < t.dist) + { + t.dist = dist; + t.brush = brush; + t.face = face; + t.selected = true; + } + } + + // if entites first, but didn't find any, check regular + + if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL) + return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST); + + return t; +} + + +/* +============ +Select_Brush + +============ +*/ +void Select_Brush (brush_t *brush) +{ + brush_t *b; + entity_t *e; + + selected_face = NULL; + e = brush->owner; + if (e) + { + // select complete entity on first click + if (e != world_entity) + { + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (b->owner == e) + goto singleselect; + for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + else + { +singleselect: + Brush_RemoveFromList (brush); + Brush_AddToList (brush, &selected_brushes); + } + + if (e->eclass) + { + UpdateEntitySel(brush->owner->eclass); + } + } + TEXMOD_UpdateCheck(); + +} + +/* +============ +Select_Ray + +If the origin is inside a brush, that brush will be ignored. +============ +*/ +void Select_Ray (vec3_t origin, vec3_t dir, int flags) +{ + trace_t t; + + t = Test_Ray (origin, dir, flags); + if (!t.brush) + return; + + if (flags == SF_SINGLEFACE) + { + selected_face = t.face; + selected_face_brush = t.brush; + Sys_UpdateWindows (W_ALL); + g_qeglobals.d_select_mode = sel_brush; + return; + } + + // move the brush to the other list + + g_qeglobals.d_select_mode = sel_brush; + + if (t.selected) + { + Brush_RemoveFromList (t.brush); + Brush_AddToList (t.brush, &active_brushes); + } else + { + Select_Brush (t.brush); + } + + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); + +} + + +void Select_Delete (qboolean undo) +{ + brush_t *brush; + + if(undo) + { + UNDO_StartBrushDelete("&Undo Deletion"); + } + selected_face = NULL; + g_qeglobals.d_select_mode = sel_brush; + + g_qeglobals.d_num_move_points = 0; + while (selected_brushes.next != &selected_brushes) + { + brush = selected_brushes.next; + Brush_Free (brush); + } + + // FIXME: remove any entities with no brushes + + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); +} + + +void Select_Deselect (void) +{ + brush_t *b; + + g_qeglobals.d_workcount++; + g_qeglobals.d_num_move_points = 0; + + b = selected_brushes.next; + + if (b == &selected_brushes) + { + if (selected_face) + { + selected_face = NULL; + Sys_UpdateWindows (W_ALL); + } + return; + } + + selected_face = NULL; + g_qeglobals.d_select_mode = sel_brush; + + // grab top / bottom height for new brushes + if (b->mins[2] < b->maxs[2]) + { + g_qeglobals.d_new_brush_bottom_z = b->mins[2]; + g_qeglobals.d_new_brush_top_z = b->maxs[2]; + } + + selected_brushes.next->prev = &active_brushes; + selected_brushes.prev->next = active_brushes.next; + active_brushes.next->prev = selected_brushes.prev; + active_brushes.next = selected_brushes.next; + selected_brushes.prev = selected_brushes.next = &selected_brushes; + + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); +} + +/* +============ +Select_Move +============ +*/ +void Select_Move (vec3_t delta) +{ + brush_t *b; + qboolean moveorigin; + + moveorigin = true; + +// actually move the selected brushes + for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + Brush_Move (b, delta, moveorigin); + if (b->owner->eclass->PhysicsModel) + { + moveorigin = false; + } + } +// Sys_UpdateWindows (W_ALL); +} + +/* +============ +Select_Clone + +Creates an exact duplicate of the selection in place, then moves +the selected brushes off of their old positions +============ +*/ +void Select_Clone (void) +{ + brush_t *b, *b2, *n, *next, *next2; + vec3_t delta; + entity_t *e; + qboolean moveorigin; + + moveorigin = true; + +// UNDO_StartBrushAdd ("&Undo Clone"); + g_qeglobals.d_workcount++; + g_qeglobals.d_select_mode = sel_brush; + + delta[0] = g_qeglobals.d_gridsize; + delta[1] = g_qeglobals.d_gridsize; + delta[2] = 0; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + // if the brush is a world brush, handle simply + if (b->owner == world_entity) + { + n = Brush_Clone (b); + Brush_AddToList (n, &active_brushes); + Entity_LinkBrush (world_entity, n); + Brush_Build( n ); + Brush_Move (b, delta, true); + continue; + } + + e = Entity_Clone (b->owner); + // clear the target / targetname + DeleteKey (e, "target"); + DeleteKey (e, "target2"); + DeleteKey (e, "targetname"); + + // if the brush is a fixed size entity, create a new entity + if (b->owner->eclass->fixedsize) + { + n = Brush_Clone (b); + Brush_AddToList (n, &active_brushes); + Entity_LinkBrush (e, n); + Brush_Build( n ); + Brush_Move (b, delta, true); + continue; + } + + // brush is a complex entity, grab all the other ones now + + next = &selected_brushes; + + for ( b2 = b ; b2 != &selected_brushes ; b2=next2) + { + next2 = b2->next; + if (b2->owner != b->owner) + { + if (next == &selected_brushes) + next = b2; + continue; + } + + // move b2 to the start of selected_brushes, + // so it won't be hit again + Brush_RemoveFromList (b2); + Brush_AddToList (b2, &selected_brushes); + + n = Brush_Clone (b2); + Brush_AddToList (n, &active_brushes); + Entity_LinkBrush (e, n); + Brush_Build( n ); + Brush_Move (b2, delta, moveorigin); + if (b->owner->eclass->PhysicsModel) + { + moveorigin = false; + } + } + + } + UNDO_FinishBrushAdd("&Undo Clone"); + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); +} + + + +/* +============ +Select_SetTexture +============ +*/ +void Select_SetTexture (texdef_t *texdef) +{ + brush_t *b; + + if (selected_face) + { + selected_face->texdef = *texdef; + Brush_Build(selected_face_brush); + } + else + { + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (!b->owner->eclass->fixedsize) + Brush_SetTexture (b, texdef); + } + Sys_UpdateWindows (W_ALL); +} + + +/* +================================================================ + + TRANSFORMATIONS + +================================================================ +*/ + +void Select_GetBounds (vec3_t mins, vec3_t maxs) +{ + brush_t *b; + int i; + + for (i=0 ; i<3 ; i++) + { + mins[i] = 99999; + maxs[i] = -99999; + } + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] < mins[i]) + mins[i] = b->mins[i]; + if (b->maxs[i] > maxs[i]) + maxs[i] = b->maxs[i]; + } +} + +void Select_GetMid (vec3_t mid) +{ + vec3_t mins, maxs; + int i; + + Select_GetBounds (mins, maxs); + for (i=0 ; i<3 ; i++) + mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize ); + // the gridsize bit makes the origin fit the grid +} + +vec3_t select_origin; +vec3_t select_matrix[3]; +qboolean select_fliporder; + +void Select_AplyMatrix (void) +{ + brush_t *b; + face_t *f; + int i, j; + vec3_t temp; + + + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + for (i=0 ; i<3 ; i++) + { + VectorSubtract (f->planepts[i], select_origin, temp); + for (j=0 ; j<3 ; j++) + { + f->planepts[i][j] = DotProduct(temp, select_matrix[j]) + + select_origin[j]; + + } + } + if (select_fliporder) + { + VectorCopy (f->planepts[0], temp); + VectorCopy (f->planepts[2], f->planepts[0]); + VectorCopy (temp, f->planepts[2]); + } + } + Brush_Build( b ); + } + Sys_UpdateWindows (W_ALL); +} + + +void Select_FlipAxis (int axis) +{ + int i; + + Select_GetMid (select_origin); + + if ((selected_brushes.next->owner != NULL) && (selected_brushes.next->owner->eclass->PhysicsModel)) + { + GetVectorForKey(selected_brushes.next->owner, "origin", select_origin); + } + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + select_matrix[axis][axis] = -1; + + select_fliporder = true; + Select_AplyMatrix (); +} + + +void Select_RotateAxis (int axis, float deg) +{ + + brush_t *b; +// brush_t *bcopy; +// face_t *f, *fcopy; +// vec3_t texvect[2], texvectcopy[2]; +// vec3_t rotnorm, rotvert; + vec3_t zaxis, origin; +// float oldscale[2], oldshift[2]; +// float delu, delv, delw; +// float maxx, maxy, minx, miny, maxz, minz; +// float delucopy, delvcopy, delwcopy; +// float maxxcopy, maxycopy, maxzcopy, minxcopy, minycopy, minzcopy; +// float dot, dotmax; +// int index; + int stayaway =0; + char text[255]; + int oldangle; + + vec3_t temp; + int i, j; + vec_t c, s; + + + if (deg == 0) + return; + + Select_GetMid (select_origin); + + if ((selected_brushes.next->owner != NULL) && + (selected_brushes.next == selected_brushes.prev) && + strcmp(selected_brushes.next->owner->eclass->name,"worldspawn") && + (selected_brushes.next->owner->eclass->fixedsize)) // one selected entity + { + GetVectorForKey (selected_brushes.next->owner, "origin", select_origin); + stayaway =1; + } + + if ((selected_brushes.next->owner != NULL) && (selected_brushes.next->owner->eclass->PhysicsModel) && + (axis == 2)) + { + oldangle = IntForKey(selected_brushes.next->owner, "angle"); + oldangle -= deg; + while (oldangle < 0) + { + oldangle +=360; + } + while (oldangle >= 360) + { + oldangle -= 360; + } + sprintf(text, "%i", oldangle); + SetKeyValue(selected_brushes.next->owner, "angle", text); + GetVectorForKey(selected_brushes.next->owner, "origin", select_origin); + + } + + + + + select_fliporder = false; + + zaxis[0] = 0; + zaxis[1] = 0; + zaxis[2] = 1; + + if (deg == 90) + { + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + i = (axis+1)%3; + j = (axis+2)%3; + VectorCopy (select_matrix[i], temp); + VectorCopy (select_matrix[j], select_matrix[i]); + VectorSubtract (vec3_origin, temp, select_matrix[j]); + } + else + { + deg = -deg; + if (deg == -180) + { + c = -1; + s = 0; + } + else if (deg == -270) + { + c = 0; + s = -1; + } + else + { + c = cos(deg/180*3.14159); + s = sin (deg/180*3.14159); + } + + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + + switch (axis) + { + case 0: + select_matrix[1][1] = c; + select_matrix[1][2] = -s; + select_matrix[2][1] = s; + select_matrix[2][2] = c; + break; + case 1: + select_matrix[0][0] = c; + select_matrix[0][2] = s; + select_matrix[2][0] = -s; + select_matrix[2][2] = c; + break; + case 2: + select_matrix[0][0] = c; + select_matrix[0][1] = -s; + select_matrix[1][0] = s; + select_matrix[1][1] = c; + break; + } + } +// TEXTURE LOCK STUFF STARTS HERE +// Note: This is Not done. It impossible, given the way texture coordinates +// are currently handled to write an all-inclusive texture lock. But, one that handles +// most mundane cases can be done. This has been started here, but I have been instructed +// to move on to other things -- dk +/* for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if (b->texLocked == true) + { + bcopy = Brush_Clone (b); + for (fcopy = bcopy->brush_faces; fcopy ; fcopy = fcopy->next) + { + for (i=0 ; i<3 ; i++) + { + VectorSubtract (fcopy->planepts[i], select_origin, temp); + for (j=0 ; j<3 ; j++) + { + fcopy->planepts[i][j] = DotProduct(temp, select_matrix[j])+ select_origin[j]; + } + } + } + + Brush_Build (bcopy); + +// at this point, we have two brushes: b is the unrotated brush, and bcopy is the rebuilt, +// rotated brush. + + for ( f = b->brush_faces; f; f = f->next) + { +// for each face on b, get the normal, rotate it, and compare to faces on bcopy to find the +// its corresponding face + fcopy = bcopy->brush_faces; + for (i=0; i<3; i++) + { + rotnorm[i] = DotProduct(f->plane.normal, select_matrix[i]); + } + VectorNormalize(rotnorm, rotnorm); +// run through all rotates faces and find the largest Dot Product between norms +// this avoids roundoff "epsilon" problems + dotmax = -9999; + i = 0; + while (fcopy) + { + dot = DotProduct(fcopy->plane.normal, rotnorm); + if (dot > dotmax) + { + dotmax = dot; + index = i; + } + i++; + fcopy = fcopy->next; + } + fcopy = bcopy->brush_faces; + i = 0; + while ( i < index ) + { + i++; + fcopy = fcopy->next; + } + +// fcopy is now the rotated face corresponding to the unrotated face, f + + TextureAxisFromPlane(&f->plane, texvect[0], texvect[1]); + TextureAxisFromPlane(&fcopy->plane, texvectcopy[0], texvectcopy[1]); +// comparing texvect and texvectcopy will tell us if we need to worry about +// changing texture axes + +// now get max and min x,y,z from both f and fcopy + maxx = -9999; + minx = 9999; + maxy = -9999; + miny = 9999; + maxz = -9999; + minz = 9999; + maxxcopy = -9999; + minxcopy = 9999; + maxycopy = -9999; + minycopy = 9999; + maxzcopy = -9999; + minzcopy = 9999; + // fixme: HOW THE HELL CAN FACE_WINDING BE NULL? + for ( i = 0 ; i < f->face_winding->numpoints; i++) + { + if (f->face_winding->points[i][0] < minx) + { + minx = f->face_winding->points[i][0]; + } + if (f->face_winding->points[i][0] > maxx) + { + maxx = f->face_winding->points[i][0]; + } + if (f->face_winding->points[i][1] < miny) + { + miny = f->face_winding->points[i][1]; + } + if (f->face_winding->points[i][1] > maxy) + { + maxy = f->face_winding->points[i][1]; + } + if (f->face_winding->points[i][2] < minz) + { + minz = f->face_winding->points[i][2]; + } + if (f->face_winding->points[i][2] > maxz) + { + maxz = f->face_winding->points[i][2]; + } + if (fcopy->face_winding->points[i][0] < minxcopy) + { + minxcopy = fcopy->face_winding->points[i][0]; + } + if (fcopy->face_winding->points[i][0] > maxxcopy) + { + maxxcopy = fcopy->face_winding->points[i][0]; + } + if (fcopy->face_winding->points[i][1] < minycopy) + { + minycopy = fcopy->face_winding->points[i][1]; + } + if (fcopy->face_winding->points[i][1] > maxycopy) + { + maxycopy = fcopy->face_winding->points[i][1]; + } + if (fcopy->face_winding->points[i][2] < minzcopy) + { + minzcopy = fcopy->face_winding->points[i][2]; + } + if (fcopy->face_winding->points[i][2] > maxzcopy) + { + maxzcopy = fcopy->face_winding->points[i][2]; + } + } + VectorSubtract (f->face_winding->points[0], select_origin, temp); + for ( i=0; i <3; i++) + { + rotvert[i] = DotProduct(temp,select_matrix[i]) + select_origin[i]; + } + //rotvert is the rotated first vertex of this face + // this rotation changes on top or bottom face + switch (axis) + { + case 0: //x rotation + if ((texvectcopy[0][1] == 1) && (texvectcopy[1][2] == -1)) //yz texture plane + { // u->y v->z w->y + f->texdef.rotate += deg; + } + else if ((texvectcopy[0][0] == 1) && (texvectcopy[1][2] == -1)) //xz texture plane + { // u->x v->z w->y + delu = maxx - minx; + delv = maxz - minz; + delw = maxy - miny; + delucopy = maxxcopy - minxcopy; + delvcopy = maxzcopy - minzcopy; + delwcopy = maxycopy - minycopy; + if (!f->texdef.scale[0]) + { + f->texdef.scale[0] = 1; + } + oldscale[1] = f->texdef.scale[1]; + f->texdef.scale[1] *= delvcopy / delv; + f->texdef.shift[1] = (f->texdef.shift[1]*oldscale[1] - (minz - minzcopy)) / f->texdef.scale[1]; + + } + else if ((texvectcopy[0][0] == 1) && (texvectcopy[1][1] == -1)) //xyplane texture for ceiling/floor + { // u->x v->y w->z + delu = maxx - minx; + delv = maxy - miny; + delw = maxz - minz; + delucopy = maxxcopy - minxcopy; + delvcopy = maxycopy - minycopy; + delwcopy = maxzcopy - minzcopy; + if (!f->texdef.scale[0]) + { + f->texdef.scale[0] = 1; + } + oldscale[1] = f->texdef.scale[1]; + f->texdef.scale[1] *= delvcopy / delv; + f->texdef.shift[1] = (f->texdef.shift[1]*oldscale[1] - (miny - minycopy)) / f->texdef.scale[1]; + } + break; + case 1: //y rotation + if ((texvectcopy[0][0] == 1) && (texvectcopy[1][2] == -1)) //xz texture plane + { // u->x v->z w->y + f->texdef.rotate -= deg; + } + else if ((texvect[0][0] == 1) && (texvect[1][1] == -1)) //xyplane texture for ceiling/floor + { // u->x v->y w->z + if ((texvectcopy[0][0] == 1) && (texvectcopy[1][1] == -1)) // staying in xy + { + delu = maxx - minx; + delv = maxy - miny; + delw = maxz - minz; + delucopy = maxxcopy - minxcopy; + delvcopy = maxycopy - minycopy; + delwcopy = maxzcopy - minzcopy; + if (!f->texdef.scale[0]) + { + f->texdef.scale[0] = 1; + } + oldscale[0] = f->texdef.scale[0]; + f->texdef.scale[0] *= delucopy / delu; + f->texdef.shift[0] = (f->texdef.shift[0]*oldscale[0] + (minx - minxcopy)) / f->texdef.scale[0]; + } + else if ((texvectcopy[0][1] == 1) && (texvectcopy[1][2] == -1)) // switching to yz + { + delu = maxy - miny; + delv = maxz - minz; + delw = maxx - minx; + delucopy = maxycopy - minycopy; + delvcopy = maxzcopy - minzcopy; + delwcopy = maxxcopy - minxcopy; + if (!f->texdef.scale[1]) + { + f->texdef.scale[1] = 1; + } + oldscale[0] = f->texdef.scale[0]; + f->texdef.scale[0] = f->texdef.scale[1]; + f->texdef.scale[1] = oldscale[0]; + f->texdef.scale[1] *= -(delvcopy / delw); + oldshift[0] = f->texdef.shift[0]; + f->texdef.shift[0] = f->texdef.shift[1]; + f->texdef.shift[1] = oldshift[0]; + f->texdef.shift[1] = (f->texdef.shift[1]*oldscale[0] + minx - minzcopy) / f->texdef.scale[1]; // FIX ME + f->texdef.rotate += 90; + } + } + else if ((texvectcopy[0][1] == 1) && (texvectcopy[1][2] == -1)) //yzplane texture for west/east walls + { // u->y v->z w->x + delu = maxy - miny; + delv = maxz - minz; + delw = maxx - minx; + delucopy = maxycopy - minycopy; + delvcopy = maxzcopy - minzcopy; + delwcopy = maxxcopy - minxcopy; + if (!f->texdef.scale[1]) + { + f->texdef.scale[1] = 1; + } + oldscale[1] = f->texdef.scale[1]; + f->texdef.scale[1] *= delvcopy / delv; + f->texdef.shift[1] = (f->texdef.shift[1]*oldscale[1] - (minz - minzcopy)) / f->texdef.scale[1]; + } + break; + case 2: //z rotation + if ((texvect[0][0] == 1) && (texvect[1][1] == -1)) //xyplane texture for ceiling/floor + { // u->x v->y w->z + f->texdef.rotate += deg; // rotate ceiling & floor textures + if (DotProduct(fcopy->plane.normal, zaxis) > 0) + { + f->texdef.shift[0] += (f->face_winding->points[0][0] - rotvert[0]) / f->texdef.scale[0]; + f->texdef.shift[1] += (f->face_winding->points[0][1] - rotvert[1]) / f->texdef.scale[1]; + } + else + { + f->texdef.shift[0] += (f->face_winding->points[0][0] - rotvert[0]) / f->texdef.scale[0]; + f->texdef.shift[1] -= (f->face_winding->points[0][1] - rotvert[1]) / f->texdef.scale[1]; + } + + // this texture plane will not change in a z rotation + } + else if ((texvect[0][1] == 1) && (texvect[1][2] == -1)) //yzplane texture for west/east walls + { // u->y v->z w->x + if ((texvectcopy[0][1] == 1) && (texvectcopy[1][2] == -1)) // not changing axes + { + delu = maxy - miny; + delv = maxz - minz; + delw = maxx - minx; + delucopy = maxycopy - minycopy; + delvcopy = maxzcopy - minzcopy; + delwcopy = maxxcopy - minxcopy; + if (!f->texdef.scale[0]) + { + f->texdef.scale[0] = 1; + } + oldscale[0] = f->texdef.scale[0]; + f->texdef.scale[0] *= delucopy / delu; + f->texdef.shift[0] = (f->texdef.shift[0]*oldscale[0] + (miny - minycopy)) / f->texdef.scale[0]; + } + else if ((texvectcopy[0][0] == 1) && (texvectcopy[1][2] == -1))// switching to xzplane + { + delu = maxx - minx; + delv = maxz - minz; + delw = maxy - miny; + delucopy = maxxcopy - minxcopy; + delvcopy = maxzcopy - minzcopy; + delwcopy = maxycopy - minycopy; + if (!f->texdef.scale[0]) + { + f->texdef.scale[0] = 1; + } + oldscale[0] = f->texdef.scale[0]; + f->texdef.scale[0] *= delucopy / delw; + f->texdef.shift[0] = (f->texdef.shift[0]*oldscale[0] + miny - minxcopy) / f->texdef.scale[0]; + } + else + { + Error; + } + } + else if ((texvect[0][0] == 1) && (texvect[1][2] == -1)) //xzplane texture for north/south walls + { // u->x v->z w->y + if ((texvectcopy[0][0] == 1) && (texvectcopy[1][2] == -1)) + { + delu = maxx - minx; + delv = maxz - minz; + delw = maxy - miny; + delucopy = maxxcopy - minxcopy; + delvcopy = maxzcopy - minzcopy; + delwcopy = maxycopy - minycopy; + if (!f->texdef.scale[0]) + { + f->texdef.scale[0] = 1; + } + oldscale[0] = f->texdef.scale[0]; + f->texdef.scale[0] *= delucopy / delu; + f->texdef.shift[0] = (f->texdef.shift[0]*oldscale[0] + (minx - minxcopy)) / f->texdef.scale[0]; + } + else if ((texvectcopy[0][1] == 1) && (texvectcopy[1][2] == -1)) // switch to yz + { + delu = maxy - miny; + delv = maxz - minz; + delw = maxx - minx; + delucopy = maxycopy - minycopy; + delvcopy = maxzcopy - minzcopy; + delwcopy = maxxcopy - minxcopy; + if (!f->texdef.scale[0]) + { + f->texdef.scale[0] = 1; + } + oldscale[0] = f->texdef.scale[0]; + f->texdef.scale[0] *= delucopy / delw; + f->texdef.shift[0] = (f->texdef.shift[0]*oldscale[0] + (minx - minycopy)) / f->texdef.scale[0]; + } + else + { + Error; // uh oh + } + } // end if + break; + default: + break; + } // end switch + } // end face loop + } // end texture lock if + } // end brush loop +// TEXTURE LOCK STUFF ENDS HERE*/ + Select_AplyMatrix (); + if ((selected_brushes.next->owner != NULL) && (stayaway == 0))// recompute origins for fixed-sized, non worldspawn + { + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if (strcmp(b->owner->eclass->name,"worldspawn") && + (b->owner->eclass->fixedsize)) // fixedsize non-worldspawn + { + VectorSubtract (b->owner->brushes.onext->mins, b->owner->eclass->mins, origin); + sprintf (text, "%i %i %i", (int)origin[0], + (int)origin[1], (int)origin[2]); + SetKeyValue (b->owner, "origin", text); + } + } + } +} + +/* +================================================================ + +GROUP SELECTIONS + +================================================================ +*/ + +void Select_CompleteTall (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + UNDO_ClearSelection(selected_brushes.next); + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (FALSE); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + for (i=0 ; i<2 ; i++) + if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) + break; + if (i == 2) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); +} + +void Select_PartialTall (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + UNDO_ClearSelection(selected_brushes.next); + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (FALSE); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + for (i=0 ; i<2 ; i++) + if (b->mins[i] > maxs[i] || b->maxs[i] < mins[i]) + break; + if (i == 2) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); +} + +void Select_Touching (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + for (i=0 ; i<3 ; i++) + if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1) + break; + if (i == 3) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); +} + +void Select_Inside (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + UNDO_ClearSelection(selected_brushes.next); + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (FALSE); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + for (i=0 ; i<3 ; i++) + if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) + break; + if (i == 3) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + Sys_UpdateWindows (W_ALL); + TEXMOD_UpdateCheck(); +} + +/* +============= +Select_Ungroup + +Turn the currently selected entity back into normal brushes +============= +*/ +void Select_Ungroup (void) +{ + entity_t *e; + brush_t *b; + + e = selected_brushes.next->owner; + + if (!e || e == world_entity || e->eclass->fixedsize) + { + Sys_Status ("Not a grouped entity.", 0); + return; + } + + for (b=e->brushes.onext ; b != &e->brushes ; b=e->brushes.onext) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &active_brushes); + Entity_UnlinkBrush (b); + Entity_LinkBrush (world_entity, b); + Brush_Build( b ); + b->owner = world_entity; + } + + Entity_Free (e); + Sys_UpdateWindows (W_ALL); +} + +/* +==================== +Select_MakeStructural +==================== +*/ +void Select_MakeStructural (void) +{ + brush_t *b; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + for (f=b->brush_faces ; f ; f=f->next) + f->texdef.contents &= ~CONTENTS_DETAIL; + Select_Deselect (); + Sys_UpdateWindows (W_ALL); +} + +void Select_MakeDetail (void) +{ + brush_t *b; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + for (f=b->brush_faces ; f ; f=f->next) + f->texdef.contents |= CONTENTS_DETAIL; + Select_Deselect (); + Sys_UpdateWindows (W_ALL); +} diff --git a/Toolkit/Programming/Tools/qe4/select.h b/Toolkit/Programming/Tools/qe4/select.h new file mode 100644 index 0000000..61c6db4 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/select.h @@ -0,0 +1,42 @@ + +typedef enum +{ + sel_brush, + // sel_sticky_brush, + // sel_face, + sel_vertex, + sel_edge +} select_t; + +typedef struct +{ + brush_t *brush; + face_t *face; + float dist; + qboolean selected; +} trace_t; + +#define SF_SELECTED_ONLY 1 +#define SF_ENTITIES_FIRST 2 +#define SF_SINGLEFACE 4 + + +trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags); + +void Select_GetBounds (vec3_t mins, vec3_t maxs); +void Select_Brush (brush_t *b); +void Select_Ray (vec3_t origin, vec3_t dir, int flags); +void Select_Delete (qboolean undo); +void Select_Deselect (void); +void Select_Clone (void); +void Select_Move (vec3_t delta); +void Select_SetTexture (texdef_t *texdef); +void Select_FlipAxis (int axis); +void Select_RotateAxis (int axis, float deg); +void Select_CompleteTall (void); +void Select_PartialTall (void); +void Select_Touching (void); +void Select_Inside (void); +void Select_MakeStructural (void); +void Select_MakeDetail (void); +void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv); diff --git a/Toolkit/Programming/Tools/qe4/textmod.c b/Toolkit/Programming/Tools/qe4/textmod.c new file mode 100644 index 0000000..68032be --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/textmod.c @@ -0,0 +1,373 @@ +#include "qe3.h" + +/* +=================================================== + + TEXTURE MODIFY - a modeless dialog found on the entity window + +=================================================== +*/ + +static HWND g_surfwin; +static LRESULT (CALLBACK* OldFieldWindowProc) (HWND, UINT, WPARAM, LPARAM); +static void GetTexMods(void); + + +#define numTMControls 5 +static int texModControl[] = { + IDC_HSHIFT, + IDC_VSHIFT, + IDC_ROTATE, + IDC_HSCALE, + IDC_VSCALE +}; + +static HWND hwndTM[numTMControls]; + + +void TEXMOD_UpdateCheck() +{ + qboolean bHaveTrue = false, bHaveFalse = false, bState; + brush_t *b; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if(b->texLocked) + { + bHaveTrue = true; + } + else + { + bHaveFalse = true; + } + if(bHaveTrue && bHaveFalse) break; + } + if(bHaveTrue) + { + if(bHaveFalse) + { + bState = 2; + } + else + { + bState = 1; + } + } + else + { + bState = 0; + } + CheckDlgButton(g_surfwin, IDC_TEXLOCK_CHECK, bState); +} + +static void ResetCheck(int state) +{ + brush_t *b; + + CheckDlgButton(g_surfwin, IDC_TEXLOCK_CHECK, state); + if(state == 2) //indeterminate + return; + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + b->texLocked = state; + } +} + +/* +========================= +FieldWndProc +========================= +*/ +static BOOL CALLBACK FieldWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + HWND hTab; + + switch (uMsg) + { +/* case WM_CHAR: + if (LOWORD(wParam) == VK_TAB) + return FALSE; + if (LOWORD(wParam) == VK_RETURN) + return FALSE; + if (LOWORD(wParam) == VK_ESCAPE) + { + SetFocus (g_qeglobals.d_hwndCamera); + return FALSE; + } + break; +*/ + + case WM_GETDLGCODE: + return DLGC_WANTALLKEYS; + case WM_KEYDOWN: + if (LOWORD(wParam) == VK_TAB) + { + if(GetKeyState(VK_SHIFT)&0x8000) + { + hTab = GetNextDlgTabItem(g_qeglobals.d_hwndTexModDlg, hwnd, TRUE); + } + else + { + hTab = GetNextDlgTabItem(g_qeglobals.d_hwndTexModDlg, hwnd, FALSE); + } + if(hTab) + { + SetFocus(hTab); + } + } + if (LOWORD(wParam) == VK_RETURN) + { + GetTexMods (); + InvalidateRect(g_qeglobals.d_hwndCamera, NULL, false); + UpdateWindow (g_qeglobals.d_hwndCamera); + } + break; +// case WM_NCHITTEST: + case WM_LBUTTONDOWN: + SetFocus (hwnd); + break; + } + return CallWindowProc (OldFieldWindowProc, hwnd, uMsg, wParam, lParam); +} + +/* +============== +SetTexMods + +Set the fields to the current texdef +=============== +*/ +void SetTexMods(void) +{ + char sz[128]; + texdef_t *pt; + + pt = &g_qeglobals.d_texturewin.texdef; + if (selected_face) + { + pt->shift[0] = selected_face->texdef.shift[0]; + pt->shift[1] = selected_face->texdef.shift[1]; + pt->scale[0] = selected_face->texdef.scale[0]; + pt->scale[1] = selected_face->texdef.scale[1]; + pt->rotate = selected_face->texdef.rotate; + } + else if ((selected_brushes.next) && (selected_brushes.next != selected_brushes.next->next)) + { + pt->shift[0] = selected_brushes.next->brush_faces->texdef.shift[0]; + pt->shift[1] = selected_brushes.next->brush_faces->texdef.shift[1]; + pt->scale[0] = selected_brushes.next->brush_faces->texdef.scale[0]; + pt->scale[1] = selected_brushes.next->brush_faces->texdef.scale[1]; + pt->rotate = selected_brushes.next->brush_faces->texdef.rotate; + } + + SendMessage (g_surfwin, WM_SETREDRAW, 0, 0); + +// SetWindowText(GetDlgItem(g_surfwin, IDC_TEXTURE), pt->name); + + sprintf(sz, "%d", (int)pt->shift[0]); + SetWindowText(GetDlgItem(g_surfwin, IDC_HSHIFT), sz); + + sprintf(sz, "%d", (int)pt->shift[1]); + SetWindowText(GetDlgItem(g_surfwin, IDC_VSHIFT), sz); + + sprintf(sz, "%4.2f", pt->scale[0]); + SetWindowText(GetDlgItem(g_surfwin, IDC_HSCALE), sz); + + sprintf(sz, "%4.2f", pt->scale[1]); + SetWindowText(GetDlgItem(g_surfwin, IDC_VSCALE), sz); + + sprintf(sz, "%d", (int)pt->rotate); + SetWindowText(GetDlgItem(g_surfwin, IDC_ROTATE), sz); +/* + sprintf(sz, "%d", (int)pt->value); + SetWindowText(GetDlgItem(g_surfwin, IDC_VALUE), sz); + + for (i=0 ; i<32 ; i++) + SendMessage(GetDlgItem(g_surfwin, g_checkboxes[i]), BM_SETCHECK, !!(pt->flags&(1<contents&(1<texdef; + } + else if ((selected_brushes.next) && (selected_brushes.next != selected_brushes.next->next)) + { + pt = &selected_brushes.next->brush_faces->texdef; + } + + + GetWindowText (GetDlgItem(g_surfwin, IDC_HSHIFT), sz, 127); + pt->shift[0] = atof(sz); + + GetWindowText (GetDlgItem(g_surfwin, IDC_VSHIFT), sz, 127); + pt->shift[1] = atof(sz); + + GetWindowText(GetDlgItem(g_surfwin, IDC_HSCALE), sz, 127); + pt->scale[0] = atof(sz); + + GetWindowText(GetDlgItem(g_surfwin, IDC_VSCALE), sz, 127); + pt->scale[1] = atof(sz); + + GetWindowText(GetDlgItem(g_surfwin, IDC_ROTATE), sz, 127); + pt->rotate = atof(sz); + + Select_SetTexture(pt); +} + +/* +================= +UpdateSpinners +================= +*/ +static void UpdateSpinners(unsigned uMsg, WPARAM wParam, LPARAM lParam) +{ + int nScrollCode; + HWND hwnd; + texdef_t *pt; + + pt = &g_qeglobals.d_texturewin.texdef; + if (selected_face) + { + pt = &selected_face->texdef; + } + else if ((selected_brushes.next) && (selected_brushes.next != selected_brushes.next->next)) + { + pt = &selected_brushes.next->brush_faces->texdef; + } + + nScrollCode = (int) LOWORD(wParam); // scroll bar value + hwnd = (HWND) lParam; // handle of scroll bar + + if ((nScrollCode != SB_LINEUP) && (nScrollCode != SB_LINEDOWN)) + return; + + if (hwnd == GetDlgItem(g_surfwin, IDC_ROTATEA)) + { + if (nScrollCode == SB_LINEUP) + pt->rotate += 45; + else + pt->rotate -= 45; + + if (pt->rotate < 0) + pt->rotate += 360; + + if (pt->rotate >= 360) + pt->rotate -= 360; + } + + else if (hwnd == GetDlgItem(g_surfwin, IDC_HSCALEA)) + { + if (nScrollCode == SB_LINEDOWN) + pt->scale[0] -= 0.1; + else + pt->scale[0] += 0.1; + } + + else if (hwnd == GetDlgItem(g_surfwin, IDC_VSCALEA)) + { + if (nScrollCode == SB_LINEUP) + pt->scale[1] += 0.1; + else + pt->scale[1] -= 0.1; + } + + else if (hwnd == GetDlgItem(g_surfwin, IDC_HSHIFTA)) + { + if (nScrollCode == SB_LINEDOWN) + pt->shift[0] -= 8; + else + pt->shift[0] += 8; + } + + else if (hwnd == GetDlgItem(g_surfwin, IDC_VSHIFTA)) + { + if (nScrollCode == SB_LINEUP) + pt->shift[1] += 8; + else + pt->shift[1] -= 8; + } + + SetTexMods(); + Select_SetTexture(pt); +} + + +BOOL CALLBACK TexModifyProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + int i; + + switch (uMsg) + { + case WM_INITDIALOG: + g_surfwin = hwndDlg; + for(i=0; i<5; i++) + { + hwndTM[i] = GetDlgItem(hwndDlg, texModControl[i]); + if(i==0) + { + OldFieldWindowProc = (void *)GetWindowLong (hwndTM[i], GWL_WNDPROC); + } + SetWindowLong (hwndTM[i], GWL_WNDPROC, (long)FieldWndProc); + } + SetTexMods (); + return FALSE; + case WM_COMMAND: + if(LOWORD(wParam) == IDC_TEXLOCK_CHECK) + { + switch(IsDlgButtonChecked(hwndDlg, IDC_TEXLOCK_CHECK)) + { + case 0: //off, turn 'em on + ResetCheck(1); + break; + case 1: //on, turn 'em off + case 2: //undecided, turn 'em off + ResetCheck(0); + break; + } + } + return FALSE; + + case WM_LBUTTONDOWN: + SetFocus(hwndDlg); + SetTexMods (); + return FALSE; + case WM_HSCROLL: + case WM_VSCROLL: + UpdateSpinners(uMsg, wParam, lParam); + InvalidateRect(g_qeglobals.d_hwndCamera, NULL, false); + UpdateWindow (g_qeglobals.d_hwndCamera); + return 0; + + default: + return FALSE; + } +} + diff --git a/Toolkit/Programming/Tools/qe4/textures.c b/Toolkit/Programming/Tools/qe4/textures.c new file mode 100644 index 0000000..86785e7 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/textures.c @@ -0,0 +1,2018 @@ +#include "qe3.h" +#include "io.h" + +#define TYP_MIPTEX 68 +static unsigned tex_palette[256]; + +static qtexture_t *notexture; + +static qboolean nomips; + +#define FONT_HEIGHT 10 + +static HGLRC s_hglrcTexture; +static HDC s_hdcTexture; + +//int texture_mode = GL_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; +//int texture_mode = GL_LINEAR; +//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; +int texture_mode = GL_LINEAR_MIPMAP_LINEAR; + +int texture_extension_number = 1; + +// current active texture directory. if empty, show textures in use +char texture_directory[32]; // use if texture_showinuse is false +qboolean texture_showinuse; + +// texture layout functions +qtexture_t *current_texture; +int current_x, current_y, current_row; + +int texture_nummenus; +#define MAX_TEXTUREDIRS 100 +char texture_menunames[MAX_TEXTUREDIRS][64]; + +qboolean g_dontuse; // set to true to load the texture but not flag as used + +void SelectTexture (int mx, int my); + +void Texture_MouseDown (int x, int y, int buttons); +void Texture_MouseUp (int x, int y, int buttons); +void Texture_MouseMoved (int x, int y, int buttons); + +//===================================================== + +void SortTextures(void) +{ + qtexture_t *q, *qtemp, *qhead, *qcur, *qprev; + + // standard insertion sort + // Take the first texture from the list and + // add it to our new list + if ( g_qeglobals.d_qtextures == NULL) + return; + + qhead = g_qeglobals.d_qtextures; + q = g_qeglobals.d_qtextures->next; + qhead->next = NULL; + + // while there are still things on the old + // list, keep adding them to the new list + while (q) + { + qtemp = q; + q = q->next; + + qprev = NULL; + qcur = qhead; + + while (qcur) + { + // Insert it here? + if (strcmp(qtemp->name, qcur->name) < 0) + { + qtemp->next = qcur; + if (qprev) + qprev->next = qtemp; + else + qhead = qtemp; + break; + } + + // Move on + + qprev = qcur; + qcur = qcur->next; + + + // is this one at the end? + + if (qcur == NULL) + { + qprev->next = qtemp; + qtemp->next = NULL; + } + } + + + } + + g_qeglobals.d_qtextures = qhead; +} + +/* +============================================================================ + + SCROLLBAR UPDATE AND RESPONSE + +============================================================================ +*/ + +void Texture_SetScrollRange (void) +{ + qtexture_t *q, *curtex; + int done; + int curx, cury, currow; + + //start at the top + curtex = g_qeglobals.d_qtextures; + curx = 8; + cury = -12 - FONT_HEIGHT; + currow = 0; + + //go thru all the textures and figure out how tall the whole list is + done = false; + + while (curtex) + { + while (1) + { + q = curtex; + if (!q) + done = true; + else + { + curtex = curtex->next; + if (q->name[0] == '(') // fake color texture + continue; + if (q->inuse) + break; // allways show in use + if (!texture_showinuse && strncmp (q->name, texture_directory, strlen(texture_directory))) + continue; + } + break; + } + + if (!done) + { + if (curx + q->width > g_qeglobals.d_texturewin.width-8 && currow) + { // go to the next row unless the texture is the first on the row + curx = 8; + cury -= currow + FONT_HEIGHT + 4; + currow = 0; + } + + // Is our texture larger than the row? If so, grow the + // row height to match it + + if (currow < q->height) + currow = q->height; + + // never go less than 64, or the names get all crunched up + curx += q->width < 64 ? 64 : q->width; + curx += 8; + } + } + + g_qeglobals.d_texturewin.scrollheight = -cury + currow - g_qeglobals.d_texturewin.height; + + SetScrollRange(g_qeglobals.d_hwndTexture, SB_VERT, 0, + g_qeglobals.d_texturewin.scrollheight, true); +} + +void Texture_SetScrollPos (void) +{ + SetScrollPos(g_qeglobals.d_hwndTexture, SB_VERT, -g_qeglobals.d_texturewin.originy, true); +} + +void Texture_ScrollLine (int ydown) +{ + g_qeglobals.d_texturewin.originy += ydown; + if (g_qeglobals.d_texturewin.originy > 0) + { + g_qeglobals.d_texturewin.originy = 0; + } + if (g_qeglobals.d_texturewin.originy < -g_qeglobals.d_texturewin.scrollheight) + { + g_qeglobals.d_texturewin.originy = -g_qeglobals.d_texturewin.scrollheight; + } + Sys_UpdateWindows (W_TEXTURE); + Texture_SetScrollPos(); +} + +void Texture_ScrollRow (int ydown)//warning: i only plan on making this work for values of 1 & -1 --ss +{ + qtexture_t *q, *curtex; + int done; + int curx, cury, currow, lastrow; + + //start at the top + curtex = g_qeglobals.d_qtextures; + curx = 8; + cury = 0;//to make the textures above top row not peek down at top of window, set this to -8 initially + //(it's set to 0 to let you go to very top of window with scrollbar arrows) + currow = 0; + + //go thru all the textures until we find the row we want to scroll past + done = false; + lastrow = 0; + + while (curtex && !done) + { + while (1) + { + q = curtex; + if (!q) + done = true; + else + { + curtex = curtex->next; + if (q->name[0] == '(') // fake color texture + continue; + if (q->inuse) + break; // allways show in use + if (!texture_showinuse && strncmp (q->name, texture_directory, strlen(texture_directory))) + continue; + } + break; + } + + if (!done) + { + if (curx + q->width > g_qeglobals.d_texturewin.width-8 && currow) + { // go to the next row unless the texture is the first on the row + curx = 8; + + if ((ydown > 0) && lastrow)//want to scroll down--set origin to cury + the last row + { + if (cury > g_qeglobals.d_texturewin.originy) + g_qeglobals.d_texturewin.originy = cury; + else + g_qeglobals.d_texturewin.originy = cury+lastrow+FONT_HEIGHT+4; + done = true; + } + else if ((ydown < 0)&&lastrow)//want to scroll up--set origin to cury + { + if (cury < g_qeglobals.d_texturewin.originy) + g_qeglobals.d_texturewin.originy = cury; + else + g_qeglobals.d_texturewin.originy = cury-currow-FONT_HEIGHT-4; + + done = true; + } + else + { + cury -= currow + FONT_HEIGHT + 4; + // Is this texture visible? + if ( (cury-q->height-FONT_HEIGHT < g_qeglobals.d_texturewin.originy) + && (cury > g_qeglobals.d_texturewin.originy - g_qeglobals.d_texturewin.height) ) + { + lastrow = currow; + } + + } + + if (!done) + { + currow = 0; + } + } + + // Is our texture larger than the row? If so, grow the + // row height to match it + + if (currow < q->height) + currow = q->height; + + // never go less than 64, or the names get all crunched up + curx += q->width < 64 ? 64 : q->width; + curx += 8; + } + } + + if (g_qeglobals.d_texturewin.originy > 0) + g_qeglobals.d_texturewin.originy = 0; + if (g_qeglobals.d_texturewin.originy < -g_qeglobals.d_texturewin.scrollheight) + g_qeglobals.d_texturewin.originy = -g_qeglobals.d_texturewin.scrollheight; + Sys_UpdateWindows (W_TEXTURE); + Texture_SetScrollPos(); + +} + +void Texture_ScrollPage (int ydown)//warning: i only plan on making this work for values of 1 & -1 --ss +{ + qtexture_t *q, *curtex; + int done; + int curx, cury, currow, lastrow, curscroll; + int pagedone, hasscrolled, totalscrolled; + + pagedone = false; + hasscrolled = false; + totalscrolled = 0; + if (!g_qeglobals.d_qtextures) + return; //JFM: stop the madness + + while ((!pagedone) || (!hasscrolled)) + { + //start at the top + curtex = g_qeglobals.d_qtextures; + curx = 8; + cury = 0;//to make the textures above top row not peek down at top of window, set this to -8 initially + //(it's set to 0 to let you go to very top of window with scrollbar arrows) + currow = 0; + + //go thru all the textures until we find the row we want to scroll past + done = false; + lastrow = 0; + + while (curtex && !done) + { + while (1) + { + q = curtex; + if (!q) + { + pagedone = true; + hasscrolled = true; + done = true; + } + else + { + curtex = curtex->next; + if (q->name[0] == '(') // fake color texture + continue; + if (q->inuse) + break; // allways show in use + if (!texture_showinuse && strncmp (q->name, texture_directory, strlen(texture_directory))) + continue; + } + break; + } + + if (!done) + { + if (curx + q->width > g_qeglobals.d_texturewin.width-8 && currow) + { // go to the next row unless the texture is the first on the row + curx = 8; + + if ((ydown > 0) && lastrow)//want to scroll down--set origin to cury + the last row + { + if (cury > g_qeglobals.d_texturewin.originy) + { + curscroll = cury - g_qeglobals.d_texturewin.originy; + } + else + { + curscroll = cury + lastrow + FONT_HEIGHT + 4 - g_qeglobals.d_texturewin.originy; + } + + if ((hasscrolled)&&(totalscrolled + curscroll > g_qeglobals.d_texturewin.height)) + {//hey, if i scroll any more, all prev. lines will go totally off the screen, so stop + pagedone = true; + } + else + {//can still safely scroll some more, so do it + g_qeglobals.d_texturewin.originy += curscroll; + totalscrolled += curscroll; + if (g_qeglobals.d_texturewin.originy > -5)//oop, that was the last one + { + pagedone = true; + } + } + + hasscrolled = true; + done = true; + } + else if ((ydown < 0)&&lastrow)//want to scroll up--set origin to cury + { + if (cury < g_qeglobals.d_texturewin.originy) + { + curscroll = g_qeglobals.d_texturewin.originy - cury; + } + else + { + curscroll = /*g_qeglobals.d_texturewin.originy - cury +*/ lastrow + FONT_HEIGHT + 4; + } + + if ((hasscrolled)&&((totalscrolled + curscroll) > g_qeglobals.d_texturewin.height)) + {//hey, if i scroll any more, all prev. lines will go totally off the screen, so stop + pagedone = true; + } + else + {//can still safely scroll some more, so do it + g_qeglobals.d_texturewin.originy -= curscroll; + totalscrolled += curscroll; + if (g_qeglobals.d_texturewin.originy < -g_qeglobals.d_texturewin.scrollheight+5)//oop, that was the last one + // -g_qeglobals.d_texturewin.scrollheight+5 caused the program to crash... ^^ this is a temp. hack fix + { + pagedone = true; + } + } + + hasscrolled = true; + done = true; + } +/* { + pagedone = true; + hasscrolled = true; + if (cury < g_qeglobals.d_texturewin.originy) + { + g_qeglobals.d_texturewin.originy = cury; + } + else + { + g_qeglobals.d_texturewin.originy = cury-currow-FONT_HEIGHT-4; + } + done = true; + } +*/ else + { + cury -= currow + FONT_HEIGHT + 4; + // Is this texture visible? + if ( (cury-q->height-FONT_HEIGHT < g_qeglobals.d_texturewin.originy) + && (cury > g_qeglobals.d_texturewin.originy - g_qeglobals.d_texturewin.height) ) + { + lastrow = currow; + } + + } + + if (!done) + { + currow = 0; + } + } + + // Is our texture larger than the row? If so, grow the + // row height to match it + + if (currow < q->height) + { + currow = q->height; + } + // never go less than 64, or the names get all crunched up + curx += q->width < 64 ? 64 : q->width; + curx += 8; + } + } + + if (g_qeglobals.d_texturewin.originy > 0) + g_qeglobals.d_texturewin.originy = 0; + if (g_qeglobals.d_texturewin.originy < -g_qeglobals.d_texturewin.scrollheight) + g_qeglobals.d_texturewin.originy = -g_qeglobals.d_texturewin.scrollheight; + } + Sys_UpdateWindows (W_TEXTURE); + Texture_SetScrollPos(); + +} + +void Texture_ScrollTo (int pos) +{ + g_qeglobals.d_texturewin.originy = pos; + if (g_qeglobals.d_texturewin.originy > 0) + g_qeglobals.d_texturewin.originy = 0; + if (g_qeglobals.d_texturewin.originy < -g_qeglobals.d_texturewin.scrollheight) + g_qeglobals.d_texturewin.originy = -g_qeglobals.d_texturewin.scrollheight; + Sys_UpdateWindows (W_TEXTURE); + Texture_SetScrollPos(); +} + +//===================================================== + + +/* +============== +Texture_InitPalette +============== +*/ +void Texture_InitPalette (byte *pal) +{ + int r,g,b,v; + int i; + int inf; + byte gammatable[256]; + float gamma; + + gamma = g_qeglobals.d_savedinfo.fGamma; + + if (gamma == 1.0) + { + for (i=0 ; i<256 ; i++) + gammatable[i] = i; + } + else + { + for (i=0 ; i<256 ; i++) + { + inf = 255 * pow ( (i+0.5)/255.5 , gamma ) + 0.5; + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = inf; + } + } + + for (i=0 ; i<256 ; i++) + { + r = gammatable[pal[0]]; + g = gammatable[pal[1]]; + b = gammatable[pal[2]]; + pal += 3; + + v = (r<<24) + (g<<16) + (b<<8) + 255; + v = BigLong (v); + + tex_palette[i] = v; + } +} + +void SetTexParameters (void) +{ + + switch ( texture_mode ) + { + case GL_NEAREST: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_mode ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + break; + case GL_LINEAR: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_mode ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + break; + } +} + +/* +============ +Texture_SetMode +============ +*/ +void Texture_SetMode(int iMenu) +{ + int i, iMode; + HMENU hMenu; + qboolean texturing = true; + + hMenu = GetMenu(g_qeglobals.d_hwndMain); + + switch(iMenu) { + case ID_VIEW_NEAREST: + iMode = GL_NEAREST; + break; + case ID_VIEW_NEARESTMIPMAP: + iMode = GL_NEAREST_MIPMAP_NEAREST; + break; + case ID_VIEW_LINEAR: + iMode = GL_NEAREST_MIPMAP_LINEAR; + break; + case ID_VIEW_BILINEAR: + iMode = GL_LINEAR; + break; + case ID_VIEW_BILINEARMIPMAP: + iMode = GL_LINEAR_MIPMAP_NEAREST; + break; + case ID_VIEW_TRILINEAR: + iMode = GL_LINEAR_MIPMAP_LINEAR; + break; + + case ID_TEXTURES_WIREFRAME: + iMode = 0; + texturing = false; + break; + + case ID_TEXTURES_FLATSHADE: + iMode = 0; + texturing = false; + break; + + } + + CheckMenuItem(hMenu, ID_VIEW_NEAREST, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_NEARESTMIPMAP, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_LINEAR, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_BILINEARMIPMAP, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_BILINEAR, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_TRILINEAR, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_TEXTURES_WIREFRAME, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_TEXTURES_FLATSHADE, MF_BYCOMMAND | MF_UNCHECKED); + + CheckMenuItem(hMenu, iMenu, MF_BYCOMMAND | MF_CHECKED); + + g_qeglobals.d_savedinfo.iTexMenu = iMenu; + texture_mode = iMode; + if ( texturing ) + SetTexParameters (); + + if ( !texturing && iMenu == ID_TEXTURES_WIREFRAME) + { + camera.draw_mode = cd_wire; + Map_BuildBrushData(false); + Sys_UpdateWindows (W_ALL); + return; + + } else if ( !texturing && iMenu == ID_TEXTURES_FLATSHADE) { + + camera.draw_mode = cd_solid; + Map_BuildBrushData(false); + Sys_UpdateWindows (W_ALL); + return; + } + + for (i=1 ; iwidth[0]); + height = LittleLong(qtex->height[0]); + + q->width = width; + q->height = height; + + q->flags = qtex->flags; + q->value = qtex->value; + q->contents = qtex->contents; + q->scale_x = 1.0; + q->scale_y = 1.0; + + dest = qmalloc (width*height*4); + + count = width*height; + source = (byte *)qtex + LittleLong(qtex->offsets[0]); + + // The dib is upside down so we want to copy it into + // the buffer bottom up. + + total[0] = total[1] = total[2] = 0; + for (i=0 ; ipalette[source[i]].b; + dest[i] <<= 8; + dest[i] += qtex->palette[source[i]].g; + dest[i] <<= 8; + dest[i] += qtex->palette[source[i]].r; + + total[0] += ((byte *)(dest+i))[0]; + total[1] += ((byte *)(dest+i))[1]; + total[2] += ((byte *)(dest+i))[2]; + } + + q->color[0] = (float)total[0]/(count*255); + q->color[1] = (float)total[1]/(count*255); + q->color[2] = (float)total[2]/(count*255); + + q->texture_number = texture_extension_number++; + + glBindTexture( GL_TEXTURE_2D, q->texture_number ); + SetTexParameters (); + + if (nomips) + glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dest); + else + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height,GL_RGBA, GL_UNSIGNED_BYTE, dest); + + free (dest); + + glBindTexture( GL_TEXTURE_2D, 0 ); + + return q; +} + +/* +================= +Texture_LoadTexture +================= +*/ +qtexture_t *Texture_LoadTexture32 (miptex32_t *qtex) +{ + unsigned *source; + unsigned *dest; + int width, height, i, count; + int total[3]; + qtexture_t *q; + + if (qtex->version != MIP32_VERSION) + { + return NULL; + } + + q = qmalloc(sizeof(*q)); + width = LittleLong(qtex->width[0]); + height = LittleLong(qtex->height[0]); + + q->width = width; + q->height = height; + + q->flags = qtex->flags; + q->value = qtex->value; + q->contents = qtex->contents; + q->scale_x = qtex->scale_x; + q->scale_y = qtex->scale_y; + + dest = qmalloc (width*height*4); + + count = width*height; + source = (unsigned *)((byte *)qtex + LittleLong(qtex->offsets[0])); + + // The dib is upside down so we want to copy it into + // the buffer bottom up. + + total[0] = total[1] = total[2] = 0; + for (i=0 ; icolor[0] = (float)total[0]/(count*255); + q->color[1] = (float)total[1]/(count*255); + q->color[2] = (float)total[2]/(count*255); + + q->texture_number = texture_extension_number++; + + glBindTexture( GL_TEXTURE_2D, q->texture_number ); + SetTexParameters (); + + if (nomips) + glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dest); + else + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height,GL_RGBA, GL_UNSIGNED_BYTE, dest); + + free (dest); + + glBindTexture( GL_TEXTURE_2D, 0 ); + + return q; +} + +/* +=============== +Texture_CreateSolid + +Create a single pixel texture of the apropriate color +=============== +*/ +qtexture_t *Texture_CreateSolid (char *name) +{ + byte data[4]; + qtexture_t *q; + + q = qmalloc(sizeof(*q)); + + sscanf (name, "(%f %f %f)", &q->color[0], &q->color[1], &q->color[2]); + + data[0] = q->color[0]*255; + data[1] = q->color[1]*255; + data[2] = q->color[2]*255; + data[3] = 255; + + q->width = q->height = 1; + q->texture_number = texture_extension_number++; + glBindTexture( GL_TEXTURE_2D, q->texture_number ); + SetTexParameters (); + + q->scale_x = 1.0; + q->scale_y = 1.0; + + if (nomips) + glTexImage2D(GL_TEXTURE_2D, 0, 3, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + else + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 1, 1,GL_RGBA, GL_UNSIGNED_BYTE, data); + + glBindTexture( GL_TEXTURE_2D, 0 ); + + return q; +} + + +/* +================= +Texture_MakeNotexture +================= +*/ +void Texture_MakeNotexture (void) +{ + qtexture_t *q; + byte data[4][4]; + + notexture = q = qmalloc(sizeof(*q)); + strcpy (q->name, "notexture"); + q->width = q->height = 64; + + memset (data, 0, sizeof(data)); + data[0][2] = data[3][2] = 255; + + q->color[0] = 0; + q->color[1] = 0; + q->color[2] = 0.5; + + q->scale_x = 1.0; + q->scale_y = 1.0; + + q->texture_number = texture_extension_number++; + glBindTexture( GL_TEXTURE_2D, q->texture_number ); + SetTexParameters (); + + if (nomips) + glTexImage2D(GL_TEXTURE_2D, 0, 3, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + else + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 2, 2,GL_RGBA, GL_UNSIGNED_BYTE, data); + + glBindTexture( GL_TEXTURE_2D, 0 ); +} + + + +/* +=============== +Texture_ForName +=============== +*/ +qtexture_t *Texture_ForName (char *name) +{ + byte *lump; + qtexture_t *q = NULL; + char filename[1024]; + +//return notexture; + for (q=g_qeglobals.d_qtextures ; q ; q=q->next) + { + if (!strcmp(name, q->name)) + { + if (!g_dontuse) + q->inuse = true; + return q; + } + } + + if (name[0] == '(') + { + q = Texture_CreateSolid (name); + strncpy (q->name, name, sizeof(q->name)-1); + } + else + { + // load the file + sprintf (filename, "%s/%s.m32", + ValueForKey (g_qeglobals.d_project_entity, "texturepath"), + name); + if (TryLoadFile (filename, &lump) == -1) + { + sprintf (filename, "%s/%s.m8", + ValueForKey (g_qeglobals.d_project_entity, "texturepath"), + name); + if (TryLoadFile (filename, &lump) == -1) + { + Sys_Printf (" load failed for %s!\n", name); + return notexture; + } + Sys_Printf ("Loading %s\n", name); + q = Texture_LoadTexture ((miptex_t *)lump); + } + else + { + Sys_Printf ("Loading %s\n", name); + q = Texture_LoadTexture32 ((miptex32_t *)lump); + } + free (lump); + if (!q) + { + return q; + } + strncpy (q->name, name, sizeof(q->name)-1); + StripExtension (q->name); + } + + if (!g_dontuse) + q->inuse = true; + q->next = g_qeglobals.d_qtextures; + g_qeglobals.d_qtextures = q; + + return q; +} + +/* +================== +FillTextureMenu + +================== +*/ +void FillTextureMenu (void) +{ + HMENU hmenu; + int i; + struct _finddata_t fileinfo; + int handle; + char dirstring[1024]; + char *path; + + hmenu = GetSubMenu (GetMenu(g_qeglobals.d_hwndMain), MENU_TEXTURE); + + // delete everything + for (i=0 ; inext) + { + q->inuse = false; + } +} + + + +/* +============== +Texture_ShowDirectory +============== +*/ +void Texture_ShowDirectory (int menunum) +{ + struct _finddata_t fileinfo; + int handle; + char name[1024]; + char dirstring[1024]; + + texture_showinuse = false; + strcpy (texture_directory, texture_menunames[menunum-CMD_TEXTUREWAD]); + + g_qeglobals.d_texturewin.originy = 0; + Sys_Status("loading all textures\n", 0); + + // load all .wal files + sprintf (dirstring, "%s/textures/%s*.m*", + ValueForKey (g_qeglobals.d_project_entity, "basepath"), + texture_menunames[menunum-CMD_TEXTUREWAD]); + + Sys_Printf ("Scanning %s\n", dirstring); + + handle = _findfirst (dirstring, &fileinfo); + if (handle == -1) + return; + + g_dontuse = true; + do + { + sprintf (name, "%s%s", texture_directory, fileinfo.name); + StripExtension (name); + Texture_ForName (name); + } while (_findnext( handle, &fileinfo ) != -1); + g_dontuse = false; + + _findclose (handle); + + SortTextures(); + SetInspectorMode(W_TEXTURE); + Sys_UpdateWindows(W_TEXTURE); + Texture_SetScrollRange(); + Texture_SetScrollPos(); + + sprintf (name, "Textures: %s", texture_directory); + SetWindowText(g_qeglobals.d_hwndEntity, name); + + // select the first texture in the list + if (!g_qeglobals.d_texturewin.texdef.name[0]) + SelectTexture (16, g_qeglobals.d_texturewin.height -16); +} + +/* +============== +Texture_ShowInuse +============== +*/ +void Texture_ShowInuse (void) +{ + char name[1024]; + face_t *f; + brush_t *b; + + texture_showinuse = true; + + g_qeglobals.d_texturewin.originy = 0; + Sys_Status("Selecting active textures\n", 0); + Texture_ClearInuse (); + + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=b->next) + for (f=b->brush_faces ; f ; f=f->next) + Texture_ForName (f->texdef.name); + + for (b=selected_brushes.next ; b != NULL && b != &selected_brushes ; b=b->next) + for (f=b->brush_faces ; f ; f=f->next) + Texture_ForName (f->texdef.name); + + SortTextures(); + SetInspectorMode(W_TEXTURE); + Sys_UpdateWindows (W_TEXTURE); + Texture_SetScrollPos(); + + sprintf (name, "Textures: in use"); + SetWindowText(g_qeglobals.d_hwndEntity, name); + + // select the first texture in the list + if (!g_qeglobals.d_texturewin.texdef.name[0]) + SelectTexture (16, g_qeglobals.d_texturewin.height -16); +} + +/* +=============== +Texture_ListInUse +=============== +*/ + +void Texture_ListInUse(void) +{ + brush_t* b; + face_t* f; + texlist_t* texturelist; // the first texture name in the list + texlist_t* thistexture; // texture currently read in + texlist_t* curTexture; // texture in the list that we're working with + texlist_t* prevTexture; // texture prior to curTexture + + + texturelist = NULL; + + SetInspectorMode(W_CONSOLE); + Sys_ClearPrintf(); + Sys_Printf ("Textures in use:\n"); + + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + if (f->texdef.name[0] != '(') // we only want texture names, not entities + { + thistexture = malloc( sizeof(texlist_t)); + if (thistexture == NULL) + { + Error("Not enough memory"); + return; + } + thistexture->uses = 0; + thistexture->name[0] = '\0'; + thistexture->prev = NULL; + thistexture->next = NULL; + strcpy(thistexture->name, f->texdef.name); + + if (texturelist == NULL) + { + thistexture->uses++; + texturelist = thistexture; //put first member on list + } + else + { + curTexture = texturelist; // grab the list + prevTexture = curTexture->prev; + while (1) + { + if (curTexture->name == NULL) // end of list + { + thistexture->uses++; + thistexture->prev = prevTexture; // add texture on + prevTexture->next = thistexture; + break; + } + if (strcmp(thistexture->name,curTexture->name) == 0) // texture already on list + { + curTexture->uses++; + free (thistexture); + break; + } + if (strcmp(thistexture->name,curTexture->name) < 0) // texture belongs ahead of this one + { + if (prevTexture == NULL) // texture goes at front of list + { + thistexture->uses++; + thistexture->next = curTexture; + curTexture->prev = thistexture; + texturelist = thistexture; // list now starts here + } + else + { + thistexture->uses++; + thistexture->prev = curTexture->prev; + thistexture->next = curTexture; + curTexture->prev = thistexture; + prevTexture->next = thistexture; + } + break; + } + prevTexture = curTexture; + curTexture = curTexture->next; // advance to next texture in list + } + } + } // texture name + } // face + } // brush + + for (b=selected_brushes.next ; b != NULL && b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + if (f->texdef.name[0] != '(') // we only want texture names, not entities + { + thistexture = malloc( sizeof(texlist_t)); + if (thistexture == NULL) + { + Error("Not enough memory"); + return; + } + thistexture->uses = 0; + thistexture->name[0] = '\0'; + thistexture->prev = NULL; + thistexture->next = NULL; + strcpy(thistexture->name, f->texdef.name); + + if (texturelist == NULL) + { + thistexture->uses++; + texturelist = thistexture; //put first member on list + } + else + { + curTexture = texturelist; // grab the list + prevTexture = curTexture->prev; + while (1) + { + if (curTexture->name == NULL) // end of list + { + thistexture->uses++; + thistexture->prev = prevTexture; // add texture on + prevTexture->next = thistexture; + break; + } + if (strcmp(thistexture->name,curTexture->name) == 0) // texture already on list + { + curTexture->uses++; + free (thistexture); + break; + } + if (strcmp(thistexture->name,curTexture->name) < 0) // texture belongs ahead of this one + { + if (prevTexture == NULL) // texture goes at front of list + { + thistexture->uses++; + thistexture->next = curTexture; + curTexture->prev = thistexture; + texturelist = thistexture; // list now starts here + } + else + { + thistexture->uses++; + thistexture->prev = curTexture->prev; + thistexture->next = curTexture; + curTexture->prev = thistexture; + prevTexture->next = thistexture; + } + break; + } + prevTexture = curTexture; + curTexture = curTexture->next; // advance to next texture in list + } + } + } // texture name + } // face + } // brush + + for (curTexture = texturelist; curTexture; curTexture=curTexture->next) + { + Sys_Printf("%s, Used on %d faces\n",curTexture->name, curTexture->uses); + } + + while (texturelist != NULL) + { + curTexture = texturelist; + texturelist = curTexture->next; + free (curTexture); + } +} + + +/* +============== +Texture_Replace +============== +*/ + +// Start with world_enitity + + +void Texture_Replace(char *from, char *to, int replaceAll) +{ + brush_t *b, *startBrush; + face_t *f, *startFace; + qtexture_t *curTex; + int foundTex = 0; + int i; + + curTex = g_qeglobals.d_qtextures; + + while(curTex && !foundTex) + { + if(!strcmpi(to, curTex->name)) + { // found it... + foundTex = 1; + } + else + { + curTex = curTex->next; + } + } + + if(!foundTex) + { // looks like the texture entered was invalid + return; + } + + if(replaceAll) + { + b = world_entity->brushes.onext; + } + else + { + b = selected_brushes.next; + } + + startBrush = b; + + while(b != NULL) + { + // Search through the face linked list + f = b->brush_faces; + + startFace = f; + + while(f != NULL) + { + // check the stuff + if (!strcmpi(from, f->texdef.name)) + { + // replace the things + + memset (&f->texdef, 0, sizeof(f->texdef)); + f->texdef.scale[0] = curTex->scale_x; + f->texdef.scale[1] = curTex->scale_y; + f->texdef.flags = curTex->flags; + f->texdef.value = curTex->value; + f->texdef.contents = curTex->contents; + f->texdef.lighting[0] = 1.0; + f->texdef.lighting[1] = 1.0; + f->texdef.lighting[2] = 1.0; + f->texdef.lighting[3] = 1.0; + strcpy (f->texdef.name, curTex->name); + } + + f = f->next; + + if(f == startFace) + { + f = NULL; + } + } + + if(replaceAll) + { + b = b->onext; + } + else + { + b = b->next; + } + if(b == startBrush) + { + b = NULL; // hit the end of the circular list + } + } + + // This is really pretty hacky. This ensures that the camera view is properly updated.... + // Otherwise the textures don't get update (?) + if(camera.draw_mode == cd_texture) + { + camera.draw_mode = cd_solid; + Map_BuildBrushData(false); + Sys_UpdateWindows (W_ALL); + + for (i=1 ; inext; + if (q->name[0] == '(') // fake color texture + continue; + if (q->inuse) + break; // allways show in use + if (!texture_showinuse && strncmp (q->name, texture_directory, strlen(texture_directory))) + continue; + break; + } + + if (current_x + q->width > g_qeglobals.d_texturewin.width-8 && current_row) + { // go to the next row unless the texture is the first on the row + current_x = 8; + current_y -= current_row + FONT_HEIGHT + 4; + current_row = 0; + } + + *x = current_x; + *y = current_y; + + // Is our texture larger than the row? If so, grow the + // row height to match it + + if (current_row < q->height) + current_row = q->height; + + // never go less than 64, or the names get all crunched up + current_x += q->width < 64 ? 64 : q->width; + current_x += 8; + + return q; +} + + +/* +============================================================================ + + MOUSE ACTIONS + +============================================================================ +*/ + +static int textures_cursorx, textures_cursory; + + +/* +============ +Texture_SetTexture + +============ +*/ +void Texture_SetTexture (texdef_t *texdef) +{ + qtexture_t *q; + int x,y; + char sz[256]; + + if (texdef->name[0] == '(') + { + Sys_Status("Can't select an entity texture\n", 0); + return; + } + g_qeglobals.d_texturewin.prevTexDef = g_qeglobals.d_texturewin.texdef; + g_qeglobals.d_texturewin.texdef = *texdef; + + Sys_UpdateWindows (W_TEXTURE); + Texture_SetScrollPos(); + sprintf(sz, "Selected texture: %s\n", texdef->name); + Sys_Status(sz, 0); + Select_SetTexture(texdef); + +// scroll origin so the texture is completely on screen + Texture_StartPos (); + while (1) + { + q = Texture_NextPos (&x, &y); + if (!q) + break; + if (!strcmpi(texdef->name, q->name)) + { + if (y > g_qeglobals.d_texturewin.originy) + { + g_qeglobals.d_texturewin.originy = y; + Sys_UpdateWindows (W_TEXTURE); + Texture_SetScrollPos(); + return; + } + + if (y-q->height-2*FONT_HEIGHT < g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height) + { + g_qeglobals.d_texturewin.originy = y-q->height-2*FONT_HEIGHT+g_qeglobals.d_texturewin.height; + Sys_UpdateWindows (W_TEXTURE); + Texture_SetScrollPos(); + return; + } + + return; + } + } +} + + +/* +============== +SelectTexture + + By mouse click +============== +*/ +void SelectTexture (int mx, int my) +{ + int x, y; + qtexture_t *q; + texdef_t tex; + + my += g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height; + + Texture_StartPos (); + while (1) + { + q = Texture_NextPos (&x, &y); + if (!q) + break; + if (mx > x && mx - x < q->width + && my < y && y - my < q->height + FONT_HEIGHT) + { + memset (&tex, 0, sizeof(tex)); + tex.scale[0] = q->scale_x; + tex.scale[1] = q->scale_y; + tex.flags = q->flags; + tex.value = q->value; + tex.contents = q->contents; + strcpy (tex.name, q->name); + Texture_SetTexture (&tex); + return; + } + } + + Sys_Status("Did not select a texture\n", 0); +} + +/* +============== +Texture_MouseDown +============== +*/ +void Texture_MouseDown (int x, int y, int buttons) +{ + Sys_GetCursorPos (&textures_cursorx, &textures_cursory); + + // lbutton = select texture + if (buttons == MK_LBUTTON ) + { + SelectTexture (x, g_qeglobals.d_texturewin.height - 1 - y); + return; + } + +} + +/* +============== +Texture_MouseUp +============== +*/ +void Texture_MouseUp (int x, int y, int buttons) +{ +} + +/* +============== +Texture_MouseMoved +============== +*/ +void Texture_MouseMoved (int x, int y, int buttons) +{ + int scale = 1; + + if ( buttons & MK_SHIFT ) + scale = 4; + + // rbutton = drag texture origin + if (buttons & MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if ( y != textures_cursory) + { + Texture_ScrollLine(( y-textures_cursory) * scale); + Sys_SetCursorPos (textures_cursorx, textures_cursory); + + } + return; + } +} + + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + +int imax(int iFloor, int i) { if (i>iFloor) return iFloor; return i; } +HFONT ghFont = NULL; + +/* +============ +Texture_Draw2 +============ +*/ +void Texture_Draw2 (int width, int height) +{ + qtexture_t *q; + int x, y; + char *name; + + glClearColor ( + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][2], + 0); + glViewport (0,0,width,height); + glClear (GL_COLOR_BUFFER_BIT); + glDisable (GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); + glLoadIdentity (); + glOrtho (0, width, g_qeglobals.d_texturewin.originy-height, g_qeglobals.d_texturewin.originy, -100, 100); + glEnable (GL_TEXTURE_2D); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + g_qeglobals.d_texturewin.width = width; + g_qeglobals.d_texturewin.height = height; + Texture_StartPos (); + + while (1) + { + q = Texture_NextPos (&x, &y); + if (!q) + break; + + // Is this texture visible? + if ( (y-q->height-FONT_HEIGHT < g_qeglobals.d_texturewin.originy) + && (y > g_qeglobals.d_texturewin.originy - height) ) + { + + // if in use, draw a background + if (q->inuse && !texture_showinuse) + { + glLineWidth (1); + glColor3f (0.5,1,0.5); + glDisable (GL_TEXTURE_2D); + + glBegin (GL_LINE_LOOP); + glVertex2f (x-1,y+1-FONT_HEIGHT); + glVertex2f (x-1,y-q->height-1-FONT_HEIGHT); + glVertex2f (x+1+q->width,y-q->height-1-FONT_HEIGHT); + glVertex2f (x+1+q->width,y+1-FONT_HEIGHT); + glEnd (); + + glEnable (GL_TEXTURE_2D); + } + + // Draw the texture + glColor3f (1,1,1); + glBindTexture( GL_TEXTURE_2D, q->texture_number ); + glBegin (GL_QUADS); + glTexCoord2f (0,0); + glVertex2f (x,y-FONT_HEIGHT); + glTexCoord2f (1,0); + glVertex2f (x+q->width,y-FONT_HEIGHT); + glTexCoord2f (1,1); + glVertex2f (x+q->width,y-FONT_HEIGHT-q->height); + glTexCoord2f (0,1); + glVertex2f (x,y-FONT_HEIGHT-q->height); + glEnd (); + + // draw the selection border + if (!strcmpi(g_qeglobals.d_texturewin.texdef.name, q->name)) + { + glLineWidth (3); + glColor3f (1,0,0); + glDisable (GL_TEXTURE_2D); + + glBegin (GL_LINE_LOOP); + glVertex2f (x-4,y-FONT_HEIGHT+4); + glVertex2f (x-4,y-FONT_HEIGHT-q->height-4); + glVertex2f (x+4+q->width,y-FONT_HEIGHT-q->height-4); + glVertex2f (x+4+q->width,y-FONT_HEIGHT+4); + glEnd (); + + glEnable (GL_TEXTURE_2D); + glLineWidth (1); + } + + // draw the texture name + glColor3f (0,0,0); + glRasterPos2f (x, y-FONT_HEIGHT+2); + + // don't draw the directory name + for (name = q->name ; *name && *name != '/' && *name != '\\' ; name++) + ; + if (!*name) + name = q->name; + else + name++; + glCallLists (strlen(name), GL_UNSIGNED_BYTE, name); + } + } + + // reset the current texture + glBindTexture( GL_TEXTURE_2D, 0 ); + glFinish(); +} + +/* +============ +WTexWndProc +============ +*/ +LONG WINAPI WTex_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + int xPos, yPos; + RECT rect; + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + case WM_CREATE: + s_hdcTexture = GetDC(hWnd); + QEW_SetupPixelFormat(s_hdcTexture, false); + + if ( ( s_hglrcTexture = wglCreateContext( s_hdcTexture ) ) == 0 ) + Error( "wglCreateContext in WTex_WndProc failed" ); + + if (!wglMakeCurrent( s_hdcTexture, s_hglrcTexture )) + Error ("wglMakeCurrent in WTex_WndProc failed"); + + if (!wglShareLists( g_qeglobals.d_hglrcBase, s_hglrcTexture ) ) + Error( "wglShareLists in WTex_WndProc failed" ); + + return 0; + + case WM_DESTROY: + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( s_hglrcTexture ); + ReleaseDC( hWnd, s_hdcTexture ); + return 0; + + case WM_PAINT: + { +// PAINTSTRUCT ps; + +// BeginPaint(hWnd, &ps); + + if ( !wglMakeCurrent( s_hdcTexture, s_hglrcTexture ) ) + Error ("wglMakeCurrent failed"); + Texture_Draw2 (rect.right-rect.left, rect.bottom-rect.top); + SwapBuffers(s_hdcTexture); + +// EndPaint(hWnd, &ps); + ValidateRect(hWnd, NULL); + } + return 0; + + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONDOWN: + SetCapture( g_qeglobals.d_hwndTexture ); + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + + Texture_MouseDown (xPos, yPos, wParam); + return 0; + + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + + Texture_MouseUp (xPos, yPos, wParam); + if (! (wParam & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON))) + ReleaseCapture (); + return 0; + + case WM_MOUSEMOVE: + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + + Texture_MouseMoved (xPos, yPos, wParam); + return 0; + + case WM_SIZE: + //i'm not worried about messing this up, since i'll get a paint message soon anyhow + g_qeglobals.d_texturewin.width = rect.right-rect.left; + g_qeglobals.d_texturewin.height = rect.bottom-rect.top; + Texture_SetScrollRange();//this is inefficient way of updating scrollbar? + return 0; + + case WM_VSCROLL: + switch(LOWORD(wParam)) + { + case SB_LINEUP: + Texture_ScrollRow(1); + break; + case SB_LINEDOWN: + Texture_ScrollRow(-1); + break; + case SB_PAGEUP: + Texture_ScrollPage(1); + break; + case SB_PAGEDOWN: + Texture_ScrollPage(-1); + break; + case SB_THUMBTRACK: + Texture_ScrollTo (-HIWORD(wParam)); + break; + case SB_THUMBPOSITION: + Texture_ScrollTo (-HIWORD(wParam)); + break; + default: + break; + } + + return 0; + + case WM_LBUTTONDBLCLK: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_TEXTURES_INSPECTOR, 0); + return 0; + case WM_MOUSEWHEEL: +// Sys_Printf ("got a wheel!\n"); +/* gcWheelDelta -= (short) HIWORD(wParam); + if (abs(gcWheelDelta) >= + WHEEL_DELTA && gucWheelScrollLines > 0) + { + texturewin.originy += gucWheelScrollLines*(gcWheelDelta / WHEEL_DELTA); + if (texturewin.originy > 0) + texturewin.originy = 0; + Sys_UpdateWindows (W_TEXTURE); + } + break; + */ + Texture_ScrollRow(HIWORD(wParam) / WHEEL_DELTA); + return 0; + + default: + if (uMsg == g_qeglobals.uMSH_MOUSEWHEEL) + { + Texture_ScrollRow(*(int *)&wParam / WHEEL_DELTA); + return 0; + } + break; + + + } + + return DefWindowProc (hWnd, uMsg, wParam, lParam); +} + + + +/* +================== +CreateTextureWindow + +We need to create a seperate window for the textures +in the inspector window, because we can't share +gl and gdi drawing in a single window +================== +*/ +#define TEXTURE_WINDOW_CLASS "QTEX" + +extern BOOL CALLBACK TexModifyProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ); + +HWND CreateTextureWindow (void) +{ + WNDCLASS wc; + HWND hwnd; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = CS_OWNDC|CS_DBLCLKS; + wc.lpfnWndProc = (WNDPROC)WTex_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = g_qeglobals.d_hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = 0; + wc.lpszClassName = TEXTURE_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Error ("WCam_Register: failed"); + + hwnd = CreateWindow (TEXTURE_WINDOW_CLASS , + "Texture View", + WS_BORDER|WS_CHILD|WS_VISIBLE|WS_VSCROLL, + 20, + 20, + 64, + 64, // size + + g_qeglobals.d_hwndEntity, // parent window + 0, // no menu + g_qeglobals.d_hInstance, + 0); + if (!hwnd) + Error ("Couldn't create texturewindow"); + + g_qeglobals.d_hwndTexModDlg = CreateDialog(g_qeglobals.d_hInstance, MAKEINTRESOURCE(IDD_TEXMODIFY), + g_qeglobals.d_hwndEntity, (DLGPROC)TexModifyProc); + return hwnd; +} + +/* +================== +Texture_Flush +================== +*/ +void Texture_Flush (void) +{ +} + + +/* +================== +Texture_Init +================== +*/ +void Texture_Init (void) +{ +// char name[1024]; +// byte *pal; + + // load the palette +// sprintf (name, "%s/pics/colormap.pcx", +// ValueForKey (g_qeglobals.d_project_entity, "basepath")); +// Load256Image (name, NULL, &pal, NULL, NULL); +// if (!pal) +// Error ("Couldn't load %s", name); +// Texture_InitPalette (pal); +// free (pal); + + // create the fallback texture + Texture_MakeNotexture (); + + g_qeglobals.d_qtextures = NULL; +} + + +/* +================== +Texture_DefaultMaterial +================== +*/ + +void Texture_DefaultMaterial(void) +{ + qtexture_t *curTex; + brush_t *b, *startBrush; + face_t *f, *startFace; + + b = world_entity->brushes.onext; + startBrush = b; + + while (b != NULL) + { + f = b->brush_faces; + startFace = f; + + while (f != NULL) + { + curTex = g_qeglobals.d_qtextures; + while(curTex) + { + if (!strcmpi(curTex->name, f->texdef.name)) + { + f->texdef.flags = ((f->texdef.flags & 0x00FFFFFF) | (curTex->flags & 0x0FF000000)); + break; + } + + curTex = curTex->next; + } + + f = f->next; + if (f == startFace) + { + f = NULL; + } + } + + b = b->onext; + if (b == startBrush) + { + b = NULL; + } + } +} \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qe4/textures.h b/Toolkit/Programming/Tools/qe4/textures.h new file mode 100644 index 0000000..0661dd1 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/textures.h @@ -0,0 +1,68 @@ + + +typedef struct +{ + char name[32]; + float shift[2]; + float rotate; + float scale[2]; + int contents; + int flags; + int value; + float lighting[4]; +} texdef_t; + + +typedef struct +{ + int width, height; + int originy; + int scrollheight; + texdef_t texdef; + texdef_t prevTexDef; +} texturewin_t; + +typedef struct qtexture_s +{ + struct qtexture_s *next; + char name[64]; // includes partial directory and extension + int width, height; + int contents; + int flags; + int value; + int texture_number; // gl bind number + vec3_t color; // for flat shade mode + qboolean inuse; // true = is present on the level + float scale_x, scale_y; +} qtexture_t; + +typedef struct texlist_s +{ + char name[64]; + int uses; + struct texlist_s* prev; + struct texlist_s* next; +} texlist_t; + + + +// a texturename of the form (0 0 0) will +// create a solid color texture + +void Texture_SetScrollRange (void); +void Texture_Init (void); +void Texture_Flush (void); +void Texture_ClearInuse (void); +void Texture_ShowInuse (void); +void Texture_ListInUse(void); +void Texture_ShowDirectory (int menunum); +void Texture_DefaultMaterial(void); + +qtexture_t *Texture_ForName (char *name); + +void Texture_Init (void); +void Texture_SetTexture (texdef_t *texdef); + +void Texture_SetMode(int iMenu); // GL_TEXTURE_NEAREST, etc.. + +void Texture_Replace(char *from, char *to, int replaceAll); \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qe4/toolbar1.bmp b/Toolkit/Programming/Tools/qe4/toolbar1.bmp new file mode 100644 index 0000000..9a3c5b5 Binary files /dev/null and b/Toolkit/Programming/Tools/qe4/toolbar1.bmp differ diff --git a/Toolkit/Programming/Tools/qe4/tower.c b/Toolkit/Programming/Tools/qe4/tower.c new file mode 100644 index 0000000..b2fe54b --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/tower.c @@ -0,0 +1,321 @@ +/* + The tower command will take two brushes at different Z's and + create a brush between the two. For this to work, the low Z plane + of the upper brush and the high Z plane of the lower brush need to + have the same number of sides +*/ + +#include "tower.h" + +void DoTower(void) +{ + brush_t* brush1 = NULL; + brush_t* brush2 = NULL; + brush_t* newBrush = NULL; + brush_t* tempBrush = NULL; + face_t* topFace = NULL; + face_t* bottomFace = NULL; + face_t* curFace; + face_t* faceList; + int zFlag = 0; + int i = 0; // loop counter + + if (!QE_DoubleBrush) + { + Sys_Status ("You need to select exactly 2 brushes!", 0); + Sys_Beep (); + return; + } + brush1 = selected_brushes.next; + brush2 = selected_brushes.next->next; +// establish brush1 as the upper brush + if (brush2->maxs[2] > brush1->mins[2]) + { + tempBrush = brush1; + brush1 = brush2; + brush2 = tempBrush; + } +// test to insure brushes do not "overlap" in the Z direction + if (brush2->maxs[2] > brush1->mins[2]) + { + Sys_Status ("Brushes are not separated in the Z direction!", 0); + Sys_Beep(); + return; + } +// find the bottom Z plane (topFace) in 1 and top Z plane in 2 (bottomFace) + topFace = brush1->brush_faces; + while (topFace != NULL) + { + zFlag = 0; + for (i = 0; i<3; i++) + { + if (abs(topFace->planepts[i][2] - brush1->mins[2]) < TOWER_EPSILON) + { + zFlag++; + } + } + if (zFlag == 3) + { + break; + } + else + { + topFace = topFace->next; + } + } + if (topFace == NULL) + { + Sys_Status ("Couldn't find flat bottom-face in top brush", 0); + Sys_Beep(); + return; + } + bottomFace = brush2->brush_faces; + while (bottomFace != NULL) + { + zFlag = 0; + for (i = 0; i<3; i++) + { + if (abs(bottomFace->planepts[i][2] - brush2->maxs[2]) < TOWER_EPSILON) + { + zFlag++; + } + } + if (zFlag == 3) + { + break; + } + else + { + bottomFace = bottomFace->next; + } + } + if (bottomFace == NULL) + { + Sys_Status ("Couldn't find flat top-face in bottom brush", 0); + Sys_Beep(); + return; + } +// count vertices on top and bottom planes to make sure they are equal + if (topFace->face_winding->numpoints != bottomFace->face_winding->numpoints) + { + + Sys_Status ("Top and Bottom faces don't have same #'s of vertices!", 0); + Sys_Beep(); + return; + } +// put top and bottom faces on brush +// reverse winding for top and bottom + faceList = Face_Alloc(); + for ( i = 0; i<3; i++) + { + VectorCopy(topFace->planepts[2-i],faceList->planepts[i]); + } + curFace = Face_Alloc(); + for ( i = 0; i < 3; i++) + { + VectorCopy(bottomFace->planepts[2-i],curFace->planepts[i]); + } + curFace->next = faceList; + faceList = curFace; + + curFace = MakePlaneList(topFace, bottomFace); + if (curFace == NULL) + { + Sys_Status ("Couldn't make planes for tower!", 0); + Sys_Beep(); + return; + } + else + { + faceList->next->next = curFace; + } + + newBrush = qmalloc(sizeof(brush_t)); + newBrush->brush_faces = faceList; + Select_Deselect(); + Brush_AddToList (newBrush, &selected_brushes); + + Entity_LinkBrush (world_entity, newBrush); + + Brush_Build(newBrush); + UNDO_FinishBrushAdd("&Undo Tower"); + Sys_UpdateWindows(W_ALL); + return; + +} + +face_t* MakePlaneList(face_t* top, face_t* bottom) +{ + face_t* fList; + face_t* curFace; + face_t* newTop; + face_t* newBot; + int i; + int j; + int k; + vec3_t t1, t2, t3; + + fList = NULL; + newTop = Face_Alloc(); + CopyFace(top, newTop); + newBot = Face_Alloc(); + CopyFace(bottom, newBot); + WrapFaces(newTop, newBot); + for (i = 0; iface_winding->numpoints; i++) + { + if (i == (newTop->face_winding->numpoints - 1)) + { + j = 0; + } + else + { + j = i + 1; + } + + curFace = Face_Alloc(); + VectorCopy(newTop->face_winding->points[j],curFace->planepts[0]); + VectorCopy(newTop->face_winding->points[i],curFace->planepts[1]); + VectorCopy(newBot->face_winding->points[i],curFace->planepts[2]); + + for (k=0 ; k<3 ; k++) + { + t1[k] = curFace->planepts[0][k] - curFace->planepts[1][k]; + t2[k] = curFace->planepts[2][k] - curFace->planepts[1][k]; + t3[k] = curFace->planepts[1][k]; + } + + CrossProduct(t1,t2, curFace->plane.normal); + if (VectorCompare (curFace->plane.normal, vec3_origin)) + { + printf ("WARNING: brush plane with no normal\n"); + + } + VectorNormalize (curFace->plane.normal, curFace->plane.normal); + curFace->plane.dist = DotProduct (t3, curFace->plane.normal); + + curFace->next = fList; + fList = curFace; + } // for loop + return fList; +} + + +void WrapFaces( face_t* top, face_t* bottom) +{ + face_t* tempFace; + int i; + float maxX; + float maxY; + int pointFlag; + + tempFace = Face_Alloc(); + //wrap the top face points the other way + CopyFace(top, tempFace); + for ( i = 0; iface_winding->numpoints; i++) + { + VectorCopy(top->face_winding->points[top->face_winding->numpoints-1-i],tempFace->face_winding->points[i]); + } + CopyFace(tempFace,top); + // top and bottom are now wrapped with normals pointing upward + // now grab the point in top with most positive x (and y if there are more than one) + maxX = top->face_winding->points[0][0]; + maxY = top->face_winding->points[0][1]; + pointFlag = 0; + + for ( i = 1; iface_winding->numpoints; i++) + { + if ( maxX > top->face_winding->points[i][0] ) + { + continue; + } + else + { + if ( maxX == top->face_winding->points[i][0] ) + { + if (top->face_winding->points[i][1] > maxY) + { + maxY = top->face_winding->points[i][1]; + pointFlag = i; + } + } + else + { + maxX = top->face_winding->points[i][0]; + maxY = top->face_winding->points[i][1]; + pointFlag = i; + } + } + } +// now, starting at the point[pointflag] in top, write the sequence starting at [0] in tempFace + for ( i = 0; iface_winding->numpoints; i++) + { + if (pointFlag == top->face_winding->numpoints) + { + pointFlag = 0; + } + VectorCopy(top->face_winding->points[pointFlag], tempFace->face_winding->points[i]); + pointFlag++; + } + CopyFace(tempFace,top); +//repeat with bottom + CopyFace(bottom, tempFace); + maxX = bottom->face_winding->points[0][0]; + maxY = bottom->face_winding->points[0][1]; + pointFlag = 0; + + for ( i = 1; iface_winding->numpoints; i++) + { + if ( maxX > bottom->face_winding->points[i][0] ) + { + continue; + } + else + { + if ( maxX == bottom->face_winding->points[i][0] ) + { + if (bottom->face_winding->points[i][1] > maxY) + { + maxY = bottom->face_winding->points[i][1]; + pointFlag = i; + } + } + else + { + maxX = bottom->face_winding->points[i][0]; + maxY = bottom->face_winding->points[i][1]; + pointFlag = i; + } + } + } +// now, starting at the point[pointflag] in bottom, write the sequence starting at [0] in tempFace + for ( i = 0; iface_winding->numpoints; i++) + { + if (pointFlag == bottom->face_winding->numpoints) + { + pointFlag = 0; + } + VectorCopy(bottom->face_winding->points[pointFlag], tempFace->face_winding->points[i]); + pointFlag++; + } + CopyFace(tempFace,bottom); + Face_Free(tempFace); + return; +} + +void CopyFace( face_t* in, face_t* out) +{ + int i; + + out->face_winding = NewWinding(in->face_winding->numpoints); + out->face_winding->numpoints = in->face_winding->numpoints; + for (i = 0; iface_winding->numpoints; i++) + { + VectorCopy(in->face_winding->points[i],out->face_winding->points[i]); + } + for (i = 0; i<3; i++) + { + VectorCopy(in->planepts[i],out->planepts[i]); + } +} + + diff --git a/Toolkit/Programming/Tools/qe4/tower.h b/Toolkit/Programming/Tools/qe4/tower.h new file mode 100644 index 0000000..6f90309 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/tower.h @@ -0,0 +1,13 @@ +// tower.h +// routines for tower.c + +#include "qe3.h" +#include "undo.h" + +#define TOWER_EPSILON 0.001f + + + void DoTower(void); + face_t* MakePlaneList(face_t* top, face_t* bottom); + void WrapFaces( face_t* top, face_t* bottom); + void CopyFace( face_t* in, face_t* out); diff --git a/Toolkit/Programming/Tools/qe4/undo.c b/Toolkit/Programming/Tools/qe4/undo.c new file mode 100644 index 0000000..1f9c1a4 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/undo.c @@ -0,0 +1,468 @@ +// undo.c +// storage for undo operations +// +#include "qe3.h" +#include "undo.h" + +extern HWND s_hwndToolbar; + +// NOTICE THAT THIS CODE IS VERY MUCH UNDER DEVELOPMENT! + + +undo_t undobuffer; + +brush_t dragbrush; //old data for dragging needs seperate location +brush_t subdata; //storage space for subtract +pbrush_t sublist; //this will be a zero terminated list + + +char NO_UNDO_STRING[] = "Can't Undo"; + +// GENERIC FUNCTIONS + +void UNDO_EnableButton () +{ + SendMessage(s_hwndToolbar, TB_ENABLEBUTTON, (WPARAM)ID_EDIT_UNDO, + (LPARAM) (MAKELONG(TRUE, 0))); +} + +void UNDO_DisableButton () +{ + SendMessage(s_hwndToolbar, TB_ENABLEBUTTON, (WPARAM)ID_EDIT_UNDO, + (LPARAM) (MAKELONG(FALSE, 0))); +} + +void UNDO_Init () +{ + undobuffer.brushdata.next = undobuffer.brushdata.prev = &undobuffer.brushdata; + undobuffer.brushlist.next = 0; + dragbrush.next = dragbrush.prev = &dragbrush; + subdata.next = subdata.prev = &subdata; + sublist.next = NULL; + undobuffer.title = NO_UNDO_STRING; +} + +void UNDO_AddPointer (pbrush_t *list, brush_t *brush) +{ + pbrush_t *pb = qmalloc(sizeof(pbrush_t)); + + pb->next = list->next; + list->next = pb; + pb->b = brush; +} + + +void UNDO_Reset () +{ + brush_t *brush; + pbrush_t *pb; + undobuffer.type = UNDO_NONE; + undobuffer.title = NO_UNDO_STRING; + + while (undobuffer.brushdata.next != &undobuffer.brushdata) + { + brush = undobuffer.brushdata.next; + Brush_Free (brush); + } + while(undobuffer.brushlist.next) + { + pb = undobuffer.brushlist.next->next; + free(undobuffer.brushlist.next); + undobuffer.brushlist.next = pb; + } + UNDO_DisableButton(); +// undobuffer.brushdata.next = undobuffer.brushdata.prev = &undobuffer.brushdata; +} + +void UNDO_DoUndo (HWND hWnd) +{ + switch(undobuffer.type) + { + case UNDO_NONE: + MessageBox (hWnd, "Nothing to undo, why do you bother me?", "NO", MB_OK); + break; + case UNDO_NEWBRUSH: + UNDO_BrushRemove (&undobuffer); + Sys_UpdateWindows (W_ALL); + break; + case UNDO_EDITBRUSH: + case UNDO_SUBTRACT: + UNDO_BrushRemove (&undobuffer); + UNDO_BrushClone (&undobuffer); + Sys_UpdateWindows (W_ALL); + break; + case UNDO_DELETEBRUSH: + UNDO_BrushClone (&undobuffer); + Sys_UpdateWindows (W_ALL); + break; + default: + break; + //not done yet, go away + } + undobuffer.type = UNDO_NONE; //don't allow multiple undos + undobuffer.title = NO_UNDO_STRING; + UNDO_DisableButton (); +} + +// BRUSH FUNCTIONS + +void Face_Free( face_t *f ); + +// BRUSH START/FINISH FUNCTIONS + + +// BrushDrag is basically an abortable version of BrushEdit +// if Finish isn't called, it has no effect on the undo buffer + +void UNDO_StartBrushDrag() +{ + brush_t *from, *data; + + while (dragbrush.next != &dragbrush) + { + from = dragbrush.next; + Brush_Free (from); + } + + from = &selected_brushes; + while (from->next != &selected_brushes) + { + from = from->next; + data = Brush_Clone(from); + Brush_AddToList(data, &dragbrush); //store data + } + +} + +void UNDO_FinishBrushDrag(char *title) +{ + brush_t *from; + + UNDO_Reset (); + undobuffer.type = UNDO_EDITBRUSH; + UNDO_EnableButton (); + if(title) + { + undobuffer.title = title; + } + else + { + undobuffer.title = "&Undo Drag"; + } + + if(dragbrush.next != &dragbrush) + { + undobuffer.brushdata.next = dragbrush.next; + undobuffer.brushdata.prev = dragbrush.prev; + dragbrush.prev->next = &undobuffer.brushdata; + dragbrush.next->prev = &undobuffer.brushdata; + dragbrush.prev = dragbrush.next = &dragbrush; + } + + from = &selected_brushes; + while (from->next != &selected_brushes) + { + from = from->next; + UNDO_AddPointer(&undobuffer.brushlist, from); //need to store pointer to original + } + +} + + + +void UNDO_FinishBrushAdd(char * title) +{ + brush_t *from; + + UNDO_Reset (); + UNDO_EnableButton (); + undobuffer.type = UNDO_NEWBRUSH; + if(title) + { + undobuffer.title = title; + } + else + { + undobuffer.title = "&Undo Add"; + } + + from = &selected_brushes; + while (from->next != &selected_brushes) + { + from = from->next; + UNDO_AddPointer(&undobuffer.brushlist, from); //need to store pointer to original + } +} + + +// the BrushEdit functions assume the selected brushes remain the same +// these are identical to the New and Delete as well, perhaps +void UNDO_StartBrushEdit(char *title) +{ + brush_t *from, *data; + + UNDO_Reset (); + undobuffer.type = UNDO_BUSY; + if(title) + { + undobuffer.title = title; + } + else + { + undobuffer.title = "&Undo Edit"; + } + + from = &selected_brushes; + while (from->next != &selected_brushes) + { + from = from->next; + data = Brush_Clone(from); + Brush_AddToList(data, &undobuffer.brushdata); //store data + } +} + +void UNDO_FinishBrushEdit(char *title) +{ + brush_t *from; + + UNDO_EnableButton (); + undobuffer.type = UNDO_EDITBRUSH; + if(title) + { // this is optional, since we may not know what the drag does at start + undobuffer.title = title; + } + + from = &selected_brushes; + while (from->next != &selected_brushes) + { + from = from->next; + UNDO_AddPointer(&undobuffer.brushlist, from); //need to store pointer to original + } +} + +void UNDO_StartBrushDelete(char *title) +{ + brush_t *from, *data; + + if(selected_brushes.next == &selected_brushes) + { + return; + } + UNDO_Reset (); + undobuffer.type = UNDO_DELETEBRUSH; + if(title) + { + undobuffer.title = title; + } + else + { + undobuffer.title = "&Undo Delete"; + } + + from = &selected_brushes; + while (from->next != &selected_brushes) + { + from = from->next; + data = Brush_Clone(from); + Brush_AddToList(data, &undobuffer.brushdata); + + } + UNDO_EnableButton(); +} + + +// needed if selection options remove current brush +void UNDO_ClearSelection (brush_t *brush) +{ + + pbrush_t *next; + qboolean found; + + + found = FALSE; + if(!undobuffer.brushlist.next) + { + return; + } + for(next = undobuffer.brushlist.next; + !next->next; + next = next->next) + { + if(next->b == brush) + { + found = TRUE; + break; + } + } + if(found) + { + UNDO_Reset(); + } +} + + + +void UNDO_StartSubtraction() +{ // just clears out brush list + brush_t *from; + pbrush_t *pb; + + while (subdata.next != &subdata) + { + from = subdata.next; + Brush_Free (from); + } + subdata.next = subdata.prev = &subdata; + while(sublist.next) + { + pb = sublist.next->next; + free(sublist.next); + sublist.next = pb; + } + +} + +void UNDO_AddToSubtractData(brush_t *brush) +{ + brush_t *data; + pbrush_t *pb, *last; + //if brush is in add list, then remove it and quit + pb = &sublist; + while(pb->next) + { + if(pb->next->b == brush) + { + last = pb->next; + pb->next = last->next; + free (last); + return; + } + pb = pb->next; + } + + data = Brush_Clone(brush); + Brush_AddToList(data, &subdata); //store data + +} + +void UNDO_AddToSubtractList(brush_t *brush) +{ + UNDO_AddPointer(&sublist, brush); + //add newly created brushes to list +} + +void UNDO_FinishSubtraction (char *title) +{ + UNDO_Reset (); + + UNDO_EnableButton (); + undobuffer.type = UNDO_SUBTRACT; + if(title) + { + undobuffer.title = title; + } + else + { + undobuffer.title = "&Undo Subtract"; + } + + //copy data from temp buffers + if(subdata.next != &subdata) + { + undobuffer.brushdata.next = subdata.next; + undobuffer.brushdata.prev = subdata.prev; + subdata.prev->next = &undobuffer.brushdata; + subdata.next->prev = &undobuffer.brushdata; + subdata.prev = subdata.next = &subdata; + } + if(sublist.next) + { + undobuffer.brushlist.next = sublist.next; + sublist.next = NULL; + } +} + + + + +// UNDO VERSIONS OF SELECT.C +/* +============ + based on Select_Clone, copies brushdata into selected +============ +*/ +void UNDO_BrushClone (undo_t *buffer) +{ + brush_t *b, *b2, *n, *next, *next2; + entity_t *e; + + g_qeglobals.d_workcount++; + g_qeglobals.d_select_mode = sel_brush; + + for (b=buffer->brushdata.next ; b != &buffer->brushdata ; b=next) + { + next = b->next; + // if the brush is a world brush, handle simply + if (b->owner == world_entity) + { + n = Brush_Clone (b); + Brush_AddToList (n, &active_brushes); + Entity_LinkBrush (world_entity, n); + Brush_Build( n ); + Select_Brush(n); + continue; + } + + e = Entity_Clone (b->owner); + + // if the brush is a fixed size entity, create a new entity + if (b->owner->eclass->fixedsize) + { + n = Brush_Clone (b); + Brush_AddToList (n, &active_brushes); + + Entity_LinkBrush (e, n); + Brush_Build( n ); + Select_Brush(n); + continue; + } + + // brush is a complex entity, grab all the other ones now + + next = &buffer->brushdata; + + for ( b2 = b ; b2 != &buffer->brushdata ; b2=next2) + { + next2 = b2->next; + if (b2->owner != b->owner) + { + if (next == &buffer->brushdata) + next = b2; + continue; + } + + n = Brush_Clone (b2); + Brush_AddToList (n, &active_brushes); + Entity_LinkBrush (e, n); + Brush_Build( n ); + Select_Brush(n); + } + + } +} + +void UNDO_BrushRemove (undo_t *buffer) +{ + pbrush_t *next; + // this does NOT update the count globals, does it need to? + while(buffer->brushlist.next) + { + next = buffer->brushlist.next->next; + Brush_Free (buffer->brushlist.next->b); + free (buffer->brushlist.next); + buffer->brushlist.next = next; + } + buffer->brushlist.next = 0; + +} + diff --git a/Toolkit/Programming/Tools/qe4/undo.h b/Toolkit/Programming/Tools/qe4/undo.h new file mode 100644 index 0000000..7b17d70 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/undo.h @@ -0,0 +1,63 @@ +// undo.h +// common routines for undo operations + +#ifndef __UNDO__ +#define __UNDO__ + +typedef enum +{ + UNDO_NONE, + UNDO_BUSY, + UNDO_NEWBRUSH, + UNDO_EDITBRUSH, + UNDO_DELETEBRUSH, + UNDO_SUBTRACT //needs to record lists differently +} undotypes; + +typedef struct pbrush_s +{ + brush_t *b; + struct pbrush_s *next; +} pbrush_t; + + + +typedef struct undo_s +{ + undotypes type; + char *title; + brush_t brushdata; //stores COPIES of the brush data + pbrush_t brushlist; //stores pointers to a brush + +} undo_t; + +void UNDO_Init (void); +void UNDO_DoUndo (HWND hWnd); +void UNDO_Reset (void); + +void UNDO_FinishBrushAdd(char *title); //needs no start + +void UNDO_StartBrushEdit(char *title); +void UNDO_FinishBrushEdit(char *title); + +void UNDO_StartBrushDrag(void); //similar to edit, but uses temp buffer +void UNDO_FinishBrushDrag(char *title); //similar to edit, but uses temp buffer + +void UNDO_StartBrushDelete(char *title); //needs no finish + +//test for and remove brush if in brushlist +void UNDO_ClearSelection(brush_t *brush); + +//not sure about the selection choices yet... +void UNDO_StartSubtraction(void); +void UNDO_AddToSubtractData(brush_t *brush); +void UNDO_AddToSubtractList(brush_t *brush); +void UNDO_FinishSubtraction(char *title); + +//these routines do the actual undoing +void UNDO_BrushClone (undo_t *buffer); //copies brushdata into world +void UNDO_BrushRemove (undo_t *buffer); //removes any brushes in brushlist + +extern undo_t undobuffer; + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/Tools/qe4/vertsel.c b/Toolkit/Programming/Tools/qe4/vertsel.c new file mode 100644 index 0000000..e14c642 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/vertsel.c @@ -0,0 +1,224 @@ + +#include "qe3.h" + +int FindPoint (vec3_t point) +{ + int i, j; + + for (i=0 ; i 0.1) + break; + if (j == 3) + return i; + } + + VectorCopy (point, g_qeglobals.d_points[g_qeglobals.d_numpoints]); + g_qeglobals.d_numpoints++; + + return g_qeglobals.d_numpoints-1; +} + +int FindEdge (int p1, int p2, face_t *f) +{ + int i; + + for (i=0 ; inumpoints ; i++) + pnum[i] = FindPoint (w->points[i]); + for (i=0 ; inumpoints ; i++) + FindEdge (pnum[i], pnum[(i+1)%w->numpoints], f); + + free (w); +} + +void SetupVertexSelection (void) +{ + face_t *f; + brush_t *b; + + g_qeglobals.d_numpoints = 0; + g_qeglobals.d_numedges = 0; + if (!QE_SingleBrush()) + return; + b = selected_brushes.next; + for (f=b->brush_faces ; f ; f=f->next) + MakeFace (f); + + Sys_UpdateWindows (W_ALL); +} + + +void SelectFaceEdge (face_t *f, int p1, int p2) +{ + winding_t *w; + int i, j, k; + int pnum[128]; + + w = MakeFaceWinding (selected_brushes.next, f); + if (!w) + return; + for (i=0 ; inumpoints ; i++) + pnum[i] = FindPoint (w->points[i]); + for (i=0 ; inumpoints ; i++) + if (pnum[i] == p1 && pnum[(i+1)%w->numpoints] == p2) + { + VectorCopy (g_qeglobals.d_points[pnum[i]], f->planepts[0]); + VectorCopy (g_qeglobals.d_points[pnum[(i+1)%w->numpoints]], f->planepts[1]); + VectorCopy (g_qeglobals.d_points[pnum[(i+2)%w->numpoints]], f->planepts[2]); + for (j=0 ; j<3 ; j++) + { + for (k=0 ; k<3 ; k++) + { + f->planepts[j][k] = floor(f->planepts[j][k]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + } + + AddPlanept (f->planepts[0]); + AddPlanept (f->planepts[1]); + break; + } + + if (i == w->numpoints) + Sys_Printf ("SelectFaceEdge: failed\n"); + free (w); +} + +void SelectVertex (int p1) +{ + brush_t *b; + winding_t *w; + int i, j, k; + face_t *f; + + b = selected_brushes.next; + for (f=b->brush_faces ; f ; f=f->next) + { + w = MakeFaceWinding (b, f); + if (!w) + continue; + for (i=0 ; inumpoints ; i++) + { + if (FindPoint (w->points[i]) == p1) + { + VectorCopy (w->points[(i+w->numpoints-1)%w->numpoints], f->planepts[0]); + VectorCopy (w->points[i], f->planepts[1]); + VectorCopy (w->points[(i+1)%w->numpoints], f->planepts[2]); + for (j=0 ; j<3 ; j++) + { + for (k=0 ; k<3 ; k++) + { + f->planepts[j][k] = floor(f->planepts[j][k]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + } + + AddPlanept (f->planepts[1]); + break; + } + } + free (w); + } +} + +void SelectEdgeByRay (vec3_t org, vec3_t dir) +{ + int i, j, besti; + float d, bestd; + vec3_t mid, temp; + pedge_t *e; + + // find the edge closest to the ray + besti = -1; + bestd = 8; + + for (i=0 ; if1, e->p1, e->p2); + SelectFaceEdge (e->f2, e->p2, e->p1); +} + +void SelectVertexByRay (vec3_t org, vec3_t dir) +{ + int i, besti; + float d, bestd; + vec3_t temp; + + // find the point closest to the ray + besti = -1; + bestd = 8; + + for (i=0 ; i %s", temppath, outputpath); + fclose (hFile); + + Pointfile_Delete (); + + if (hwndBsp) + DestroyWindow(hwndBsp); + + bsp_StartTask(batpath); +// i removed these next two lines and changed the bsp_printf to send bsp output to console +// hwndBsp=CreateDialog(g_qeglobals.d_hInstance, (char *)IDD_BSP, g_qeglobals.d_hwndMain, BspDlgProc); +// SetCancelButton("Abort"); + +// Sleep (100); // give the new process a chance to open its window + +// BringWindowToTop( hwndBsp ); // pop us back on top +// SetFocus (hwndBsp); +} + diff --git a/Toolkit/Programming/Tools/qe4/win_bsp.h b/Toolkit/Programming/Tools/qe4/win_bsp.h new file mode 100644 index 0000000..1e998fa --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/win_bsp.h @@ -0,0 +1,2 @@ +void bsp_CheckTask(void); +void bsp_StartBsp (char *command); diff --git a/Toolkit/Programming/Tools/qe4/win_cam.c b/Toolkit/Programming/Tools/qe4/win_cam.c new file mode 100644 index 0000000..c8279ab --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/win_cam.c @@ -0,0 +1,265 @@ +// win_cam.c -- windows specific camera view code + +#include "qe3.h" + +/* +============ +CameraWndProc +============ +*/ +LONG WINAPI WCam_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + int fwKeys, xPos, yPos; + RECT rect; + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + case WM_CREATE: + { + HFONT hfont; + + g_qeglobals.d_hdcBase = GetDC(hWnd); + QEW_SetupPixelFormat(g_qeglobals.d_hdcBase, true); + + if ( ( g_qeglobals.d_hglrcBase = wglCreateContext( g_qeglobals.d_hdcBase ) ) == 0 ) + Error ("wglCreateContext failed"); + if (!wglMakeCurrent( g_qeglobals.d_hdcBase, g_qeglobals.d_hglrcBase )) + Error ("wglMakeCurrent failed"); + + Texture_SetMode(g_qeglobals.d_savedinfo.iTexMenu); + + // + // create GL font + // + hfont = CreateFont( + 10, // logical height of font + 7, // logical average character width + 0, // angle of escapement + 0, // base-line orientation angle + 0, // font weight + 0, // italic attribute flag + 0, // underline attribute flag + 0, // strikeout attribute flag + 0, // character set identifier + 0, // output precision + 0, // clipping precision + 0, // output quality + 0, // pitch and family + 0 // pointer to typeface name string + ); + + if ( !hfont ) + Error( "couldn't create font" ); + + SelectObject (g_qeglobals.d_hdcBase, hfont); + + if ( ( g_qeglobals.d_font_list = glGenLists (256) ) == 0 ) + Error( "couldn't create font dlists" ); + + // create the bitmap display lists + // we're making images of glyphs 0 thru 255 + if ( !wglUseFontBitmaps (g_qeglobals.d_hdcBase, 1, 255, g_qeglobals.d_font_list) ) + Error( "wglUseFontBitmaps faileD" ); + + // indicate start of glyph display lists + glListBase (g_qeglobals.d_font_list); + + // report OpenGL information + Sys_Printf ("GL_VENDOR: %s\n", glGetString (GL_VENDOR)); + Sys_Printf ("GL_RENDERER: %s\n", glGetString (GL_RENDERER)); + Sys_Printf ("GL_VERSION: %s\n", glGetString (GL_VERSION)); + Sys_Printf ("GL_EXTENSIONS: %s\n", glGetString (GL_EXTENSIONS)); + } + return 0; + case WM_PAINT: + { +// PAINTSTRUCT ps; + + if (!wglMakeCurrent( g_qeglobals.d_hdcBase, g_qeglobals.d_hglrcBase )) + Error ("wglMakeCurrent failed"); + +// if ( BeginPaint(hWnd, &ps) ) +// { + QE_CheckOpenGLForErrors(); + Cam_Draw (); + QE_CheckOpenGLForErrors(); + +// EndPaint(hWnd, &ps); + SwapBuffers(g_qeglobals.d_hdcBase); +// } + ValidateRect(hWnd, NULL); + } + return 0; + + case WM_USER+267: // benchmark + { + PAINTSTRUCT ps; + WINDOWPLACEMENT wp; + double start, end; + int i; + + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( wp ); + GetWindowPlacement( g_qeglobals.d_hwndCamera, &wp ); + + MoveWindow( g_qeglobals.d_hwndCamera, 30, 30, 400, 400, TRUE ); + + BeginPaint(hWnd, &ps); + if (!wglMakeCurrent( g_qeglobals.d_hdcBase, g_qeglobals.d_hglrcBase)) + Error ("wglMakeCurrent failed"); + glDrawBuffer (GL_FRONT); + + start = Sys_DoubleTime (); + for (i=0 ; i<100 ; i++) + { + camera.angles[YAW] = i*4; + Cam_Draw (); + } + SwapBuffers(g_qeglobals.d_hdcBase); + glDrawBuffer (GL_BACK); + end = Sys_DoubleTime (); + EndPaint(hWnd, &ps); + Sys_Printf ("%5.2f seconds\n", end-start); + + SetWindowPlacement( g_qeglobals.d_hwndCamera, &wp ); + } + break; + + case WM_KEYDOWN: + if ( QE_KeyDown (wParam) ) + return 0; + else + return DefWindowProc( hWnd, uMsg, wParam, lParam ); + + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONDOWN: + if (GetTopWindow(g_qeglobals.d_hwndMain) != hWnd) + BringWindowToTop(hWnd); + + SetFocus (g_qeglobals.d_hwndCamera); + SetCapture (g_qeglobals.d_hwndCamera); + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + Cam_MouseDown (xPos, yPos, fwKeys); + return 0; + + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + Cam_MouseUp (xPos, yPos, fwKeys); + if (! (fwKeys & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON))) + ReleaseCapture (); + return 0; + + case WM_MOUSEMOVE: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + Cam_MouseMoved (xPos, yPos, fwKeys); + return 0; + + case WM_SIZE: + camera.width = rect.right; + camera.height = rect.bottom; + InvalidateRect(g_qeglobals.d_hwndCamera, NULL, false); + return 0; + + case WM_KILLFOCUS: + case WM_SETFOCUS: + SendMessage( hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0 ); + return 0; + + case WM_NCCALCSIZE:// don't let windows copy pixels + DefWindowProc (hWnd, uMsg, wParam, lParam); + return WVR_REDRAW; + + case WM_CLOSE: + DestroyWindow (hWnd); + return 0; + + case WM_DESTROY: + QEW_StopGL( hWnd, g_qeglobals.d_hglrcBase, g_qeglobals.d_hdcBase ); + return 0; + + case WM_MOUSEWHEEL: + PostMessage (g_qeglobals.d_hwndTexture, WM_MOUSEWHEEL, wParam, lParam); + return 0; + + default: + if (uMsg == g_qeglobals.uMSH_MOUSEWHEEL) + { + PostMessage (g_qeglobals.d_hwndTexture, g_qeglobals.uMSH_MOUSEWHEEL, wParam, lParam); + return 0; + } + break; + + } + + return DefWindowProc( hWnd, uMsg, wParam, lParam ); +} + + +/* +============== +WCam_Create +============== +*/ +void WCam_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + char *title; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = CS_OWNDC; + wc.lpfnWndProc = (WNDPROC)WCam_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = 0; + wc.lpszClassName = CAMERA_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Error ("WCam_Register: failed"); + + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAIL ) + title = "Camera View (DETAIL EXCLUDED)"; + else + title = "Camera View"; + + g_qeglobals.d_hwndCamera = CreateWindow (CAMERA_WINDOW_CLASS , + title, + QE3_STYLE, + ZWIN_WIDTH, + 20, + (int)(screen_width*CWIN_SIZE), + (int)(screen_height*CWIN_SIZE), // size + + g_qeglobals.d_hwndMain, // parent window + 0, // no menu + hInstance, + 0); + if (!g_qeglobals.d_hwndCamera) + Error ("Couldn't create g_qeglobals.d_hwndCamera"); + + LoadWindowState(g_qeglobals.d_hwndCamera, "camerawindow"); + ShowWindow (g_qeglobals.d_hwndCamera, SW_SHOWDEFAULT); +} diff --git a/Toolkit/Programming/Tools/qe4/win_dlg.c b/Toolkit/Programming/Tools/qe4/win_dlg.c new file mode 100644 index 0000000..d2a1ddb --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/win_dlg.c @@ -0,0 +1,970 @@ + +#include "qe3.h" +#include "undo.h" + +BOOL CALLBACK GammaDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char sz[256]; + + switch (uMsg) + { + case WM_INITDIALOG: + sprintf(sz, "%1.1f", g_qeglobals.d_savedinfo.fGamma); + SetWindowText(GetDlgItem(hwndDlg, IDC_G_EDIT), sz); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + + case IDOK: + GetWindowText(GetDlgItem(hwndDlg, IDC_G_EDIT), sz, 255); + g_qeglobals.d_savedinfo.fGamma = atof(sz); + EndDialog(hwndDlg, 1); + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + } + } + return FALSE; +} + + + +void DoGamma(void) +{ + char *psz, sz[256]; + if ( DialogBox(g_qeglobals.d_hInstance, (char *)IDD_GAMMA, g_qeglobals.d_hwndMain, GammaDlgProc)) + { + psz = ValueForKey(world_entity, "_wad"); + if (psz) + { + strcpy(sz, psz); + Texture_Flush(); + Texture_ShowInuse(); + } + } +} + +//================================================ + + +void SelectBrush (int entitynum, int brushnum) +{ + entity_t *e; + brush_t *b; + int i; + + if (entitynum == 0) + e = world_entity; + else + { + e = entities.next; + while (--entitynum) + { + e=e->next; + if (e == &entities) + { + Sys_Status ("No such entity.", 0); + return; + } + } + } + + b = e->brushes.onext; + if (b == &e->brushes) + { + Sys_Status ("No such brush.", 0); + return; + } + while (brushnum--) + { + b=b->onext; + if (b == &e->brushes) + { + Sys_Status ("No such brush.", 0); + return; + } + } + + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + + + Sys_UpdateWindows (W_ALL); + for (i=0 ; i<3 ; i++) + g_qeglobals.d_xy.origin[i] = (b->mins[i] + b->maxs[i])/2; + + Sys_Status ("Selected.", 0); +} + +/* +================= +GetSelectionIndex +================= +*/ +void GetSelectionIndex (int *ent, int *brush) +{ + brush_t *b, *b2; + entity_t *entity; + + *ent = *brush = 0; + + b = selected_brushes.next; + if (b == &selected_brushes) + return; + + // find entity + if (b->owner != world_entity) + { + (*ent)++; + for (entity = entities.next ; entity != &entities + ; entity=entity->next, (*ent)++) + ; + } + + // find brush + for (b2=b->owner->brushes.onext + ; b2 != b && b2 != &b->owner->brushes + ; b2=b2->onext, (*brush)++) + ; +} + +BOOL CALLBACK FindBrushDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char entstr[256]; + char brushstr[256]; + HWND h; + int ent, brush; + + switch (uMsg) + { + case WM_INITDIALOG: + // set entity and brush number + GetSelectionIndex (&ent, &brush); + sprintf (entstr, "%i", ent); + sprintf (brushstr, "%i", brush); + SetWindowText(GetDlgItem(hwndDlg, IDC_FIND_ENTITY), entstr); + SetWindowText(GetDlgItem(hwndDlg, IDC_FIND_BRUSH), brushstr); + + h = GetDlgItem(hwndDlg, IDC_FIND_ENTITY); + SetFocus (h); + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + GetWindowText(GetDlgItem(hwndDlg, IDC_FIND_ENTITY), entstr, 255); + GetWindowText(GetDlgItem(hwndDlg, IDC_FIND_BRUSH), brushstr, 255); + SelectBrush (atoi(entstr), atoi(brushstr)); + EndDialog(hwndDlg, 1); + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + } + } + return FALSE; +} + + + +void DoFind(void) +{ + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_FINDBRUSH, g_qeglobals.d_hwndMain, FindBrushDlgProc); +} + + +/* +=================================================== + + Set Max View Distance + +=================================================== +*/ + +BOOL CALLBACK SeMaxViewDistDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char toStr[256]; + char* curDist; + int decimal, sign; + float vDist; + HWND h; + + switch (uMsg) + { + case WM_INITDIALOG: + curDist = _fcvt(g_qeglobals.d_maxViewDist,0, &decimal, &sign); + SetWindowText(GetDlgItem(hwndDlg, IDC_MAXVIEWDIST), curDist); + h = GetDlgItem(hwndDlg, IDC_MAXVIEWDIST); + SetFocus (h);//put the cursor on the x text entry box + return FALSE; + + case WM_COMMAND: + GetWindowText(GetDlgItem(hwndDlg, IDC_MAXVIEWDIST), toStr, 255); + vDist = atof(toStr); + switch (LOWORD(wParam)) + { + case IDOK: + // set some global view range here. + if(vDist > 16) + { // less than this would be meaningless, I believe + g_qeglobals.d_maxViewDist = vDist; + g_qeglobals.d_savedinfo.maxViewDist = vDist; + } + Sys_UpdateWindows (W_CAMERA); + EndDialog(hwndDlg, 0); + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + } + } + return FALSE; +} + +void DoSetMaxViewDist(void) +{ + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_MAXVIEWDIST, g_qeglobals.d_hwndMain, SeMaxViewDistDlgProc); +} + + +void DoDefaultTextures(void) +{ + brush_t *b; + face_t *f; + + for (b=active_brushes.next ; b != &active_brushes ; b=b->next) + { + for(f=b->brush_faces; f ; f=f->next) + { + f->texdef.scale[0] = f->d_texture->scale_x; + f->texdef.scale[1] = f->d_texture->scale_y; + } + } + + if(camera.draw_mode == cd_texture) + { + camera.draw_mode = cd_solid; + Map_BuildBrushData(false); + Sys_UpdateWindows (W_ALL); + + if (camera.draw_mode != cd_texture) + { + camera.draw_mode = cd_texture; + Map_BuildBrushData(false); + } + + Sys_UpdateWindows (W_ALL); + } +} + +/* +=================================================== + + REPLACE TEXTURE + +=================================================== +*/ + +BOOL CALLBACK ReplaceTextureDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char fromStr[256]; + char toStr[256]; + + switch (uMsg) + { + case WM_INITDIALOG: + // init the two boxes to the last two selected textures + SetWindowText(GetDlgItem(hwndDlg, IDC_REP_EDIT2), g_qeglobals.d_texturewin.texdef.name); + SetWindowText(GetDlgItem(hwndDlg, IDC_REP_EDIT1), g_qeglobals.d_texturewin.prevTexDef.name); + return FALSE; + + case WM_COMMAND: + GetWindowText(GetDlgItem(hwndDlg, IDC_REP_EDIT2), toStr, 255); + GetWindowText(GetDlgItem(hwndDlg, IDC_REP_EDIT1), fromStr, 255); + switch (LOWORD(wParam)) + { + case IDD_REPLACEALL: + Texture_Replace(fromStr, toStr, 1); + EndDialog(hwndDlg, 0); + return TRUE; + + case IDD_REPLACESELECTED: + Texture_Replace(fromStr, toStr, 0); + EndDialog(hwndDlg, 0); + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + } + } + return FALSE; +} + + + +void DoTextureReplace(void) +{ + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_REPLACE, g_qeglobals.d_hwndMain, ReplaceTextureDlgProc); +} + + + +/* +=================================================== + + ARBITRARY ROTATE + +=================================================== +*/ + + +BOOL CALLBACK RotateDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char str[256]; + HWND h; + float v; + + switch (uMsg) + { + case WM_INITDIALOG: + h = GetDlgItem(hwndDlg, IDC_ROTX); + SetFocus (h);//put the cursor on the x text entry box + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + + case IDOK: + UNDO_StartBrushEdit ("&Undo Rotation"); + GetWindowText(GetDlgItem(hwndDlg, IDC_ROTX), str, 255); + v = atof(str); + if (v) + Select_RotateAxis (0, v); + + GetWindowText(GetDlgItem(hwndDlg, IDC_ROTY), str, 255); + v = atof(str); + if (v) + Select_RotateAxis (1, v); + + GetWindowText(GetDlgItem(hwndDlg, IDC_ROTZ), str, 255); + v = atof(str); + if (v) + Select_RotateAxis (2, v); + UNDO_FinishBrushEdit (NULL); + EndDialog(hwndDlg, 1); + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + } + } + + return FALSE; +} + + + +void DoRotate(void) +{ + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_ROTATE, g_qeglobals.d_hwndMain, RotateDlgProc); +} + +/* +=================================================== + + ARBITRARY ROTATE + +=================================================== +*/ + + +BOOL CALLBACK ScaleDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char str[256]; + HWND h; + float v; + int b1, nox, noy, noz; + + switch (uMsg) + { + case WM_INITDIALOG: + h = GetDlgItem(hwndDlg, IDC_SCALE); + SetWindowText(h, "1.0"); + SetFocus (h);//set focus to scale text entry box + SendMessage(h, WM_LBUTTONDBLCLK, 0, 0);//don't know an easier way to highlight this text --ss + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + + case IDOK: + GetWindowText(GetDlgItem(hwndDlg, IDC_SCALE), str, 255); + v = atof(str); + if (v) + { // Scale all of the selected brushes here by this value + UNDO_StartBrushEdit ("&Undo Scale"); + b1 = SendMessage(GetDlgItem(hwndDlg, IDC_SCALE_EACH_ORIGIN), BM_GETCHECK, 0, 0); + b1 = (b1) ? 0:1; // these need to be swapped for the function + nox = SendMessage(GetDlgItem(hwndDlg, IDC_CHECK_NOX), BM_GETCHECK, 0, 0); + noy = SendMessage(GetDlgItem(hwndDlg, IDC_CHECK_NOY), BM_GETCHECK, 0, 0); + noz = SendMessage(GetDlgItem(hwndDlg, IDC_CHECK_NOZ), BM_GETCHECK, 0, 0); + + Brush_Scale(v, b1, nox, noy, noz); + UNDO_FinishBrushEdit (NULL); + } + EndDialog(hwndDlg, 1); + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + + return TRUE; + } + } + + return FALSE; +} + + + +void DoScale(void) +{ + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_SCALE, g_qeglobals.d_hwndMain, ScaleDlgProc); +} + +/* +=================================================== + + ARBITRARY SIDES + +=================================================== +*/ + + +BOOL CALLBACK SidesDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char str[256]; + HWND h; + + switch (uMsg) + { + case WM_INITDIALOG: + h = GetDlgItem(hwndDlg, IDC_FIND_ENTITY); + SetFocus (h); + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDOK: + GetWindowText(GetDlgItem(hwndDlg, IDC_SIDES), str, 255); + + UNDO_StartBrushEdit("&Undo Sides"); + Brush_MakeSided (atoi(str)); + UNDO_FinishBrushEdit (NULL); + + EndDialog(hwndDlg, 1); + break; + + case ID_BRUSH_SNAPOK: + + GetWindowText(GetDlgItem(hwndDlg, IDC_SIDES), str, 255); + + UNDO_StartBrushEdit("&Undo Sides"); + Brush_MakeSided_Snap (atoi(str)); + UNDO_FinishBrushEdit (NULL); + + EndDialog(hwndDlg, 1); + break; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + break; + } + default: + return FALSE; + } +} + + + +void DoSides(void) +{ + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_SIDES, g_qeglobals.d_hwndMain, SidesDlgProc); +} + +//====================================================================== + +/* +=================== +DoAbout +=================== +*/ +BOOL CALLBACK AboutDlgProc( HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + char renderer[1024]; + char version[1024]; + char vendor[1024]; + char extensions[4096]; + + sprintf( renderer, "Renderer:\t%s", glGetString( GL_RENDERER ) ); + sprintf( version, "Version:\t\t%s", glGetString( GL_VERSION ) ); + sprintf( vendor, "Vendor:\t\t%s", glGetString( GL_VENDOR ) ); + sprintf( extensions, "\n%s", glGetString( GL_EXTENSIONS ) ); + + SetWindowText( GetDlgItem( hwndDlg, IDC_ABOUT_GLRENDERER ), renderer ); + SetWindowText( GetDlgItem( hwndDlg, IDC_ABOUT_GLVERSION ), version ); + SetWindowText( GetDlgItem( hwndDlg, IDC_ABOUT_GLVENDOR ), vendor ); + SetWindowText( GetDlgItem( hwndDlg, IDC_ABOUT_GLEXTENSIONS ), extensions ); + } + return TRUE; + + case WM_CLOSE: + EndDialog( hwndDlg, 1 ); + return TRUE; + + case WM_COMMAND: + if ( LOWORD( wParam ) == IDOK ) + EndDialog(hwndDlg, 1); + return TRUE; + } + return FALSE; +} + +void DoAbout(void) +{ + DialogBox( g_qeglobals.d_hInstance, ( char * ) IDD_ABOUT, g_qeglobals.d_hwndMain, AboutDlgProc ); +} + + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + +texdef_t g_old_texdef; +qboolean g_changed_surface; + +int g_checkboxes[64] = { + IDC_CHECK1, IDC_CHECK2, IDC_CHECK3, IDC_CHECK4, + IDC_CHECK5, IDC_CHECK6, IDC_CHECK7, IDC_CHECK8, + IDC_CHECK9, IDC_CHECK10, IDC_CHECK11, IDC_CHECK12, + IDC_CHECK13, IDC_CHECK14, IDC_CHECK15, IDC_CHECK16, + IDC_CHECK17, IDC_CHECK18, IDC_CHECK19, IDC_CHECK20, + IDC_CHECK21, IDC_CHECK22, IDC_CHECK23, IDC_CHECK24, + IDC_CHECK25, IDC_CHECK26, IDC_CHECK27, IDC_CHECK28, + IDC_CHECK29, IDC_CHECK30, IDC_CHECK31, IDC_CHECK32, + + IDC_CHECK33, IDC_CHECK34, IDC_CHECK35, IDC_CHECK36, + IDC_CHECK37, IDC_CHECK38, IDC_CHECK39, IDC_CHECK40, + IDC_CHECK41, IDC_CHECK42, IDC_CHECK43, IDC_CHECK44, + IDC_CHECK45, IDC_CHECK46, IDC_CHECK47, IDC_CHECK48, + IDC_CHECK49, IDC_CHECK50, IDC_CHECK51, IDC_CHECK52, + IDC_CHECK53, IDC_CHECK54, IDC_CHECK55, IDC_CHECK56, + IDC_CHECK57, IDC_CHECK58, IDC_CHECK59, IDC_CHECK60, + IDC_CHECK61, IDC_CHECK62, IDC_CHECK63, IDC_CHECK64 + }; + +/* +============== +SetSurfMods + +Set the fields to the current texdef +=============== +*/ +void SetSurfMods(HWND hwnd) +{ + char sz[128]; + texdef_t *pt; + int i; + HWND comboBox; + materialtype_t *mat; + + pt = &g_qeglobals.d_texturewin.texdef; + + i = (pt->flags & 0x0FF000000) >> 24; + comboBox = GetDlgItem(hwnd, IDC_TEXTURE_MATERIAL); + for (mat=materialtypes ; mat->name ; mat++) + { + SendMessage(comboBox, CB_ADDSTRING, 0, (LPARAM)mat->name); + if (i == mat->value) + { + SendMessage(comboBox, CB_SELECTSTRING, (WPARAM)(-1), (LPARAM)mat->name); + } + } + + SendMessage (hwnd, WM_SETREDRAW, 0, 0); + + SetWindowText(GetDlgItem(hwnd, IDC_TEXTURE), pt->name); + + sprintf(sz, "%d", (int)pt->shift[0]); + SetWindowText(GetDlgItem(hwnd, IDC_HSHIFT), sz); + + sprintf(sz, "%d", (int)pt->shift[1]); + SetWindowText(GetDlgItem(hwnd, IDC_VSHIFT), sz); + + sprintf(sz, "%4.2f", pt->scale[0]); + SetWindowText(GetDlgItem(hwnd, IDC_HSCALE), sz); + + sprintf(sz, "%4.2f", pt->scale[1]); + SetWindowText(GetDlgItem(hwnd, IDC_VSCALE), sz); + + sprintf(sz, "%d", (int)pt->rotate); + SetWindowText(GetDlgItem(hwnd, IDC_ROTATE), sz); + + sprintf(sz, "%d", (int)pt->value); + SetWindowText(GetDlgItem(hwnd, IDC_VALUE), sz); + + sprintf(sz, "%f", pt->lighting[0]); + SetWindowText(GetDlgItem(hwnd, IDC_LIGHT_RED), sz); + + sprintf(sz, "%f", pt->lighting[1]); + SetWindowText(GetDlgItem(hwnd, IDC_LIGHT_GREEN), sz); + + sprintf(sz, "%f", pt->lighting[2]); + SetWindowText(GetDlgItem(hwnd, IDC_LIGHT_BLUE), sz); + + sprintf(sz, "%f", pt->lighting[3]); + SetWindowText(GetDlgItem(hwnd, IDC_LIGHT_ALPHA), sz); + +// for (i=0 ; i<32 ; i++) top 8 bits are now material + for (i=0 ; i<24 ; i++) + SendMessage(GetDlgItem(hwnd, g_checkboxes[i]), BM_SETCHECK, !!(pt->flags&(1<contents&(1<name, sz, sizeof(pt->name)-1); + if (pt->name[0] <= ' ') + { + strcpy (pt->name, "none"); + SetWindowText(GetDlgItem(hwnd, IDC_TEXTURE), pt->name); + } + + GetWindowText (GetDlgItem(hwnd, IDC_HSHIFT), sz, 127); + pt->shift[0] = atof(sz); + + GetWindowText (GetDlgItem(hwnd, IDC_VSHIFT), sz, 127); + pt->shift[1] = atof(sz); + + GetWindowText(GetDlgItem(hwnd, IDC_HSCALE), sz, 127); + pt->scale[0] = atof(sz); + + GetWindowText(GetDlgItem(hwnd, IDC_VSCALE), sz, 127); + pt->scale[1] = atof(sz); + + GetWindowText(GetDlgItem(hwnd, IDC_ROTATE), sz, 127); + pt->rotate = atof(sz); + + GetWindowText(GetDlgItem(hwnd, IDC_VALUE), sz, 127); + pt->value = atof(sz); + + GetWindowText(GetDlgItem(hwnd, IDC_LIGHT_RED), sz, 127); + pt->lighting[0] = atof(sz); + + GetWindowText(GetDlgItem(hwnd, IDC_LIGHT_GREEN), sz, 127); + pt->lighting[1] = atof(sz); + + GetWindowText(GetDlgItem(hwnd, IDC_LIGHT_BLUE), sz, 127); + pt->lighting[2] = atof(sz); + + GetWindowText(GetDlgItem(hwnd, IDC_LIGHT_ALPHA), sz, 127); + pt->lighting[3] = atof(sz); + + pt->flags = 0; +// for (i=0 ; i<32 ; i++) top 8 bits are now material + for (i=0 ; i<24 ; i++) + { + b = SendMessage(GetDlgItem(hwnd, g_checkboxes[i]), BM_GETCHECK, 0, 0); + if (b != 1 && b != 0) + continue; + pt->flags |= b<contents = 0; + for (i=0 ; i<32 ; i++) + { + b = SendMessage(GetDlgItem(hwnd, g_checkboxes[32+i]), BM_GETCHECK, 0, 0); + if (b != 1 && b != 0) + continue; + pt->contents |= b<name ; mat++) + { + if (!strcmp(mat->name, sz)) + { + // assumes SURF_MATERIAL is in top 8 bits + pt->flags = (pt->flags & 0x0FFFFFF) | (mat->value << 24); + break; + } + } + + g_changed_surface = true; + Select_SetTexture(pt); +} + +/* +================= +UpdateSpinners +================= +*/ +void UpdateSpinners(HWND wnd, unsigned uMsg, WPARAM wParam, LPARAM lParam) +{ + int nScrollCode; + HWND hwnd; + texdef_t *pt; + + pt = &g_qeglobals.d_texturewin.texdef; + + nScrollCode = (int) LOWORD(wParam); // scroll bar value + hwnd = (HWND) lParam; // handle of scroll bar + + if ((nScrollCode != SB_LINEUP) && (nScrollCode != SB_LINEDOWN)) + return; + + if (hwnd == GetDlgItem(wnd, IDC_ROTATEA)) + { + if (nScrollCode == SB_LINEUP) + pt->rotate += 45; + else + pt->rotate -= 45; + + if (pt->rotate < 0) + pt->rotate += 360; + + if (pt->rotate >= 360) + pt->rotate -= 360; + } + + else if (hwnd == GetDlgItem(wnd, IDC_HSCALEA)) + { + if (nScrollCode == SB_LINEDOWN) + pt->scale[0] -= 0.1; + else + pt->scale[0] += 0.1; + } + + else if (hwnd == GetDlgItem(wnd, IDC_VSCALEA)) + { + if (nScrollCode == SB_LINEUP) + pt->scale[1] += 0.1; + else + pt->scale[1] -= 0.1; + } + + else if (hwnd == GetDlgItem(wnd, IDC_HSHIFTA)) + { + if (nScrollCode == SB_LINEDOWN) + pt->shift[0] -= 8; + else + pt->shift[0] += 8; + } + + else if (hwnd == GetDlgItem(wnd, IDC_VSHIFTA)) + { + if (nScrollCode == SB_LINEUP) + pt->shift[1] += 8; + else + pt->shift[1] -= 8; + } + + SetSurfMods(wnd); + g_changed_surface = true; + Select_SetTexture(pt); +} + + + +BOOL CALLBACK SurfaceDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + SetSurfMods (hwndDlg); + return 0; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + + case IDOK: + GetSurfMods (hwndDlg); + EndDialog(hwndDlg, 1); + return 1; + break; + + case IDAPPLY: + GetSurfMods (hwndDlg); + InvalidateRect(g_qeglobals.d_hwndCamera, NULL, false); + UpdateWindow (g_qeglobals.d_hwndCamera); + return 1; + break; + + case IDCANCEL: +// g_qeglobals.d_texturewin.texdef = g_old_texdef; +// if (g_changed_surface) +// Select_SetTexture(&g_qeglobals.d_texturewin.texdef); + EndDialog(hwndDlg, 0); + return 1; + break; + } + break; + + case WM_HSCROLL: + case WM_VSCROLL: + UpdateSpinners(hwndDlg, uMsg, wParam, lParam); + InvalidateRect(g_qeglobals.d_hwndCamera, NULL, false); + UpdateWindow (g_qeglobals.d_hwndCamera); + return 1; + + default: + return 0; + } + return 0; +} + +static undo_t surfaceUndo; + +void SurfaceDlg_Init() +{ + surfaceUndo.brushdata.next = surfaceUndo.brushdata.prev = &surfaceUndo.brushdata; +} + +void DoSurface (void) +{ + brush_t *from, *data; + + //need to save all data if brush selection active + // how can you tell if only one face selected?????? + if(!selected_face) + { + while (surfaceUndo.brushdata.next != &surfaceUndo.brushdata) + { + from = surfaceUndo.brushdata.next; + Brush_Free (from); + } + + from = &selected_brushes; + while (from->next != &selected_brushes) + { + from = from->next; + data = Brush_Clone(from); + Brush_AddToList(data, &surfaceUndo.brushdata); //store data + } + } + else + { + // save current state for cancel + g_old_texdef = g_qeglobals.d_texturewin.texdef; + } + g_changed_surface = false; + + if(!DialogBox(g_qeglobals.d_hInstance, (char *)IDD_SURFACE, g_qeglobals.d_hwndMain, SurfaceDlgProc)) + { //cancelled, undo changes + if(g_changed_surface) + { + if(!selected_face) + { + while (selected_brushes.next != &selected_brushes) + { + from = selected_brushes.next; + Brush_Free (from); + } + UNDO_Reset (); //clone can destroy undo info + UNDO_BrushClone (&surfaceUndo); + } + else + { + g_qeglobals.d_texturewin.texdef = g_old_texdef; + Select_SetTexture(&g_qeglobals.d_texturewin.texdef); + } + } + } +} + diff --git a/Toolkit/Programming/Tools/qe4/win_ent.c b/Toolkit/Programming/Tools/qe4/win_ent.c new file mode 100644 index 0000000..550a65a --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/win_ent.c @@ -0,0 +1,1314 @@ +#include "qe3.h" +#include "entityw.h" + +int rgIds[EntLast] = { + IDC_E_LIST, + IDC_E_COMMENT, + IDC_CHECK1, + IDC_CHECK2, + IDC_CHECK3, + IDC_CHECK4, + IDC_CHECK5, + IDC_CHECK6, + IDC_CHECK7, + IDC_CHECK8, + IDC_CHECK9, + IDC_CHECK10, + IDC_CHECK11, + IDC_CHECK12, + + IDC_CHECK13, + IDC_CHECK14, + IDC_CHECK15, + IDC_CHECK16, + IDC_CHECK17, + IDC_CHECK18, + IDC_CHECK19, + IDC_CHECK20, + IDC_CHECK21, + + IDC_E_PROPS, + IDC_E_0, + IDC_E_45, + IDC_E_90, + IDC_E_135, + IDC_E_180, + IDC_E_225, + IDC_E_270, + IDC_E_315, + IDC_E_UP, + IDC_E_DOWN, + IDC_E_DELPROP, + + IDC_STATIC_KEY, + IDC_E_KEY_FIELD, + IDC_STATIC_VALUE, + IDC_E_VALUE_FIELD, + + IDC_E_COLOR +}; + +#define TEXMODIFY_HEIGHT 90 + +HWND hwndEnt[EntLast]; + +int inspector_mode; // W_TEXTURE, W_ENTITY, or W_CONSOLE + +qboolean multiple_entities; + +entity_t *edit_entity; + +HWND CreateTextureWindow (void); + +BOOL CALLBACK EntityWndProc( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam); // second message parameter + +void SizeEntityDlg(int iWidth, int iHeight); +void AddProp(void); +void GetTexMods(void); + + +LRESULT (CALLBACK* OldFieldWindowProc) (HWND, UINT, WPARAM, LPARAM); +LRESULT (CALLBACK* OldEntityListWindowProc) (HWND, UINT, WPARAM, LPARAM); + +/* +========================= +FieldWndProc + +Just to handle tab and enter... +========================= +*/ +BOOL CALLBACK FieldWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_CHAR: + if (LOWORD(wParam) == VK_TAB) + return FALSE; + if (LOWORD(wParam) == VK_RETURN) + return FALSE; + if (LOWORD(wParam) == VK_ESCAPE) + { + SetFocus (g_qeglobals.d_hwndCamera); + return FALSE; + } + break; + + case WM_KEYDOWN: + if (LOWORD(wParam) == VK_TAB) + { + if (hwnd == hwndEnt[EntKeyField]) + { + SendMessage (hwndEnt[EntValueField], WM_SETTEXT, 0, (long)""); + SetFocus (hwndEnt[EntValueField]); + } + else + SetFocus (hwndEnt[EntKeyField]); + } + if (LOWORD(wParam) == VK_RETURN) + { + if (hwnd == hwndEnt[EntKeyField]) + { + SendMessage (hwndEnt[EntValueField], WM_SETTEXT, 0, (long)""); + SetFocus (hwndEnt[EntValueField]); + } + else + { + AddProp (); + SetFocus (g_qeglobals.d_hwndCamera); + } + } + break; +// case WM_NCHITTEST: + case WM_LBUTTONDOWN: + SetFocus (hwnd); + break; + } + return CallWindowProc (OldFieldWindowProc, hwnd, uMsg, wParam, lParam); +} + + +/* +========================= +EntityListWndProc + +Just to handle enter... +========================= +*/ +BOOL CALLBACK EntityListWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_KEYDOWN: + if (LOWORD(wParam) == VK_RETURN) + { + SendMessage ( g_qeglobals.d_hwndEntity, + WM_COMMAND, + (LBN_DBLCLK<<16) + IDC_E_LIST, + 0 ); + return 0; + } + break; + } + return CallWindowProc (OldEntityListWindowProc, hwnd, uMsg, wParam, lParam); +} + + +/* +================ +GetEntityControls + +Finds the controls from the dialog and +moves them to the window +================ +*/ +void GetEntityControls(HWND ghwndEntity) +{ + int i; + + for (i = 0; i < EntLast; i++) + { + if (i == EntList || i == EntProps || i == EntComment) + continue; + if (i == EntKeyField || i == EntValueField) + continue; + hwndEnt[i] = GetDlgItem(ghwndEntity, rgIds[i]); + if (hwndEnt[i]) + SetParent (hwndEnt[i], g_qeglobals.d_hwndEntity ); + } + + + // SetParent apears to not modify some internal state + // on listboxes, so create it from scratch... + + hwndEnt[EntList] = CreateWindow ("listbox", NULL, + LBS_STANDARD | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT + | WS_VSCROLL | WS_CHILD | WS_VISIBLE, + 5, 5, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_LIST, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntList]) + Error ("CreateWindow failed"); + + hwndEnt[EntProps] = CreateWindow ("listbox", NULL, + LBS_STANDARD | LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS + | WS_VSCROLL | WS_CHILD | WS_VISIBLE, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_PROPS, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntProps]) + Error ("CreateWindow failed"); + + hwndEnt[EntComment] = CreateWindow ("edit", NULL, + ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_COMMENT, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntComment]) + Error ("CreateWindow failed"); + + hwndEnt[EntKeyField] = CreateWindow ("edit", NULL, + WS_CHILD | WS_VISIBLE | WS_BORDER, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_KEY_FIELD, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntKeyField]) + Error ("CreateWindow failed"); + + hwndEnt[EntValueField] = CreateWindow ("edit", NULL, + WS_CHILD | WS_VISIBLE | WS_BORDER, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_VALUE_FIELD, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntValueField]) + Error ("CreateWindow failed"); + + g_qeglobals.d_hwndEdit = CreateWindow ("edit", NULL, + ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_STATUS, + g_qeglobals.d_hInstance, + NULL); + if (!g_qeglobals.d_hwndEdit) + Error ("CreateWindow failed"); + + g_qeglobals.d_hwndTexture = CreateTextureWindow (); + +#if 0 + for (i=0 ; inext) + { + iIndex = SendMessage(hwndEnt[EntList], LB_ADDSTRING, 0 , (LPARAM)pec->name); + SendMessage(hwndEnt[EntList], LB_SETITEMDATA, iIndex, (LPARAM)pec); + } + +} + + +/* +============== +WEnt_Create +============== +*/ +void WEnt_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)EntityWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = GetStockObject (LTGRAY_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = ENT_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Error ("RegisterClass: failed"); + + g_qeglobals.d_hwndEntity = CreateWindow (ENT_WINDOW_CLASS , + "Entity", + QE3_STYLE, + 20, + 20, + 100, + 480, // size + + g_qeglobals.d_hwndMain, // parent + 0, // no menu + hInstance, + NULL); + + if (!g_qeglobals.d_hwndEntity ) + Error ("Couldn't create Entity window"); +} + +/* +============== +CreateEntityWindow +============== +*/ +BOOL CreateEntityWindow(HINSTANCE hInstance) +{ + HWND hwndEntityPalette; + + inspector_mode = W_ENTITY; + + WEnt_Create (hInstance); + + hwndEntityPalette = CreateDialog(hInstance, (char *)IDD_ENTITY, g_qeglobals.d_hwndMain, (DLGPROC)NULL); + if (!hwndEntityPalette) + Error ("CreateDialog failed"); + + GetEntityControls (hwndEntityPalette); + DestroyWindow (hwndEntityPalette); + + OldFieldWindowProc = (void *)GetWindowLong (hwndEnt[EntKeyField], GWL_WNDPROC); + SetWindowLong (hwndEnt[EntKeyField], GWL_WNDPROC, (long)FieldWndProc); + SetWindowLong (hwndEnt[EntValueField], GWL_WNDPROC, (long)FieldWndProc); + + OldEntityListWindowProc = (void *)GetWindowLong (hwndEnt[EntList], GWL_WNDPROC); + SetWindowLong (hwndEnt[EntList], GWL_WNDPROC, (long)EntityListWndProc); + + FillClassList (); + + LoadWindowState(g_qeglobals.d_hwndEntity, "EntityWindow"); + + ShowWindow (g_qeglobals.d_hwndEntity, SW_SHOW); + SetInspectorMode (W_CONSOLE); + + return TRUE; +} + +/* +============== +SetInspectorMode +============== +*/ +void SetInspectorMode(int iType) +{ + RECT rc; + HMENU hMenu = GetMenu( g_qeglobals.d_hwndMain ); + + // Is the caller asking us to cycle to the next window? + + if (iType == -1) + { + if (inspector_mode == W_ENTITY) + iType = W_TEXTURE; + else if (inspector_mode == W_TEXTURE) + iType = W_CONSOLE; + else + iType = W_ENTITY; + } + + inspector_mode = iType; + switch(iType) + { + + case W_ENTITY: + SetWindowText(g_qeglobals.d_hwndEntity, "Entity"); + EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_ENABLED | MF_BYCOMMAND ); + break; + + case W_TEXTURE: +// title is set by textures.c SetWindowText(g_qeglobals.d_hwndEntity, "Textures"); + EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND ); + break; + + case W_CONSOLE: + SetWindowText(g_qeglobals.d_hwndEntity, "Console"); + EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND ); + break; + + default: + break; + } + + GetWindowRect (g_qeglobals.d_hwndEntity, &rc); + SizeEntityDlg( rc.right - rc.left - 8, rc.bottom - rc.top - 32); + + RedrawWindow (g_qeglobals.d_hwndEntity, NULL, NULL, RDW_ERASE | RDW_INVALIDATE + | RDW_ERASENOW | RDW_UPDATENOW | RDW_ALLCHILDREN); + +// InvalidateRect(entwindow, NULL, true); +// ShowWindow (entwindow, SW_SHOW); +// UpdateWindow (entwindow); + + SetWindowPos( g_qeglobals.d_hwndEntity, + HWND_TOP, + rc.left, rc.top, + rc.right - rc.left, rc.bottom - rc.top, + SWP_NOSIZE | SWP_NOMOVE ); +} + + + + + +// SetKeyValuePairs +// +// Reset the key/value (aka property) listbox and fill it with the +// k/v pairs from the entity being edited. +// + +void SetKeyValuePairs (void) +{ + epair_t *pep; + RECT rc; + char sz[4096]; + + if (edit_entity == NULL) + return; + + // set key/value pair list + + GetWindowRect(hwndEnt[EntProps], &rc); + SendMessage(hwndEnt[EntProps], LB_SETCOLUMNWIDTH, (rc.right - rc.left)/2, 0); + SendMessage(hwndEnt[EntProps], LB_RESETCONTENT, 0, 0); + + // Walk through list and add pairs + + for (pep = edit_entity->epairs ; pep ; pep = pep->next) + { + // if the key is less than 8 chars, add a tab for alignment + if (strlen(pep->key) > 8) + sprintf (sz, "%s\t%s", pep->key, pep->value); + else + sprintf (sz, "%s\t\t%s", pep->key, pep->value); + SendMessage(hwndEnt[EntProps], LB_ADDSTRING, 0, (LPARAM)sz); + } + +} + +// SetSpawnFlags +// +// Update the checkboxes to reflect the flag state of the entity +// +void SetSpawnFlags(void) +{ + int f; + int i; + int v; + + f = atoi(ValueForKey (edit_entity, "spawnflags")); + for (i=0 ; inext) + SetKeyValue(b->owner, "spawnflags", sz); + } + else + SetKeyValue (edit_entity, "spawnflags", sz); + SetKeyValuePairs (); +} + +// UpdateSel +// +// Update the listbox, checkboxes and k/v pairs to reflect the new selection +// + +BOOL UpdateSel(int iIndex, eclass_t *pec) +{ + int i; + brush_t *b; + + if (selected_brushes.next == &selected_brushes) + { + edit_entity = world_entity; + multiple_entities = false; + } + else + { + edit_entity = selected_brushes.next->owner; + for (b=selected_brushes.next->next ; b != &selected_brushes ; b=b->next) + { + if (b->owner != edit_entity) + { + multiple_entities = true; + break; + } + } + } + + if (iIndex != LB_ERR) + SendMessage(hwndEnt[EntList], LB_SETCURSEL, iIndex, 0); + + if (pec == NULL) + return TRUE; + + // Set up the description + + SendMessage(hwndEnt[EntComment], WM_SETTEXT, 0, + (LPARAM)TranslateString(pec->comments)); + + for (i=0 ; iflagnames[i] && pec->flagnames[i][0] != 0) + { + EnableWindow(hwnd, TRUE); + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)pec->flagnames[i]); + } else { + + // disable check box + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)" "); + EnableWindow(hwnd, FALSE); + } + } + //need to set the last 8 as well + + for (i=FIRST_HIGH_SPAWNFLAG ; iflagnames[i - (FIRST_HIGH_SPAWNFLAG - LAST_LOW_SPAWNFLAG)] && pec->flagnames[i - (FIRST_HIGH_SPAWNFLAG - LAST_LOW_SPAWNFLAG)][0] != 0) + { + EnableWindow(hwnd, TRUE); + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)pec->flagnames[i - (FIRST_HIGH_SPAWNFLAG - LAST_LOW_SPAWNFLAG)]); + } else { + + // disable check box + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)" "); + EnableWindow(hwnd, FALSE); + } + } + + SetSpawnFlags(); + SetKeyValuePairs(); + return TRUE; +} + +BOOL UpdateEntitySel(eclass_t *pec) +{ + int iIndex; + + iIndex = (int)SendMessage(hwndEnt[EntList], LB_FINDSTRINGEXACT, + (WPARAM)-1, (LPARAM)pec->name); + + return UpdateSel(iIndex, pec); +} + +// CreateEntity +// +// Creates a new entity based on the currently selected brush and entity type. +// + +void CreateEntity(void) +{ + eclass_t *pecNew; + entity_t *petNew; + int i; + HWND hwnd; + char sz[1024]; + + // check to make sure we have a brush + + if (selected_brushes.next == &selected_brushes) + { + MessageBox(g_qeglobals.d_hwndMain, "You must have a selected brush to create an entity" + , "info", 0); + return; + } + + + // find out what type of entity we are trying to create + + hwnd = hwndEnt[EntList]; + + i = SendMessage(hwndEnt[EntList], LB_GETCURSEL, 0, 0); + + if (i < 0) + { + MessageBox(g_qeglobals.d_hwndMain, "You must have a selected class to create an entity" + , "info", 0); + return; + } + + SendMessage(hwnd, LB_GETTEXT, i, (LPARAM)sz); + + if (!stricmp(sz, "worldspawn")) + { + MessageBox(g_qeglobals.d_hwndMain, "Can't create an entity with worldspawn.", "info", 0); + return; + } + //sz is new entity name + //pecNew is the entity data + pecNew = Eclass_ForName(sz, false); + + // create it + + petNew = Entity_Create(pecNew); + + if (petNew == NULL) + { + MessageBox(g_qeglobals.d_hwndMain, "Failed to create entity.", "info", 0); + return; + } + + if (selected_brushes.next == &selected_brushes) + edit_entity = world_entity; + else + edit_entity = selected_brushes.next->owner; + + SetKeyValuePairs(); + Select_Deselect (); + Select_Brush (edit_entity->brushes.onext); +} + + + +/* +=============== +AddProp + +=============== +*/ +void AddProp(void) +{ + char key[4096]; + char value[4096]; + float angle, oldangle; + + if (edit_entity == NULL) + return; + if (selected_brushes.next->owner == NULL) + return; + + // Get current selection text + + SendMessage(hwndEnt[EntKeyField], WM_GETTEXT, sizeof(key)-1, (LPARAM)key); + SendMessage(hwndEnt[EntValueField], WM_GETTEXT, sizeof(value)-1, (LPARAM)value); + + if (selected_brushes.next != selected_brushes.prev) + { + brush_t *b; + + if (!strcmp(key,"angle") && (edit_entity->eclass->fixedsize)) // don't let them add angle to multiple FIXEDSIZED entities, + { // even then, don't rotate them + Sys_Printf ("Can't add angle property to multiple entities.\n"); + return; + } + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + SetKeyValue(b->owner, key, value); + } + else + { + oldangle = FloatForKey(edit_entity, "angle"); + SetKeyValue(edit_entity, key, value); + if (!strcmp(key,"angle") && (edit_entity->eclass->fixedsize)) + { + angle = FloatForKey(edit_entity, "angle"); + Select_RotateAxis( 2, oldangle-angle); + } + } + // refresh the prop listbox + + SetKeyValuePairs(); +} + +/* +=============== +GetEntityColor +=============== + */ + +int GetEntityColor(int iIndex) +{ + + int rgbclr; + vec3_t colorVec; + + if ((iIndex == COLOR_ENTITY) && (KeyExists(edit_entity, ENTKEY_COLOR))) + { + GetVectorForKey (edit_entity, ENTKEY_COLOR, colorVec); + rgbclr = + (int)(colorVec[0]*255) + + (((int)(colorVec[1]*255))<<8) + + (((int)(colorVec[2]*255))<<16); + } + else + { + rgbclr = + (int)(g_qeglobals.d_savedinfo.colors[iIndex][0]*255) + + (((int)(g_qeglobals.d_savedinfo.colors[iIndex][1]*255))<<8) + + (((int)(g_qeglobals.d_savedinfo.colors[iIndex][2]*255))<<16); + } + return rgbclr; +} + + +/* +=============== +DelProp + +=============== +*/ +void DelProp(void) +{ + char sz[4096]; + float angle; + + if (edit_entity == NULL) + return; + + if (selected_brushes.next->owner == NULL) + return; + + // Get current selection text + + SendMessage(hwndEnt[EntKeyField], WM_GETTEXT, sizeof(sz)-1, (LPARAM)sz); + + if (selected_brushes.next != selected_brushes.prev) + { + brush_t *b; + + if (!strcmp(sz,"angle")&& (edit_entity->eclass->fixedsize)) // don't let them delete angle from multiple FIXEDSIZED brushes + { + Sys_Printf("Can't delete angle from multiple entities.\n"); + return; + } + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + DeleteKey(b->owner, sz); + } + else + { + if (!strcmp(sz,"angle") && (edit_entity->eclass->fixedsize)) + { + angle = FloatForKey(edit_entity, "angle"); + if (angle > -1) + { + Select_RotateAxis(2, angle-0); + }// return it to zero + } + DeleteKey(edit_entity, sz); + } + + // refresh the prop listbox + + SetKeyValuePairs(); +} + +/* +=============== +EditProp + +=============== +*/ +void EditProp(void) +{ + int i; + HWND hwnd; + char sz[4096]; + char *val; + + if (edit_entity == NULL) + return; + + hwnd = hwndEnt[EntProps]; + + // Get current selection text + + i = SendMessage(hwnd, LB_GETCURSEL, 0, 0); + + if (i < 0) + return; + + SendMessage(hwnd, LB_GETTEXT, i, (LPARAM)sz); + + // strip it down to the key name + + for(i=0;sz[i] != '\t';i++) + ; + + sz[i] = '\0'; + + val = sz + i + 1; + if (*val == '\t') + val++; + + SendMessage(hwndEnt[EntKeyField], WM_SETTEXT, 0, (LPARAM)sz); + SendMessage(hwndEnt[EntValueField], WM_SETTEXT, 0, (LPARAM)val); +} + + +HDWP defer; +int col; +void MOVE(HWND e, int x, int y, int w, int h) +{ +// defer=DeferWindowPos(defer,e,HWND_TOP,col+(x),y,w,h,SWP_SHOWWINDOW); +// MoveWindow (e, col+x, y, w, h, FALSE); + SetWindowPos (e, HWND_TOP, col+x, y, w, h, + SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER); +} + + +/* +=============== +SizeEnitityDlg + +Positions all controls so that the active inspector +is displayed correctly and the inactive ones are +off the side +=============== +*/ +void SizeEntityDlg(int iWidth, int iHeight) +{ + int y, x, xCheck, yCheck; + int i, iRow; + int w, h; + + iHeight -= TEXMODIFY_HEIGHT; + if (iWidth < 32 || iHeight < 32) + return; + + SendMessage( g_qeglobals.d_hwndEntity, WM_SETREDRAW, 0, 0); + + //========================================== + + // + // console + // + + if (inspector_mode == W_CONSOLE) + col = 0; + else + col = iWidth; + + MOVE(g_qeglobals.d_hwndEdit, DlgXBorder, DlgYBorder+TEXMODIFY_HEIGHT,iWidth - (2 * DlgXBorder), iHeight - (2 * DlgYBorder) ); + + //========================================== + + // + // texture controls + // + if (inspector_mode == W_TEXTURE) + col = 0; + else + col = iWidth; + + MOVE(g_qeglobals.d_hwndTexture, DlgXBorder, DlgYBorder+TEXMODIFY_HEIGHT, iWidth - (2 * DlgXBorder), iHeight - (2 * DlgYBorder) ); + + //========================================== + + // + // entity controls + // + if (inspector_mode == W_ENTITY) + col = 0; + else + col = iWidth; + + + // top half includes the entity list (2/3) and the + // comments (1/3) - 2 gaps, above and below. + + y = iHeight/2; + y -= 2 * DlgYBorder; + y = y / 3; + w = iWidth - (2 * DlgXBorder); + MOVE(hwndEnt[EntList], DlgXBorder, DlgYBorder+TEXMODIFY_HEIGHT, w, 2 * y); + + MOVE(hwndEnt[EntComment], + DlgXBorder, 2 * DlgYBorder + 2 * y+TEXMODIFY_HEIGHT, + w, y - (2 * DlgYBorder)); + + // bottom half includes flags (fixed), k/v pairs, + // and buttons (fixed). + + // xCheck = width of a single check box + // yCheck = distance from top of one check to the next + + xCheck = (iWidth - (2 * DlgXBorder)) / 3; + yCheck = 15; + + x = DlgXBorder; + + for (iRow = 0; iRow <= NUM_SPAWNFLAGS; iRow += 7) + { + y = iHeight/2+TEXMODIFY_HEIGHT; + + + for (i = 0; i < 7; i++) + { + MOVE(hwndEnt[EntCheck1 + i + iRow], + x, y, xCheck, yCheck); + y += yCheck; + } + + x += xCheck; + } + + // + // properties scroll box + // + yCheck = 20; + y = iHeight/2 + 6 * yCheck; // + TEXMODIFY_HEIGHT; + + w = iWidth - (2 * DlgXBorder); + h = (iHeight - (yCheck * 5 + 2 * DlgYBorder) ) - y; + + MOVE(hwndEnt[EntProps], DlgXBorder, y+TEXMODIFY_HEIGHT, w, h); + + y += h + DlgYBorder+TEXMODIFY_HEIGHT; + + // + // key / value fields + // + w = iWidth-(DlgXBorder+45); + MOVE(hwndEnt[EntKeyLabel], DlgXBorder, y, 40, yCheck); + MOVE(hwndEnt[EntKeyField], DlgXBorder+40, y, w, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntValueLabel], DlgXBorder, y, 40, yCheck); + MOVE(hwndEnt[EntValueField], DlgXBorder+40, y, w, yCheck); + y += yCheck; + + // + // angle check boxes + // + i = y; + x = DlgXBorder; + + xCheck = yCheck*2; + + MOVE(hwndEnt[EntDir135], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDir180], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDir225], x, y, xCheck, yCheck); + + y = i; + x += xCheck; + + + MOVE(hwndEnt[EntDir90], x, y, xCheck, yCheck); + y += yCheck; + y += yCheck; + + MOVE(hwndEnt[EntDir270], x, y, xCheck, yCheck); + + y = i; + x += xCheck; + + + MOVE(hwndEnt[EntDir45], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDir0], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDir315], x, y, xCheck, yCheck); + + y = i + yCheck/2; + x += xCheck + xCheck/2; + + + MOVE(hwndEnt[EntDirUp], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDirDown], x, y, xCheck, yCheck); + + y = i; + x += 1.5 * xCheck; + + MOVE(hwndEnt[EntDelProp], x, y, xCheck*2, yCheck); + y += yCheck; + + SendMessage( g_qeglobals.d_hwndEntity, WM_SETREDRAW, 1, 0); +// InvalidateRect(entwindow, NULL, TRUE); +} + + +/* +========================= +EntityWndProc +========================= +*/ +BOOL CALLBACK EntityWndProc( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam) // second message parameter +{ + RECT rc; + float angle; + + GetClientRect(hwndDlg, &rc); + + switch (uMsg) + { + case WM_GETMINMAXINFO: + { + LPMINMAXINFO lpmmi; + + lpmmi = (LPMINMAXINFO) lParam; + lpmmi->ptMinTrackSize.x = 320; + lpmmi->ptMinTrackSize.y = 0; + } + return 0; + + case WM_WINDOWPOSCHANGING: + { + LPWINDOWPOS lpwp; + lpwp = (LPWINDOWPOS) lParam; + + DefWindowProc (hwndDlg, uMsg, wParam, lParam); + + lpwp->flags |= SWP_NOCOPYBITS; + SizeEntityDlg(lpwp->cx-8, lpwp->cy-32); + return 0; + + } + return 0; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_E_DELPROP: + DelProp(); + SetFocus (g_qeglobals.d_hwndCamera); + break; + + case IDC_E_0: + if (selected_brushes.next->owner != NULL) + { + if ((edit_entity->eclass->fixedsize) && (selected_brushes.next != selected_brushes.prev)) + break; + angle = FloatForKey(edit_entity, "angle"); + SetKeyValue (edit_entity, "angle", "0"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + if ((angle > -1) && (edit_entity->eclass->fixedsize) + && (selected_brushes.next == selected_brushes.prev)) // only one FIXEDSIZED entity can be selected + { + Select_RotateAxis( 2, angle ); + } + } + break; + case IDC_E_45: + if (selected_brushes.next->owner != NULL) + { + if ((edit_entity->eclass->fixedsize) && (selected_brushes.next != selected_brushes.prev)) + break; + angle = FloatForKey(edit_entity, "angle"); + SetKeyValue (edit_entity, "angle", "45"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + if ((angle > -1) && (edit_entity->eclass->fixedsize) + && (selected_brushes.next == selected_brushes.prev)) // only one FIXEDSIZED entity can be selected + { + Select_RotateAxis( 2, angle-45 ); + } + } + break; + case IDC_E_90: + if (selected_brushes.next->owner != NULL) + { + if ((edit_entity->eclass->fixedsize) && (selected_brushes.next != selected_brushes.prev)) + break; + angle = FloatForKey(edit_entity, "angle"); + SetKeyValue (edit_entity, "angle", "90"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + if ((angle > -1) && (edit_entity->eclass->fixedsize) + && (selected_brushes.next == selected_brushes.prev)) // only one FIXEDSIZED entity can be selected + { + Select_RotateAxis( 2, angle-90 ); + } + } + break; + case IDC_E_135: + if (selected_brushes.next->owner != NULL) + { + if ((edit_entity->eclass->fixedsize) && (selected_brushes.next != selected_brushes.prev)) + break; + angle = FloatForKey(edit_entity, "angle"); + SetKeyValue (edit_entity, "angle", "135"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + if ((angle > -1) && (edit_entity->eclass->fixedsize) + && (selected_brushes.next == selected_brushes.prev)) // only one FIXEDSIZED entity can be selected + { + Select_RotateAxis( 2, angle-135 ); + } + } + break; + case IDC_E_180: + if (selected_brushes.next->owner != NULL) + { + if ((edit_entity->eclass->fixedsize) && (selected_brushes.next != selected_brushes.prev)) + break; + angle = FloatForKey(edit_entity, "angle"); + SetKeyValue (edit_entity, "angle", "180"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + if ((angle > -1) && (edit_entity->eclass->fixedsize) + && (selected_brushes.next == selected_brushes.prev)) // only one FIXEDSIZED entity can be selected + { + Select_RotateAxis( 2, angle-180 ); + } + } + break; + case IDC_E_225: + if (selected_brushes.next->owner != NULL) + { + if ((edit_entity->eclass->fixedsize) && (selected_brushes.next != selected_brushes.prev)) + break; + angle = FloatForKey(edit_entity, "angle"); + SetKeyValue (edit_entity, "angle", "225"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + if ((angle > -1) && (edit_entity->eclass->fixedsize) + && (selected_brushes.next == selected_brushes.prev)) // only one FIXEDSIZED entity can be selected + { + Select_RotateAxis( 2, angle-225 ); + } + } + break; + case IDC_E_270: + if (selected_brushes.next->owner != NULL) + { + if ((edit_entity->eclass->fixedsize) && (selected_brushes.next != selected_brushes.prev)) + break; + angle = FloatForKey(edit_entity, "angle"); + SetKeyValue (edit_entity, "angle", "270"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + if ((angle > -1) && (edit_entity->eclass->fixedsize) + && (selected_brushes.next == selected_brushes.prev)) // only one FIXEDSIZED entity can be selected + { + Select_RotateAxis( 2, angle-270 ); + } + } + break; + case IDC_E_315: + if (selected_brushes.next->owner != NULL) + { + if ((edit_entity->eclass->fixedsize) && (selected_brushes.next != selected_brushes.prev)) + break; + angle = FloatForKey(edit_entity, "angle"); + SetKeyValue (edit_entity, "angle", "315"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + if ((angle > -1) && (edit_entity->eclass->fixedsize) + && (selected_brushes.next == selected_brushes.prev)) // only one FIXEDSIZED entity can be selected + { + Select_RotateAxis( 2, angle-315 ); + } + } + break; + case IDC_E_UP: + SetKeyValue (edit_entity, "angle", "-1"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_DOWN: + SetKeyValue (edit_entity, "angle", "-2"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + + case IDC_CHECK1: + case IDC_CHECK2: + case IDC_CHECK3: + case IDC_CHECK4: + case IDC_CHECK5: + case IDC_CHECK6: + case IDC_CHECK7: + case IDC_CHECK8: + case IDC_CHECK9: + case IDC_CHECK10: + case IDC_CHECK11: + case IDC_CHECK12: + + case IDC_CHECK13: //more spawn flags + case IDC_CHECK14: + case IDC_CHECK15: + case IDC_CHECK16: + case IDC_CHECK17: + case IDC_CHECK18: + case IDC_CHECK19: + case IDC_CHECK20: + case IDC_CHECK21: + + GetSpawnFlags(); + SetFocus (g_qeglobals.d_hwndCamera); + break; + + + case IDC_E_PROPS: + switch (HIWORD(wParam)) + { + case LBN_SELCHANGE: + + EditProp(); + return TRUE; + } + break; + + case IDC_E_LIST: + + switch (HIWORD(wParam)) { + + case LBN_SELCHANGE: + { + int iIndex; + eclass_t *pec; + + iIndex = SendMessage(hwndEnt[EntList], LB_GETCURSEL, 0, 0); + pec = (eclass_t *)SendMessage(hwndEnt[EntList], LB_GETITEMDATA, + iIndex, 0); + + UpdateSel(iIndex, pec); + + return TRUE; + break; + } + + case LBN_DBLCLK: + CreateEntity (); + SetFocus (g_qeglobals.d_hwndCamera); + break; + } + break; + + + default: + return DefWindowProc( hwndDlg, uMsg, wParam, lParam ); + } + + return 0; + } + + + return DefWindowProc (hwndDlg, uMsg, wParam, lParam); +} diff --git a/Toolkit/Programming/Tools/qe4/win_main.c b/Toolkit/Programming/Tools/qe4/win_main.c new file mode 100644 index 0000000..81589eb --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/win_main.c @@ -0,0 +1,1615 @@ +#include "qe3.h" +#include +#include "mru.h" +#include "entityw.h" +#include "undo.h" +#include "tower.h" +#include "win_bsp.h" + +HWND s_hwndToolbar; + +BOOL SaveRegistryInfo(const char *pszName, void *pvBuf, long lSize); +BOOL LoadRegistryInfo(const char *pszName, void *pvBuf, long *plSize); + +static HWND CreateMyStatusWindow(HINSTANCE hInst); +static HWND CreateToolBar(HINSTANCE hinst); + +extern int WXY_Print( void ); + +extern int inspector_mode; + +/* +============================================================================== + + MENU + +============================================================================== +*/ + +void OpenDialog (void); +void SaveAsDialog (void); +qboolean ConfirmModified (void); +void Select_Ungroup (void); + +void QE_ExpandBspString (char *bspaction, char *out, char *mapname) +{ + char *in; + char src[1024]; + char rsh[1024]; + char base[256]; + + strcpy(src, mapname); + strlwr(src); + in = strstr(src, "maps/"); + if (!in) + { + in = strstr(src, "maps\\"); + } + if (in) + { + in += 5; + strcpy(base, in); + in = base; + while (*in) + { + if (*in == '\\') + { + *in = '/'; + } + in++; + } + } + else + { + ExtractFileName (mapname, base); + } + sprintf (src, "%s/maps/%s", ValueForKey(g_qeglobals.d_project_entity, "remotebasepath"), base); + strcpy (rsh, ValueForKey(g_qeglobals.d_project_entity, "rshcmd")); + + in = ValueForKey( g_qeglobals.d_project_entity, bspaction ); + while (*in) + { + if (in[0] == '!') + { + strcpy (out, rsh); + out += strlen(rsh); + in++; + continue; + } + if (in[0] == '$') + { + strcpy (out, src); + out += strlen(src); + in++; + continue; + } + if (in[0] == '@') + { + *out++ = '"'; + in++; + continue; + } + *out++ = *in++; + } + *out = 0; +} + + + +void RunBsp (char *command) +{ + char sys[1024]; + char batpath[1024]; + char outputpath[1024]; + char temppath[512]; + char name[1024]; + FILE *hFile; + BOOL ret; + PROCESS_INFORMATION ProcessInformation; + STARTUPINFO startupinfo; + + SetInspectorMode (W_CONSOLE); + + if (bsp_process) + { + Sys_Printf ("BSP is still going...\n"); + return; + } + + GetTempPath(512, temppath); + sprintf (outputpath, "%sjunk.txt", temppath); + + strcpy (name, currentmap); + if (region_active) + { + Map_SaveFile (name, false); + StripExtension (name); + strcat (name, ".reg"); + } + + Map_SaveFile (name, region_active); + + + QE_ExpandBspString (command, sys, name); + + Sys_ClearPrintf (); + Sys_Printf ("======================================\nRunning bsp command...\n"); + Sys_Printf ("\n%s\n", sys); + + // + // write qe3bsp.bat + // + sprintf (batpath, "%sqe3bsp.bat", temppath); + hFile = fopen(batpath, "w"); + if (!hFile) + Error ("Can't write to %s", batpath); + fprintf (hFile, sys); + fclose (hFile); + + // + // write qe3bsp2.bat + // + sprintf (batpath, "%sqe3bsp2.bat", temppath); + hFile = fopen(batpath, "w"); + if (!hFile) + Error ("Can't write to %s", batpath); + fprintf (hFile, "%sqe3bsp.bat > %s", temppath, outputpath); + fclose (hFile); + + Pointfile_Delete (); + + GetStartupInfo (&startupinfo); + + ret = CreateProcess( + batpath, // pointer to name of executable module + NULL, // pointer to command line string + NULL, // pointer to process security attributes + NULL, // pointer to thread security attributes + FALSE, // handle inheritance flag + 0 /*DETACHED_PROCESS*/, // creation flags + NULL, // pointer to new environment block + NULL, // pointer to current directory name + &startupinfo, // pointer to STARTUPINFO + &ProcessInformation // pointer to PROCESS_INFORMATION + ); + + if (!ret) + Error ("CreateProcess failed"); + + bsp_process = ProcessInformation.hProcess; + + Sleep (100); // give the new process a chance to open it's window + + BringWindowToTop( g_qeglobals.d_hwndMain ); // pop us back on top + SetFocus (g_qeglobals.d_hwndCamera); +} + +/* +============= +DoColor + +============= +*/ +qboolean DoColor(int iIndex) +{ + CHOOSECOLOR cc; + static COLORREF custom[16]; + + cc.lStructSize = sizeof(cc); + cc.hwndOwner = g_qeglobals.d_hwndMain; + //cc.hInstance = g_qeglobals.d_hInstance; + cc.rgbResult = GetEntityColor(iIndex); + cc.lpCustColors = custom; + cc.Flags = CC_FULLOPEN|CC_RGBINIT; + //cc.lCustData; + //cc.lpfnHook; + //cc.lpTemplateName + + if (!ChooseColor(&cc)) + return false; + + g_qeglobals.d_savedinfo.colors[iIndex][0] = (cc.rgbResult&255)/255.0; + g_qeglobals.d_savedinfo.colors[iIndex][1] = ((cc.rgbResult>>8)&255)/255.0; + g_qeglobals.d_savedinfo.colors[iIndex][2] = ((cc.rgbResult>>16)&255)/255.0; + + /* + ** scale colors so that at least one component is at 1.0F + ** if this is meant to select an entity color + */ + if ( iIndex == COLOR_ENTITY ) + { + float largest = 0.0F; + + if ( g_qeglobals.d_savedinfo.colors[iIndex][0] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][0]; + if ( g_qeglobals.d_savedinfo.colors[iIndex][1] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][1]; + if ( g_qeglobals.d_savedinfo.colors[iIndex][2] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][2]; + + if ( largest == 0.0F ) + { + g_qeglobals.d_savedinfo.colors[iIndex][0] = 1.0F; + g_qeglobals.d_savedinfo.colors[iIndex][1] = 1.0F; + g_qeglobals.d_savedinfo.colors[iIndex][2] = 1.0F; + } + else + { + float scaler = 1.0F / largest; + + g_qeglobals.d_savedinfo.colors[iIndex][0] *= scaler; + g_qeglobals.d_savedinfo.colors[iIndex][1] *= scaler; + g_qeglobals.d_savedinfo.colors[iIndex][2] *= scaler; + } + } + + Sys_UpdateWindows (W_ALL); + + return true; +} + + +/* Copied from MSDN */ + +BOOL DoMru(HWND hWnd,WORD wId) +{ + char szFileName[128]; + OFSTRUCT of; + BOOL fExist; + + GetMenuItem(g_qeglobals.d_lpMruMenu, wId, TRUE, szFileName, sizeof(szFileName)); + + // Test if the file exists. + + fExist = OpenFile(szFileName ,&of,OF_EXIST) != HFILE_ERROR; + + if (fExist) { + + // Place the file on the top of MRU. + AddNewItem(g_qeglobals.d_lpMruMenu,(LPSTR)szFileName); + + // Now perform opening this file !!! + Map_LoadFile (szFileName); + } + else + // Remove the file on MRU. + DelMenuItem(g_qeglobals.d_lpMruMenu,wId,TRUE); + + // Refresh the File menu. + PlaceMenuMRUItem(g_qeglobals.d_lpMruMenu,GetSubMenu(GetMenu(hWnd),0), + ID_FILE_EXIT); + + return fExist; +} + + +/* handle all WM_COMMAND messages here */ +LONG WINAPI CommandHandler ( + HWND hWnd, + WPARAM wParam, + LPARAM lParam) +{ + HMENU hMenu; + + switch (LOWORD(wParam)) + { +// +// file menu +// + case ID_FILE_EXIT: + /* exit application */ + if (!ConfirmModified()) + return TRUE; + + PostMessage (hWnd, WM_CLOSE, 0, 0L); + break; + + case ID_FILE_OPEN: + if (!ConfirmModified()) + return TRUE; + OpenDialog (); + WriteUserLog("Menu: Open"); + break; + + case ID_FILE_NEW: + if (!ConfirmModified()) + return TRUE; + Map_New (); + break; + case ID_FILE_SAVE: + if (!strcmp(currentmap, "unnamed.map")) + SaveAsDialog (); + else + Map_SaveFile (currentmap, false); // ignore region + break; + case ID_FILE_SAVEAS: + SaveAsDialog (); + break; + + case ID_FILE_LOADPROJECT: + if (!ConfirmModified()) + return TRUE; + ProjectDialog (); + break; + + case ID_FILE_POINTFILE: + if (g_qeglobals.d_pointfile_display_list) + Pointfile_Clear (); + else + Pointfile_Check (); + break; + + case ID_FILE_PRINT_CONSOLE: + PrintConsole(); + break; + +// +// edit menu +// + case ID_EDIT_UNDO: + UNDO_DoUndo (hWnd); + break; + case ID_EDIT_REDO: + MessageBox (hWnd, "Trust me, you don't want this option", "NO", MB_OK); + break; + +// +// view menu +// + case ID_VIEW_ENTITY: + SetInspectorMode(W_ENTITY); + break; + case ID_VIEW_CONSOLE: + SetInspectorMode(W_CONSOLE); + break; + case ID_VIEW_TEXTURE: + SetInspectorMode(W_TEXTURE); + break; + + case ID_VIEW_100: + g_qeglobals.d_xy.scale = 1; + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); + break; + case ID_VIEW_ZOOMIN: + g_qeglobals.d_xy.scale *= 5.0/4; + if (g_qeglobals.d_xy.scale > 16) + g_qeglobals.d_xy.scale = 16; + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); + break; + case ID_VIEW_ZOOMOUT: + g_qeglobals.d_xy.scale *= 4.0/5; + if (g_qeglobals.d_xy.scale < 0.1) + g_qeglobals.d_xy.scale = 0.1; + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); + break; + + case ID_VIEW_Z100: + z.scale = 1; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); + break; + case ID_VIEW_ZZOOMIN: + z.scale *= 5.0/4; + if (z.scale > 4) + z.scale = 4; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); + break; + case ID_VIEW_ZZOOMOUT: + z.scale *= 4.0/5; + if (z.scale < 0.125) + z.scale = 0.125; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); + break; + + case ID_VIEW_CENTER: + camera.angles[ROLL] = camera.angles[PITCH] = 0; + camera.angles[YAW] = 22.5 * + floor( (camera.angles[YAW]+11)/22.5 ); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + + case ID_VIEW_UPFLOOR: + Cam_ChangeFloor (true); + break; + case ID_VIEW_DOWNFLOOR: + Cam_ChangeFloor (false); + break; + + case ID_VIEW_SHOWNAMES: + g_qeglobals.d_savedinfo.show_names = !g_qeglobals.d_savedinfo.show_names; + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWNAMES, MF_BYCOMMAND | (g_qeglobals.d_savedinfo.show_names ? MF_CHECKED : MF_UNCHECKED) ); + Map_BuildBrushData(false); + Sys_UpdateWindows (W_XY); + break; + + case ID_VIEW_SHOWCOORDINATES: + g_qeglobals.d_savedinfo.show_coordinates ^= 1; + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWCOORDINATES, MF_BYCOMMAND | (g_qeglobals.d_savedinfo.show_coordinates ? MF_CHECKED : MF_UNCHECKED) ); + Sys_UpdateWindows (W_XY); + break; + + case ID_VIEW_SHOWBLOCKS: + g_qeglobals.show_blocks ^= 1; + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWBLOCKS, MF_BYCOMMAND | (g_qeglobals.show_blocks ? MF_CHECKED : MF_UNCHECKED) ); + Sys_UpdateWindows (W_XY); + break; + + case ID_VIEW_SHOWLIGHTS: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIGHTS ) & EXCLUDE_LIGHTS ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWPATH: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_PATHS ) & EXCLUDE_PATHS ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWENT: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_ENT ) & EXCLUDE_ENT ) + CheckMenuItem( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_UNCHECKED); + else + { + CheckMenuItem( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_CHECKED); + if ( g_qeglobals.d_savedinfo.exclude & BUOY_ONLY) + { + g_qeglobals.d_savedinfo.exclude ^= BUOY_ONLY; + CheckMenuItem( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWBUOYONLY, MF_BYCOMMAND | MF_UNCHECKED); + } + } + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWWATER: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_WATER ) & EXCLUDE_WATER ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWCLIP: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CLIP ) & EXCLUDE_CLIP ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWDETAIL: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_DETAIL ) & EXCLUDE_DETAIL ) + { + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWDETAIL, MF_BYCOMMAND | MF_UNCHECKED ); + SetWindowText (g_qeglobals.d_hwndCamera, "Camera View (DETAIL EXCLUDED)"); + } + else + { + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWDETAIL, MF_BYCOMMAND | MF_CHECKED ); + SetWindowText (g_qeglobals.d_hwndCamera, "Camera View"); + } + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWWORLD: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_WORLD ) & EXCLUDE_WORLD ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWBUOYONLY: + if ( ( g_qeglobals.d_savedinfo.exclude ^= BUOY_ONLY ) & BUOY_ONLY ) + { + CheckMenuItem( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWBUOYONLY, MF_BYCOMMAND | MF_CHECKED); + if (!( g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT)) + { + g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_ENT; + CheckMenuItem( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_UNCHECKED); + } + } + else + { + CheckMenuItem( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWBUOYONLY, MF_BYCOMMAND | MF_UNCHECKED); + } + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + +// +// grid menu +// + case ID_GRID_1: + case ID_GRID_2: + case ID_GRID_4: + case ID_GRID_8: + case ID_GRID_16: + case ID_GRID_32: + case ID_GRID_64: + { + hMenu = GetMenu(hWnd); + + CheckMenuItem(hMenu, ID_GRID_1, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_2, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_4, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_8, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_16, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_32, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_64, MF_BYCOMMAND | MF_UNCHECKED); + + switch (LOWORD(wParam)) + { + case ID_GRID_1: g_qeglobals.d_gridsize = 0; break; + case ID_GRID_2: g_qeglobals.d_gridsize = 1; break; + case ID_GRID_4: g_qeglobals.d_gridsize = 2; break; + case ID_GRID_8: g_qeglobals.d_gridsize = 3; break; + case ID_GRID_16: g_qeglobals.d_gridsize = 4; break; + case ID_GRID_32: g_qeglobals.d_gridsize = 5; break; + case ID_GRID_64: g_qeglobals.d_gridsize = 6; break; + } + g_qeglobals.d_gridsize = 1 << g_qeglobals.d_gridsize; + + CheckMenuItem(hMenu, LOWORD(wParam), MF_BYCOMMAND | MF_CHECKED); + Sys_UpdateWindows (W_XY|W_Z); + break; + } + +// +// texture menu +// + case ID_VIEW_NEAREST: + case ID_VIEW_NEARESTMIPMAP: + case ID_VIEW_LINEAR: + case ID_VIEW_BILINEAR: + case ID_VIEW_BILINEARMIPMAP: + case ID_VIEW_TRILINEAR: + case ID_TEXTURES_WIREFRAME: + case ID_TEXTURES_FLATSHADE: + Texture_SetMode (LOWORD(wParam)); + break; + + case ID_TEXTURES_SHOWINUSE: + Sys_BeginWait (); + Texture_ShowInuse (); + SetInspectorMode(W_TEXTURE); + break; + + case ID_TEXTURES_INSPECTOR: + DoSurface (); + break; + + case CMD_TEXTUREWAD: + case CMD_TEXTUREWAD+1: + case CMD_TEXTUREWAD+2: + case CMD_TEXTUREWAD+3: + case CMD_TEXTUREWAD+4: + case CMD_TEXTUREWAD+5: + case CMD_TEXTUREWAD+6: + case CMD_TEXTUREWAD+7: + case CMD_TEXTUREWAD+8: + case CMD_TEXTUREWAD+9: + case CMD_TEXTUREWAD+10: + case CMD_TEXTUREWAD+11: + case CMD_TEXTUREWAD+12: + case CMD_TEXTUREWAD+13: + case CMD_TEXTUREWAD+14: + case CMD_TEXTUREWAD+15: + case CMD_TEXTUREWAD+16: + case CMD_TEXTUREWAD+17: + case CMD_TEXTUREWAD+18: + case CMD_TEXTUREWAD+19: + case CMD_TEXTUREWAD+20: + case CMD_TEXTUREWAD+21: + case CMD_TEXTUREWAD+22: + case CMD_TEXTUREWAD+23: + case CMD_TEXTUREWAD+24: + case CMD_TEXTUREWAD+25: + case CMD_TEXTUREWAD+26: + case CMD_TEXTUREWAD+27: + case CMD_TEXTUREWAD+28: + case CMD_TEXTUREWAD+29: + case CMD_TEXTUREWAD+30: + case CMD_TEXTUREWAD+31: + Sys_BeginWait (); + Texture_ShowDirectory (LOWORD(wParam)); + SetInspectorMode(W_TEXTURE); + break; + +// +// bsp menu +// + case CMD_BSPCOMMAND: + case CMD_BSPCOMMAND+1: + case CMD_BSPCOMMAND+2: + case CMD_BSPCOMMAND+3: + case CMD_BSPCOMMAND+4: + case CMD_BSPCOMMAND+5: + case CMD_BSPCOMMAND+6: + case CMD_BSPCOMMAND+7: + case CMD_BSPCOMMAND+8: + case CMD_BSPCOMMAND+9: + case CMD_BSPCOMMAND+10: + case CMD_BSPCOMMAND+11: + case CMD_BSPCOMMAND+12: + case CMD_BSPCOMMAND+13: + case CMD_BSPCOMMAND+14: + case CMD_BSPCOMMAND+15: + case CMD_BSPCOMMAND+16: + case CMD_BSPCOMMAND+17: + case CMD_BSPCOMMAND+18: + case CMD_BSPCOMMAND+19: + case CMD_BSPCOMMAND+20: + case CMD_BSPCOMMAND+21: + case CMD_BSPCOMMAND+22: + case CMD_BSPCOMMAND+23: + case CMD_BSPCOMMAND+24: + case CMD_BSPCOMMAND+25: + case CMD_BSPCOMMAND+26: + case CMD_BSPCOMMAND+27: + case CMD_BSPCOMMAND+28: + case CMD_BSPCOMMAND+29: + case CMD_BSPCOMMAND+30: + case CMD_BSPCOMMAND+31: + { + extern char *bsp_commands[256]; + +// RunBsp (bsp_commands[LOWORD(wParam-CMD_BSPCOMMAND)]); + bsp_StartBsp (bsp_commands[LOWORD(wParam-CMD_BSPCOMMAND)]); + } + break; + +// +// misc menu +// + case ID_MISC_BENCHMARK: + SendMessage ( g_qeglobals.d_hwndCamera, + WM_USER+267, 0, 0); + break; + + case ID_TEXTUREBK: + DoColor(COLOR_TEXTUREBACK); + Sys_UpdateWindows (W_ALL); + break; + + case ID_MISC_SELECTENTITYCOLOR: + { + extern int inspector_mode; + + if ( ( inspector_mode == W_ENTITY ) && DoColor(COLOR_ENTITY) == true ) + { + extern void AddProp( void ); + + char buffer[100]; + + sprintf( buffer, "%f %f %f", g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][0], + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][1], + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][2] ); + + SetWindowText( hwndEnt[EntValueField], buffer ); + SetWindowText( hwndEnt[EntKeyField], ENTKEY_COLOR ); + AddProp(); + } + Sys_UpdateWindows( W_ALL ); + } + break; + + case ID_MISC_PRINTXY: + WXY_Print(); + break; + + case ID_COLORS_XYBK: + DoColor(COLOR_GRIDBACK); + Sys_UpdateWindows (W_ALL); + break; + + case ID_COLORS_MAJOR: + DoColor(COLOR_GRIDMAJOR); + Sys_UpdateWindows (W_ALL); + break; + + case ID_COLORS_MINOR: + DoColor(COLOR_GRIDMINOR); + Sys_UpdateWindows (W_ALL); + break; + + case ID_MISC_GAMMA: + DoGamma(); + break; + + case ID_MISC_SETMAXVIEWDISTANCE: + DoSetMaxViewDist(); + break; + + case ID_MISC_DEFAULTTEXTURES: + DoDefaultTextures(); + break; + + case ID_MISC_FINDBRUSH: + DoFind(); + break; + + case ID_MISC_REPLACETEXTURE: + DoTextureReplace(); + break; + + case ID_MISC_NEXTLEAKSPOT: + Pointfile_Next(); + break; + case ID_MISC_PREVIOUSLEAKSPOT: + Pointfile_Prev(); + break; + +// +// brush menu +// + case ID_BRUSH_3SIDED: + UNDO_StartBrushEdit("&Undo 3side"); + Brush_MakeSided (3); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_3SNAP: + UNDO_StartBrushEdit("&Undo 3side Snap"); + Brush_MakeSided_Snap (3); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_4SIDED: + UNDO_StartBrushEdit("&Undo 4side"); + Brush_MakeSided (4); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_4SNAP: + UNDO_StartBrushEdit("&Undo 4side Snap"); + Brush_MakeSided_Snap (4); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_5SIDED: + UNDO_StartBrushEdit("&Undo 5side"); + Brush_MakeSided (5); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_5SNAP: + UNDO_StartBrushEdit("&Undo 5side Snap"); + Brush_MakeSided_Snap (5); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_6SIDED: + UNDO_StartBrushEdit("&Undo 6side"); + Brush_MakeSided (6); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_6SNAP: + UNDO_StartBrushEdit("&Undo 6side Snap"); + Brush_MakeSided_Snap (6); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_7SIDED: + UNDO_StartBrushEdit("&Undo 7side"); + Brush_MakeSided (7); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_7SNAP: + UNDO_StartBrushEdit("&Undo 7side Snap"); + Brush_MakeSided_Snap (7); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_8SIDED: + UNDO_StartBrushEdit("&Undo 8side"); + Brush_MakeSided (8); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_8SNAP: + UNDO_StartBrushEdit("&Undo 8side Snap"); + Brush_MakeSided_Snap (8); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_9SIDED: + UNDO_StartBrushEdit("&Undo 9side"); + Brush_MakeSided (9); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_9SNAP: + UNDO_StartBrushEdit("&Undo 9side Snap"); + Brush_MakeSided_Snap (9); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_ARBITRARYSIDED: + DoSides (); + break; + +// +// select menu +// + case ID_BRUSH_FLIPX: + UNDO_StartBrushEdit ("&Undo FlipX"); + Select_FlipAxis (0); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_FLIPY: + UNDO_StartBrushEdit ("&Undo FlipY"); + Select_FlipAxis (1); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_FLIPZ: + UNDO_StartBrushEdit ("&Undo FlipZ"); + Select_FlipAxis (2); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_ROTATEX: + UNDO_StartBrushEdit ("&Undo RotateX"); + Select_RotateAxis (0, 90); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_ROTATEY: + UNDO_StartBrushEdit ("&Undo RotateY"); + Select_RotateAxis (1, 90); + UNDO_FinishBrushEdit (NULL); + break; + case ID_BRUSH_ROTATEZ: + UNDO_StartBrushEdit ("&Undo RotateZ"); + Select_RotateAxis (2, 90); + UNDO_FinishBrushEdit (NULL); + break; + + case ID_SELECTION_ARBITRARYROTATION: + DoRotate (); + break; + + case ID_SELECTION_UNGROUPENTITY: + Select_Ungroup (); + break; + + case ID_SELECTION_CONNECT: + ConnectEntities (); + break; + + case ID_SELECTION_DRAGVERTECIES: + if (g_qeglobals.d_select_mode == sel_vertex) + { + g_qeglobals.d_select_mode = sel_brush; + Sys_UpdateWindows (W_ALL); + } + else + { + SetupVertexSelection (); + if (g_qeglobals.d_numpoints) + g_qeglobals.d_select_mode = sel_vertex; + } + break; + case ID_SELECTION_DRAGEDGES: + if (g_qeglobals.d_select_mode == sel_edge) + { + g_qeglobals.d_select_mode = sel_brush; + Sys_UpdateWindows (W_ALL); + } + else + { + SetupVertexSelection (); + if (g_qeglobals.d_numpoints) + g_qeglobals.d_select_mode = sel_edge; + } + break; + case ID_SELECTION_SELECTPARTIALTALL: + Select_PartialTall (); + break; + case ID_SELECTION_SELECTCOMPLETETALL: + Select_CompleteTall (); + break; + case ID_SELECTION_SELECTTOUCHING: + Select_Touching (); + break; + case ID_SELECTION_SELECTINSIDE: + Select_Inside (); + break; + case ID_SELECTION_CSGSUBTRACT: + CSG_Subtract (); + break; + case ID_SELECTION_MAKEHOLLOW: + CSG_MakeHollow (); + break; + + case ID_SELECTION_CLONE: + Select_Clone (); + break; + case ID_SELECTION_DELETE: + Select_Delete (TRUE); + break; + case ID_SELECTION_DESELECT: + Select_Deselect (); + break; + + case ID_SELECTION_MAKE_DETAIL: + Select_MakeDetail (); + break; + case ID_SELECTION_MAKE_STRUCTURAL: + Select_MakeStructural (); + break; + + case ID_SELECTION_SCALE: + DoScale(); + break; + case ID_SELECTION_TOWER: + DoTower(); + break; + +// +// region menu +// + case ID_REGION_OFF: + Map_RegionOff (); + break; + case ID_REGION_SETXY: + Map_RegionXY (); + break; + case ID_REGION_SETTALLBRUSH: + Map_RegionTallBrush (); + break; + case ID_REGION_SETBRUSH: + Map_RegionBrush (); + break; + case ID_REGION_SETSELECTION: + Map_RegionSelectedBrushes (); + break; + + case IDMRU+1: + case IDMRU+2: + case IDMRU+3: + case IDMRU+4: + case IDMRU+5: + case IDMRU+6: + case IDMRU+7: + case IDMRU+8: + case IDMRU+9: + DoMru(hWnd,LOWORD(wParam)); + break; + +// LIST TEXTURES IN USE + + case ID_TEXTURE_LISTINUSE: + Texture_ListInUse(); + break; + + case ID_ENTITY_LISTINUSE: + Entity_ListInUse(); + break; + +// +// help menu +// + + case ID_HELP_ABOUT: + DoAbout(); + break; + + default: + return FALSE; + } + + return TRUE; +} + +/* +============ +WMAIN_WndProc +============ +*/ +LONG WINAPI WMAIN_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LONG lRet = 1; + RECT rect; + HDC maindc; + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + case WM_TIMER: + QE_CountBrushesAndUpdateStatusBar(); + QE_CheckAutoSave(); + return 0; + + case WM_DESTROY: + SaveMruInReg(g_qeglobals.d_lpMruMenu,"Software\\id\\QuakeEd4\\MRU"); + DeleteMruMenu(g_qeglobals.d_lpMruMenu); + PostQuitMessage(0); + KillTimer( hWnd, QE_TIMER0 ); + return 0; + + case WM_CREATE: + maindc = GetDC(hWnd); +// QEW_SetupPixelFormat(maindc, false); + g_qeglobals.d_lpMruMenu = CreateMruMenuDefault(); + LoadMruInReg(g_qeglobals.d_lpMruMenu,"Software\\id\\QuakeEd4\\MRU"); + + // Refresh the File menu. + PlaceMenuMRUItem(g_qeglobals.d_lpMruMenu,GetSubMenu(GetMenu(hWnd),0), + ID_FILE_EXIT); + + return 0; + + case WM_SIZE: + // resize the status window + MoveWindow( g_qeglobals.d_hwndStatus, -100, 100, 10, 10, true); + return 0; + + case WM_KEYDOWN: + return QE_KeyDown (wParam); + + case WM_CLOSE: + /* call destroy window to cleanup and go away */ + QE_ResetIdle(); + WriteUserLog("Closed QE4"); + SaveWindowState(g_qeglobals.d_hwndXY, "xywindow"); + SaveWindowState(g_qeglobals.d_hwndCamera, "camerawindow"); + SaveWindowState(g_qeglobals.d_hwndZ, "zwindow"); + SaveWindowState(g_qeglobals.d_hwndEntity, "EntityWindow"); + SaveWindowState(g_qeglobals.d_hwndMain, "mainwindow"); + + // FIXME: is this right? + SaveRegistryInfo("SavedInfo", &g_qeglobals.d_savedinfo, sizeof(g_qeglobals.d_savedinfo)); + DestroyWindow (hWnd); + return 0; + + case WM_COMMAND: + return CommandHandler (hWnd, wParam, lParam); + return 0; + + case WM_INITMENU: + switch (undobuffer.type) + { + HMENU hMenu; + case UNDO_NONE: + hMenu = GetMenu(hWnd); + ModifyMenu(hMenu, ID_EDIT_UNDO, MF_BYCOMMAND | MFT_STRING, ID_EDIT_UNDO, + "Can't Undo"); + EnableMenuItem(hMenu, ID_EDIT_UNDO, MFS_DISABLED); + break; + case UNDO_BUSY: + hMenu = GetMenu(hWnd); + ModifyMenu(hMenu, ID_EDIT_UNDO, MF_BYCOMMAND | MFT_STRING, ID_EDIT_UNDO, + "&Undo Busy - ERROR"); + EnableMenuItem(hMenu, ID_EDIT_UNDO, MFS_DISABLED); + break; + case UNDO_NEWBRUSH: + case UNDO_EDITBRUSH: + case UNDO_DELETEBRUSH: + case UNDO_SUBTRACT: + hMenu = GetMenu(hWnd); + ModifyMenu(hMenu, ID_EDIT_UNDO, MF_BYCOMMAND | MFT_STRING, ID_EDIT_UNDO, + undobuffer.title); + EnableMenuItem(hMenu, ID_EDIT_UNDO, MFS_ENABLED); + break; + default: + hMenu = GetMenu(hWnd); + ModifyMenu(hMenu, ID_EDIT_UNDO, MF_BYCOMMAND | MFT_STRING, ID_EDIT_UNDO, + "Invalid State - ERROR"); + EnableMenuItem(hMenu, ID_EDIT_UNDO, MFS_DISABLED); + break; + + } + // REDO will be enabled someday as well + break; + + case WM_MOUSEWHEEL:// this Should be the message i get (and where i get it) in newest nt + if (inspector_mode == W_ENTITY) + { + if ((short)HIWORD(wParam) > 0) + { + PostMessage (hwndEnt[EntList], WM_VSCROLL, SB_LINEUP, lParam); + } + else + { + PostMessage (hwndEnt[EntList], WM_VSCROLL, SB_LINEDOWN, lParam); + } + } + else if (inspector_mode == W_TEXTURE) // i Believe this is ent window too, but it doesn't have to be, so stick with hwndTexture glob + { + PostMessage (g_qeglobals.d_hwndTexture, g_qeglobals.uMSH_MOUSEWHEEL, (short)HIWORD(wParam), lParam); + } + else //console uses entity window + { + if ((short)HIWORD(wParam) > 0) + { + PostMessage (g_qeglobals.d_hwndEdit, WM_VSCROLL, SB_LINEUP, lParam); + } + else + { + PostMessage (g_qeglobals.d_hwndEdit, WM_VSCROLL, SB_LINEDOWN, lParam); + } + } + return 0; + + default://parent window gets mousewheel message in win95 & early nt--pass it on + if (uMsg == g_qeglobals.uMSH_MOUSEWHEEL) + { + if (inspector_mode == W_ENTITY) + { + if (*(int *)&wParam > 0) + { + PostMessage (hwndEnt[EntList], WM_VSCROLL, SB_LINEUP, lParam); + } + else + { + PostMessage (hwndEnt[EntList], WM_VSCROLL, SB_LINEDOWN, lParam); + } + } + else if (inspector_mode == W_TEXTURE) // i Believe this is ent window too, but it doesn't have to be, so stick with hwndTexture glob + { + PostMessage (g_qeglobals.d_hwndTexture, g_qeglobals.uMSH_MOUSEWHEEL, (short)LOWORD(wParam), lParam); + } + else //console uses entity window + { + if (*(int *)&wParam > 0) + { + PostMessage (g_qeglobals.d_hwndEdit, WM_VSCROLL, SB_LINEUP, lParam); + } + else + { + PostMessage (g_qeglobals.d_hwndEdit, WM_VSCROLL, SB_LINEDOWN, lParam); + } + } + return 0; + } + break; + } + + return DefWindowProc (hWnd, uMsg, wParam, lParam); +} + + + + +/* +============== +Main_Create +============== +*/ +void Main_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + int i; + HMENU hMenu; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)WMAIN_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); + wc.lpszClassName = "QUAKE_MAIN"; + + if (!RegisterClass (&wc) ) + Error ("WCam_Register: failed"); + + + g_qeglobals.d_hwndMain = CreateWindow ("QUAKE_MAIN" , + "QuakeEd 3", + WS_OVERLAPPEDWINDOW | + WS_CLIPSIBLINGS | + WS_CLIPCHILDREN, + 0,0,screen_width,screen_height+GetSystemMetrics(SM_CYSIZE), // size + 0, + 0, // no menu + hInstance, + NULL); + if (!g_qeglobals.d_hwndMain) + Error ("Couldn't create main window"); + + /* create a timer so that we can count brushes */ + SetTimer( g_qeglobals.d_hwndMain, + QE_TIMER0, + 1000, + NULL ); + + LoadWindowState(g_qeglobals.d_hwndMain, "mainwindow"); + + s_hwndToolbar = CreateToolBar(hInstance); + + g_qeglobals.d_hwndStatus = CreateMyStatusWindow(hInstance); + + // + // load misc info from registry + // + i = sizeof(g_qeglobals.d_savedinfo); + LoadRegistryInfo("SavedInfo", &g_qeglobals.d_savedinfo, &i); + + if (g_qeglobals.d_savedinfo.iSize != sizeof(g_qeglobals.d_savedinfo)) + { + // fill in new defaults + + g_qeglobals.d_savedinfo.iSize = sizeof(g_qeglobals.d_savedinfo); + g_qeglobals.d_savedinfo.fGamma = 1.0; + g_qeglobals.d_savedinfo.iTexMenu = ID_VIEW_NEAREST; + + g_qeglobals.d_savedinfo.exclude = 0; + g_qeglobals.d_savedinfo.show_coordinates = true; + g_qeglobals.d_savedinfo.show_names = true; + + for (i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 1.0; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.75; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.5; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25; + } + } + + if ( ( hMenu = GetMenu( g_qeglobals.d_hwndMain ) ) != 0 ) + { + /* + ** by default all of these are checked because that's how they're defined in the menu editor + */ + if ( !g_qeglobals.d_savedinfo.show_names ) + CheckMenuItem( hMenu, ID_VIEW_SHOWNAMES, MF_BYCOMMAND | MF_UNCHECKED ); + if ( !g_qeglobals.d_savedinfo.show_coordinates ) + CheckMenuItem( hMenu, ID_VIEW_SHOWCOORDINATES, MF_BYCOMMAND | MF_UNCHECKED ); + + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS ) + CheckMenuItem( hMenu, ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT ) + CheckMenuItem( hMenu, ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS ) + CheckMenuItem( hMenu, ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_WATER ) + CheckMenuItem( hMenu, ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD ) + CheckMenuItem( hMenu, ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP ) + CheckMenuItem( hMenu, ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & BUOY_ONLY ) + { + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS ) + { + CheckMenuItem( hMenu, ID_VIEW_SHOWBUOYONLY, MF_BYCOMMAND | MF_CHECKED ); + } + else + { + g_qeglobals.d_savedinfo.exclude ^= BUOY_ONLY; + CheckMenuItem( hMenu, ID_VIEW_SHOWBUOYONLY, MF_BYCOMMAND | MF_UNCHECKED ); + } + } + } + + ShowWindow (g_qeglobals.d_hwndMain, SW_SHOWDEFAULT); +} + + +/* +============================================================= + +REGISTRY INFO + +============================================================= +*/ + +BOOL SaveRegistryInfo(const char *pszName, void *pvBuf, long lSize) +{ + LONG lres; + DWORD dwDisp; + HKEY hKeyId; + + lres = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\id\\QuakeEd4", 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyId, &dwDisp); + + if (lres != ERROR_SUCCESS) + return FALSE; + + lres = RegSetValueEx(hKeyId, pszName, 0, REG_BINARY, pvBuf, lSize); + + RegCloseKey(hKeyId); + + if (lres != ERROR_SUCCESS) + return FALSE; + + return TRUE; +} + +BOOL LoadRegistryInfo(const char *pszName, void *pvBuf, long *plSize) +{ + HKEY hKey; + long lres, lType, lSize; + + if (plSize == NULL) + plSize = &lSize; + + lres = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\id\\QuakeEd4", 0, KEY_READ, &hKey); + + if (lres != ERROR_SUCCESS) + return FALSE; + + lres = RegQueryValueEx(hKey, pszName, NULL, &lType, pvBuf, plSize); + + RegCloseKey(hKey); + + if (lres != ERROR_SUCCESS) + return FALSE; + + return TRUE; +} + +BOOL SaveWindowState(HWND hWnd, const char *pszName) +{ + RECT rc; + + GetWindowRect(hWnd, &rc); + if (hWnd != g_qeglobals.d_hwndMain) + MapWindowPoints(NULL, g_qeglobals.d_hwndMain, (POINT *)&rc, 2); + return SaveRegistryInfo(pszName, &rc, sizeof(rc)); +} + + +BOOL LoadWindowState(HWND hWnd, const char *pszName) +{ + RECT rc; + LONG lSize = sizeof(rc); + + if (LoadRegistryInfo(pszName, &rc, &lSize)) + { + if (rc.left < 0) + rc.left = 0; + if (rc.top < 0) + rc.top = 0; + if (rc.right < rc.left + 16) + rc.right = rc.left + 16; + if (rc.bottom < rc.top + 16) + rc.bottom = rc.top + 16; + + MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top, FALSE); + return TRUE; + } + + return FALSE; +} + +/* +=============================================================== + + STATUS WINDOW + +=============================================================== +*/ + +void Sys_UpdateStatusBar( void ) +{ + extern int g_numbrushes, g_numentities; + + char numbrushbuffer[100]=""; + + sprintf( numbrushbuffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities ); + + Sys_Status( numbrushbuffer, 2 ); +} + +void Sys_Status(const char *psz, int part ) +{ + SendMessage(g_qeglobals.d_hwndStatus, SB_SETTEXT, part, (LPARAM)psz); +} + +static HWND CreateMyStatusWindow(HINSTANCE hInst) +{ + HWND hWnd; + int partsize[3] = { 300, 1100, -1 }; + + hWnd = CreateWindowEx( WS_EX_TOPMOST, // no extended styles + STATUSCLASSNAME, // status bar + "", // no text + WS_CHILD | WS_BORDER | WS_VISIBLE, // styles + -100, -100, 10, 10, // x, y, cx, cy + g_qeglobals.d_hwndMain, // parent window + (HMENU)100, // window ID + hInst, // instance + NULL); // window data + + SendMessage( hWnd, SB_SETPARTS, 3, ( long ) partsize ); + + return hWnd; +} + +//============================================================== + +#define NUMBUTTONS 21 +HWND CreateToolBar(HINSTANCE hinst) +{ + HWND hwndTB; + TBADDBITMAP tbab; + TBBUTTON tbb[NUMBUTTONS]; + + // Ensure that the common control DLL is loaded. + + InitCommonControls(); + + // Create a toolbar that the user can customize and that has a + // tooltip associated with it. + + hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, (LPSTR) NULL, + WS_CHILD | TBSTYLE_TOOLTIPS | CCS_ADJUSTABLE | WS_BORDER, + 0, 0, 0, 0, g_qeglobals.d_hwndMain, (HMENU) IDR_TOOLBAR1, hinst, NULL); + + // Send the TB_BUTTONSTRUCTSIZE message, which is required for + // backward compatibility. + + SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0); + + // Add the bitmap containing button images to the toolbar. + + tbab.hInst = hinst; + tbab.nID = IDR_TOOLBAR1; + SendMessage(hwndTB, TB_ADDBITMAP, (WPARAM)NUMBUTTONS, (WPARAM) &tbab); + + // Fill the TBBUTTON array with button information, and add the + // buttons to the toolbar. + + tbb[0].iBitmap = 0; + tbb[0].idCommand = ID_BRUSH_FLIPX; + tbb[0].fsState = TBSTATE_ENABLED; + tbb[0].fsStyle = TBSTYLE_BUTTON; + tbb[0].dwData = 0; + tbb[0].iString = 0; + + tbb[1].iBitmap = 2; + tbb[1].idCommand = ID_BRUSH_FLIPY; + tbb[1].fsState = TBSTATE_ENABLED; + tbb[1].fsStyle = TBSTYLE_BUTTON; + tbb[1].dwData = 0; + tbb[1].iString = 0; + + tbb[2].iBitmap = 4; + tbb[2].idCommand = ID_BRUSH_FLIPZ; + tbb[2].fsState = TBSTATE_ENABLED; + tbb[2].fsStyle = TBSTYLE_BUTTON; + tbb[2].dwData = 0; + tbb[2].iString = 0; + + tbb[3].iBitmap = 1; + tbb[3].idCommand = ID_BRUSH_ROTATEX; + tbb[3].fsState = TBSTATE_ENABLED; + tbb[3].fsStyle = TBSTYLE_BUTTON; + tbb[3].dwData = 0; + tbb[3].iString = 0; + + tbb[4].iBitmap = 3; + tbb[4].idCommand = ID_BRUSH_ROTATEY; + tbb[4].fsState = TBSTATE_ENABLED; + tbb[4].fsStyle = TBSTYLE_BUTTON; + tbb[4].dwData = 0; + tbb[4].iString = 0; + + tbb[5].iBitmap = 5; + tbb[5].idCommand = ID_BRUSH_ROTATEZ; + tbb[5].fsState = TBSTATE_ENABLED; + tbb[5].fsStyle = TBSTYLE_BUTTON; + tbb[5].dwData = 0; + tbb[5].iString = 0; + + tbb[6].iBitmap = 6; + tbb[6].idCommand = ID_SELECTION_SCALE; + tbb[6].fsState = TBSTATE_ENABLED; + tbb[6].fsStyle = TBSTYLE_BUTTON; + tbb[6].dwData = 0; + tbb[6].iString = 0; + + tbb[7].iBitmap = 7; + tbb[7].idCommand = ID_SELECTION_SELECTCOMPLETETALL; + tbb[7].fsState = TBSTATE_ENABLED; + tbb[7].fsStyle = TBSTYLE_BUTTON; + tbb[7].dwData = 0; + tbb[7].iString = 0; + + tbb[8].iBitmap = 8; + tbb[8].idCommand = ID_SELECTION_SELECTTOUCHING; + tbb[8].fsState = TBSTATE_ENABLED; + tbb[8].fsStyle = TBSTYLE_BUTTON; + tbb[8].dwData = 0; + tbb[8].iString = 0; + + tbb[9].iBitmap = 9; + tbb[9].idCommand = ID_SELECTION_SELECTPARTIALTALL; + tbb[9].fsState = TBSTATE_ENABLED; + tbb[9].fsStyle = TBSTYLE_BUTTON; + tbb[9].dwData = 0; + tbb[9].iString = 0; + + + tbb[10].iBitmap = 10; + tbb[10].idCommand = ID_SELECTION_SELECTINSIDE; + tbb[10].fsState = TBSTATE_ENABLED; + tbb[10].fsStyle = TBSTYLE_BUTTON; + tbb[10].dwData = 0; + tbb[10].iString = 0; + + tbb[11].iBitmap = 11; + tbb[11].idCommand = ID_SELECTION_CSGSUBTRACT; + tbb[11].fsState = TBSTATE_ENABLED; + tbb[11].fsStyle = TBSTYLE_BUTTON; + tbb[11].dwData = 0; + tbb[11].iString = 0; + + + tbb[12].iBitmap = 12; + tbb[12].idCommand = ID_SELECTION_MAKEHOLLOW; + tbb[12].fsState = TBSTATE_ENABLED; + tbb[12].fsStyle = TBSTYLE_BUTTON; + tbb[12].dwData = 0; + tbb[12].iString = 0; + + tbb[13].iBitmap = 13; + tbb[13].idCommand = ID_TEXTURES_WIREFRAME; + tbb[13].fsState = TBSTATE_ENABLED; + tbb[13].fsStyle = TBSTYLE_BUTTON; + tbb[13].dwData = 0; + tbb[13].iString = 0; + + tbb[14].iBitmap = 14; + tbb[14].idCommand = ID_TEXTURES_FLATSHADE; + tbb[14].fsState = TBSTATE_ENABLED; + tbb[14].fsStyle = TBSTYLE_BUTTON; + tbb[14].dwData = 0; + tbb[14].iString = 0; + + tbb[15].iBitmap = 15; + tbb[15].idCommand = ID_VIEW_TRILINEAR; + tbb[15].fsState = TBSTATE_ENABLED; + tbb[15].fsStyle = TBSTYLE_BUTTON; + tbb[15].dwData = 0; + tbb[15].iString = 0; + + tbb[16].iBitmap = 0; + tbb[16].idCommand = 0; + tbb[16].fsState = 0; + tbb[16].fsStyle = TBSTYLE_SEP; + tbb[16].dwData = 0; + tbb[16].iString = 0; + + tbb[17].iBitmap = 16; + tbb[17].idCommand = ID_EDIT_UNDO; + tbb[17].fsState = 0; + tbb[17].fsStyle = TBSTYLE_BUTTON; + tbb[17].dwData = 0; + tbb[17].iString = 0; + + tbb[18].iBitmap = 0; + tbb[18].idCommand = 0; + tbb[18].fsState = 0; + tbb[18].fsStyle = TBSTYLE_SEP; + tbb[18].dwData = 0; + tbb[18].iString = 0; + + tbb[19].iBitmap = 17; + tbb[19].idCommand = ID_TEXTURE_LISTINUSE; + tbb[19].fsState = TBSTATE_ENABLED; + tbb[19].fsStyle = TBSTYLE_BUTTON; + tbb[19].dwData = 0; + tbb[19].iString = 0; + + tbb[20].iBitmap = 18; + tbb[20].idCommand = ID_ENTITY_LISTINUSE; + tbb[20].fsState = TBSTATE_ENABLED; + tbb[20].fsStyle = TBSTYLE_BUTTON; + tbb[20].dwData = 0; + tbb[20].iString = 0; + + + + SendMessage(hwndTB, TB_ADDBUTTONS, (WPARAM)NUMBUTTONS, + (LPARAM) (LPTBBUTTON) &tbb); + + ShowWindow(hwndTB, SW_SHOW); + + return hwndTB; +} + diff --git a/Toolkit/Programming/Tools/qe4/win_qe3.c b/Toolkit/Programming/Tools/qe4/win_qe3.c new file mode 100644 index 0000000..affb0ce --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/win_qe3.c @@ -0,0 +1,617 @@ +#include "qe3.h" +#include "win_bsp.h" +#include "mru.h" + +int screen_width; +int screen_height; +qboolean have_quit; +char UserName[256]; +int update_bits; + +HANDLE bsp_process; + +//=========================================== + +#define ShortTime "%a %b %d %Y %I:%M:%S %p" + +void WriteUserLog(char *fmt, ...) +{ + char Buffer[1024], FileName[1024], TimeBuff[1024]; + int Length; + va_list argptr; + FILE *FH; + struct tm *tblock; + time_t TempTime; + + va_start(argptr, fmt); + Length = vsprintf(Buffer, fmt, argptr); + va_end(argptr); + + TempTime = time(NULL); + tblock = localtime(&TempTime); + strftime(TimeBuff,80,ShortTime,tblock); + + sprintf(FileName, "h:\\rjohnson\\ul\\%s.txt", UserName); + FH = fopen(FileName, "r+"); + if (!FH) + { + FH = fopen(FileName, "w"); + if (!FH) + { + return; + } + } + else + { + fseek(FH, 0, SEEK_END); + } + fprintf(FH, "%s %s\n", TimeBuff, Buffer); + fclose(FH); +} + +void Sys_SetTitle (char *text) +{ + SetWindowText (g_qeglobals.d_hwndMain, text); +} + +HCURSOR waitcursor; + +void Sys_BeginWait (void) +{ + waitcursor = SetCursor (LoadCursor (NULL, IDC_WAIT)); +} + +void Sys_EndWait (void) +{ + if (waitcursor) + { + SetCursor (waitcursor); + waitcursor = NULL; + } +} + + +void Sys_GetCursorPos (int *x, int *y) +{ + POINT lpPoint; + + GetCursorPos (&lpPoint); + *x = lpPoint.x; + *y = lpPoint.y; +} + +void Sys_SetCursorPos (int x, int y) +{ + SetCursorPos (x, y); +} + +void Sys_UpdateWindows (int bits) +{ +// Sys_Printf("updating 0x%X\n", bits); + update_bits |= bits; +//update_bits = -1; +} + + +void Sys_Beep (void) +{ + MessageBeep (MB_ICONASTERISK); +} + +char *TranslateString (char *buf) +{ + static char buf2[32768]; + int i, l; + char *out; + + l = strlen(buf); + out = buf2; + for (i=0 ; iepairs ; ep ; ep=ep->next) + { + if (ep->key[0] == 'b' && ep->key[1] == 's' && ep->key[2] == 'p') + { + bsp_commands[i] = ep->key; + AppendMenu (hmenu, MF_ENABLED|MF_STRING, + CMD_BSPCOMMAND+i, (LPCTSTR)ep->key); + i++; + } + } + count = i; +} + +//============================================== + +/* +=============== +CheckBspProcess + +See if the BSP is done yet +=============== +*/ +void CheckBspProcess (void) +{ + char outputpath[1024]; + char temppath[512]; + DWORD exitcode; + char *out; + BOOL ret; + + if (!bsp_process) + return; + + ret = GetExitCodeProcess (bsp_process, &exitcode); + if (!ret) + Error ("GetExitCodeProcess failed"); + if (exitcode == STILL_ACTIVE) + return; + + bsp_process = 0; + + GetTempPath(512, temppath); + sprintf (outputpath, "%sjunk.txt", temppath); + + LoadFile (outputpath, (void *)&out); + Sys_Printf ("%s", out); + Sys_Printf ("\ncompleted.\n"); + free (out); + Sys_Beep (); + + Pointfile_Check (); +} + +extern int cambuttonstate; + +/* +================== +WinMain + +================== +*/ +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance + ,LPSTR lpCmdLine, int nCmdShow) +{ + MSG msg; + double time, oldtime, delta; + HACCEL accelerators; + DWORD Size; + + Size = sizeof(UserName); + GetUserName(UserName, &Size); + + WriteUserLog("Opened QE4"); + + g_qeglobals.d_hInstance = hInstance; + + InitCommonControls (); + + screen_width = GetSystemMetrics (SM_CXFULLSCREEN); + screen_height = GetSystemMetrics (SM_CYFULLSCREEN); + + // hack for broken NT 4.0 dual screen + if (screen_width > 2*screen_height) + screen_width /= 2; + + accelerators = LoadAccelerators (hInstance + , MAKEINTRESOURCE(IDR_ACCELERATOR1)); + if (!accelerators) + Error ("LoadAccelerators failed"); + + Main_Create (hInstance); + + WCam_Create (hInstance); + WXY_Create (hInstance); + WZ_Create (hInstance); + CreateEntityWindow(hInstance); + + // the project file can be specified on the command line, + // or implicitly found in the scripts directory + if (lpCmdLine && strlen(lpCmdLine)) + { + ParseCommandLine (lpCmdLine); + if (!QE_LoadProject(argv[1])) + Error ("Couldn't load %s project file", argv[1]); + } + else if (!QE_LoadProject("scripts/quake.qe4")) + Error ("Couldn't load scripts/quake.qe4 project file"); + + QE_Init (); + + + // The unintellimouse uses a Registered + // message to transmit + // wheel rotation info. So get ready for it! + // dis glob inited to 0 in QE_Init + + g_qeglobals.uMSH_MOUSEWHEEL = + RegisterWindowMessage(MSH_MOUSEWHEEL); + if ( !g_qeglobals.uMSH_MOUSEWHEEL ) + { + Error ("RegisterWindowMessag Failed!"); + } + + Sys_Printf ("Entering message loop\n"); + + oldtime = Sys_DoubleTime (); + + while (!have_quit) + { + Sys_EndWait (); // remove wait cursor if active + + while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + { + if (!TranslateAccelerator(g_qeglobals.d_hwndMain, accelerators, &msg) ) + { + if(!IsDialogMessage(g_qeglobals.d_hwndTexModDlg, &msg)) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + } + if (msg.message == WM_QUIT) + have_quit = true; + } + + + bsp_CheckTask (); + + time = Sys_DoubleTime (); + delta = time - oldtime; + oldtime = time; + if (delta > 0.2) + delta = 0.2; + + // run time dependant behavior + Cam_MouseControl (delta); + + // update any windows now + if (update_bits & W_CAMERA) + { + InvalidateRect(g_qeglobals.d_hwndCamera, NULL, false); + UpdateWindow (g_qeglobals.d_hwndCamera); + } + if (update_bits & (W_Z | W_Z_OVERLAY) ) + { + InvalidateRect(g_qeglobals.d_hwndZ, NULL, false); + UpdateWindow (g_qeglobals.d_hwndZ); + } + + if ( update_bits & W_TEXTURE ) + { + InvalidateRect(g_qeglobals.d_hwndTexture, NULL, false); + UpdateWindow (g_qeglobals.d_hwndEntity); + } + + if (update_bits & (W_XY | W_XY_OVERLAY)) + { + InvalidateRect(g_qeglobals.d_hwndXY, NULL, false); + UpdateWindow (g_qeglobals.d_hwndXY); + } + + update_bits = 0; + + if (!cambuttonstate && !have_quit) + { // if not driving in the camera view, block + WaitMessage (); + } + + } + + /* return success of application */ + return TRUE; + +} + diff --git a/Toolkit/Programming/Tools/qe4/win_qe3.rc b/Toolkit/Programming/Tools/qe4/win_qe3.rc new file mode 100644 index 0000000..52206d5 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/win_qe3.rc @@ -0,0 +1,878 @@ +//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 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU1 MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New", ID_FILE_NEW + MENUITEM "&Open", ID_FILE_OPEN + MENUITEM "&Save", ID_FILE_SAVE + MENUITEM "Save &as...", ID_FILE_SAVEAS + MENUITEM "&Pointfile", ID_FILE_POINTFILE + MENUITEM "Load &project", ID_FILE_LOADPROJECT + MENUITEM "Print &Console Window", ID_FILE_PRINT_CONSOLE + MENUITEM "E&xit", ID_FILE_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo", ID_EDIT_UNDO, GRAYED + MENUITEM "&Redo", ID_EDIT_REDO, GRAYED + MENUITEM SEPARATOR + MENUITEM "&Copy brush", ID_EDIT_COPYBRUSH, GRAYED + MENUITEM "&Paste brush", ID_EDIT_PASTEBRUSH, GRAYED + END + POPUP "&View" + BEGIN + MENUITEM "Texture View\tT", ID_VIEW_TEXTURE + MENUITEM "Console View\tO", ID_VIEW_CONSOLE + MENUITEM "Entity View\tN", ID_VIEW_ENTITY + MENUITEM SEPARATOR + MENUITEM "&Center\tEnd", ID_VIEW_CENTER + MENUITEM "&Up Floor\tPage Up", ID_VIEW_UPFLOOR + MENUITEM "&Down Floor\tPage Down", ID_VIEW_DOWNFLOOR + MENUITEM SEPARATOR + MENUITEM "&XY 100%", ID_VIEW_100 + MENUITEM "XY Zoom &In\tDelete", ID_VIEW_ZOOMIN + MENUITEM "XY Zoom &Out\tInsert", ID_VIEW_ZOOMOUT + MENUITEM SEPARATOR + MENUITEM "Show &Names", ID_VIEW_SHOWNAMES, CHECKED + MENUITEM "Show Blocks", ID_VIEW_SHOWBLOCKS + MENUITEM "Show C&oordinates", ID_VIEW_SHOWCOORDINATES + , CHECKED + MENUITEM "Show &Entities", ID_VIEW_SHOWENT, CHECKED + MENUITEM "Show &Path", ID_VIEW_SHOWPATH, CHECKED + MENUITEM "Show &Lights", ID_VIEW_SHOWLIGHTS, CHECKED + MENUITEM "Show &Water", ID_VIEW_SHOWWATER, CHECKED + MENUITEM "Show Clip &Brush", ID_VIEW_SHOWCLIP, CHECKED + MENUITEM "Show Wor&ld", ID_VIEW_SHOWWORLD, CHECKED + MENUITEM "Show Detail\tctrl-D", ID_VIEW_SHOWDETAIL, CHECKED + MENUITEM "Show Bouy Only", ID_VIEW_SHOWBUOYONLY + MENUITEM SEPARATOR + MENUITEM "&Z 100%", ID_VIEW_Z100 + MENUITEM "Z Zoo&m In\tctrl-Delete", ID_VIEW_ZZOOMIN + MENUITEM "Z Zoom O&ut\tctrl-Insert", ID_VIEW_ZZOOMOUT + END + POPUP "&Selection" + BEGIN + MENUITEM "Drag &Edges\tE", ID_SELECTION_DRAGEDGES + MENUITEM "Drag &Vertecies\tV", ID_SELECTION_DRAGVERTECIES + MENUITEM "&Clone\tspace", ID_SELECTION_CLONE + MENUITEM "Deselect\tEsc", ID_SELECTION_DESELECT + MENUITEM "&Delete\tBackspace", ID_SELECTION_DELETE + MENUITEM "Flip &X", ID_BRUSH_FLIPX + MENUITEM "Flip &Y", ID_BRUSH_FLIPY + MENUITEM "Flip &Z", ID_BRUSH_FLIPZ + MENUITEM "Rotate X", ID_BRUSH_ROTATEX + MENUITEM "Rotate Y", ID_BRUSH_ROTATEY + MENUITEM "Rotate Z", ID_BRUSH_ROTATEZ + MENUITEM "Arbitrary rotation", ID_SELECTION_ARBITRARYROTATION + + MENUITEM "Make &Hollow", ID_SELECTION_MAKEHOLLOW + MENUITEM "CSG &Subtract", ID_SELECTION_CSGSUBTRACT + MENUITEM "Select Complete &Tall", ID_SELECTION_SELECTCOMPLETETALL + + MENUITEM "Select T&ouching", ID_SELECTION_SELECTTOUCHING + MENUITEM "Select &Partial Tall", ID_SELECTION_SELECTPARTIALTALL + + MENUITEM "Select &Inside", ID_SELECTION_SELECTINSIDE + MENUITEM "Connect entities\tCtrl-k", ID_SELECTION_CONNECT + MENUITEM "Ungroup entity", ID_SELECTION_UNGROUPENTITY + MENUITEM "Make detail\tCtrl-m", ID_SELECTION_MAKE_DETAIL + MENUITEM "Make structural", ID_SELECTION_MAKE_STRUCTURAL + MENUITEM "Scale", ID_SELECTION_SCALE + MENUITEM "To&wer\tW", ID_SELECTION_TOWER + END + POPUP "&Bsp" + BEGIN + MENUITEM SEPARATOR + END + POPUP "&Grid" + BEGIN + MENUITEM "Grid1\t&1", ID_GRID_1 + MENUITEM "Grid2\t&2", ID_GRID_2 + MENUITEM "Grid4\t&3", ID_GRID_4 + MENUITEM "Grid8\t&4", ID_GRID_8, CHECKED + MENUITEM "Grid16\t&5", ID_GRID_16 + MENUITEM "Grid32\t&6", ID_GRID_32 + MENUITEM "Grid64\t&7", ID_GRID_64 + END + POPUP "&Textures" + BEGIN + MENUITEM "Show In &Use\tU", ID_TEXTURES_SHOWINUSE + MENUITEM "&Surface inspector\tS", ID_TEXTURES_INSPECTOR + MENUITEM SEPARATOR + MENUITEM "&Wireframe", ID_TEXTURES_WIREFRAME + MENUITEM "&Flat shade", ID_TEXTURES_FLATSHADE + MENUITEM "&Nearest", ID_VIEW_NEAREST + MENUITEM "Nearest &Mipmap", ID_VIEW_NEARESTMIPMAP + MENUITEM "&Linear", ID_VIEW_LINEAR + MENUITEM "&Bilinear", ID_VIEW_BILINEAR + MENUITEM "B&ilinear Mipmap", ID_VIEW_BILINEARMIPMAP + MENUITEM "T&rilinear", ID_VIEW_TRILINEAR + MENUITEM SEPARATOR + MENUITEM "&Default Materials", ID_TEXTURES_DEFAULT_MATERIALS + + END + POPUP "&Misc" + BEGIN + MENUITEM "&Benchmark", ID_MISC_BENCHMARK + POPUP "&Colors" + BEGIN + MENUITEM "&Texture Background", ID_TEXTUREBK + MENUITEM "Grid Background", ID_COLORS_XYBK + MENUITEM "Grid Major", ID_COLORS_MAJOR + MENUITEM "Grid Minor", ID_COLORS_MINOR + END + MENUITEM "&Gamma", ID_MISC_GAMMA + MENUITEM "Find brush", ID_MISC_FINDBRUSH + MENUITEM "Next leak spot\tctrl-l", ID_MISC_NEXTLEAKSPOT + MENUITEM "Previous leak spot\tctrl-p", ID_MISC_PREVIOUSLEAKSPOT + MENUITEM "&Print XY View", ID_MISC_PRINTXY + MENUITEM "&Select Entity Color\tK", ID_MISC_SELECTENTITYCOLOR + MENUITEM "&Replace Texture", ID_MISC_REPLACETEXTURE + MENUITEM "Set Max View Distance", ID_MISC_SETMAXVIEWDISTANCE + MENUITEM "Default Textures", ID_MISC_DEFAULTTEXTURES + END + POPUP "&Region" + BEGIN + MENUITEM "&Off", ID_REGION_OFF + MENUITEM "&Set XY", ID_REGION_SETXY + MENUITEM "Set &Tall Brush", ID_REGION_SETTALLBRUSH + MENUITEM "Set &Brush", ID_REGION_SETBRUSH + MENUITEM "Set Se&lected Brushes", ID_REGION_SETSELECTION + END + POPUP "&Brush" + BEGIN + MENUITEM "3 sided\tctrl-3", ID_BRUSH_3SIDED + MENUITEM "3 sided snap\tctrl-shift-3", ID_BRUSH_3SNAP + MENUITEM "4 sided\tctrl-4", ID_BRUSH_4SIDED + MENUITEM "4 sided snap\tctrl-shift-4", ID_BRUSH_4SNAP + MENUITEM "5 sided\tctrl-5", ID_BRUSH_5SIDED + MENUITEM "5 sided snap\tctrl-shift-5", ID_BRUSH_5SNAP + MENUITEM "6 sided\tctrl-6", ID_BRUSH_6SIDED + MENUITEM "6 sided snap\tctrl-shift-6", ID_BRUSH_6SNAP + MENUITEM "7 sided\tctrl-7", ID_BRUSH_7SIDED + MENUITEM "7 sided snap\tctrl-shift-7", ID_BRUSH_7SNAP + MENUITEM "8 sided\tctrl-8", ID_BRUSH_8SIDED + MENUITEM "8 sided snap\tctrl-shift-8", ID_BRUSH_8SNAP + MENUITEM "9 sided\tctrl-9", ID_BRUSH_9SIDED + MENUITEM "9 sided snap\tctrl-shift-9", ID_BRUSH_9SNAP + MENUITEM "Arbitrary sided", ID_BRUSH_ARBITRARYSIDED + END + POPUP "&Help" + BEGIN + MENUITEM "&About", ID_HELP_ABOUT + END +END + + +#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 + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_FINDTEXTURE DIALOG DISCARDABLE 0, 0, 129, 53 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Find Texture" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,10,30,50,14 + PUSHBUTTON "Cancel",IDCANCEL,70,30,50,14 + EDITTEXT IDC_EDIT1,10,10,110,14,ES_AUTOHSCROLL +END + +IDD_ENTITY DIALOGEX 0, 0, 234, 389 +STYLE DS_3DLOOK | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | + WS_CAPTION | WS_THICKFRAME +EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE +CAPTION "Entity" +FONT 8, "MS Sans Serif" +BEGIN + LISTBOX IDC_E_LIST,5,5,180,99,LBS_SORT | LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | WS_VSCROLL | WS_TABSTOP, + WS_EX_CLIENTEDGE + EDITTEXT IDC_E_COMMENT,5,106,180,50,ES_MULTILINE | ES_READONLY | + WS_VSCROLL,WS_EX_CLIENTEDGE + PUSHBUTTON "135",IDC_E_135,5,328,15,15 + PUSHBUTTON "180",IDC_E_180,5,343,15,15 + PUSHBUTTON "225",IDC_E_225,5,358,15,15 + PUSHBUTTON "270",IDC_E_270,21,358,15,15 + PUSHBUTTON "90",IDC_E_90,21,328,15,15 + PUSHBUTTON "45",IDC_E_45,35,328,15,15 + PUSHBUTTON "0",IDC_E_0,35,343,15,15 + PUSHBUTTON "315",IDC_E_315,35,358,15,15 + PUSHBUTTON "Up",IDC_E_UP,60,333,15,15 + PUSHBUTTON "Dn",IDC_E_DOWN,60,348,15,15 + CONTROL "",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,160,50,8 + CONTROL "",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,170,50,8 + CONTROL "",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,180,50,8 + CONTROL "",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,190,50,8 + CONTROL "",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,160,50,8 + CONTROL "",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,170,50,8 + CONTROL "",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,180,50,8 + CONTROL "",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,190,50,8 + CONTROL "!Easy",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 125,160,50,8 + CONTROL "!Medium",IDC_CHECK10,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,125,170,50,8 + CONTROL "!Hard",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,125,180,50,10 + CONTROL "!DeathMatch",IDC_CHECK12,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,125,190,55,10 + LISTBOX IDC_E_PROPS,5,243,180,50,LBS_SORT | LBS_USETABSTOPS | + LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | + WS_VSCROLL | WS_TABSTOP,WS_EX_CLIENTEDGE + PUSHBUTTON "Del Key/Pair",IDC_E_DELPROP,105,333,45,15 + EDITTEXT IDC_E_STATUS,83,350,95,30,ES_MULTILINE | ES_AUTOVSCROLL | + ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL + LTEXT "Key",IDC_STATIC_KEY,5,298,25,10 + LTEXT "Value",IDC_STATIC_VALUE,5,313,25,10 + EDITTEXT IDC_E_KEY_FIELD,40,298,135,14,ES_AUTOHSCROLL + EDITTEXT IDC_E_VALUE_FIELD,40,313,135,14,ES_AUTOHSCROLL + CONTROL "!Co-Op",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,5,206,55,10 + CONTROL "14",IDC_CHECK14,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,215,55,10 + CONTROL "15",IDC_CHECK15,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,224,55,10 + CONTROL "16",IDC_CHECK16,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,206,55,10 + CONTROL "17",IDC_CHECK17,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,215,55,10 + CONTROL "18",IDC_CHECK18,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,224,55,10 + CONTROL "19",IDC_CHECK19,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,126,206,55,10 + CONTROL "20",IDC_CHECK20,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,126,215,55,10 + CONTROL "21",IDC_CHECK21,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,126,224,55,10 +END + +IDD_GAMMA DIALOGEX 0, 0, 127, 76 +STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Gamma" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,10,40,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,40,50,14 + EDITTEXT IDC_G_EDIT,30,15,66,13,ES_AUTOHSCROLL,WS_EX_CLIENTEDGE +END + +IDD_FINDBRUSH DIALOGEX 0, 0, 127, 76 +STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Find brush" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,5,55,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,55,50,14 + EDITTEXT IDC_FIND_ENTITY,80,15,46,13,ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE + EDITTEXT IDC_FIND_BRUSH,80,30,46,13,ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE + LTEXT "Entity number",IDC_STATIC,10,15,60,8 + LTEXT "Brush number",IDC_STATIC,10,30,65,8 +END + +IDD_ROTATE DIALOG DISCARDABLE 0, 0, 186, 71 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Arbitrary rotation" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "&X",IDC_STATIC,5,10,8,8 + EDITTEXT IDC_ROTX,30,5,40,14,ES_AUTOHSCROLL + LTEXT "&Y",IDC_STATIC,5,25,8,8 + EDITTEXT IDC_ROTY,30,25,40,14,ES_AUTOHSCROLL + LTEXT "&Z",IDC_STATIC,5,45,8,8 + EDITTEXT IDC_ROTZ,30,45,40,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 +END + +IDD_SIDES DIALOG DISCARDABLE 0, 0, 187, 90 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Arbitrary sides" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,130,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,130,49,50,14 + EDITTEXT IDC_SIDES,50,15,40,14,ES_AUTOHSCROLL + LTEXT "Sides",IDC_STATIC,15,15,18,8 + DEFPUSHBUTTON "SNAP OK",ID_BRUSH_SNAPOK,130,28,50,14,WS_GROUP +END + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 274, 212 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About QuakeEd" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,217,7,50,14 + CONTROL 127,IDC_STATIC,"Static",SS_BITMAP,7,7,83,58 + CONTROL "QuakeEd 4.0(beta)\nCopyright (C) 1997 id Software, Inc.", + IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,100,10, + 110,23 + GROUPBOX "OpenGL Properties",IDC_STATIC,5,75,265,50 + LTEXT "Vendor:\t\tWHOEVER",IDC_ABOUT_GLVENDOR,10,90,125,10 + LTEXT "Version:\t\t1.1",IDC_ABOUT_GLVERSION,10,100,125,10 + LTEXT "Renderer:\tWHATEVER",IDC_ABOUT_GLRENDERER,10,110,125,10 + LTEXT "WHATEVER",IDC_ABOUT_GLEXTENSIONS,10,140,255,60 + GROUPBOX "OpenGL Extensions",IDC_STATIC,5,130,265,80 +END + +IDD_SURFACE DIALOG DISCARDABLE 400, 100, 391, 213 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Surface inspector" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,7,183,40,14 + PUSHBUTTON "Cancel",IDCANCEL,107,183,40,14 + EDITTEXT IDC_HSHIFT,83,35,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_HSHIFTA,117,35,10,15,SBS_VERT + LTEXT "Horizontal shift",IDC_STATIC,7,35,65,8 + LTEXT "Vertical shift",IDC_STATIC,7,50,65,8 + LTEXT "Horizontal stretch",IDC_STATIC,7,65,65,8 + LTEXT "Vertical stretch",IDC_STATIC,7,80,65,8 + LTEXT "Rotate",IDC_STATIC,7,95,65,8 + LTEXT "Light/AnimSpeed",IDC_STATIC,7,110,65,8 + EDITTEXT IDC_VSHIFT,83,50,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_VSHIFTA,117,50,10,15,SBS_VERT + EDITTEXT IDC_HSCALE,83,65,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_HSCALEA,117,65,10,15,SBS_VERT + EDITTEXT IDC_VSCALE,83,80,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_VSCALEA,117,80,10,15,SBS_VERT + EDITTEXT IDC_ROTATE,83,95,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_ROTATEA,117,95,10,15,SBS_VERT + EDITTEXT IDC_VALUE,83,110,35,15,ES_AUTOHSCROLL + EDITTEXT IDC_LIGHT_RED,7,136,35,15,ES_AUTOHSCROLL + EDITTEXT IDC_LIGHT_GREEN,42,136,35,15,ES_AUTOHSCROLL + EDITTEXT IDC_LIGHT_BLUE,77,136,35,15,ES_AUTOHSCROLL + EDITTEXT IDC_LIGHT_ALPHA,113,136,35,15,ES_AUTOHSCROLL + PUSHBUTTON "Apply",IDAPPLY,57,183,40,14 + CONTROL "light",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,10,41,8 + CONTROL "slick",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,20,41,8 + CONTROL "sky",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,30,41,8 + CONTROL "warp",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,40,41,8 + CONTROL "trans33",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,50,41,8 + CONTROL "trans66",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,60,41,8 + CONTROL "flowing",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,70,41,8 + CONTROL "nodraw",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,80,41,8 + CONTROL "hint",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,90,41,8 + CONTROL "skip",IDC_CHECK10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,100,41,8 + CONTROL "tall wall",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,110,41,8 + CONTROL "Alpha Tex",IDC_CHECK12,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,120,45,8 + CONTROL "AnimSpeed",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,130,41,8 + CONTROL "Undulate",IDC_CHECK14,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,140,49,8 + CONTROL "Sky Reflect",IDC_CHECK15,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,150,41,8 + CONTROL "8000",IDC_CHECK16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,160,41,8 + EDITTEXT IDC_TEXTURE,50,15,80,14,ES_AUTOHSCROLL + LTEXT "Texture",IDC_STATIC,10,18,30,8 + CONTROL "10000",IDC_CHECK17,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,213,10,41,8 + CONTROL "20000",IDC_CHECK18,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,213,20,41,8 + CONTROL "40000",IDC_CHECK19,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,213,30,41,8 + CONTROL "80000",IDC_CHECK20,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,213,40,41,8 + CONTROL "100000",IDC_CHECK21,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,213,50,41,8 + CONTROL "200000",IDC_CHECK22,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,213,60,41,8 + CONTROL "400000",IDC_CHECK23,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,213,70,41,8 + CONTROL "800000",IDC_CHECK24,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,213,80,41,8 + CONTROL "material",IDC_CHECK25,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,213,90,41,8 + CONTROL "material",IDC_CHECK26,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,213,100,41,8 + CONTROL "material",IDC_CHECK27,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,213,110,41,8 + CONTROL "material",IDC_CHECK28,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,213,120,41,8 + CONTROL "material",IDC_CHECK29,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,213,130,40,8 + CONTROL "material",IDC_CHECK30,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,213,140,45,8 + CONTROL "material",IDC_CHECK31,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,213,150,45,8 + CONTROL "material",IDC_CHECK32,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,213,160,45,8 + CONTROL "solid",IDC_CHECK33,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,280,10,41,8 + CONTROL "window",IDC_CHECK34,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,280,20,41,8 + CONTROL "push/pull",IDC_CHECK35,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,280,31,41,8 + CONTROL "lava",IDC_CHECK36,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,41,41,8 + CONTROL "slime",IDC_CHECK37,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,280,50,41,8 + CONTROL "water",IDC_CHECK38,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,280,60,41,8 + CONTROL "mist",IDC_CHECK39,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,71,41,8 + CONTROL "80",IDC_CHECK40,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,81,41,8 + CONTROL "100",IDC_CHECK41,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,90,41,8 + CONTROL "200",IDC_CHECK42,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,100,41,8 + CONTROL "400",IDC_CHECK43,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,111,41,8 + CONTROL "800",IDC_CHECK44,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,121,41,8 + CONTROL "1000",IDC_CHECK45,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,130,41,8 + CONTROL "2000",IDC_CHECK46,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,140,41,8 + CONTROL "4000",IDC_CHECK47,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,151,41,8 + CONTROL "8000",IDC_CHECK48,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,161,41,8 + CONTROL "playerclip",IDC_CHECK49,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,10,41,8 + CONTROL "monsterclip",IDC_CHECK50,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,20,50,8 + CONTROL "current_0",IDC_CHECK51,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,31,50,8 + CONTROL "current_90",IDC_CHECK52,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,41,50,8 + CONTROL "current_180",IDC_CHECK53,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,50,50,8 + CONTROL "current_270",IDC_CHECK54,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,60,50,8 + CONTROL "current_up",IDC_CHECK55,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,71,50,8 + CONTROL "current_dn",IDC_CHECK56,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,81,50,8 + CONTROL "origin",IDC_CHECK57,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,90,41,8 + CONTROL "monster",IDC_CHECK58,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,100,41,8 + CONTROL "corpse",IDC_CHECK59,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,111,41,8 + CONTROL "detail",IDC_CHECK60,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,121,41,8 + CONTROL "translucent",IDC_CHECK61,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,130,50,8 + CONTROL "ladder",IDC_CHECK62,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,140,45,8 + CONTROL "camnoblck",IDC_CHECK63,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,151,47,8 + CONTROL "80000000",IDC_CHECK64,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,161,45,8 + GROUPBOX "Surf flags",IDC_STATIC,150,0,115,175 + GROUPBOX "Content flags",IDC_STATIC,269,0,115,175 + LTEXT "Lighting",IDC_STATIC,7,124,74,11 + COMBOBOX IDC_TEXTURE_MATERIAL,53,157,95,49,CBS_DROPDOWNLIST | + CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Material",IDC_STATIC,7,158,38,12 +END + +IDD_REPLACE DIALOG DISCARDABLE 0, 0, 332, 63 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Replace Textures" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "&Replace All",IDD_REPLACEALL,259,7,66,14 + PUSHBUTTON "&Cancel",IDCANCEL,259,38,66,14 + PUSHBUTTON "Replace &Selected",IDD_REPLACESELECTED,260,22,65,15 + EDITTEXT IDC_REP_EDIT1,104,7,152,13,ES_AUTOHSCROLL + LTEXT "Source Texture:",IDC_STATIC,7,7,55,12 + EDITTEXT IDC_REP_EDIT2,104,22,152,12,ES_AUTOHSCROLL + LTEXT "Destination Texture:",IDC_STATIC,7,23,95,10 +END + +IDD_SCALE DIALOG DISCARDABLE 0, 0, 251, 97 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Scale Brush" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "&Okay",IDOK,193,7,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,193,24,50,14 + LTEXT "&Scale Multiplier",IDC_STATIC,7,7,50,14 + EDITTEXT IDC_SCALE,61,7,97,14,ES_AUTOHSCROLL + CONTROL "&Use Center of Each Brush As Its Own Origin", + IDC_SCALE_EACH_ORIGIN,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,24,158,13 + CONTROL "Exclude &X Axis",IDC_CHECK_NOX,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,37,152,12 + CONTROL "Exclude &Y Axis",IDC_CHECK_NOY,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,50,152,11 + CONTROL "Exclude &Z Axis",IDC_CHECK_NOZ,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,63,156,11 +END + +IDD_MAXVIEWDIST DIALOG DISCARDABLE 0, 0, 186, 47 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Max View Distance" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "&Max View Distance",IDC_STATIC,7,18,65,13 + EDITTEXT IDC_MAXVIEWDIST,71,17,55,11,ES_AUTOHSCROLL + DEFPUSHBUTTON "&OK",IDOK,129,7,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,129,24,50,14 +END + +IDD_BSP DIALOGEX 0, 0, 298, 271 +STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | + WS_SYSMENU +CAPTION "BSP Progress" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + PUSHBUTTON "Abort",IDCANCEL,113,239,63,14 + EDITTEXT IDC_BSPTEXT,7,7,284,219,ES_MULTILINE | ES_AUTOHSCROLL | + ES_READONLY | WS_VSCROLL | WS_HSCROLL,WS_EX_CLIENTEDGE +END + +IDD_TEXMODIFY DIALOG DISCARDABLE 0, 0, 213, 58 +STYLE WS_CHILD | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Horiz shift",IDC_STATIC,17,7,34,8 + EDITTEXT IDC_HSHIFT,55,7,35,15,ES_AUTOHSCROLL + LTEXT "Vert shift",IDC_STATIC,19,22,33,8 + EDITTEXT IDC_VSHIFT,55,22,35,15,ES_AUTOHSCROLL + LTEXT "Rotate",IDC_STATIC,19,36,29,8 + EDITTEXT IDC_ROTATE,55,36,35,15,ES_AUTOHSCROLL + LTEXT "Horiz stretch",IDC_STATIC,109,7,44,8 + EDITTEXT IDC_HSCALE,157,7,35,15,ES_AUTOHSCROLL + LTEXT "Vert stretch",IDC_STATIC,109,23,42,8 + EDITTEXT IDC_VSCALE,157,23,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_HSHIFTA,89,7,10,15,SBS_VERT + SCROLLBAR IDC_VSHIFTA,89,22,10,15,SBS_VERT + SCROLLBAR IDC_ROTATEA,89,36,10,15,SBS_VERT + SCROLLBAR IDC_HSCALEA,193,7,10,15,SBS_VERT + SCROLLBAR IDC_VSCALEA,193,23,10,15,SBS_VERT + CONTROL "Lock Textures",IDC_TEXLOCK_CHECK,"Button",BS_3STATE | + WS_TABSTOP,110,41,73,10 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Id Software\0" + VALUE "FileDescription", "qe3\0" + VALUE "FileVersion", "1.5\0" + VALUE "InternalName", "qe3\0" + VALUE "LegalCopyright", "Copyright © 1996\0" + VALUE "OriginalFilename", "qe4.exe\0" + VALUE "ProductName", "Id Software qe4\0" + VALUE "ProductVersion", "1.5\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE +BEGIN + "3", ID_BRUSH_3SIDED, VIRTKEY, CONTROL, NOINVERT + "3", ID_BRUSH_3SNAP, VIRTKEY, SHIFT, CONTROL, + NOINVERT + "4", ID_BRUSH_4SIDED, VIRTKEY, CONTROL, NOINVERT + "4", ID_BRUSH_4SNAP, VIRTKEY, SHIFT, CONTROL, + NOINVERT + "5", ID_BRUSH_5SIDED, VIRTKEY, CONTROL, NOINVERT + "5", ID_BRUSH_5SNAP, VIRTKEY, SHIFT, CONTROL, + NOINVERT + "6", ID_BRUSH_6SIDED, VIRTKEY, CONTROL, NOINVERT + "6", ID_BRUSH_6SNAP, VIRTKEY, SHIFT, CONTROL, + NOINVERT + "7", ID_BRUSH_7SIDED, VIRTKEY, CONTROL, NOINVERT + "7", ID_BRUSH_7SNAP, VIRTKEY, SHIFT, CONTROL, + NOINVERT + "8", ID_BRUSH_8SIDED, VIRTKEY, CONTROL, NOINVERT + "8", ID_BRUSH_8SNAP, VIRTKEY, SHIFT, CONTROL, + NOINVERT + "9", ID_BRUSH_9SIDED, VIRTKEY, CONTROL, NOINVERT + "9", ID_BRUSH_9SNAP, VIRTKEY, SHIFT, CONTROL, + NOINVERT + "D", ID_VIEW_SHOWDETAIL, VIRTKEY, CONTROL, NOINVERT + "K", ID_SELECTION_CONNECT, VIRTKEY, CONTROL, NOINVERT + "L", ID_MISC_NEXTLEAKSPOT, VIRTKEY, CONTROL, NOINVERT + "M", ID_SELECTION_MAKE_DETAIL, VIRTKEY, CONTROL, NOINVERT + "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT + "P", ID_MISC_PREVIOUSLEAKSPOT, VIRTKEY, CONTROL, NOINVERT + "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT + VK_DELETE, ID_VIEW_ZZOOMIN, VIRTKEY, CONTROL, NOINVERT + VK_INSERT, ID_VIEW_ZZOOMOUT, VIRTKEY, CONTROL, NOINVERT + "X", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Toolbar +// + +IDR_TOOLBAR1 TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_BRUSH_FLIPX + BUTTON ID_BRUSH_ROTATEX + BUTTON ID_BRUSH_FLIPY + BUTTON ID_BRUSH_ROTATEY + BUTTON ID_BRUSH_FLIPZ + BUTTON ID_BRUSH_ROTATEZ + BUTTON ID_BUTTON40148 + BUTTON ID_SELECTION_SELECTCOMPLETETALL + BUTTON ID_SELECTION_SELECTTOUCHING + BUTTON ID_SELECTION_SELECTPARTIALTALL + BUTTON ID_SELECTION_SELECTINSIDE + BUTTON ID_SELECTION_CSGSUBTRACT + BUTTON ID_SELECTION_MAKEHOLLOW + BUTTON ID_TEXTURES_WIREFRAME + BUTTON ID_TEXTURES_FLATSHADE + BUTTON ID_VIEW_TRILINEAR + SEPARATOR + BUTTON ID_BUTTON_UNDO + SEPARATOR + BUTTON ID_TEXTURE_LISTINUSE + BUTTON ID_ENTITY_LISTINUSE +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDR_TOOLBAR1 BITMAP DISCARDABLE "toolbar1.bmp" +IDB_BITMAP1 BITMAP DISCARDABLE "q.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ENTITY, DIALOG + BEGIN + RIGHTMARGIN, 227 + BOTTOMMARGIN, 387 + END + + IDD_GAMMA, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 120 + TOPMARGIN, 7 + BOTTOMMARGIN, 68 + END + + IDD_FINDBRUSH, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 120 + TOPMARGIN, 7 + BOTTOMMARGIN, 68 + END + + IDD_ROTATE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 64 + END + + IDD_SIDES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + TOPMARGIN, 7 + BOTTOMMARGIN, 86 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 267 + TOPMARGIN, 7 + BOTTOMMARGIN, 205 + END + + IDD_SURFACE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 384 + TOPMARGIN, 7 + BOTTOMMARGIN, 206 + END + + IDD_REPLACE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 325 + TOPMARGIN, 7 + BOTTOMMARGIN, 57 + END + + IDD_SCALE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 90 + END + + IDD_MAXVIEWDIST, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 40 + END + + IDD_BSP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 291 + TOPMARGIN, 7 + BOTTOMMARGIN, 264 + END + + IDD_TEXMODIFY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 206 + TOPMARGIN, 7 + BOTTOMMARGIN, 51 + END +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 "icon1.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Toolkit/Programming/Tools/qe4/win_xy.c b/Toolkit/Programming/Tools/qe4/win_xy.c new file mode 100644 index 0000000..6cc900c --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/win_xy.c @@ -0,0 +1,286 @@ +// win_xy.c -- windows specific xy view code + +#include "qe3.h" + +static HDC s_hdcXY; +static HGLRC s_hglrcXY; + +static unsigned s_stipple[32] = +{ + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, +}; + +/* +============ +WXY_WndProc +============ +*/ +LONG WINAPI WXY_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + int fwKeys, xPos, yPos; + RECT rect; + + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + case WM_CREATE: + + s_hdcXY = GetDC(hWnd); + + QEW_SetupPixelFormat(s_hdcXY, false); + + if ( ( s_hglrcXY = wglCreateContext( s_hdcXY ) ) == 0 ) + Error( "wglCreateContext in WXY_WndProc failed" ); + + if (!wglMakeCurrent( s_hdcXY, s_hglrcXY )) + Error ("wglMakeCurrent failed"); + + if (!wglShareLists( g_qeglobals.d_hglrcBase, s_hglrcXY ) ) + { + Error( "wglShareLists in WXY_WndProc failed" ); + } + + glPolygonStipple ((char *)s_stipple); + glLineStipple (3, 0xaaaa); + + return 0; + + case WM_DESTROY: + QEW_StopGL( hWnd, s_hglrcXY, s_hdcXY ); + return 0; + + case WM_PAINT: + { +// PAINTSTRUCT ps; + +// BeginPaint(hWnd, &ps); + + if (!wglMakeCurrent( s_hdcXY, s_hglrcXY )) + Error ("wglMakeCurrent failed"); + + QE_CheckOpenGLForErrors(); + XY_Draw (); + QE_CheckOpenGLForErrors(); + + SwapBuffers(s_hdcXY); + ValidateRect(hWnd, NULL); +// EndPaint(hWnd, &ps); + } + return 0; + + case WM_KEYDOWN: + return QE_KeyDown (wParam); + + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONDOWN: + if ( GetTopWindow( g_qeglobals.d_hwndMain ) != hWnd) + BringWindowToTop(hWnd); + SetFocus( g_qeglobals.d_hwndXY ); + SetCapture( g_qeglobals.d_hwndXY ); + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + XY_MouseDown (xPos, yPos, fwKeys); + return 0; + + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + XY_MouseUp (xPos, yPos, fwKeys); + if (! (fwKeys & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON))) + ReleaseCapture (); + return 0; + + case WM_MOUSEMOVE: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + XY_MouseMoved (xPos, yPos, fwKeys); + return 0; + + case WM_SIZE: + g_qeglobals.d_xy.width = rect.right; + g_qeglobals.d_xy.height = rect.bottom; + InvalidateRect( g_qeglobals.d_hwndXY, NULL, false); + return 0; + + case WM_NCCALCSIZE:// don't let windows copy pixels + DefWindowProc (hWnd, uMsg, wParam, lParam); + return WVR_REDRAW; + + case WM_KILLFOCUS: + case WM_SETFOCUS: + SendMessage( hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0 ); + return 0; + + case WM_CLOSE: + DestroyWindow (hWnd); + return 0; + } + + return DefWindowProc (hWnd, uMsg, wParam, lParam); +} + + +/* +============== +WXY_Create +============== +*/ +void WXY_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = CS_OWNDC; + wc.lpfnWndProc = (WNDPROC)WXY_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; //(HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = NULL; + wc.lpszClassName = XY_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Error ("RegisterClass: failed"); + + g_qeglobals.d_hwndXY = CreateWindow (XY_WINDOW_CLASS , + "XY View", + QE3_STYLE , + ZWIN_WIDTH, + (int)(screen_height*CWIN_SIZE)-20, + screen_width-ZWIN_WIDTH, + (int)(screen_height*(1.0-CWIN_SIZE)-38), // size + + g_qeglobals.d_hwndMain, // parent + 0, // no menu + hInstance, + NULL); + + if (!g_qeglobals.d_hwndXY ) + Error ("Couldn't create XY View"); + + LoadWindowState(g_qeglobals.d_hwndXY, "xywindow"); + ShowWindow(g_qeglobals.d_hwndXY, SW_SHOWDEFAULT); +} + +static void WXY_InitPixelFormat( PIXELFORMATDESCRIPTOR *pPFD ) +{ + memset( pPFD, 0, sizeof( *pPFD ) ); + + pPFD->nSize = sizeof( PIXELFORMATDESCRIPTOR ); + pPFD->nVersion = 1; + pPFD->dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; + pPFD->iPixelType = PFD_TYPE_RGBA; + pPFD->cColorBits = 24; + pPFD->cDepthBits = 32; + pPFD->iLayerType = PFD_MAIN_PLANE; + +} + +void WXY_Print( void ) +{ + DOCINFO di; + + PRINTDLG pd; + + /* + ** initialize the PRINTDLG struct and execute it + */ + memset( &pd, 0, sizeof( pd ) ); + pd.lStructSize = sizeof( pd ); + pd.hwndOwner = g_qeglobals.d_hwndXY; + pd.Flags = PD_RETURNDC; + pd.hInstance = 0; + if ( !PrintDlg( &pd ) || !pd.hDC ) + { + MessageBox( g_qeglobals.d_hwndMain, "Could not PrintDlg()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + + /* + ** StartDoc + */ + memset( &di, 0, sizeof( di ) ); + di.cbSize = sizeof( di ); + di.lpszDocName = "QE4"; + if ( StartDoc( pd.hDC, &di ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "Could not StartDoc()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + + /* + ** StartPage + */ + if ( StartPage( pd.hDC ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "Could not StartPage()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + + /* + ** read pixels from the XY window + */ + { + int bmwidth = 320, bmheight = 320; + int pwidth, pheight; + + RECT r; + + GetWindowRect( g_qeglobals.d_hwndXY, &r ); + + bmwidth = r.right - r.left; + bmheight = r.bottom - r.top; + + pwidth = GetDeviceCaps( pd.hDC, PHYSICALWIDTH ) - GetDeviceCaps( pd.hDC, PHYSICALOFFSETX ); + pheight = GetDeviceCaps( pd.hDC, PHYSICALHEIGHT ) - GetDeviceCaps( pd.hDC, PHYSICALOFFSETY ); + + StretchBlt( pd.hDC, + 0, 0, + pwidth, pheight, + s_hdcXY, + 0, 0, + bmwidth, bmheight, + SRCCOPY ); + } + + /* + ** EndPage and EndDoc + */ + if ( EndPage( pd.hDC ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "QE4 Print Error", "Could not EndPage()", MB_OK | MB_ICONERROR ); + return; + } + + if ( EndDoc( pd.hDC ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "QE4 Print Error", "Could not EndDoc()", MB_OK | MB_ICONERROR ); + return; + } +} diff --git a/Toolkit/Programming/Tools/qe4/win_z.c b/Toolkit/Programming/Tools/qe4/win_z.c new file mode 100644 index 0000000..d041482 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/win_z.c @@ -0,0 +1,173 @@ +// win_cam.c -- windows specific camera view code + +#include "qe3.h" + +static HDC s_hdcZ; +static HGLRC s_hglrcZ; + +/* +============ +WZ_WndProc +============ +*/ +LONG WINAPI WZ_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + int fwKeys, xPos, yPos; + RECT rect; + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + + case WM_DESTROY: + QEW_StopGL( hWnd, s_hglrcZ, s_hdcZ ); + return 0; + + case WM_CREATE: + s_hdcZ = GetDC(hWnd); + QEW_SetupPixelFormat( s_hdcZ, false); + if ( ( s_hglrcZ = wglCreateContext( s_hdcZ ) ) == 0 ) + Error( "wglCreateContext in WZ_WndProc failed" ); + + if (!wglMakeCurrent( s_hdcZ, s_hglrcZ )) + Error ("wglMakeCurrent in WZ_WndProc failed"); + + if (!wglShareLists( g_qeglobals.d_hglrcBase, s_hglrcZ ) ) + Error( "wglShareLists in WZ_WndProc failed" ); + return 0; + + case WM_PAINT: + { +// PAINTSTRUCT ps; + +// BeginPaint(hWnd, &ps); + + if ( !wglMakeCurrent( s_hdcZ, s_hglrcZ ) ) + Error ("wglMakeCurrent failed"); + QE_CheckOpenGLForErrors(); + + Z_Draw (); + SwapBuffers(s_hdcZ); + ValidateRect(hWnd, NULL); +// EndPaint(hWnd, &ps); + } + return 0; + + + case WM_KEYDOWN: + QE_KeyDown (wParam); + return 0; + + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONDOWN: + if (GetTopWindow(g_qeglobals.d_hwndMain) != hWnd) + BringWindowToTop(hWnd); + + SetFocus( g_qeglobals.d_hwndZ ); + SetCapture( g_qeglobals.d_hwndZ ); + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + Z_MouseDown (xPos, yPos, fwKeys); + return 0; + + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + Z_MouseUp (xPos, yPos, fwKeys); + if (! (fwKeys & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON))) + ReleaseCapture (); + return 0; + + case WM_GETMINMAXINFO: + { + MINMAXINFO *pmmi = (LPMINMAXINFO) lParam; + + pmmi->ptMinTrackSize.x = ZWIN_WIDTH; + return 0; + } + + case WM_MOUSEMOVE: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + Z_MouseMoved (xPos, yPos, fwKeys); + return 0; + + case WM_SIZE: + z.width = rect.right; + z.height = rect.bottom; + InvalidateRect( g_qeglobals.d_hwndZ, NULL, false); + return 0; + + case WM_NCCALCSIZE:// don't let windows copy pixels + DefWindowProc (hWnd, uMsg, wParam, lParam); + return WVR_REDRAW; + + case WM_KILLFOCUS: + case WM_SETFOCUS: + SendMessage( hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0 ); + return 0; + + case WM_CLOSE: + /* call destroy window to cleanup and go away */ + DestroyWindow (hWnd); + return 0; + } + + return DefWindowProc (hWnd, uMsg, wParam, lParam); +} + + +/* +============== +WZ_Create +============== +*/ +void WZ_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = CS_OWNDC; + wc.lpfnWndProc = (WNDPROC)WZ_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = Z_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Error ("WCam_Register: failed"); + + g_qeglobals.d_hwndZ = CreateWindow (Z_WINDOW_CLASS , + "Z", + QE3_STYLE, + 0,20,ZWIN_WIDTH,screen_height-38, // size + g_qeglobals.d_hwndMain, // parent + 0, // no menu + hInstance, + NULL); + if (!g_qeglobals.d_hwndZ) + Error ("Couldn't create zwindow"); + + LoadWindowState(g_qeglobals.d_hwndZ, "zwindow"); + ShowWindow (g_qeglobals.d_hwndZ, SW_SHOWDEFAULT); +} diff --git a/Toolkit/Programming/Tools/qe4/xy.c b/Toolkit/Programming/Tools/qe4/xy.c new file mode 100644 index 0000000..32d2fe8 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/xy.c @@ -0,0 +1,1024 @@ + +#include "qe3.h" +#include "clip.h" +#include "undo.h" + +#define PAGEFLIPS 2 + +/* +============ +XY_Init +============ +*/ +void XY_Init (void) +{ + + g_qeglobals.d_xy.origin[0] = 0; + g_qeglobals.d_xy.origin[1] = 20; + g_qeglobals.d_xy.origin[2] = 46; + g_qeglobals.d_xy.scale = 1; +} + + +/* +============================================================================ + + MOUSE ACTIONS + +============================================================================ +*/ + +static int cursorx, cursory; +static int buttonstate; +static int pressx, pressy; +static vec3_t pressdelta; +static qboolean press_selection; +static vec3_t cliplinestart; +static vec3_t cliplineend; + +void XY_ToPoint (int x, int y, vec3_t point) +{ + point[0] = g_qeglobals.d_xy.origin[0] + (x - g_qeglobals.d_xy.width/2)/g_qeglobals.d_xy.scale; + point[1] = g_qeglobals.d_xy.origin[1] + (y - g_qeglobals.d_xy.height/2)/g_qeglobals.d_xy.scale; + point[2] = 0; +} + +void XY_ToGridPoint (int x, int y, vec3_t point) +{ + point[0] = g_qeglobals.d_xy.origin[0] + (x - g_qeglobals.d_xy.width/2)/g_qeglobals.d_xy.scale; + point[1] = g_qeglobals.d_xy.origin[1] + (y - g_qeglobals.d_xy.height/2)/g_qeglobals.d_xy.scale; + point[2] = 0; + point[0] = floor(point[0]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + point[1] = floor(point[1]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; +} + +/* +============== +XY_MouseDown +============== +*/ +void Drag_Reset (void); +void XY_MouseDown (int x, int y, int buttons) +{ + vec3_t point; + vec3_t origin, dir, right, up; + + Drag_Reset(); + buttonstate = buttons; + pressx = x; + pressy = y; + VectorCopy (vec3_origin, pressdelta); + + XY_ToPoint (x, y, point); + + VectorCopy (point, origin); + origin[2] = 8192; + + dir[0] = 0; dir[1] = 0; dir[2] = -1; + right[0] = 1/g_qeglobals.d_xy.scale; right[1] = 0; right[2] = 0; + up[0] = 0; up[1] = 1/g_qeglobals.d_xy.scale; up[2] = 0; + + press_selection = (selected_brushes.next != &selected_brushes); + + Sys_GetCursorPos (&cursorx, &cursory); + + // lbutton = manipulate selection + // shift-LBUTTON = select + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == (MK_LBUTTON | MK_CONTROL)) + || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) + || (buttons == (MK_LBUTTON | MK_RBUTTON))) + { + Drag_Begin (x, y, buttons, + right, up, + origin, dir); + return; + } + + // control mbutton = move camera + if (buttonstate == (MK_CONTROL|MK_MBUTTON) ) + { + camera.origin[0] = point[0]; + camera.origin[1] = point[1]; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + } + + // mbutton = angle camera + if (buttonstate == MK_MBUTTON) + { + VectorSubtract (point, camera.origin, point); + if (point[1] || point[0]) + { + camera.angles[YAW] = 180/Q_PI*atan2 (point[1], point[0]); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + } + } + + // shift mbutton = move z checker + if (buttonstate == (MK_SHIFT|MK_MBUTTON) ) + { + XY_ToPoint (x, y, point); + z.origin[0] = point[0]; + z.origin[1] = point[1]; + Sys_UpdateWindows (W_XY_OVERLAY|W_Z); + return; + } + // control rbutton = clip brush + if (buttonstate == (MK_CONTROL|MK_RBUTTON)) + { + if (!QE_SingleBrush()) + { + Sys_Status ("Must have exactly one brush selected.", 0); + Sys_Beep (); + return; + } + XY_ToGridPoint(x, y, cliplinestart); + XY_ToGridPoint(x, y, cliplineend); + Begin_Clip(x, y); + return; + } +} + +/* +============== +XY_MouseUp +============== +*/ +void XY_MouseUp (int x, int y, int buttons) +{ + Drag_MouseUp (); + + if (!press_selection) + Sys_UpdateWindows (W_ALL); + + if (buttonstate == (MK_CONTROL|MK_RBUTTON)) + { + if (!QE_SingleBrush()) + { + Sys_Status ("Must have exactly one brush selected.", 0); + Sys_Beep (); + } + else + { + Finish_Clip( x, y); + } + } + + + buttonstate = 0; +} + +qboolean DragDelta (int x, int y, vec3_t move) +{ + vec3_t xvec, yvec, delta; + int i; + + xvec[0] = 1/g_qeglobals.d_xy.scale; + xvec[1] = xvec[2] = 0; + yvec[1] = 1/g_qeglobals.d_xy.scale; + yvec[0] = yvec[2] = 0; + + for (i=0 ; i<3 ; i++) + { + delta[i] = xvec[i]*(x - pressx) + yvec[i]*(y - pressy); + delta[i] = floor(delta[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + VectorSubtract (delta, pressdelta, move); + VectorCopy (delta, pressdelta); + + if (move[0] || move[1] || move[2]) + return true; + return false; +} + +/* +============== +NewBrushDrag +============== +*/ +void NewBrushDrag (int x, int y) +{ + vec3_t mins, maxs, junk; + int i; + float temp; + brush_t *n; + + if (!DragDelta (x,y, junk)) + return; + // delete the current selection + if (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next); + XY_ToGridPoint (pressx, pressy, mins); + mins[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z/g_qeglobals.d_gridsize)); + XY_ToGridPoint (x, y, maxs); + maxs[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z/g_qeglobals.d_gridsize)); + if (maxs[2] <= mins[2]) + maxs[2] = mins[2] + g_qeglobals.d_gridsize; + + for (i=0 ; i<3 ; i++) + { + if (mins[i] == maxs[i]) + return; // don't create a degenerate brush + if (mins[i] > maxs[i]) + { + temp = mins[i]; + mins[i] = maxs[i]; + maxs[i] = temp; + } + } + + n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); + if (!n) + return; + + Brush_AddToList (n, &selected_brushes); + + Entity_LinkBrush (world_entity, n); + + Brush_Build( n ); + UNDO_FinishBrushAdd ("&Undo New Brush"); + +// Sys_UpdateWindows (W_ALL); + Sys_UpdateWindows (W_XY| W_CAMERA); +} + +/* +============== +XY_MouseMoved +============== +*/ +void XY_MouseMoved (int x, int y, int buttons) +{ + vec3_t point; + + if (!buttonstate) + return; + + // lbutton without selection = drag new brush + if (buttonstate == MK_LBUTTON && !press_selection) + { + NewBrushDrag (x, y); + return; + } + + // lbutton (possibly with control and or shift) + // with selection = drag selection + if (buttonstate & MK_LBUTTON) + { + Drag_MouseMoved (x, y, buttons); + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA); + return; + } + + // control mbutton = move camera + if (buttonstate == (MK_CONTROL|MK_MBUTTON) ) + { + XY_ToPoint (x, y, point); + camera.origin[0] = point[0]; + camera.origin[1] = point[1]; + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA); + return; + } + + // shift mbutton = move z checker + if (buttonstate == (MK_SHIFT|MK_MBUTTON) ) + { + XY_ToPoint (x, y, point); + z.origin[0] = point[0]; + z.origin[1] = point[1]; + Sys_UpdateWindows (W_XY_OVERLAY|W_Z); + return; + } + + // mbutton = angle camera + if (buttonstate == MK_MBUTTON ) + { + XY_ToPoint (x, y, point); + VectorSubtract (point, camera.origin, point); + if (point[1] || point[0]) + { + camera.angles[YAW] = 180/Q_PI*atan2 (point[1], point[0]); + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA); + } + return; + } + + // rbutton = drag xy origin + if (buttonstate == MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if (x != cursorx || y != cursory) + { + g_qeglobals.d_xy.origin[0] -= (x-cursorx)/g_qeglobals.d_xy.scale; + g_qeglobals.d_xy.origin[1] += (y-cursory)/g_qeglobals.d_xy.scale; + Sys_SetCursorPos (cursorx, cursory); + Sys_UpdateWindows (W_XY | W_XY_OVERLAY); + } + return; + } + // control + rbutton, draw line for clipping plane + if (buttonstate == (MK_CONTROL|MK_RBUTTON)) + { + XY_ToGridPoint(x, y, cliplineend); + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); + } + +} + + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + + +/* +============== +XY_DrawGrid +============== +*/ +void XY_DrawGrid (void) +{ + float x, y, xb, xe, yb, ye; + int w, h; + char text[32]; + + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_1D); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + + w = g_qeglobals.d_xy.width/2 / g_qeglobals.d_xy.scale; + h = g_qeglobals.d_xy.height/2 / g_qeglobals.d_xy.scale; + + xb = g_qeglobals.d_xy.origin[0] - w; + if (xb < region_mins[0]) + xb = region_mins[0]; + xb = 64 * floor (xb/64); + + xe = g_qeglobals.d_xy.origin[0] + w; + if (xe > region_maxs[0]) + xe = region_maxs[0]; + xe = 64 * ceil (xe/64); + + yb = g_qeglobals.d_xy.origin[1] - h; + if (yb < region_mins[1]) + yb = region_mins[1]; + yb = 64 * floor (yb/64); + + ye = g_qeglobals.d_xy.origin[1] + h; + if (ye > region_maxs[1]) + ye = region_maxs[1]; + ye = 64 * ceil (ye/64); + + // draw major blocks + + glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]); + + if ( g_qeglobals.d_showgrid ) + { + + glBegin (GL_LINES); + + for (x=xb ; x<=xe ; x+=64) + { + glVertex2f (x, yb); + glVertex2f (x, ye); + } + for (y=yb ; y<=ye ; y+=64) + { + glVertex2f (xb, y); + glVertex2f (xe, y); + } + + glEnd (); + + } + + // draw minor blocks + if ( g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*g_qeglobals.d_xy.scale >= 4) + { + glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]); + + glBegin (GL_LINES); + for (x=xb ; x region_maxs[0]) + xe = region_maxs[0]; + xe = 1024 * ceil (xe/1024); + + yb = g_qeglobals.d_xy.origin[1] - h; + if (yb < region_mins[1]) + yb = region_mins[1]; + yb = 1024 * floor (yb/1024); + + ye = g_qeglobals.d_xy.origin[1] + h; + if (ye > region_maxs[1]) + ye = region_maxs[1]; + ye = 1024 * ceil (ye/1024); + + // draw major blocks + + glColor3f(0,0,1); + glLineWidth (2); + + glBegin (GL_LINES); + + for (x=xb ; x<=xe ; x+=1024) + { + glVertex2f (x, yb); + glVertex2f (x, ye); + } + for (y=yb ; y<=ye ; y+=1024) + { + glVertex2f (xb, y); + glVertex2f (xe, y); + } + + glEnd (); + glLineWidth (1); + + // draw coordinate text if needed + + for (x=xb ; xowner) + return FALSE; // during construction + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) + { + if (!strncmp(pb->brush_faces->texdef.name, "clip", 4)) + return TRUE; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WATER) + { + if (pb->brush_faces->texdef.flags == 40) + { +// if (pb->brush_faces->texdef.name[0] == '*') + return TRUE; + } + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAIL) + { + if (pb->brush_faces->texdef.contents & CONTENTS_DETAIL) + return TRUE; + } + + if (pb->owner == world_entity) + { + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) + return TRUE; + return FALSE; + } + else if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT) + { + if (g_qeglobals.d_savedinfo.exclude & BUOY_ONLY) + { + if (!strcmp(ValueForKey (pb->owner , "classname"), "info_buoy")) + { + return FALSE; + } + } + return TRUE; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS) + { + if (!strncmp(pb->owner->eclass->name, "light", 5)) + return TRUE; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) + { + if (!strncmp(pb->owner->eclass->name, "path", 4)) + return TRUE; + } + + return FALSE; +} + +/* +============================================================= + + PATH LINES + +============================================================= +*/ + +/* +================== +DrawPathLines + +Draws connections between entities. +Needs to consider all entities, not just ones on screen, +because the lines can be visible when neither end is. +Called for both camera view and xy view. +================== +*/ +void DrawPathLines (void) +{ + int i, j, k; + vec3_t mid, mid1; + entity_t *se, *te; + brush_t *sb, *tb; + char *psz; + vec3_t dir, s1, s2; + vec_t len, f; + int arrows; + int num_entities; + char *ent_target[MAX_MAP_ENTITIES]; + entity_t *ent_entity[MAX_MAP_ENTITIES]; + + + num_entities = 0; + for (te = entities.next ; te != &entities && num_entities != MAX_MAP_ENTITIES ; te = te->next) + { + ent_target[num_entities] = ValueForKey (te, "target"); + ent_target[num_entities + 1] = ValueForKey (te, "target2"); + if (ent_target[num_entities][0]) + { + ent_entity[num_entities] = te; + num_entities++; + if (ent_target[num_entities][0]) + { + ent_entity[num_entities] = te; + num_entities++; + } + } + } + + for (se = entities.next ; se != &entities ; se = se->next) + { + psz = ValueForKey(se, "targetname"); + + if (psz == NULL || psz[0] == '\0') + continue; + + sb = se->brushes.onext; + if (sb == &se->brushes) + continue; + + for (k=0 ; kbrushes.onext; + if (tb == &te->brushes) + continue; + + for (i=0 ; i<3 ; i++) + mid[i] = (sb->mins[i] + sb->maxs[i])*0.5; + + for (i=0 ; i<3 ; i++) + mid1[i] = (tb->mins[i] + tb->maxs[i])*0.5; + + VectorSubtract (mid1, mid, dir); + len = VectorNormalize (dir, dir); + s1[0] = -dir[1]*8 + dir[0]*8; + s2[0] = dir[1]*8 + dir[0]*8; + s1[1] = dir[0]*8 + dir[1]*8; + s2[1] = -dir[0]*8 + dir[1]*8; + + glColor3f (se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]); + + glBegin(GL_LINES); + glVertex3fv(mid); + glVertex3fv(mid1); + + arrows = (int)(len / 256) + 1; + + for (i=0 ; inext) + { + if (brush->mins[0] > maxs[0] + || brush->mins[1] > maxs[1] + || brush->maxs[0] < mins[0] + || brush->maxs[1] < mins[1] ) + { + culled++; + continue; // off screen + } + + if (FilterBrush (brush)) + continue; + drawn++; + if (brush->owner != e) + { + e = brush->owner; + glColor3fv(e->eclass->color); + } + Brush_DrawXY( brush ); + } + + DrawPathLines (); + + // + // draw pointfile + // + if ( g_qeglobals.d_pointfile_display_list) + glCallList (g_qeglobals.d_pointfile_display_list); + + // + // draw block grid + // + if ( g_qeglobals.show_blocks) + XY_DrawBlockGrid (); + + // + // now draw selected brushes + // + glTranslatef( g_qeglobals.d_select_translate[0], g_qeglobals.d_select_translate[1], g_qeglobals.d_select_translate[2]); + + glColor3f(1.0, 0.0, 0.0); + glEnable (GL_LINE_STIPPLE); + glLineStipple (3, 0xaaaa); + glLineWidth (2); + + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + drawn++; + Brush_DrawXY( brush ); + } + + glDisable (GL_LINE_STIPPLE); + glLineWidth (1); + + // edge / vertex flags + + if (g_qeglobals.d_select_mode == sel_vertex) + { + glPointSize (4); + glColor3f (0,1,0); + glBegin (GL_POINTS); + for (i=0 ; imins[0] + b->maxs[0])/2; + } + + dir[0] = 0; dir[1] = 1; dir[2] = 0; + + vright[0] = 0; vright[1] = 0; vright[2] = 0; + + // LBUTTON = manipulate selection + // shift-LBUTTON = select + // middle button = grab texture + // ctrl-middle button = set entire brush to texture + // ctrl-shift-middle button = set single face to texture + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == MK_MBUTTON) +// || (buttons == (MK_MBUTTON|MK_CONTROL)) + || (buttons == (MK_MBUTTON|MK_SHIFT|MK_CONTROL)) ) + { + Drag_Begin (x, y, buttons, + vright, vup, + org, dir); + return; + } + + // control mbutton = move camera + if ((buttons == (MK_CONTROL|MK_MBUTTON) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) + { + camera.origin[2] = org[2] ; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); + } + + +} + +/* +============== +Z_MouseUp +============== +*/ +void Z_MouseUp (int x, int y, int buttons) +{ + Drag_MouseUp (); +} + +/* +============== +Z_MouseMoved +============== +*/ +void Z_MouseMoved (int x, int y, int buttons) +{ + if (!buttons) + return; + if (buttons == MK_LBUTTON) + { + Drag_MouseMoved (x, y, buttons); + Sys_UpdateWindows (W_Z|W_CAMERA); + return; + } + // rbutton = drag z origin + if (buttons == MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if ( y != cursory) + { + z.origin[2] += y-cursory; + Sys_SetCursorPos (cursorx, cursory); + Sys_UpdateWindows (W_Z); + } + return; + } + // control mbutton = move camera + if ((buttons == (MK_CONTROL|MK_MBUTTON) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) + { + camera.origin[2] = (y - (z.height/2))/z.scale; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); + } + +} + + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + + +/* +============== +Z_DrawGrid +============== +*/ +void Z_DrawGrid (void) +{ + float zz, zb, ze; + int w, h; + char text[32]; + + w = z.width/2 / z.scale; + h = z.height/2 / z.scale; + + zb = z.origin[2] - h; + if (zb < region_mins[2]) + zb = region_mins[2]; + zb = 64 * floor (zb/64); + + ze = z.origin[2] + h; + if (ze > region_maxs[2]) + ze = region_maxs[2]; + ze = 64 * ceil (ze/64); + + // draw major blocks + + glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]); + + glBegin (GL_LINES); + + glVertex2f (0, zb); + glVertex2f (0, ze); + + for (zz=zb ; zz= 4) + { + glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]); + + glBegin (GL_LINES); + for (zz=zb ; zznext) + { + if (brush->mins[0] >= z.origin[0] + || brush->maxs[0] <= z.origin[0] + || brush->mins[1] >= z.origin[1] + || brush->maxs[1] <= z.origin[1]) + continue; + + if (!Brush_Ray (org_top, dir_down, brush, &top)) + continue; + top = org_top[2] - top; + if (!Brush_Ray (org_bottom, dir_up, brush, &bottom)) + continue; + bottom = org_bottom[2] + bottom; + + q = Texture_ForName (brush->brush_faces->texdef.name); + glColor3f (q->color[0], q->color[1], q->color[2]); + glBegin (GL_QUADS); + glVertex2f (-xCam, bottom); + glVertex2f (xCam, bottom); + glVertex2f (xCam, top); + glVertex2f (-xCam, top); + glEnd (); + + glColor3f (1,1,1); + glBegin (GL_LINE_LOOP); + glVertex2f (-xCam, bottom); + glVertex2f (xCam, bottom); + glVertex2f (xCam, top); + glVertex2f (-xCam, top); + glEnd (); + } + + // + // now draw selected brushes + // + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + if ( !(brush->mins[0] >= z.origin[0] + || brush->maxs[0] <= z.origin[0] + || brush->mins[1] >= z.origin[1] + || brush->maxs[1] <= z.origin[1]) ) + { + if (Brush_Ray (org_top, dir_down, brush, &top)) + { + top = org_top[2] - top; + if (Brush_Ray (org_bottom, dir_up, brush, &bottom)) + { + bottom = org_bottom[2] + bottom; + + q = Texture_ForName (brush->brush_faces->texdef.name); + glColor3f (q->color[0], q->color[1], q->color[2]); + glBegin (GL_QUADS); + glVertex2f (-xCam, bottom); + glVertex2f (xCam, bottom); + glVertex2f (xCam, top); + glVertex2f (-xCam, top); + glEnd (); + } + } + } + + glColor3f (1,0,0); + glBegin (GL_LINE_LOOP); + glVertex2f (-xCam, brush->mins[2]); + glVertex2f (xCam, brush->mins[2]); + glVertex2f (xCam, brush->maxs[2]); + glVertex2f (-xCam, brush->maxs[2]); + glEnd (); + } + + + ZDrawCameraIcon (); + + glFinish(); + QE_CheckOpenGLForErrors(); + + if (z.timing) + { + end = Sys_DoubleTime (); + Sys_Printf ("z: %i ms\n", (int)(1000*(end-start))); + } +} + diff --git a/Toolkit/Programming/Tools/qe4/z.h b/Toolkit/Programming/Tools/qe4/z.h new file mode 100644 index 0000000..185bc62 --- /dev/null +++ b/Toolkit/Programming/Tools/qe4/z.h @@ -0,0 +1,21 @@ + +// window system independent camera view code + +typedef struct +{ + int width, height; + + qboolean timing; + + vec3_t origin; // at center of window + float scale; +} z_t; + +extern z_t z; + +void Z_Init (void); +void Z_MouseDown (int x, int y, int buttons); +void Z_MouseUp (int x, int y, int buttons); +void Z_MouseMoved (int x, int y, int buttons); +void Z_Draw (void); + diff --git a/Toolkit/Programming/Tools/ref_common/Font1.c b/Toolkit/Programming/Tools/ref_common/Font1.c new file mode 100644 index 0000000..ad71599 --- /dev/null +++ b/Toolkit/Programming/Tools/ref_common/Font1.c @@ -0,0 +1,212 @@ +// TMix (c) Raven Software (Pagan). +// 96 textures processed. +// 56% of total area consumed +// 0 of textures were unable to be placed. + +typedef struct glxy_s +{ + float xl, yt, xr, yb; + int w, h, baseline; +} glxy_t; + +#define glxy(label, x, y, w, h, b) static glxy_t label = {(x / 256.000000), (y / 128.000000), ((x + w) / 256.000000), ((y + h) / 128.000000), w, h, b }; + +// Format: xpos,ypos,width,height,baseline + + glxy(PERCENT, 0, 0, 17, 21, 20); + glxy(U_W, 18, 0, 24, 14, 12); + glxy(AT, 42, 0, 19, 18, 14); + glxy(U_A, 62, 0, 20, 17, 16); + glxy(U_P, 82, 0, 17, 20, 14); + glxy(POUND, 100, 0, 19, 18, 17); + glxy(U_M, 120, 0, 19, 17, 13); + glxy(U_N, 140, 0, 19, 17, 15); + glxy(U_D, 160, 0, 16, 19, 16); + glxy(U_B, 176, 0, 16, 18, 16); + glxy(U_K, 192, 0, 19, 15, 14); + glxy(STRING, 212, 0, 13, 21, 18); + glxy(U_Q, 226, 0, 18, 16, 14); + glxy(U_R, 18, 14, 14, 20, 14); + glxy(U_E, 192, 16, 15, 18, 15); + glxy(U_H, 226, 16, 17, 16, 14); + glxy(L_B, 244, 0, 11, 22, 18); + glxy(L_H, 32, 18, 14, 19, 16); + glxy(N_2, 46, 18, 17, 15, 13); + glxy(QUERY, 64, 18, 13, 19, 18); + glxy(U_L, 100, 18, 16, 16, 15); + glxy(U_T, 116, 18, 16, 16, 14); + glxy(U_Y, 132, 18, 14, 18, 13); + glxy(L_K, 176, 18, 15, 17, 15); + glxy(L_M, 78, 20, 19, 13, 9); + glxy(L_W, 146, 20, 19, 13, 11); + glxy(TILDE, 0, 22, 15, 17, 16); + glxy(U_C, 208, 22, 15, 16, 15); + glxy(AST, 244, 22, 12, 19, 18); + glxy(U_V, 224, 32, 15, 16, 14); + glxy(U_X, 16, 34, 14, 17, 14); + glxy(U_Z, 46, 34, 15, 16, 14); + glxy(L_Y, 78, 34, 13, 18, 9); + glxy(HASH, 92, 34, 15, 15, 13); + glxy(U_F, 108, 34, 14, 16, 14); + glxy(U_G, 146, 34, 11, 19, 14); + glxy(U_S, 158, 34, 14, 16, 14); + glxy(N_5, 192, 34, 14, 16, 13); + glxy(CARET, 122, 36, 13, 17, 16); + glxy(L_F, 172, 36, 11, 19, 16); + glxy(L_J, 136, 36, 9, 21, 15); + glxy(L_P, 30, 38, 12, 18, 8); + glxy(PLUS, 62, 38, 14, 15, 14); + glxy(L_D, 206, 38, 11, 18, 15); + glxy(L_V, 0, 40, 14, 15, 12); + glxy(U_U, 240, 42, 14, 14, 12); + glxy(N_3, 218, 48, 12, 16, 13); + glxy(FSLASH, 230, 48, 10, 18, 17); + glxy(N_4, 42, 50, 14, 14, 12); + glxy(OPENB, 92, 50, 9, 18, 17); + glxy(GREAT, 102, 50, 13, 14, 13); + glxy(BSLASH, 158, 50, 9, 18, 17); + glxy(LESS, 184, 50, 13, 14, 13); + glxy(L_G, 14, 52, 10, 17, 8); + glxy(N_8, 76, 52, 13, 14, 12); + glxy(L_T, 56, 54, 11, 16, 13); + glxy(U_J, 116, 54, 10, 17, 14); + glxy(N_9, 146, 54, 11, 16, 14); + glxy(OPENCB, 126, 54, 9, 18, 17); + glxy(CLOSECB, 0, 56, 9, 18, 17); + glxy(CLOSESB, 24, 56, 9, 17, 16); + glxy(L_A, 168, 56, 14, 12, 9); + glxy(AMP, 198, 56, 11, 15, 13); + glxy(N_7, 240, 56, 11, 15, 13); + glxy(PLING, 68, 54, 8, 18, 16); + glxy(OPENSB, 136, 58, 9, 17, 16); + glxy(CLOSEB, 34, 56, 8, 17, 16); + glxy(L_I, 210, 56, 8, 17, 14); + glxy(U_O, 42, 64, 10, 15, 13); + glxy(EQUAL, 102, 64, 14, 11, 10); + glxy(L_N, 182, 64, 14, 11, 9); + glxy(U_I, 218, 64, 10, 15, 14); + glxy(L_Q, 76, 66, 11, 14, 8); + glxy(N_6, 228, 66, 10, 15, 13); + glxy(QUOTE, 88, 68, 8, 17, 16); + glxy(L_Z, 158, 68, 13, 12, 9); + glxy(N_0, 172, 68, 9, 15, 13); + glxy(L_U, 10, 70, 13, 11, 9); + glxy(L_X, 52, 70, 12, 12, 9); + glxy(BAR, 252, 56, 3, 21, 16); + glxy(L_L, 146, 70, 7, 16, 14); + glxy(N_1, 64, 72, 8, 15, 13); + glxy(APOST, 96, 68, 5, 17, 16); + glxy(L_E, 166, 20, 10, 12, 9); + glxy(SQUOTE, 116, 72, 5, 17, 16); + glxy(L_C, 122, 72, 9, 12, 9); + glxy(L_O, 196, 72, 9, 11, 9); + glxy(L_S, 184, 36, 6, 13, 10); + glxy(SEMICOLON, 238, 72, 5, 14, 11); + glxy(L_R, 0, 74, 9, 10, 8); + glxy(STOP, 244, 72, 5, 13, 12); + glxy(UNDER, 24, 74, 12, 5, 0); + glxy(COLON, 36, 74, 5, 12, 11); + glxy(MINUS, 206, 74, 8, 8, 7); + glxy(COMMA, 218, 38, 5, 7, 4); + +glxy_t *font1[96] = +{ + 0, + &PLING, + "E, + &HASH, + &STRING, + &PERCENT, + &, + &SQUOTE, + &OPENB, + &CLOSEB, + &AST, + &PLUS, + &COMMA, + &MINUS, + &STOP, + &FSLASH, + &N_0, + &N_1, + &N_2, + &N_3, + &N_4, + &N_5, + &N_6, + &N_7, + &N_8, + &N_9, + &COLON, + &SEMICOLON, + &LESS, + &EQUAL, + &GREAT, + &QUERY, + &AT, + &U_A, + &U_B, + &U_C, + &U_D, + &U_E, + &U_F, + &U_G, + &U_H, + &U_I, + &U_J, + &U_K, + &U_L, + &U_M, + &U_N, + &U_O, + &U_P, + &U_Q, + &U_R, + &U_S, + &U_T, + &U_U, + &U_V, + &U_W, + &U_X, + &U_Y, + &U_Z, + &OPENSB, + &BSLASH, + &CLOSESB, + &CARET, + &UNDER, + &APOST, + &L_A, + &L_B, + &L_C, + &L_D, + &L_E, + &L_F, + &L_G, + &L_H, + &L_I, + &L_J, + &L_K, + &L_L, + &L_M, + &L_N, + &L_O, + &L_P, + &L_Q, + &L_R, + &L_S, + &L_T, + &L_U, + &L_V, + &L_W, + &L_X, + &L_Y, + &L_Z, + &OPENCB, + &BAR, + &CLOSECB, + &TILDE, + &POUND, +}; + +// end diff --git a/Toolkit/Programming/Tools/ref_common/fmodel.h b/Toolkit/Programming/Tools/ref_common/fmodel.h new file mode 100644 index 0000000..79a24b8 --- /dev/null +++ b/Toolkit/Programming/Tools/ref_common/fmodel.h @@ -0,0 +1,242 @@ + +/* +======================================================================== + +.FM triangle flexible model file format + +======================================================================== +*/ + +#ifndef __FMODEL_HEADER +#define __FMODEL_HEADER + + +typedef unsigned char byte; +typedef int qboolean; +typedef float vec3_t[3]; + +#define MAX_FM_TRIANGLES 2048 +#define MAX_FM_VERTS 2048 +#define MAX_FM_FRAMES 2048 +#define MAX_FM_SKINS 64 +#define MAX_FM_SKINNAME 64 +#define MAX_FM_MESH_NODES 16 // also defined in game/qshared.h + + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +#define SKINPAGE_WIDTH 640 +#define SKINPAGE_HEIGHT 480 + +#define ENCODED_WIDTH_X 92 +#define ENCODED_WIDTH_Y 475 +#define ENCODED_HEIGHT_X 128 +#define ENCODED_HEIGHT_Y 475 + +#define SCALE_ADJUST_FACTOR 0.96 + +#define INFO_HEIGHT 5 +#define INFO_Y (SKINPAGE_HEIGHT-INFO_HEIGHT) + +extern byte *BasePalette; +extern byte *BasePixels,*TransPixels; +extern int BaseWidth, BaseHeight, TransWidth, TransHeight; +extern int ScaleWidth, ScaleHeight; + +int ExtractNumber(byte *pic, int x, int y); +void DrawTextChar(int x, int y, char *text); +void DrawLine(int x1, int y1, int x2, int y2); + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +// Initial Header +#define FM_HEADER_NAME "header" +#define FM_HEADER_VER 2 + +typedef struct +{ + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + int num_mesh_nodes; +} fmheader_t; + + +// Skin Header +#define FM_SKIN_NAME "skin" +#define FM_SKIN_VER 1 + + +// ST Coord Header +#define FM_ST_NAME "st coord" +#define FM_ST_VER 1 + +typedef struct +{ + short s; + short t; +} fmstvert_t; + + +// Tri Header +#define FM_TRI_NAME "tris" +#define FM_TRI_VER 1 + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} fmtriangle_t; + + +// Frame Header +#define FM_FRAME_NAME "frames" +#define FM_FRAME_VER 1 + +// Frame for compression, just the names +#define FM_SHORT_FRAME_NAME "short frames" +#define FM_SHORT_FRAME_VER 1 + +// Normals for compressed frames +#define FM_NORMAL_NAME "normals" +#define FM_NORMAL_VER 1 + +// Compressed Frame Data +#define FM_COMP_NAME "comp data" +#define FM_COMP_VER 1 + +// GL Cmds Header +#define FM_GLCMDS_NAME "glcmds" +#define FM_GLCMDS_VER 1 + + +// Mesh Nodes Header +#define FM_MESH_NAME "mesh nodes" +#define FM_MESH_VER 3 + +// Skeleton Header +#define FM_SKELETON_NAME "skeleton" +#define FM_SKELETON_VER 1 + +// References Header +#define FM_REFERENCES_NAME "references" +#define FM_REFERENCES_VER 1 + +typedef struct +{ + + union + { + + byte tris[MAX_FM_TRIANGLES>>3]; + + struct { + short *triIndicies; + int num_tris; + }; + + }; + + byte verts[MAX_FM_VERTS>>3]; + short start_glcmds, num_glcmds; +} fmmeshnode_t; + +//================================================================= + +// Frame info +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} fmtrivertx_t; + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + fmtrivertx_t verts[1]; // variable sized +} fmaliasframe_t; + +#ifndef _TOOL // the following is only relevant to the game code + +typedef struct +{ + int start_frame; + int num_frames; + int degrees; + char *mat; + char *ccomp; + unsigned char *cbase; + float *cscale; + float *coffset; + float trans[3]; + float scale[3]; + float bmin[3]; + float bmax[3]; + float *complerp; +} fmgroup_t; + +#define MAX_COMP_DOF 25 + +#define FRAME_NAME_LEN (16) + +typedef struct fmdl_s +{ + fmheader_t header; + fmstvert_t *st_verts; + fmtriangle_t *tris; + fmaliasframe_t *frames; + int *glcmds; + char *skin_names; + fmmeshnode_t *mesh_nodes; + //compression stuff + int ngroups; + fmgroup_t *compdata; + int *frame_to_group; + char *framenames; + byte *lightnormalindex; + //end comp stuff + + int skeletalType; + int rootCluster; + struct ModelSkeleton_s *skeletons; + + int referenceType; + struct M_Reference_s *refsForFrame; +} fmdl_t; + +/***************************************************** + * Flex Model Loading Routines + *****************************************************/ + +extern fmdl_t *fmodel; + +void Mod_LoadFlexModel (struct model_s *mod, void *buffer, int length); +void Mod_RegisterFlexModel(struct model_s *mod); +void R_DrawFlexModel (entity_t *e); + +void GL_LerpVert(vec3_t newPoint, vec3_t oldPoint, vec3_t interpolatedPoint, float move[3], float frontv[3], float backv[3]); + +#endif + + +#endif // #define __FMODEL_HEADER diff --git a/Toolkit/Programming/Tools/ref_common/m_Reference.c b/Toolkit/Programming/Tools/ref_common/m_Reference.c new file mode 100644 index 0000000..5513b86 --- /dev/null +++ b/Toolkit/Programming/Tools/ref_common/m_Reference.c @@ -0,0 +1,23 @@ +#include "Reference.h" + +#ifdef _REF_GL +#include "gl_local.h" +#else +#include "r_local.h" +#endif + +#include "fmodel.h" + +int GetReferencedID(struct model_s *model) +{ + fmdl_t *temp = model->extradata; + + if (model->model_type) + { + if(temp->referenceType < NUM_REFERENCED && temp->referenceType > REF_NULL) + { + return temp->referenceType; + } + } + return REF_NULL; +} \ No newline at end of file diff --git a/Toolkit/Programming/Tools/ref_common/m_Reference.h b/Toolkit/Programming/Tools/ref_common/m_Reference.h new file mode 100644 index 0000000..4c5b929 --- /dev/null +++ b/Toolkit/Programming/Tools/ref_common/m_Reference.h @@ -0,0 +1,8 @@ +#include "Placement.h" + +typedef struct M_Reference_s +{ + Placement_t placement; +} M_Reference_t; + +int GetReferencedID(struct model_s *model); diff --git a/Toolkit/Programming/Tools/ref_common/m_SkeletalCluster.h b/Toolkit/Programming/Tools/ref_common/m_SkeletalCluster.h new file mode 100644 index 0000000..b9dad1f --- /dev/null +++ b/Toolkit/Programming/Tools/ref_common/m_SkeletalCluster.h @@ -0,0 +1,10 @@ +typedef int qboolean; + +typedef struct M_SkeletalCluster_s +{ + int children; // must be the first field + int numVerticies; + int *verticies; + qboolean inUse; +} M_SkeletalCluster_t; + diff --git a/Toolkit/Programming/Tools/ref_common/m_Skeleton.h b/Toolkit/Programming/Tools/ref_common/m_Skeleton.h new file mode 100644 index 0000000..6ece519 --- /dev/null +++ b/Toolkit/Programming/Tools/ref_common/m_Skeleton.h @@ -0,0 +1,21 @@ +#include "Placement.h" +#include "Matrix.h" + +typedef int qboolean; + +typedef struct M_SkeletalJoint_s +{ + int children; // must be the first field + Placement_t model; // relative to the model, used for dynamic software rotation + Placement_t parent; // relative to the parent joint (or model in case of root joint), used for + // inverse kinematics + matrix3_t rotation; + qboolean inUse; +} M_SkeletalJoint_t; + +typedef struct ModelSkeleton_s +{ + M_SkeletalJoint_t *rootJoint; + struct ArrayedListNode_s *rootNode; +} ModelSkeleton_t; + diff --git a/Toolkit/Programming/Tools/ref_common/part_uvs.h b/Toolkit/Programming/Tools/ref_common/part_uvs.h new file mode 100644 index 0000000..df0d666 --- /dev/null +++ b/Toolkit/Programming/Tools/ref_common/part_uvs.h @@ -0,0 +1,145 @@ +// Need to shunt all particle textures in 0.5 of a pixel to avoid texture bleed + +#define FRAC (1.0F / 256.0F) +#define UNIT (1.0F / 128.0F) + +#define PRT_LT00 ((0.0F * UNIT) + FRAC) +#define PRT_LT04 ((4.0F * UNIT) + FRAC) +#define PRT_LT08 ((8.0F * UNIT) + FRAC) +#define PRT_LT12 ((12.0F * UNIT) + FRAC) +#define PRT_LT16 ((16.0F * UNIT) + FRAC) +#define PRT_LT24 ((24.0F * UNIT) + FRAC) +#define PRT_LT32 ((32.0F * UNIT) + FRAC) +#define PRT_LT40 ((40.0F * UNIT) + FRAC) +#define PRT_LT48 ((48.0F * UNIT) + FRAC) +#define PRT_LT56 ((56.0F * UNIT) + FRAC) +#define PRT_LT64 ((64.0F * UNIT) + FRAC) +#define PRT_LT72 ((72.0F * UNIT) + FRAC) +#define PRT_LT80 ((80.0F * UNIT) + FRAC) +#define PRT_LT88 ((88.0F * UNIT) + FRAC) +#define PRT_LT96 ((96.0F * UNIT) + FRAC) +#define PRT_LT112 ((112.0F * UNIT) + FRAC) + +#define PRT_RB04 ((4.0F * UNIT) - FRAC) +#define PRT_RB08 ((8.0F * UNIT) - FRAC) +#define PRT_RB12 ((12.0F * UNIT) - FRAC) +#define PRT_RB16 ((16.0F * UNIT) - FRAC) +#define PRT_RB24 ((24.0F * UNIT) - FRAC) +#define PRT_RB32 ((32.0F * UNIT) - FRAC) +#define PRT_RB40 ((40.0F * UNIT) - FRAC) +#define PRT_RB48 ((48.0F * UNIT) - FRAC) +#define PRT_RB56 ((56.0F * UNIT) - FRAC) +#define PRT_RB64 ((64.0F * UNIT) - FRAC) +#define PRT_RB72 ((72.0F * UNIT) - FRAC) +#define PRT_RB80 ((80.0F * UNIT) - FRAC) +#define PRT_RB88 ((88.0F * UNIT) - FRAC) +#define PRT_RB96 ((96.0F * UNIT) - FRAC) +#define PRT_RB112 ((112.0F * UNIT) - FRAC) +#define PRT_RB128 ((128.0F * UNIT) - FRAC) + +typedef struct tex_coords_s +{ + float lx; + float ty; + float rx; + float by; +} tex_coords_t; + +// Note: Coordinates are described in 16x16 cells because there are the most common +static tex_coords_t part_TexCoords[NUM_PARTICLE_TYPES] = +{ + // Small 4x4 particles in the upper left (0,0) + PRT_LT00, PRT_LT00, PRT_RB04, PRT_RB04, // PART_4x4_WHITE, + PRT_LT04, PRT_LT00, PRT_RB08, PRT_RB04, // PART_4x4_BLUE, + PRT_LT08, PRT_LT00, PRT_RB12, PRT_RB04, // PART_4x4_RED, + PRT_LT12, PRT_LT00, PRT_RB16, PRT_RB04, // PART_4x4_GREEN, + + PRT_LT00, PRT_LT04, PRT_RB04, PRT_RB08, // PART_4x4_CYAN, + PRT_LT04, PRT_LT04, PRT_RB08, PRT_RB08, // PART_4x4_YELLOW, + PRT_LT08, PRT_LT04, PRT_RB12, PRT_RB08, // PART_4x4_MAGENTA, + PRT_LT12, PRT_LT04, PRT_RB16, PRT_RB08, // PART_4x4_ORANGE, + + PRT_LT00, PRT_LT08, PRT_RB04, PRT_RB12, // PART_4x4_BLUE2, + PRT_LT04, PRT_LT08, PRT_RB08, PRT_RB12, // PART_4x4_BLUE3, + PRT_LT08, PRT_LT08, PRT_RB12, PRT_RB12, // PART_4x4_UNUSED1, + PRT_LT12, PRT_LT08, PRT_RB16, PRT_RB12, // PART_4x4_UNUSED2, + + PRT_LT00, PRT_LT12, PRT_RB04, PRT_RB16, // PART_4x4_BLOOD1, + PRT_LT04, PRT_LT12, PRT_RB08, PRT_RB16, // PART_4x4_BLOOD2, + PRT_LT08, PRT_LT12, PRT_RB12, PRT_RB16, // PART_4x4_GREENBLOOD1, + PRT_LT12, PRT_LT12, PRT_RB16, PRT_RB16, // PART_4x4_GREENBLOOD2, + + // Unused 16x16 section, to right of above 16x16 section (1,0) + PRT_LT16, PRT_LT00, PRT_RB24, PRT_RB08, // PART_8x8_BUBBLE, + PRT_LT24, PRT_LT00, PRT_RB32, PRT_RB08, // PART_8x8_BLOOD, + PRT_LT16, PRT_LT08, PRT_RB24, PRT_RB16, // PART_8x8_GLOBBIT1, + PRT_LT24, PRT_LT08, PRT_RB32, PRT_RB16, // PART_8x8_GLOBBIT2, + + // Two sections, directly below the above two sections (0,1) and (1,1) + PRT_LT00, PRT_LT16, PRT_RB16, PRT_RB32, // PART_16x16_MIST, + PRT_LT16, PRT_LT16, PRT_RB32, PRT_RB32, // PART_16x16_GLOB, + + // Next 32x32 section, to the left of the above 32x32 section (2,0), (3,0), (2,1) and (3,1) + PRT_LT32, PRT_LT00, PRT_RB48, PRT_RB16, // PART_16x16_STAR, + PRT_LT48, PRT_LT00, PRT_RB64, PRT_RB16, // PART_16x16_WATERDROP, + PRT_LT32, PRT_LT16, PRT_RB48, PRT_RB32, // PART_16x16_LIGHTNING, + PRT_LT48, PRT_LT16, PRT_RB64, PRT_RB32, // PART_16x16_BLOOD, + + // Two 32x32 sections, below the above two 32x32 sections (0,2) and (2,2) + PRT_LT00, PRT_LT32, PRT_RB32, PRT_RB64, // PART_32x32_STEAM, + PRT_LT32, PRT_LT32, PRT_RB64, PRT_RB64, // PART_32x32_WFALL, + + // Three 32x32 sections, in the upper right 1/4 of the page (4,0) (6,0) (4,2) + PRT_LT64, PRT_LT00, PRT_RB96, PRT_RB32, // PART_32x32_FIRE0, + PRT_LT96, PRT_LT00, PRT_RB128, PRT_RB32, // PART_32x32_FIRE1, + PRT_LT64, PRT_LT32, PRT_RB96, PRT_RB64, // PART_32x32_FIRE2, + + // The single remaining 32x32 section, in the lower right of the above one (6,2) + PRT_LT96, PRT_LT32, PRT_RB112, PRT_RB48, // PART_16x16_SPARK_B, + PRT_LT112, PRT_LT32, PRT_RB128, PRT_RB48, // PART_16x16_SPARK_R, + PRT_LT96, PRT_LT48, PRT_RB112, PRT_RB64, // PART_16x16_SPARK_G, + PRT_LT112, PRT_LT48, PRT_RB128, PRT_RB64, // PART_16x16_SPARK_Y, + + // The third 32x32 section down, on the left (0,4) + PRT_LT00, PRT_LT64, PRT_RB32, PRT_RB96, // PART_32x32_FIREBALL, + + // The next 32x32 section to the right of the above cell (2,4), (3,4), (2,5) and (3,5) + PRT_LT32, PRT_LT64, PRT_RB48, PRT_RB80, // PART_16x16_SPARK_C + // These are little 8x8 critters + PRT_LT48, PRT_LT64, PRT_RB56, PRT_RB72, // PART_8x8_RED_X, + PRT_LT56, PRT_LT64, PRT_RB64, PRT_RB72, // PART_8x8_RED_CIRCLE + PRT_LT48, PRT_LT72, PRT_RB56, PRT_RB80, // PART_8x8_GREEN_X + PRT_LT56, PRT_LT72, PRT_RB64, PRT_RB80, // PART_8x8_GREEN_CIRCLE + + PRT_LT32, PRT_LT80, PRT_RB40, PRT_RB88, // PART_8x8_BLUE_X + PRT_LT40, PRT_LT80, PRT_RB48, PRT_RB88, // PART_8x8_BLUE_CIRCLE + PRT_LT32, PRT_LT88, PRT_RB40, PRT_RB96, // PART_8x8_CYAN_X + PRT_LT40, PRT_LT88, PRT_RB48, PRT_RB96, // PART_8x8_CYAN_CIRCLE + + PRT_LT48, PRT_LT80, PRT_RB56, PRT_RB88, // PART_8x8_RED_DIAMOND, + PRT_LT56, PRT_LT80, PRT_RB64, PRT_RB88, // PART_8x8_GREEN_DIAMOND, + PRT_LT48, PRT_LT88, PRT_RB56, PRT_RB96, // PART_8x8_BLUE_DIAMOND, + PRT_LT56, PRT_LT88, PRT_RB64, PRT_RB96, // PART_8x8_CYAN_DIAMOND, + + // Bottom two 32x32 sections, lower left (0,6) and (2,6) + PRT_LT00, PRT_LT96, PRT_RB32, PRT_RB128, // PART_32x32_BUBBLE, + PRT_LT32, PRT_LT96, PRT_RB64, PRT_RB128, // PART_32x32_ALPHA_GLOBE, + + // Upper left of lower right quadrant (4,4) + PRT_LT64, PRT_LT64, PRT_RB80, PRT_RB80, // PART_16x16_SPARK_I + PRT_LT80, PRT_LT64, PRT_RB96, PRT_RB80, // PART_16x16_BLUE_PUFF + PRT_LT64, PRT_LT80, PRT_RB80, PRT_RB96, // PART_16x16_UNUSED + PRT_LT80, PRT_LT80, PRT_RB96, PRT_RB96, // PART_16x16_ORANGE_PUFF + + // Remaining two 32x32's in lower right quadrant (6,4) & (4,6) + PRT_LT96, PRT_LT64, PRT_RB128, PRT_RB96, // PART_32x32_BLOOD + PRT_LT64, PRT_LT96, PRT_RB96, PRT_RB128, // PART_32x32_GREENBLOOD + + // Remaining four 16x16's in lower right quadrant (6,6), (6, 7), (7, 6) and (7,7) + PRT_LT96, PRT_LT96, PRT_RB112, PRT_RB112, // PART_16x16_FIRE1, + PRT_LT112, PRT_LT96, PRT_RB128, PRT_RB112, // PART_16x16_FIRE2, + PRT_LT96, PRT_LT112, PRT_RB112, PRT_RB128, // PART_16x16_FIRE3, + PRT_LT112, PRT_LT112, PRT_RB128, PRT_RB128 // PART_16x16_GREENBLOOD, +}; + +// end \ No newline at end of file diff --git a/Toolkit/Programming/Tools/ref_common/r_Skeletons.c b/Toolkit/Programming/Tools/ref_common/r_Skeletons.c new file mode 100644 index 0000000..bed3230 --- /dev/null +++ b/Toolkit/Programming/Tools/ref_common/r_Skeletons.c @@ -0,0 +1,688 @@ +// +// r_Skeletons.c +// +// Copyright 1998 Raven Software +// +// Heretic II +// + +#include "q_fmodel.h" + +#include + +M_SkeletalCluster_t SkeletalClusters[MAX_ARRAYED_SKELETAL_JOINTS]; +ArrayedListNode_t ClusterNodes[MAX_ARRAYED_JOINT_NODES]; + +extern void *Hunk_Alloc (int size); + +void CreateSkeletonAsHunk(int structure, ModelSkeleton_t *skel) +{ + skel->rootJoint = Hunk_Alloc(numJointsInSkeleton[structure]*sizeof(M_SkeletalJoint_t)); + skel->rootNode = Hunk_Alloc(numNodesInSkeleton[structure]*sizeof(ArrayedListNode_t)); + + SkeletonCreators[structure](skel->rootJoint, sizeof(M_SkeletalJoint_t), skel->rootNode, 0); +} + +void CreateSkeletonInPlace(int structure, ModelSkeleton_t *skel) +{ + SkeletonCreators[structure](skel->rootJoint, sizeof(M_SkeletalJoint_t), skel->rootNode, 0); +} + +static int GetRootIndex(int max, int numJoints) +{ + int i, j, max2; + qboolean cont = false; + + for(i = 0; i < max; ++i) + { + if(!SkeletalClusters[i].inUse) + { + max2 = i + numJoints; + + // check the size of the array + if(max2 > max) + { + assert(0); + return -1; + } + + // check for a big enough unused block + for(j = i + 1; j < max2; ++j) + { + if(SkeletalClusters[j].inUse) + { + i = j; + cont = true; + break; + } + } + + if(cont) // not a big enough block, so continue searching + { + cont = false; + continue; + } + + // found a block, mark it as used + for(j = i; j < max2; ++j) + { + SkeletalClusters[j].inUse = true; + } + + return i; + } + } + + // couldn't find a block + assert(0); + return -1; +} + +int CreateSkeleton(int structure) +{ + int index; + + index = GetRootIndex(MAX_ARRAYED_SKELETAL_JOINTS, numJointsInSkeleton[structure]); + + SkeletonCreators[structure](SkeletalClusters, sizeof(M_SkeletalCluster_t), ClusterNodes, index); + + return index; +} + +void ClearSkeleton(ModelSkeleton_t *skel, int root) +{ + int child; + + for(child = skel->rootJoint[root].children; child != ARRAYEDLISTNODE_NULL; child = skel->rootNode[child].next) + { + ClearSkeleton(skel, skel->rootNode[child].data); + + FreeNode(skel->rootNode, child); + } + + skel->rootJoint[root].inUse = false; +} + +static void RotateModelSegment(M_SkeletalJoint_t *joint, vec3_t *modelVerticies, vec3_t angles, M_SkeletalCluster_t *modelCluster) +{ + int i; + matrix3_t rotation, rotation2, toWorld, partialBackToLocal; + vec3_t localAngles; + float roll, orig_roll; + +// Com_Printf("direction: %f, %f, %f\n", joint->model.direction[0], joint->model.direction[1], joint->model.direction[2]); + + localAngles[0] = angles[0]; + localAngles[1] = angles[1]; + orig_roll = localAngles[2] = angles[2]; + + memset(rotation, 0, sizeof(rotation)); + +#ifdef _REF_GL +#ifdef _DEBUG +#if 0 + { + float ref[3]; + paletteRGBA_t color; + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + VectorCopy(joint->model.origin, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 0; + color.a = 225; + VectorMA(joint->model.origin, 10.0, joint->model.direction, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + VectorMA(joint->model.origin, 10.0, joint->model.up, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + } +#endif +#endif +#endif + +// localAngles[ROLL] += Matricies3FromDirAndUp(joint->model.direction, joint->model.up, toWorld, partialBackToLocal); + localAngles[ROLL] += roll = Matricies3FromDirAndUp(joint->model.direction, joint->model.up, toWorld, partialBackToLocal); + +#ifdef _DEBUG +#if 0 + if(Q_fabs(roll) > 1.0) + { +// Com_Printf("direction: %f, %f, %f\n", joint->model.direction[0], joint->model.direction[1], joint->model.direction[2]); + Com_Printf("roll: %f, %f, %f\n", orig_roll, roll, localAngles[ROLL]); + } +#endif +#endif + + Matrix3FromAngles(localAngles, rotation); + +#ifdef _DEBUG +#if 0 + { + float ref[3]; + float ref2[3]; + paletteRGBA_t color; + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + VectorCopy(joint->model.origin, ref); + ref[0] += 50; + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 0; + color.a = 225; + VectorMA(joint->model.origin, 10.0, joint->model.direction, ref); + Matrix3MultByVec3(rotation, ref, ref2); + ref2[0] += 50; + ref2[2] += 50; + V_AddParticle(ref2, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + VectorMA(joint->model.origin, 10.0, joint->model.up, ref); + Matrix3MultByVec3(rotation, ref, ref2); + ref2[0] += 50; + ref2[2] += 50; + V_AddParticle(ref2, color, 1.0, 0); + } +#endif +#endif + + Matrix3MultByMatrix3(rotation, toWorld, rotation2); + +// Com_Printf("rotation matrix: %f, %f, %f\n", rotation2[0][0], rotation2[1][1], rotation2 +// [2][2]); + + Matrix3MultByMatrix3(partialBackToLocal, rotation2, rotation); + +#ifdef _DEBUG +#if 0 + { + float ref[3]; + float ref2[3]; + paletteRGBA_t color; + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + VectorCopy(joint->model.origin, ref); + ref[0] += 100; + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 0; + color.a = 225; + VectorMA(joint->model.origin, 10.0, joint->model.direction, ref); + Matrix3MultByVec3(rotation, ref, ref2); + ref2[0] += 100; + ref2[2] += 50; + V_AddParticle(ref2, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + VectorMA(joint->model.origin, 10.0, joint->model.up, ref); + Matrix3MultByVec3(rotation, ref, ref2); + ref2[0] += 100; + ref2[2] += 50; + V_AddParticle(ref2, color, 1.0, 0); + } +#endif +#endif + + for(i = 0; i < modelCluster->numVerticies; ++i) + { + RotatePointAboutLocalOrigin(rotation, joint->model.origin, modelVerticies[modelCluster->verticies[i]]); + } +} + +void RotateModelSegments(ModelSkeleton_t *skel, int jointIndex, int modelClusterIndex, int anglesIndex, + vec3_t *modelVerticies) +{ + int child, child2, jointChild; + M_SkeletalCluster_t *modelCluster; + CL_SkeletalJoint_t *modelJointAngles; + M_SkeletalJoint_t *joint; + + modelCluster = &SkeletalClusters[modelClusterIndex]; + modelJointAngles = &ri.skeletalJoints[anglesIndex]; + joint = skel->rootJoint + jointIndex; + + if(modelCluster->children != ARRAYEDLISTNODE_NULL) + { + assert(joint->children != ARRAYEDLISTNODE_NULL); +// assert(modelJointAngles->children != ARRAYEDLISTNODE_NULL); + + // hack here - to avoid a weird assert crash. + for(child = modelCluster->children, child2 = modelJointAngles->children, + jointChild = joint->children; + + ((child != ARRAYEDLISTNODE_NULL) && (child2 != ARRAYEDLISTNODE_NULL)); + + child = ClusterNodes[child].next, child2 = ri.jointNodes[child2].next, + jointChild = skel->rootNode[jointChild].next) + { +// assert(child2 != ARRAYEDLISTNODE_NULL); + assert(jointChild != ARRAYEDLISTNODE_NULL); + + RotateModelSegments(skel, skel->rootNode[jointChild].data, + ClusterNodes[child].data, ri.jointNodes[child2].data, modelVerticies); + } + } + + RotateModelSegment(joint, modelVerticies, modelJointAngles->angles, modelCluster); +} + +static void TransformPlacement(matrix3_t rotation, vec3_t origin, Placement_t *placement) +{ + RotatePointAboutLocalOrigin(rotation, origin, placement->origin); + RotatePointAboutLocalOrigin(rotation, origin, placement->direction); + RotatePointAboutLocalOrigin(rotation, origin, placement->up); +} + +static void RotateDecendents(ModelSkeleton_t *skel, M_SkeletalJoint_t *joint, M_SkeletalJoint_t *ancestor) +{ + int jointChild; + + for(jointChild = joint->children; jointChild != ARRAYEDLISTNODE_NULL; + jointChild = skel->rootNode[jointChild].next) + { + joint = skel->rootJoint + skel->rootNode[jointChild].data; + + TransformPlacement(ancestor->rotation, ancestor->parent.origin, &joint->parent); + + RotateDecendents(skel, joint, ancestor); + } +} + +static void RotateJoint(ModelSkeleton_t *skel, M_SkeletalJoint_t *joint, vec3_t angles) +{ + matrix3_t rotation, rotation2, toWorld, partialBackToLocal; + vec3_t localAngles; + + VectorCopy(angles, localAngles); + + memset(rotation, 0, sizeof(rotation)); + + localAngles[ROLL] += Matricies3FromDirAndUp(joint->model.direction, joint->model.up, toWorld, partialBackToLocal); + + Matrix3FromAngles(localAngles, rotation); + + Matrix3MultByMatrix3(rotation, toWorld, rotation2); + + Matrix3MultByMatrix3(partialBackToLocal, rotation2, joint->rotation); + + VectorCopy(joint->model.origin, joint->parent.origin); + + Matrix3MultByVec3(joint->rotation, joint->model.direction, joint->parent.direction); + Vec3ScaleAssign(10.0, joint->parent.direction); + Vec3AddAssign(joint->parent.origin, joint->parent.direction); + + Matrix3MultByVec3(joint->rotation, joint->model.up, joint->parent.up); + Vec3ScaleAssign(10.0, joint->parent.up); + Vec3AddAssign(joint->parent.origin, joint->parent.up); + + RotateDecendents(skel, joint, joint); +} + +void SetupJointRotations(ModelSkeleton_t *skel, int jointIndex, int anglesIndex) +{ + int child2, jointChild; + CL_SkeletalJoint_t *modelJointAngles; + M_SkeletalJoint_t *joint; + + modelJointAngles = &ri.skeletalJoints[anglesIndex]; + joint = skel->rootJoint + jointIndex; + + if(joint->children != ARRAYEDLISTNODE_NULL) + { + assert(modelJointAngles->children != ARRAYEDLISTNODE_NULL); + + for(child2 = modelJointAngles->children, jointChild = joint->children; + + child2 != ARRAYEDLISTNODE_NULL; + + child2 = ri.jointNodes[child2].next, + jointChild = skel->rootNode[jointChild].next) + { + assert(jointChild != ARRAYEDLISTNODE_NULL); + + SetupJointRotations(skel, skel->rootNode[jointChild].data, + ri.jointNodes[child2].data); + } + } + + RotateJoint(skel, joint, modelJointAngles->angles); +} + +void FinishJointRotations(ModelSkeleton_t *skel, int jointIndex) +{ + int jointChild; + M_SkeletalJoint_t *joint; + matrix3_t rotation, rotation2, toWorld, partialBackToLocal; + vec3_t localAngles; + + joint = skel->rootJoint + jointIndex; + + for(jointChild = joint->children; jointChild != ARRAYEDLISTNODE_NULL; + jointChild = skel->rootNode[jointChild].next) + { + FinishJointRotations(skel, skel->rootNode[jointChild].data); + } + + localAngles[YAW] = 0; + localAngles[PITCH] = 0; + + memset(rotation, 0, sizeof(rotation)); + +#ifdef _DEBUG +#if 0 + { + float ref[3]; + paletteRGBA_t color; + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + VectorCopy(joint->parent.origin, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 0; + color.a = 225; + VectorCopy(joint->parent.direction, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + VectorCopy(joint->parent.up, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + } +#endif +#endif + + Vec3SubtractAssign(joint->parent.origin, joint->parent.direction); + Vec3SubtractAssign(joint->parent.origin, joint->parent.up); + + VectorNormalize(joint->parent.direction); + VectorNormalize(joint->parent.up); + +#if 0 + if(joint->parent.direction[0] < 0) + { + Com_Printf("direction screwed %f %f %f\n", joint->parent.direction[0], + joint->parent.direction[1], joint->parent.direction[2]); + } +#endif + + localAngles[ROLL] = Matricies3FromDirAndUp(joint->parent.direction, joint->parent.up, toWorld, partialBackToLocal); + +#ifdef _DEBUG +#if 0 + if(Q_fabs(localAngles[ROLL]) > 1.0) + { + Com_Printf("direction: %f, %f, %f\n", joint->parent.direction[0], joint->parent.direction[1], joint->parent.direction[2]); + Com_Printf("roll: %f\n", localAngles[ROLL]); + } +#endif +#endif + Matricies3FromDirAndUp(joint->model.direction, joint->model.up, toWorld, NULL); + + Matrix3FromAngles(localAngles, rotation); + +#ifdef _DEBUG +#if 0 + { + float ref[3]; + float ref2[3]; + paletteRGBA_t color; + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + VectorCopy(joint->parent.origin, ref); + ref[0] += 50; + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 0; + color.a = 225; + VectorMA(joint->parent.origin, 10.0, joint->parent.direction, ref); + Matrix3MultByVec3(rotation, ref, ref2); + ref2[0] += 50; + ref2[2] += 50; + V_AddParticle(ref2, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + VectorMA(joint->parent.origin, 10.0, joint->parent.up, ref); + Matrix3MultByVec3(rotation, ref, ref2); + ref2[0] += 50; + ref2[2] += 50; + V_AddParticle(ref2, color, 1.0, 0); + } +#endif +#endif + + Matrix3MultByMatrix3(rotation, toWorld, rotation2); + + Matrix3MultByMatrix3(partialBackToLocal, rotation2, joint->rotation); +} + +void LinearllyInterpolateJoints(ModelSkeleton_t *newSkel, int newIndex, + ModelSkeleton_t *oldSkel, int oldIndex, ModelSkeleton_t *liSkel, int liIndex, + float move[3], float frontv[3], float backv[3]) +{ + M_SkeletalJoint_t *newJoint, *oldJoint, *liJoint; + int newChild, oldChild, liChild; + + newJoint = newSkel->rootJoint + newIndex; + oldJoint = oldSkel->rootJoint + oldIndex; + liJoint = liSkel->rootJoint + liIndex; + + if(newJoint->children != ARRAYEDLISTNODE_NULL) + { + assert(oldJoint->children != ARRAYEDLISTNODE_NULL); + assert(liJoint->children != ARRAYEDLISTNODE_NULL); + + for(newChild = newJoint->children, oldChild = oldJoint->children, + liChild = liJoint->children; + + newChild != ARRAYEDLISTNODE_NULL; + + newChild = newSkel->rootNode[newChild].next, + oldChild = oldSkel->rootNode[oldChild].next, + liChild = liSkel->rootNode[liChild].next) + { + assert(oldChild != ARRAYEDLISTNODE_NULL); + assert(liChild != ARRAYEDLISTNODE_NULL); + + LinearllyInterpolateJoints(newSkel, newSkel->rootNode[newChild].data, + oldSkel, oldSkel->rootNode[oldChild].data, liSkel, + liSkel->rootNode[liChild].data, move, frontv, backv); + } + } + + GL_LerpVert(newJoint->model.origin, oldJoint->model.origin, liJoint->model.origin, move, frontv, backv); + + // linerally interpolater direction and up vectors, which will unnormalize them relative to their local origin + GL_LerpVert(newJoint->model.direction, oldJoint->model.direction, liJoint->model.direction, move, frontv, backv); + GL_LerpVert(newJoint->model.up, oldJoint->model.up, liJoint->model.up, move, frontv, backv); + +#ifdef _DEBUG +#if 0 + { + float ref[3]; + paletteRGBA_t color; + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + VectorCopy(liJoint->model.origin, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 0; + color.a = 225; + VectorCopy(liJoint->model.direction, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + VectorCopy(liJoint->model.up, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + VectorCopy(newJoint->model.origin, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 0; + color.a = 225; + VectorCopy(newJoint->model.direction, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + VectorCopy(newJoint->model.up, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + VectorCopy(oldJoint->model.origin, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 0; + color.a = 225; + VectorCopy(oldJoint->model.direction, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + VectorCopy(oldJoint->model.up, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + } +#endif +#endif + + Vec3SubtractAssign(liJoint->model.origin, liJoint->model.direction); + Vec3SubtractAssign(liJoint->model.origin, liJoint->model.up); + + // renormalize them + Vec3Normalize(liJoint->model.direction); + Vec3Normalize(liJoint->model.up); + +#ifdef _DEBUG +#if 0 + { + float ref[3]; + paletteRGBA_t color; + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + VectorCopy(liJoint->model.origin, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 0; + color.a = 225; + VectorCopy(liJoint->model.direction, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + VectorCopy(liJoint->model.up, ref); + ref[2] += 50; + V_AddParticle(ref, color, 1.0, 0); + } +#endif +#endif + +} + +void SetupCompressedJoints(ModelSkeleton_t *liSkel, int liIndex, + float *lerp) +{ + M_SkeletalJoint_t *liJoint; + int liChild; + + liJoint = liSkel->rootJoint + liIndex; + + if(liJoint->children != ARRAYEDLISTNODE_NULL) + { + for(liChild = liJoint->children; liChild != ARRAYEDLISTNODE_NULL; + liChild = liSkel->rootNode[liChild].next) + { + SetupCompressedJoints(liSkel, liSkel->rootNode[liChild].data, lerp + 9); + } + } + + VectorCopy(lerp, liJoint->model.origin); + lerp+=3; + VectorCopy(lerp, liJoint->model.direction); + lerp+=3; + VectorCopy(lerp, liJoint->model.up); + +#if 0 + { + paletteRGBA_t color; + color.r = 255; + color.g = 0; + color.b = 0; + color.a = 255; + V_AddParticle(liJoint->model.origin, color, 1.0, 0); + color.r = 0; + color.a = 225; + V_AddParticle(liJoint->model.direction, color, 1.0, 0); + color.r = 255; + color.g = 255; + color.b = 255; + V_AddParticle(liJoint->model.up, color, 1.0, 0); + } +#endif + + Vec3SubtractAssign(liJoint->model.origin, liJoint->model.direction); + Vec3SubtractAssign(liJoint->model.origin, liJoint->model.up); + + // renormalize them + Vec3Normalize(liJoint->model.direction); + Vec3Normalize(liJoint->model.up); +} + +#if 0 +void DoJointRotations(int rootJoint, fmdl_t *pSegMod, vec3_t *lerped, vec3_t move, vec3_t frontv, + vec3_t backv) +{ + static M_SkeletalJoint_t temp_SkeletalJoints[MAX_JOINTS_PER_SKELETON]; + static ArrayedListNode_t temp_JointNodes[MAX_JOINT_NODES_PER_SKELETON]; + static ModelSkeleton_t liRootJoint = {temp_SkeletalJoints, temp_JointNodes}; + + CreateSkeletonInPlace(pSegMod->skeletalType, &liRootJoint); + + LinearllyInterpolateJoints(pSegMod->skeletons + currententity->frame, 0, + pSegMod->skeletons + currententity->oldframe, 0, &liRootJoint, 0, move, + frontv, backv); + + RotateModelSegments(&liRootJoint, 0, pSegMod->rootCluster, + rootJoint, lerped); + + ClearSkeleton(&liRootJoint, 0); +// free(liRootJoint); +} + +#endif \ No newline at end of file diff --git a/Toolkit/Programming/Tools/ref_common/r_Skeletons.h b/Toolkit/Programming/Tools/ref_common/r_Skeletons.h new file mode 100644 index 0000000..6e697ac --- /dev/null +++ b/Toolkit/Programming/Tools/ref_common/r_Skeletons.h @@ -0,0 +1,30 @@ +#ifndef M_SKELETON_H +#define M_SKELETON_H +#include "m_Skeleton.h" +#endif +#ifndef M_SKELETALCLUSTER_H +#define M_SKELETALCLUSTER_H +#include "m_SkeletalCluster.h" +#endif +#ifndef SKELETONS_H +#define SKELETONS_H +#include "Skeletons.h" +#endif + +extern M_SkeletalCluster_t SkeletalClusters[MAX_ARRAYED_SKELETAL_JOINTS]; +extern struct ArrayedListNode_s ClusterNodes[MAX_ARRAYED_JOINT_NODES]; + +int CreateSkeleton(int structure); +void CreateSkeletonAsHunk(int structure, ModelSkeleton_t *skel); +void CreateSkeletonInPlace(int structure, ModelSkeleton_t *skel); +void ClearSkeleton(ModelSkeleton_t *skel, int root); + +void SetupJointRotations(ModelSkeleton_t *skel, int jointIndex, int anglesIndex); +void FinishJointRotations(ModelSkeleton_t *skel, int jointIndex); +void LinearllyInterpolateJoints(ModelSkeleton_t *newSkel, int newIndex, + ModelSkeleton_t *oldSkel, int oldIndex, ModelSkeleton_t *liSkel, int liIndex, + float move[3], float frontv[3], float backv[3]); +void SetupCompressedJoints(ModelSkeleton_t *liSkel, int liIndex, + float *lerp); +void RotateModelSegments(ModelSkeleton_t *skel, int jointIndex, int modelClusterIndex, int anglesIndex, + vec3_t *modelVerticies); \ No newline at end of file diff --git a/base/cinematics/messages.txt b/base/cinematics/messages.txt new file mode 100644 index 0000000..e69de29